@farming-labs/docs 0.2.62 → 0.2.64

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 (58) hide show
  1. package/dist/agent-CQTH7NFu.mjs +624 -0
  2. package/dist/agent-DKKptIgy.mjs +4365 -0
  3. package/dist/agent-evals-B7MIxuEX.mjs +2144 -0
  4. package/dist/agent-export-CBgWgPvH.mjs +910 -0
  5. package/dist/agent-scope-C_U--OZ7.mjs +283 -0
  6. package/dist/agent-skills-bundle.d.mts +13 -0
  7. package/dist/agent-skills-bundle.mjs +12 -0
  8. package/dist/agent-skills-server-CPja6Syt.d.mts +14 -0
  9. package/dist/agent-skills-server-DraIb6FV.mjs +415 -0
  10. package/dist/agent-skills-vite.d.mts +31 -0
  11. package/dist/agent-skills-vite.mjs +70 -0
  12. package/dist/agents-XWZBub6f.mjs +221 -0
  13. package/dist/analytics-Bx44lg6d.mjs +177 -0
  14. package/dist/cli/index.d.mts +15 -0
  15. package/dist/cli/index.mjs +452 -0
  16. package/dist/client/react.d.mts +45 -0
  17. package/dist/client/react.mjs +223 -0
  18. package/dist/cloud-analytics-CSyFE6SS.mjs +132 -0
  19. package/dist/cloud-ask-ai-sbpjOR2K.mjs +382 -0
  20. package/dist/cloud-ask-ai-zpwkdwnF.d.mts +23 -0
  21. package/dist/cloud-pdNC-tyj.mjs +1615 -0
  22. package/dist/code-blocks-DnNVNK2M.mjs +871 -0
  23. package/dist/codeblocks-CFuurVIH.mjs +250 -0
  24. package/dist/config-Wcdj-D0a.mjs +369 -0
  25. package/dist/dev-Cmy6DtdF.mjs +1333 -0
  26. package/dist/docs-cloud-server.d.mts +70 -0
  27. package/dist/docs-cloud-server.mjs +310 -0
  28. package/dist/doctor-DtGYZ41i.mjs +2036 -0
  29. package/dist/downgrade-w7e6Se0L.mjs +184 -0
  30. package/dist/errors-DbOhkE1h.mjs +20 -0
  31. package/dist/golden-evaluations-Dj-9Eo3v.mjs +1785 -0
  32. package/dist/i18n-CCaFUnAN.mjs +40 -0
  33. package/dist/index.d.mts +1150 -0
  34. package/dist/index.mjs +10 -0
  35. package/dist/init-CQY0Woe3.mjs +1264 -0
  36. package/dist/mcp-B9dcsivk.mjs +156 -0
  37. package/dist/mcp.d.mts +298 -0
  38. package/dist/mcp.mjs +4430 -0
  39. package/dist/metadata-DWExHQnx.mjs +237 -0
  40. package/dist/package-version-n5AFur8a.mjs +128 -0
  41. package/dist/reading-time-CYZ5VvKU.mjs +742 -0
  42. package/dist/review-CLoHTywU.mjs +673 -0
  43. package/dist/robots-BIpC4j4P.mjs +201 -0
  44. package/dist/robots-CUTahhoY.mjs +179 -0
  45. package/dist/search-B6V6qtiI.mjs +1826 -0
  46. package/dist/search-CaSyi6H6.d.mts +279 -0
  47. package/dist/search-DSjCeOk7.mjs +104 -0
  48. package/dist/server.d.mts +343 -0
  49. package/dist/server.mjs +14 -0
  50. package/dist/sitemap-Cykpe3Tz.mjs +249 -0
  51. package/dist/sitemap-server-C_6Wes83.mjs +1137 -0
  52. package/dist/standards-discovery-C4HUqMd2.d.mts +227 -0
  53. package/dist/standards-discovery-jkykaXq1.mjs +519 -0
  54. package/dist/templates-Bq_P7ctv.mjs +2465 -0
  55. package/dist/types-lMBIdZg0.d.mts +3315 -0
  56. package/dist/upgrade-oz-GChgt.mjs +56 -0
  57. package/dist/utils-DpiIioYb.mjs +225 -0
  58. package/package.json +1 -1
@@ -0,0 +1,4365 @@
1
+ import { C as buildDocsApiCatalog, E as createDocsStandardsResponse, O as isDocsStandardsDiscoveryRequest, a as DEFAULT_A2A_AGENT_CARD_ROUTE, c as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, g as DEFAULT_API_CATALOG_ROUTE, h as DEFAULT_API_CATALOG_FORMAT, k as resolveDocsDiscoveryApiRoute, l as DEFAULT_AGENT_SKILLS_ROUTE_PATTERN, n as API_CATALOG_MEDIA_TYPE, o as DEFAULT_AGENT_SKILLS_ARCHIVE_ROUTE_PATTERN, r as API_CATALOG_PROFILE_URI, s as DEFAULT_AGENT_SKILLS_INDEX_FORMAT, t as AGENT_SKILLS_DISCOVERY_SCHEMA_URI, v as DEFAULT_LEGACY_SKILLS_INDEX_ROUTE } from "./standards-discovery-jkykaXq1.mjs";
2
+ import { createProcessor } from "@mdx-js/mdx";
3
+
4
+ //#region src/mcp-auth.ts
5
+ const DEFAULT_MCP_ROUTE = "/api/docs/mcp";
6
+ const DEFAULT_MCP_PUBLIC_ROUTE = "/mcp";
7
+ const DEFAULT_MCP_WELL_KNOWN_ROUTE = "/.well-known/mcp";
8
+ const DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE = "/.well-known/oauth-protected-resource";
9
+ function normalizeDocsMcpEndpointPath(route, fallback = DEFAULT_MCP_ROUTE) {
10
+ const normalized = `/${route?.trim().split(/[?#]/, 1)[0] || fallback}`.replace(/\/+/g, "/");
11
+ return normalized !== "/" ? normalized.replace(/\/+$/, "") : fallback;
12
+ }
13
+ function getDocsMcpResourcePaths(route) {
14
+ return Array.from(new Set([
15
+ normalizeDocsMcpEndpointPath(route),
16
+ DEFAULT_MCP_PUBLIC_ROUTE,
17
+ DEFAULT_MCP_WELL_KNOWN_ROUTE
18
+ ]));
19
+ }
20
+ function buildDocsMcpProtectedResourceMetadataRoute(resourcePath) {
21
+ const candidate = resourcePath.trim().split(/[?#]/, 1)[0] || "/";
22
+ const trailingSlash = candidate.length > 1 && candidate.endsWith("/");
23
+ const normalized = candidate === "/" ? "/" : normalizeDocsMcpEndpointPath(candidate);
24
+ return normalized === "/" ? DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE : `${DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE}${normalized}${trailingSlash ? "/" : ""}`;
25
+ }
26
+ function getDocsMcpProtectedResourceMetadataRoutes(route) {
27
+ return getDocsMcpResourcePaths(route).map(buildDocsMcpProtectedResourceMetadataRoute);
28
+ }
29
+ function hasDocsMcpProtectedResourceConfig(mcp) {
30
+ if (!mcp || typeof mcp !== "object" || mcp.enabled === false || typeof mcp.security?.authenticate !== "function") return false;
31
+ return normalizeDocsMcpAuthorizationServerUrls(mcp.security?.protectedResource?.authorizationServers).length > 0;
32
+ }
33
+ function normalizeDocsMcpAuthorizationServerUrls(values) {
34
+ if (!Array.isArray(values)) return [];
35
+ return Array.from(new Set(values.filter((value) => typeof value === "string").map((value) => value.trim()).filter(isAbsoluteHttpUrl)));
36
+ }
37
+ function isDocsMcpOAuthScopeToken(value) {
38
+ return typeof value === "string" && /^[\x21\x23-\x5B\x5D-\x7E]+$/u.test(value);
39
+ }
40
+ function isDocsMcpRequest(url, mcp) {
41
+ const route = typeof mcp === "object" ? mcp.route : void 0;
42
+ if (isDocsMcpResourcePath(url.pathname, route)) return true;
43
+ return hasDocsMcpProtectedResourceConfig(mcp) && isDocsMcpProtectedResourceMetadataRequestPath(url.pathname, route);
44
+ }
45
+ function isDocsMcpResourcePath(pathname, route) {
46
+ return isCanonicalResourcePath(pathname, getDocsMcpResourcePaths(route));
47
+ }
48
+ function resolveDocsMcpResourceLocation(request, route) {
49
+ const requestUrl = new URL(request.url);
50
+ const allowedPaths = getDocsMcpResourcePaths(route);
51
+ const normalizedRequestPath = normalizeRequestPath(requestUrl.pathname);
52
+ const resourcePath = isCanonicalResourcePath(requestUrl.pathname, allowedPaths) ? requestUrl.pathname : normalizedRequestPath;
53
+ const resourceUrl = new URL(requestUrl);
54
+ resourceUrl.pathname = resourcePath;
55
+ const metadataUrl = new URL(resourceUrl);
56
+ metadataUrl.pathname = buildDocsMcpProtectedResourceMetadataRoute(resourcePath);
57
+ return {
58
+ resourceUrl,
59
+ metadataUrl
60
+ };
61
+ }
62
+ function resolveDocsMcpProtectedResourceMetadataLocation(request, route) {
63
+ const rawUrl = new URL(request.url);
64
+ const allowedPaths = getDocsMcpResourcePaths(route);
65
+ if (!rawUrl.pathname.startsWith(`${DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE}/`)) return;
66
+ const requestedResourcePath = rawUrl.pathname.slice(37);
67
+ if (!isCanonicalResourcePath(requestedResourcePath, allowedPaths)) return void 0;
68
+ const metadataUrl = new URL(rawUrl);
69
+ const resourceUrl = new URL(metadataUrl);
70
+ resourceUrl.pathname = requestedResourcePath;
71
+ return {
72
+ resourceUrl,
73
+ metadataUrl
74
+ };
75
+ }
76
+ function isDocsMcpProtectedResourceMetadataPath(pathname) {
77
+ const normalized = normalizeRequestPath(pathname);
78
+ return normalized === DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE || normalized.startsWith(`${DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE}/`);
79
+ }
80
+ function normalizeRequestPath(pathname) {
81
+ const normalized = `/${pathname}`.replace(/\/+/g, "/");
82
+ return normalized === "/" ? normalized : normalized.replace(/\/+$/, "");
83
+ }
84
+ function isCanonicalResourcePath(pathname, resourcePaths) {
85
+ return resourcePaths.some((resourcePath) => pathname === resourcePath || resourcePath !== "/" && pathname === `${resourcePath}/`);
86
+ }
87
+ function isDocsMcpProtectedResourceMetadataRequestPath(pathname, route) {
88
+ if (!pathname.startsWith(`${DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE}/`)) return false;
89
+ return isCanonicalResourcePath(pathname.slice(37), getDocsMcpResourcePaths(route));
90
+ }
91
+ function isAbsoluteHttpUrl(value) {
92
+ try {
93
+ const url = new URL(value);
94
+ const loopbackHttp = url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]");
95
+ return (url.protocol === "https:" || loopbackHttp) && !url.username && !url.password && !url.search && !url.hash;
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
100
+
101
+ //#endregion
102
+ //#region src/agent-contract.ts
103
+ const PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS = [
104
+ "task",
105
+ "outcome",
106
+ "appliesTo",
107
+ "prerequisites",
108
+ "files",
109
+ "commands",
110
+ "sideEffects",
111
+ "verification",
112
+ "rollback",
113
+ "failureModes"
114
+ ];
115
+ const PAGE_AGENT_CONTRACT_FIELDS = ["tokenBudget", ...PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS];
116
+ const PAGE_AGENT_CONTRACT_FIELD_SCHEMA = {
117
+ tokenBudget: "number",
118
+ task: "string",
119
+ outcome: "string",
120
+ appliesTo: {
121
+ framework: "string|string[]",
122
+ version: "string|string[]",
123
+ package: "string|string[]"
124
+ },
125
+ prerequisites: "string[]",
126
+ files: "string[]",
127
+ commands: "Array<string|{run,cwd?,description?}>",
128
+ sideEffects: "string[]",
129
+ verification: "Array<string|{description?,run?,expect?}>",
130
+ rollback: "string[]",
131
+ failureModes: "Array<string|{symptom,resolution?}>"
132
+ };
133
+ const APPLIES_TO_FIELDS = [
134
+ "framework",
135
+ "version",
136
+ "package"
137
+ ];
138
+ const COMMAND_FIELDS = [
139
+ "run",
140
+ "cwd",
141
+ "description"
142
+ ];
143
+ const VERIFICATION_FIELDS = [
144
+ "description",
145
+ "run",
146
+ "expect"
147
+ ];
148
+ const FAILURE_MODE_FIELDS = ["symptom", "resolution"];
149
+ const PAGE_AGENT_CONTRACT_START_MARKER = "<!-- farming-labs:agent-contract:start -->";
150
+ const PAGE_AGENT_CONTRACT_END_MARKER = "<!-- farming-labs:agent-contract:end -->";
151
+ function isRecord(value) {
152
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
153
+ }
154
+ function normalizeString(value) {
155
+ if (typeof value !== "string") return void 0;
156
+ return value.trim() || void 0;
157
+ }
158
+ function normalizeStringList(value) {
159
+ if (!Array.isArray(value)) return void 0;
160
+ const seen = /* @__PURE__ */ new Set();
161
+ const normalized = [];
162
+ for (const item of value) {
163
+ const text = normalizeString(item);
164
+ if (!text || seen.has(text)) continue;
165
+ seen.add(text);
166
+ normalized.push(text);
167
+ }
168
+ return normalized.length > 0 ? normalized : void 0;
169
+ }
170
+ function normalizeStringOrList(value) {
171
+ const single = normalizeString(value);
172
+ if (single) return [single];
173
+ return normalizeStringList(value);
174
+ }
175
+ function normalizeAppliesTo(value) {
176
+ if (!isRecord(value)) return void 0;
177
+ const framework = normalizeStringOrList(value.framework);
178
+ const version = normalizeStringOrList(value.version);
179
+ const packageNames = normalizeStringOrList(value.package);
180
+ if (!framework && !version && !packageNames) return void 0;
181
+ return {
182
+ ...framework ? { framework } : {},
183
+ ...version ? { version } : {},
184
+ ...packageNames ? { package: packageNames } : {}
185
+ };
186
+ }
187
+ function normalizeCommands(value) {
188
+ if (!Array.isArray(value)) return void 0;
189
+ const commands = [];
190
+ for (const item of value) {
191
+ const shorthand = normalizeString(item);
192
+ if (shorthand) {
193
+ commands.push(shorthand);
194
+ continue;
195
+ }
196
+ if (!isRecord(item)) continue;
197
+ const run = normalizeString(item.run);
198
+ if (!run) continue;
199
+ const cwd = normalizeString(item.cwd);
200
+ const description = normalizeString(item.description);
201
+ commands.push({
202
+ run,
203
+ ...cwd ? { cwd } : {},
204
+ ...description ? { description } : {}
205
+ });
206
+ }
207
+ return commands.length > 0 ? commands : void 0;
208
+ }
209
+ function normalizeVerification(value) {
210
+ if (!Array.isArray(value)) return void 0;
211
+ const verification = [];
212
+ for (const item of value) {
213
+ const shorthand = normalizeString(item);
214
+ if (shorthand) {
215
+ verification.push(shorthand);
216
+ continue;
217
+ }
218
+ if (!isRecord(item)) continue;
219
+ const description = normalizeString(item.description);
220
+ const run = normalizeString(item.run);
221
+ const expect = normalizeString(item.expect);
222
+ if (!description && !run && !expect) continue;
223
+ verification.push({
224
+ ...description ? { description } : {},
225
+ ...run ? { run } : {},
226
+ ...expect ? { expect } : {}
227
+ });
228
+ }
229
+ return verification.length > 0 ? verification : void 0;
230
+ }
231
+ function normalizeFailureModes(value) {
232
+ if (!Array.isArray(value)) return void 0;
233
+ const failureModes = [];
234
+ for (const item of value) {
235
+ const shorthand = normalizeString(item);
236
+ if (shorthand) {
237
+ failureModes.push(shorthand);
238
+ continue;
239
+ }
240
+ if (!isRecord(item)) continue;
241
+ const symptom = normalizeString(item.symptom);
242
+ if (!symptom) continue;
243
+ const resolution = normalizeString(item.resolution);
244
+ failureModes.push({
245
+ symptom,
246
+ ...resolution ? { resolution } : {}
247
+ });
248
+ }
249
+ return failureModes.length > 0 ? failureModes : void 0;
250
+ }
251
+ function normalizeTokenBudget(value) {
252
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
253
+ return Math.ceil(value);
254
+ }
255
+ /**
256
+ * Normalize untrusted page frontmatter into the stable agent contract shape.
257
+ * Invalid fields are omitted so malformed author input cannot break page delivery.
258
+ */
259
+ function normalizePageAgentFrontmatter(value) {
260
+ if (!isRecord(value)) return void 0;
261
+ const tokenBudget = normalizeTokenBudget(value.tokenBudget);
262
+ const task = normalizeString(value.task);
263
+ const outcome = normalizeString(value.outcome);
264
+ const appliesTo = normalizeAppliesTo(value.appliesTo);
265
+ const prerequisites = normalizeStringList(value.prerequisites);
266
+ const files = normalizeStringList(value.files);
267
+ const commands = normalizeCommands(value.commands);
268
+ const sideEffects = normalizeStringList(value.sideEffects);
269
+ const verification = normalizeVerification(value.verification);
270
+ const rollback = normalizeStringList(value.rollback);
271
+ const failureModes = normalizeFailureModes(value.failureModes);
272
+ const normalized = {
273
+ ...tokenBudget !== void 0 ? { tokenBudget } : {},
274
+ ...task ? { task } : {},
275
+ ...outcome ? { outcome } : {},
276
+ ...appliesTo ? { appliesTo } : {},
277
+ ...prerequisites ? { prerequisites } : {},
278
+ ...files ? { files } : {},
279
+ ...commands ? { commands } : {},
280
+ ...sideEffects ? { sideEffects } : {},
281
+ ...verification ? { verification } : {},
282
+ ...rollback ? { rollback } : {},
283
+ ...failureModes ? { failureModes } : {}
284
+ };
285
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
286
+ }
287
+ function hasStructuredPageAgentContract(value) {
288
+ const normalized = normalizePageAgentFrontmatter(value);
289
+ if (!normalized) return false;
290
+ return PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS.some((field) => normalized[field] !== void 0);
291
+ }
292
+ function addStringIssue(issues, object, field) {
293
+ if (!(field in object)) return;
294
+ if (!normalizeString(object[field])) issues.push({
295
+ path: `agent.${field}`,
296
+ message: "must be a non-empty string"
297
+ });
298
+ }
299
+ function addStringListIssues(issues, object, field) {
300
+ if (!(field in object)) return;
301
+ const value = object[field];
302
+ if (!Array.isArray(value) || value.length === 0) {
303
+ issues.push({
304
+ path: `agent.${field}`,
305
+ message: "must be a non-empty string array"
306
+ });
307
+ return;
308
+ }
309
+ value.forEach((item, index) => {
310
+ if (!normalizeString(item)) issues.push({
311
+ path: `agent.${field}[${index}]`,
312
+ message: "must be a non-empty string"
313
+ });
314
+ });
315
+ }
316
+ function editDistance(left, right) {
317
+ const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
318
+ for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
319
+ const current = [leftIndex];
320
+ for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) current[rightIndex] = Math.min((current[rightIndex - 1] ?? 0) + 1, (previous[rightIndex] ?? 0) + 1, (previous[rightIndex - 1] ?? 0) + (left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1));
321
+ previous.splice(0, previous.length, ...current);
322
+ }
323
+ return previous[right.length] ?? 0;
324
+ }
325
+ function closestKnownField(field, allowed) {
326
+ const closest = allowed.map((candidate) => ({
327
+ candidate,
328
+ distance: editDistance(field, candidate)
329
+ })).sort((left, right) => left.distance - right.distance || left.candidate.localeCompare(right.candidate))[0];
330
+ if (!closest) return void 0;
331
+ const threshold = Math.max(1, Math.min(3, Math.floor(closest.candidate.length / 3)));
332
+ return closest.distance <= threshold ? closest.candidate : void 0;
333
+ }
334
+ function addUnknownKeyIssues(issues, object, allowed, path) {
335
+ for (const field of Object.keys(object)) {
336
+ if (allowed.includes(field)) continue;
337
+ const suggestion = closestKnownField(field, allowed);
338
+ issues.push({
339
+ path: `${path}.${field}`,
340
+ message: suggestion ? `is not recognized; did you mean "${path}.${suggestion}"?` : "is not recognized"
341
+ });
342
+ }
343
+ }
344
+ /** Return author-facing validation issues without throwing. */
345
+ function getPageAgentFrontmatterIssues(value) {
346
+ if (value === void 0) return [];
347
+ if (!isRecord(value)) return [{
348
+ path: "agent",
349
+ message: "must be an object"
350
+ }];
351
+ const issues = [];
352
+ addUnknownKeyIssues(issues, value, PAGE_AGENT_CONTRACT_FIELDS, "agent");
353
+ if ("tokenBudget" in value && (typeof value.tokenBudget !== "number" || !Number.isFinite(value.tokenBudget) || value.tokenBudget <= 0)) issues.push({
354
+ path: "agent.tokenBudget",
355
+ message: "must be a positive finite number"
356
+ });
357
+ addStringIssue(issues, value, "task");
358
+ addStringIssue(issues, value, "outcome");
359
+ if ("appliesTo" in value) if (!isRecord(value.appliesTo)) issues.push({
360
+ path: "agent.appliesTo",
361
+ message: "must be an object"
362
+ });
363
+ else {
364
+ addUnknownKeyIssues(issues, value.appliesTo, APPLIES_TO_FIELDS, "agent.appliesTo");
365
+ for (const field of [
366
+ "framework",
367
+ "version",
368
+ "package"
369
+ ]) {
370
+ if (!(field in value.appliesTo)) continue;
371
+ const fieldValue = value.appliesTo[field];
372
+ if (!normalizeStringOrList(fieldValue)) {
373
+ issues.push({
374
+ path: `agent.appliesTo.${field}`,
375
+ message: "must be a non-empty string or string array"
376
+ });
377
+ continue;
378
+ }
379
+ if (Array.isArray(fieldValue)) fieldValue.forEach((item, index) => {
380
+ if (!normalizeString(item)) issues.push({
381
+ path: `agent.appliesTo.${field}[${index}]`,
382
+ message: "must be a non-empty string"
383
+ });
384
+ });
385
+ }
386
+ if (!normalizeAppliesTo(value.appliesTo)) issues.push({
387
+ path: "agent.appliesTo",
388
+ message: "must include framework, version, or package"
389
+ });
390
+ }
391
+ for (const field of [
392
+ "prerequisites",
393
+ "files",
394
+ "sideEffects",
395
+ "rollback"
396
+ ]) addStringListIssues(issues, value, field);
397
+ if ("commands" in value) if (!Array.isArray(value.commands) || value.commands.length === 0) issues.push({
398
+ path: "agent.commands",
399
+ message: "must be a non-empty array"
400
+ });
401
+ else value.commands.forEach((command, index) => {
402
+ if (normalizeString(command)) return;
403
+ if (!isRecord(command)) {
404
+ issues.push({
405
+ path: `agent.commands[${index}]`,
406
+ message: "must be a command string or an object with a non-empty run field"
407
+ });
408
+ return;
409
+ }
410
+ addUnknownKeyIssues(issues, command, COMMAND_FIELDS, `agent.commands[${index}]`);
411
+ if (!normalizeString(command.run)) {
412
+ issues.push({
413
+ path: `agent.commands[${index}]`,
414
+ message: "must be a command string or an object with a non-empty run field"
415
+ });
416
+ return;
417
+ }
418
+ for (const field of ["cwd", "description"]) if (field in command && !normalizeString(command[field])) issues.push({
419
+ path: `agent.commands[${index}].${field}`,
420
+ message: "must be a non-empty string"
421
+ });
422
+ });
423
+ if ("verification" in value) if (!Array.isArray(value.verification) || value.verification.length === 0) issues.push({
424
+ path: "agent.verification",
425
+ message: "must be a non-empty array"
426
+ });
427
+ else value.verification.forEach((step, index) => {
428
+ if (normalizeString(step)) return;
429
+ if (!isRecord(step)) {
430
+ issues.push({
431
+ path: `agent.verification[${index}]`,
432
+ message: "must be a string or an object with description, run, or expect"
433
+ });
434
+ return;
435
+ }
436
+ addUnknownKeyIssues(issues, step, VERIFICATION_FIELDS, `agent.verification[${index}]`);
437
+ if (!normalizeVerification([step])) {
438
+ issues.push({
439
+ path: `agent.verification[${index}]`,
440
+ message: "must be a string or an object with description, run, or expect"
441
+ });
442
+ return;
443
+ }
444
+ for (const field of [
445
+ "description",
446
+ "run",
447
+ "expect"
448
+ ]) if (field in step && !normalizeString(step[field])) issues.push({
449
+ path: `agent.verification[${index}].${field}`,
450
+ message: "must be a non-empty string"
451
+ });
452
+ });
453
+ if ("failureModes" in value) if (!Array.isArray(value.failureModes) || value.failureModes.length === 0) issues.push({
454
+ path: "agent.failureModes",
455
+ message: "must be a non-empty array"
456
+ });
457
+ else value.failureModes.forEach((mode, index) => {
458
+ if (normalizeString(mode)) return;
459
+ if (!isRecord(mode)) {
460
+ issues.push({
461
+ path: `agent.failureModes[${index}]`,
462
+ message: "must be a string or an object with a non-empty symptom field"
463
+ });
464
+ return;
465
+ }
466
+ addUnknownKeyIssues(issues, mode, FAILURE_MODE_FIELDS, `agent.failureModes[${index}]`);
467
+ if (!normalizeString(mode.symptom)) {
468
+ issues.push({
469
+ path: `agent.failureModes[${index}]`,
470
+ message: "must be a string or an object with a non-empty symptom field"
471
+ });
472
+ return;
473
+ }
474
+ if ("resolution" in mode && !normalizeString(mode.resolution)) issues.push({
475
+ path: `agent.failureModes[${index}].resolution`,
476
+ message: "must be a non-empty string"
477
+ });
478
+ });
479
+ return issues;
480
+ }
481
+ function yamlString(value) {
482
+ return JSON.stringify(value);
483
+ }
484
+ function renderYamlStringList(lines, indent, key, values) {
485
+ lines.push(`${indent}${key}:`);
486
+ for (const value of values) lines.push(`${indent} - ${yamlString(value)}`);
487
+ }
488
+ function renderYamlObjectList(lines, indent, key, values, fields) {
489
+ lines.push(`${indent}${key}:`);
490
+ for (const value of values) {
491
+ if (typeof value === "string") {
492
+ lines.push(`${indent} - ${yamlString(value)}`);
493
+ continue;
494
+ }
495
+ const record = value;
496
+ const firstField = fields.find((field) => normalizeString(record[field]));
497
+ if (!firstField) continue;
498
+ lines.push(`${indent} - ${firstField}: ${yamlString(normalizeString(record[firstField]))}`);
499
+ for (const field of fields) {
500
+ const fieldValue = normalizeString(record[field]);
501
+ if (field === firstField || !fieldValue) continue;
502
+ lines.push(`${indent} ${field}: ${yamlString(fieldValue)}`);
503
+ }
504
+ }
505
+ }
506
+ /** Render normalized `agent` YAML in a stable field order. */
507
+ function renderPageAgentFrontmatterYamlLines(value, indentation = 0) {
508
+ const agent = normalizePageAgentFrontmatter(value);
509
+ if (!agent) return [];
510
+ const indent = " ".repeat(Math.max(0, indentation));
511
+ const child = `${indent} `;
512
+ const lines = [`${indent}agent:`];
513
+ if (agent.tokenBudget !== void 0) lines.push(`${child}tokenBudget: ${agent.tokenBudget}`);
514
+ if (agent.task) lines.push(`${child}task: ${yamlString(agent.task)}`);
515
+ if (agent.outcome) lines.push(`${child}outcome: ${yamlString(agent.outcome)}`);
516
+ if (agent.appliesTo) {
517
+ lines.push(`${child}appliesTo:`);
518
+ const appliesIndent = `${child} `;
519
+ for (const field of [
520
+ "framework",
521
+ "version",
522
+ "package"
523
+ ]) {
524
+ const values = normalizeStringOrList(agent.appliesTo[field]);
525
+ if (values) renderYamlStringList(lines, appliesIndent, field, values);
526
+ }
527
+ }
528
+ if (agent.prerequisites) renderYamlStringList(lines, child, "prerequisites", agent.prerequisites);
529
+ if (agent.files) renderYamlStringList(lines, child, "files", agent.files);
530
+ if (agent.commands) renderYamlObjectList(lines, child, "commands", agent.commands, [
531
+ "run",
532
+ "cwd",
533
+ "description"
534
+ ]);
535
+ if (agent.sideEffects) renderYamlStringList(lines, child, "sideEffects", agent.sideEffects);
536
+ if (agent.verification) renderYamlObjectList(lines, child, "verification", agent.verification, [
537
+ "description",
538
+ "run",
539
+ "expect"
540
+ ]);
541
+ if (agent.rollback) renderYamlStringList(lines, child, "rollback", agent.rollback);
542
+ if (agent.failureModes) renderYamlObjectList(lines, child, "failureModes", agent.failureModes, ["symptom", "resolution"]);
543
+ return lines;
544
+ }
545
+ function inlineCode(value) {
546
+ const longestRun = Math.max(0, ...[...value.matchAll(/`+/g)].map((match) => match[0].length));
547
+ const fence = "`".repeat(longestRun + 1);
548
+ const padding = value.startsWith("`") || value.endsWith("`") ? " " : "";
549
+ return `${fence}${padding}${value}${padding}${fence}`;
550
+ }
551
+ function renderTextList(lines, title, values, code = false) {
552
+ lines.push("", `### ${title}`, "");
553
+ for (const value of values) lines.push(`- ${code ? inlineCode(value) : value}`);
554
+ }
555
+ /** Render the structured contract as deterministic, compact machine-readable Markdown. */
556
+ function renderPageAgentContractMarkdown(value) {
557
+ const agent = normalizePageAgentFrontmatter(value);
558
+ if (!agent || !hasStructuredPageAgentContract(agent)) return "";
559
+ const lines = [PAGE_AGENT_CONTRACT_START_MARKER, "## Agent Contract"];
560
+ if (agent.task) lines.push("", `Task: ${agent.task}`);
561
+ if (agent.outcome) lines.push(`Outcome: ${agent.outcome}`);
562
+ if (agent.appliesTo) {
563
+ lines.push("", "### Applies To", "");
564
+ for (const [label, field] of [
565
+ ["Framework", "framework"],
566
+ ["Version", "version"],
567
+ ["Package", "package"]
568
+ ]) {
569
+ const values = normalizeStringOrList(agent.appliesTo[field]);
570
+ if (values) lines.push(`- ${label}: ${values.map(inlineCode).join(", ")}`);
571
+ }
572
+ }
573
+ if (agent.prerequisites) renderTextList(lines, "Prerequisites", agent.prerequisites);
574
+ if (agent.files) renderTextList(lines, "Files", agent.files, true);
575
+ if (agent.commands) {
576
+ lines.push("", "### Commands", "");
577
+ for (const command of agent.commands) {
578
+ if (typeof command === "string") {
579
+ lines.push(`- ${inlineCode(command)}`);
580
+ continue;
581
+ }
582
+ const details = [command.cwd ? `cwd ${inlineCode(command.cwd)}` : void 0, command.description].filter(Boolean);
583
+ lines.push(`- ${inlineCode(command.run)}${details.length ? ` — ${details.join("; ")}` : ""}`);
584
+ }
585
+ }
586
+ if (agent.sideEffects) renderTextList(lines, "Side Effects", agent.sideEffects);
587
+ if (agent.verification) {
588
+ lines.push("", "### Verification", "");
589
+ for (const step of agent.verification) {
590
+ if (typeof step === "string") {
591
+ lines.push(`- ${step}`);
592
+ continue;
593
+ }
594
+ const summary = step.description ?? (step.run ? `Run ${inlineCode(step.run)}` : step.expect ?? "Verification step");
595
+ lines.push(`- ${summary}`);
596
+ if (step.run && step.description) lines.push(` - Run: ${inlineCode(step.run)}`);
597
+ if (step.expect && step.expect !== summary) lines.push(` - Expected: ${step.expect}`);
598
+ }
599
+ }
600
+ if (agent.rollback) renderTextList(lines, "Rollback", agent.rollback);
601
+ if (agent.failureModes) {
602
+ lines.push("", "### Failure Modes", "");
603
+ for (const mode of agent.failureModes) {
604
+ if (typeof mode === "string") {
605
+ lines.push(`- ${mode}`);
606
+ continue;
607
+ }
608
+ lines.push(`- ${mode.symptom}${mode.resolution ? ` — Recovery: ${mode.resolution}` : ""}`);
609
+ }
610
+ }
611
+ lines.push(PAGE_AGENT_CONTRACT_END_MARKER);
612
+ return lines.join("\n");
613
+ }
614
+ /** Remove generated contract blocks while preserving handwritten guidance. */
615
+ function stripGeneratedPageAgentContractMarkdown(markdown) {
616
+ const newline = markdown.includes("\r\n") ? "\r\n" : "\n";
617
+ const output = [];
618
+ let fence;
619
+ let pendingBlock;
620
+ let skipEmptySeparator = false;
621
+ for (const line of markdown.split(/\r?\n/)) {
622
+ if (pendingBlock) {
623
+ pendingBlock.push(line);
624
+ if (isGeneratedAgentContractMarker(line, PAGE_AGENT_CONTRACT_END_MARKER)) {
625
+ pendingBlock = void 0;
626
+ skipEmptySeparator = true;
627
+ }
628
+ continue;
629
+ }
630
+ if (!fence && isGeneratedAgentContractMarker(line, PAGE_AGENT_CONTRACT_START_MARKER)) {
631
+ pendingBlock = [line];
632
+ continue;
633
+ }
634
+ if (skipEmptySeparator && line.length === 0) continue;
635
+ skipEmptySeparator = false;
636
+ output.push(line);
637
+ fence = advanceMarkdownFence(line, fence);
638
+ }
639
+ if (pendingBlock) output.push(...pendingBlock);
640
+ while (output[0] === "") output.shift();
641
+ return output.join(newline);
642
+ }
643
+ function isGeneratedAgentContractMarker(line, marker) {
644
+ if (line.trim() !== marker) return false;
645
+ const markerIndex = line.indexOf(marker);
646
+ return markerIndex <= 3 && /^ *$/.test(line.slice(0, markerIndex));
647
+ }
648
+ function advanceMarkdownFence(line, fence) {
649
+ if (fence) {
650
+ const closing = /^ {0,3}(`+|~+)[\t ]*$/.exec(line)?.[1];
651
+ if (closing?.[0] === fence.character && closing.length >= fence.length) return;
652
+ return fence;
653
+ }
654
+ const opening = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
655
+ if (!opening?.[1]) return void 0;
656
+ if (opening[1][0] === "`" && opening[2]?.includes("`")) return void 0;
657
+ return {
658
+ character: opening[1][0],
659
+ length: opening[1].length
660
+ };
661
+ }
662
+ function isAgentContractHeadingText(value) {
663
+ return value.trim().toLowerCase() === "agent contract";
664
+ }
665
+ function hasPageAgentContractHeading(markdown) {
666
+ let fence;
667
+ let previousLine;
668
+ for (const line of markdown.split(/\r?\n/)) {
669
+ const nextFence = advanceMarkdownFence(line, fence);
670
+ if (fence || nextFence) {
671
+ fence = nextFence;
672
+ previousLine = void 0;
673
+ continue;
674
+ }
675
+ const atxText = /^ {0,3}#{1,6}(?:[\t ]+|$)(.*)$/.exec(line)?.[1]?.replace(/[\t ]+#+[\t ]*$/, "").trim();
676
+ if (atxText && isAgentContractHeadingText(atxText)) return true;
677
+ if (previousLine && /^ {0,3}(?:=+|-+)[\t ]*$/.test(line) && isAgentContractHeadingText(previousLine)) return true;
678
+ previousLine = line.trim().length > 0 && !/^ {4}/.test(line) && !/^ {0,3}\t/.test(line) ? line : void 0;
679
+ }
680
+ return false;
681
+ }
682
+ /** Insert one generated contract unless the document already has handwritten contract guidance. */
683
+ function upsertPageAgentContractMarkdown(markdown, value) {
684
+ const cleaned = stripGeneratedPageAgentContractMarkdown(markdown);
685
+ const contract = renderPageAgentContractMarkdown(value);
686
+ if (!contract || hasPageAgentContractHeading(cleaned)) return cleaned;
687
+ return cleaned ? `${contract}\n\n${cleaned.replace(/^\r?\n+/, "")}` : contract;
688
+ }
689
+
690
+ //#endregion
691
+ //#region src/related.ts
692
+ function normalizeDocsRelated(value) {
693
+ if (!Array.isArray(value)) return [];
694
+ const seen = /* @__PURE__ */ new Set();
695
+ const links = [];
696
+ for (const item of value) {
697
+ const parsed = parseRelatedInput(item);
698
+ if (!parsed) continue;
699
+ const dedupeKey = normalizeRelatedLookupPath(parsed.href) ?? parsed.href;
700
+ if (seen.has(dedupeKey)) continue;
701
+ seen.add(dedupeKey);
702
+ links.push({ href: parsed.href });
703
+ }
704
+ return links;
705
+ }
706
+ function renderDocsRelatedMarkdownLines(related) {
707
+ if (!related?.length) return [];
708
+ return [`Related: ${related.map((link) => normalizeInlineText(link.href)).join(", ")}`];
709
+ }
710
+ function parseRelatedInput(value) {
711
+ if (typeof value === "string") {
712
+ const href = cleanString(value);
713
+ return href ? { href } : null;
714
+ }
715
+ return null;
716
+ }
717
+ function cleanString(value) {
718
+ if (typeof value !== "string") return void 0;
719
+ return value.trim() || void 0;
720
+ }
721
+ function normalizeRelatedLookupPath(value) {
722
+ const trimmed = value.trim();
723
+ if (!trimmed) return null;
724
+ let pathname = trimmed;
725
+ try {
726
+ pathname = new URL(trimmed, "https://docs.local").pathname;
727
+ } catch {
728
+ pathname = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
729
+ }
730
+ pathname = pathname.replace(/\/+/g, "/").replace(/\.md$/i, "");
731
+ if (!pathname.startsWith("/")) pathname = `/${pathname}`;
732
+ if (pathname !== "/") pathname = pathname.replace(/\/+$/, "");
733
+ return pathname;
734
+ }
735
+ function normalizeInlineText(value) {
736
+ return value.replace(/\s+/g, " ").trim();
737
+ }
738
+
739
+ //#endregion
740
+ //#region src/sitemap.ts
741
+ const DEFAULT_SITEMAP_XML_ROUTE = "/sitemap.xml";
742
+ const DEFAULT_SITEMAP_MD_ROUTE = "/sitemap.md";
743
+ const DEFAULT_SITEMAP_MD_DOCS_ROUTE = "/docs/sitemap.md";
744
+ const DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE = "/.well-known/sitemap.md";
745
+ const DEFAULT_SITEMAP_MANIFEST_PATH = ".farming-labs/sitemap-manifest.json";
746
+ function normalizeUrlPath(value) {
747
+ const normalized = value.replace(/\/+/g, "/");
748
+ if (normalized === "/") return normalized;
749
+ return normalized.replace(/\/+$/, "");
750
+ }
751
+ function normalizeRoutePrefix(value) {
752
+ if (!value) return "";
753
+ const normalized = normalizeUrlPath(`/${value.replace(/^\/+|\/+$/g, "")}`);
754
+ return normalized === "/" ? "" : normalized;
755
+ }
756
+ function joinRoute(prefix, route) {
757
+ return normalizeUrlPath(`${prefix}/${route.replace(/^\/+/, "")}`);
758
+ }
759
+ function normalizeDateOnly(value) {
760
+ if (!value) return void 0;
761
+ const trimmed = value.trim();
762
+ if (!trimmed) return void 0;
763
+ const dateOnly = trimmed.match(/^(\d{4}-\d{2}-\d{2})/);
764
+ if (dateOnly) return dateOnly[1];
765
+ const parsed = new Date(trimmed);
766
+ if (Number.isNaN(parsed.getTime())) return void 0;
767
+ return parsed.toISOString().slice(0, 10);
768
+ }
769
+ function normalizeBaseUrl(value) {
770
+ if (!value) return void 0;
771
+ return value.trim().replace(/\/+$/, "") || void 0;
772
+ }
773
+ function isEnabledObject(config) {
774
+ if (config === false) return false;
775
+ if (config === void 0) return true;
776
+ if (config === true) return true;
777
+ return config.enabled !== false;
778
+ }
779
+ function resolveDocsSitemapConfig(sitemap, defaults = {}) {
780
+ const objectConfig = sitemap && typeof sitemap === "object" ? sitemap : {};
781
+ const routePrefix = normalizeRoutePrefix(objectConfig.routePrefix);
782
+ const xmlConfig = objectConfig.xml;
783
+ const markdownConfig = objectConfig.markdown;
784
+ const xmlEnabled = xmlConfig === false ? false : typeof xmlConfig === "object" ? xmlConfig.enabled ?? true : true;
785
+ const markdownEnabled = markdownConfig === false ? false : typeof markdownConfig === "object" ? markdownConfig.enabled ?? true : true;
786
+ return {
787
+ enabled: isEnabledObject(sitemap),
788
+ routePrefix,
789
+ baseUrl: normalizeBaseUrl(objectConfig.baseUrl ?? defaults.baseUrl),
790
+ manifestPath: objectConfig.manifestPath ?? DEFAULT_SITEMAP_MANIFEST_PATH,
791
+ xml: {
792
+ enabled: xmlEnabled,
793
+ includeLastmod: typeof xmlConfig === "object" ? xmlConfig.includeLastmod ?? true : true,
794
+ route: joinRoute(routePrefix, DEFAULT_SITEMAP_XML_ROUTE)
795
+ },
796
+ markdown: {
797
+ enabled: markdownEnabled,
798
+ includeDescriptions: typeof markdownConfig === "object" ? markdownConfig.includeDescriptions ?? true : true,
799
+ includeLastmod: typeof markdownConfig === "object" ? markdownConfig.includeLastmod ?? true : true,
800
+ linkTarget: typeof markdownConfig === "object" ? markdownConfig.linkTarget ?? "both" : "both",
801
+ route: joinRoute(routePrefix, DEFAULT_SITEMAP_MD_ROUTE),
802
+ docsRoute: routePrefix ? void 0 : DEFAULT_SITEMAP_MD_DOCS_ROUTE,
803
+ wellKnownRoute: joinRoute(routePrefix, DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE)
804
+ }
805
+ };
806
+ }
807
+ function resolveDocsSitemapRequest(url, sitemap, options = {}) {
808
+ const pathname = normalizeUrlPath(url.pathname);
809
+ const format = url.searchParams.get("format")?.trim();
810
+ if (pathname === resolveDocsDiscoveryApiRoute(options.apiRoute)) {
811
+ if (format === "sitemap-xml") return "xml";
812
+ if (format === "sitemap-md" || format === "sitemap-markdown") return "markdown";
813
+ }
814
+ const resolved = resolveDocsSitemapConfig(sitemap);
815
+ if (!resolved.enabled) return null;
816
+ if (resolved.xml.enabled && pathname === resolved.xml.route) return "xml";
817
+ if (resolved.markdown.enabled && (pathname === resolved.markdown.route || pathname === resolved.markdown.docsRoute || pathname === resolved.markdown.wellKnownRoute)) return "markdown";
818
+ return null;
819
+ }
820
+ function toDocsSitemapMarkdownUrl(url) {
821
+ const normalized = normalizeUrlPath(url);
822
+ return normalized.endsWith(".md") ? normalized : `${normalized}.md`;
823
+ }
824
+ function absolutizeUrl(baseUrl, url) {
825
+ if (/^https?:\/\//i.test(url)) return url;
826
+ const base = normalizeBaseUrl(baseUrl);
827
+ return base ? `${base}${url.startsWith("/") ? url : `/${url}`}` : url;
828
+ }
829
+ function escapeXml(value) {
830
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
831
+ }
832
+ function hashString(value) {
833
+ let hash = 14695981039346656037n;
834
+ const bytes = new TextEncoder().encode(value);
835
+ for (const byte of bytes) {
836
+ hash ^= BigInt(byte);
837
+ hash = BigInt.asUintN(64, hash * 1099511628211n);
838
+ }
839
+ return `"fnv1a64-${hash.toString(16).padStart(16, "0")}"`;
840
+ }
841
+ function newestLastmod(pages) {
842
+ let newest;
843
+ for (const page of pages) {
844
+ const date = normalizeDateOnly(page.lastmod);
845
+ if (!date) continue;
846
+ if (!newest || date > newest) newest = date;
847
+ }
848
+ return newest;
849
+ }
850
+ function titleize(value) {
851
+ return value.replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
852
+ }
853
+ function sitemapSectionName(entry, pageUrl) {
854
+ const normalizedEntry = `/${entry.replace(/^\/+|\/+$/g, "") || "docs"}`;
855
+ const normalizedUrl = normalizeUrlPath(pageUrl);
856
+ if (normalizedUrl === normalizedEntry) return "Overview";
857
+ const firstSegment = (normalizedUrl.startsWith(`${normalizedEntry}/`) ? normalizedUrl.slice(normalizedEntry.length + 1) : normalizedUrl.replace(/^\/+/, "")).split("/").filter(Boolean)[0];
858
+ return firstSegment ? titleize(firstSegment) : "Pages";
859
+ }
860
+ function buildDocsSitemapManifest(options) {
861
+ const baseUrl = normalizeBaseUrl(options.baseUrl);
862
+ const seen = /* @__PURE__ */ new Set();
863
+ const pages = [];
864
+ for (const page of options.pages) {
865
+ const url = normalizeUrlPath(page.url);
866
+ if (seen.has(url)) continue;
867
+ seen.add(url);
868
+ const resolvedLastmod = options.resolveLastmod?.(page);
869
+ const fallbackLastmod = normalizeDateOnly(page.lastmod ?? page.lastModified);
870
+ const lastmod = normalizeDateOnly(resolvedLastmod?.lastmod) ?? fallbackLastmod;
871
+ pages.push({
872
+ url,
873
+ absoluteUrl: absolutizeUrl(baseUrl, url),
874
+ markdownUrl: page.markdownUrl ?? toDocsSitemapMarkdownUrl(url),
875
+ title: page.title,
876
+ description: page.description,
877
+ sourcePath: page.sourcePath,
878
+ lastmod,
879
+ lastmodSource: resolvedLastmod?.lastmodSource ?? (lastmod ? "unknown" : void 0),
880
+ related: page.related?.map((link) => link.href)
881
+ });
882
+ }
883
+ pages.sort((left, right) => left.url.localeCompare(right.url));
884
+ return {
885
+ version: 1,
886
+ generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
887
+ baseUrl,
888
+ entry: options.entry ?? "docs",
889
+ siteTitle: options.siteTitle,
890
+ pages
891
+ };
892
+ }
893
+ function renderDocsSitemapXml(manifest, options = {}) {
894
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? manifest.baseUrl);
895
+ const includeLastmod = options.includeLastmod ?? true;
896
+ const lines = ["<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">"];
897
+ for (const page of manifest.pages) {
898
+ lines.push(" <url>");
899
+ lines.push(` <loc>${escapeXml(page.absoluteUrl ?? absolutizeUrl(baseUrl, page.url))}</loc>`);
900
+ const lastmod = normalizeDateOnly(page.lastmod);
901
+ if (includeLastmod && lastmod) lines.push(` <lastmod>${lastmod}</lastmod>`);
902
+ lines.push(" </url>");
903
+ }
904
+ lines.push("</urlset>");
905
+ return `${lines.join("\n")}\n`;
906
+ }
907
+ function renderDocsSitemapMarkdown(manifest, options = {}) {
908
+ const siteTitle = manifest.siteTitle ?? "Documentation";
909
+ const includeDescriptions = options.includeDescriptions ?? true;
910
+ const includeLastmod = options.includeLastmod ?? true;
911
+ const linkTarget = options.linkTarget ?? "both";
912
+ const lines = [`# ${siteTitle} Sitemap`, ""];
913
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? manifest.baseUrl);
914
+ if (baseUrl) lines.push(`Base URL: ${baseUrl}`);
915
+ lines.push(`Docs entry: /${manifest.entry.replace(/^\/+|\/+$/g, "") || "docs"}`);
916
+ lines.push(`Generated: ${normalizeDateOnly(manifest.generatedAt) ?? manifest.generatedAt}`, "");
917
+ const groups = /* @__PURE__ */ new Map();
918
+ for (const page of manifest.pages) {
919
+ const sectionName = sitemapSectionName(manifest.entry, page.url);
920
+ groups.set(sectionName, [...groups.get(sectionName) ?? [], page]);
921
+ }
922
+ for (const [sectionName, pages] of groups) {
923
+ lines.push(`## ${sectionName}`, "");
924
+ for (const page of pages) {
925
+ const primaryHref = linkTarget === "markdown" ? page.markdownUrl : page.url;
926
+ lines.push(`- [${page.title}](${primaryHref})`);
927
+ if (linkTarget === "both" || linkTarget === "markdown") lines.push(` Markdown: ${page.markdownUrl}`);
928
+ if (includeDescriptions && page.description) lines.push(` Description: ${page.description}`);
929
+ const lastmod = normalizeDateOnly(page.lastmod);
930
+ if (includeLastmod && lastmod) lines.push(` Last updated: ${lastmod}`);
931
+ if (page.related && page.related.length > 0) lines.push(` Related: ${page.related.join(", ")}`);
932
+ lines.push("");
933
+ }
934
+ }
935
+ return lines.join("\n").replace(/\n{3,}/g, "\n\n");
936
+ }
937
+ function readDocsSitemapManifestFromContentMap(contentMap) {
938
+ if (!contentMap) return null;
939
+ const raw = contentMap[`/${DEFAULT_SITEMAP_MANIFEST_PATH}`] ?? contentMap[DEFAULT_SITEMAP_MANIFEST_PATH];
940
+ if (!raw) return null;
941
+ try {
942
+ return JSON.parse(raw);
943
+ } catch {
944
+ return null;
945
+ }
946
+ }
947
+ function resolveDocsSitemapPageLastmod(manifest, url) {
948
+ if (!manifest) return void 0;
949
+ const normalizedUrl = normalizeUrlPath(url);
950
+ return normalizeDateOnly(manifest.pages.find((entry) => normalizeUrlPath(entry.url) === normalizedUrl)?.lastmod);
951
+ }
952
+ function createDocsSitemapResponse({ request, apiRoute, sitemap, entry = "docs", siteTitle, baseUrl, pages, manifest }) {
953
+ const url = new URL(request.url);
954
+ const format = resolveDocsSitemapRequest(url, sitemap, { apiRoute });
955
+ if (!format) return null;
956
+ const resolved = resolveDocsSitemapConfig(sitemap, { baseUrl });
957
+ if (!resolved.enabled) return null;
958
+ if (format === "xml" && !resolved.xml.enabled) return null;
959
+ if (format === "markdown" && !resolved.markdown.enabled) return null;
960
+ const nextManifest = manifest ?? buildDocsSitemapManifest({
961
+ pages,
962
+ entry,
963
+ siteTitle,
964
+ baseUrl: resolved.baseUrl ?? url.origin
965
+ });
966
+ const responseBaseUrl = resolved.baseUrl ?? nextManifest.baseUrl ?? url.origin;
967
+ const body = format === "xml" ? renderDocsSitemapXml(nextManifest, {
968
+ baseUrl: responseBaseUrl,
969
+ includeLastmod: resolved.xml.includeLastmod
970
+ }) : renderDocsSitemapMarkdown(nextManifest, {
971
+ baseUrl: responseBaseUrl,
972
+ includeDescriptions: resolved.markdown.includeDescriptions,
973
+ includeLastmod: resolved.markdown.includeLastmod,
974
+ linkTarget: resolved.markdown.linkTarget
975
+ });
976
+ const headers = new Headers({
977
+ "Content-Type": format === "xml" ? "application/xml; charset=utf-8" : "text/markdown; charset=utf-8",
978
+ "Cache-Control": "public, max-age=0, must-revalidate",
979
+ ETag: hashString(body)
980
+ });
981
+ const lastModified = newestLastmod(nextManifest.pages);
982
+ if (lastModified) headers.set("Last-Modified", (/* @__PURE__ */ new Date(`${lastModified}T00:00:00.000Z`)).toUTCString());
983
+ if (request.headers.get("if-none-match") === headers.get("ETag")) return new Response(null, {
984
+ status: 304,
985
+ headers
986
+ });
987
+ return new Response(body, { headers });
988
+ }
989
+
990
+ //#endregion
991
+ //#region src/audience.ts
992
+ /** Resolve whether content with an optional audience restriction is visible. */
993
+ function resolveDocsAudienceExposure(only, audience) {
994
+ return only !== "human" && only !== "agent" || only === audience;
995
+ }
996
+ const DOCS_AUDIENCE_TAG_NAMES = [
997
+ "Audience",
998
+ "Agent",
999
+ "Human"
1000
+ ];
1001
+ const DOCS_AUDIENCE_TAG_CANDIDATE_PATTERN = /<\/?(?:Audience|Agent|Human)(?=[\s/>])/;
1002
+ function parseAudienceOnly(attributes) {
1003
+ if (/\{\s*\.\.\./.test(attributes)) return void 0;
1004
+ const value = attributes.match(/(?:^|\s)only\s*=\s*(?:"(human|agent)"|'(human|agent)'|\{\s*"(human|agent)"\s*\}|\{\s*'(human|agent)'\s*\})/)?.slice(1).find(Boolean);
1005
+ return value === "human" || value === "agent" ? value : void 0;
1006
+ }
1007
+ function isEscapedAt(content, index) {
1008
+ let backslashes = 0;
1009
+ for (let cursor = index - 1; cursor >= 0 && content[cursor] === "\\"; cursor -= 1) backslashes += 1;
1010
+ return backslashes % 2 === 1;
1011
+ }
1012
+ const JAVASCRIPT_REGEX_PREFIX_KEYWORDS = new Set([
1013
+ "await",
1014
+ "case",
1015
+ "delete",
1016
+ "do",
1017
+ "else",
1018
+ "each",
1019
+ "if",
1020
+ "in",
1021
+ "instanceof",
1022
+ "key",
1023
+ "new",
1024
+ "of",
1025
+ "return",
1026
+ "throw",
1027
+ "catch",
1028
+ "const",
1029
+ "debug",
1030
+ "html",
1031
+ "render",
1032
+ "snippet",
1033
+ "then",
1034
+ "typeof",
1035
+ "void",
1036
+ "yield"
1037
+ ]);
1038
+ function canStartJavascriptRegex(content, cursor, boundary) {
1039
+ let previous = cursor - 1;
1040
+ while (previous > boundary && /\s/.test(content[previous] ?? "")) previous -= 1;
1041
+ if (previous <= boundary || /[([{=,:;!?&|>]/.test(content[previous] ?? "")) return true;
1042
+ const precedingWord = content.slice(boundary + 1, cursor).match(/([A-Za-z_$][\w$]*)\s*$/)?.[1];
1043
+ return JAVASCRIPT_REGEX_PREFIX_KEYWORDS.has(precedingWord ?? "");
1044
+ }
1045
+ function readAudienceTagAt(content, index) {
1046
+ let cursor = index + 1;
1047
+ const closing = content[cursor] === "/";
1048
+ if (closing) cursor += 1;
1049
+ const name = DOCS_AUDIENCE_TAG_NAMES.find((candidate) => content.startsWith(candidate, cursor) && /[\s/>]/.test(content[cursor + candidate.length] ?? ""));
1050
+ if (!name) return void 0;
1051
+ cursor += name.length;
1052
+ const attributesStart = cursor;
1053
+ let braceDepth = 0;
1054
+ let quote;
1055
+ let blockComment = false;
1056
+ let lineComment = false;
1057
+ while (cursor < content.length) {
1058
+ const character = content[cursor];
1059
+ const next = content[cursor + 1];
1060
+ if (lineComment) {
1061
+ if (character === "\n") lineComment = false;
1062
+ cursor += 1;
1063
+ continue;
1064
+ }
1065
+ if (blockComment) {
1066
+ if (character === "*" && next === "/") {
1067
+ blockComment = false;
1068
+ cursor += 2;
1069
+ } else cursor += 1;
1070
+ continue;
1071
+ }
1072
+ if (quote) {
1073
+ if (character === "\\") {
1074
+ cursor += 2;
1075
+ continue;
1076
+ }
1077
+ if (character === quote) quote = void 0;
1078
+ cursor += 1;
1079
+ continue;
1080
+ }
1081
+ if (braceDepth > 0 && character === "/" && next === "*") {
1082
+ blockComment = true;
1083
+ cursor += 2;
1084
+ continue;
1085
+ }
1086
+ if (braceDepth > 0 && character === "/" && next === "/") {
1087
+ lineComment = true;
1088
+ cursor += 2;
1089
+ continue;
1090
+ }
1091
+ if (character === "\"" || character === "'" || character === "`") quote = character;
1092
+ else if (character === "{") braceDepth += 1;
1093
+ else if (character === "}" && braceDepth > 0) braceDepth -= 1;
1094
+ else if (character === ">" && braceDepth === 0) {
1095
+ let attributesEnd = cursor;
1096
+ let slashIndex = cursor - 1;
1097
+ while (slashIndex >= attributesStart && /\s/.test(content[slashIndex] ?? "")) slashIndex -= 1;
1098
+ const selfClosing = content[slashIndex] === "/";
1099
+ if (selfClosing) attributesEnd = slashIndex;
1100
+ const attributes = content.slice(attributesStart, attributesEnd);
1101
+ return {
1102
+ index,
1103
+ end: cursor + 1,
1104
+ name,
1105
+ closing,
1106
+ selfClosing,
1107
+ attributes,
1108
+ only: name === "Agent" ? "agent" : name === "Human" ? "human" : parseAudienceOnly(attributes)
1109
+ };
1110
+ }
1111
+ cursor += 1;
1112
+ }
1113
+ }
1114
+ function findAudienceTags(content, protectedRanges) {
1115
+ const tags = [];
1116
+ let cursor = 0;
1117
+ while (cursor < content.length) {
1118
+ const index = content.indexOf("<", cursor);
1119
+ if (index === -1) break;
1120
+ if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1121
+ cursor = index + 1;
1122
+ continue;
1123
+ }
1124
+ const tag = readAudienceTagAt(content, index);
1125
+ if (tag) {
1126
+ tags.push(tag);
1127
+ cursor = tag.end;
1128
+ } else cursor = index + 1;
1129
+ }
1130
+ return tags;
1131
+ }
1132
+ const docsAudienceMdxProcessor = createProcessor({ format: "mdx" });
1133
+ const docsAudienceMarkdownProcessor = createProcessor({ format: "md" });
1134
+ function getOffset(position, edge) {
1135
+ const value = position?.[edge]?.offset;
1136
+ return typeof value === "number" ? value : void 0;
1137
+ }
1138
+ function maskRangesForMdxParser(content, ranges) {
1139
+ if (ranges.length === 0) return content;
1140
+ const characters = content.split("");
1141
+ for (const range of ranges) for (let index = range.start; index < range.end; index += 1) if (characters[index] !== "\n" && characters[index] !== "\r") characters[index] = " ";
1142
+ return characters.join("");
1143
+ }
1144
+ function findLeadingFrontmatterRange(content) {
1145
+ const bomLength = content.startsWith("") ? 1 : 0;
1146
+ const opening = content.slice(bomLength).match(/^(---|\+\+\+)[\t ]*(?:\r?\n|$)/);
1147
+ const marker = opening?.[1];
1148
+ if (!opening || !marker) return void 0;
1149
+ let offset = bomLength + opening[0].length;
1150
+ for (const line of content.slice(offset).split(/(?<=\n)/)) {
1151
+ offset += line.length;
1152
+ const value = line.replace(/\r?\n$/, "");
1153
+ if (marker === "---" ? /^(?:---|\.\.\.)[\t ]*$/.test(value) : /^\+\+\+[\t ]*$/.test(value)) return {
1154
+ start: 0,
1155
+ end: offset
1156
+ };
1157
+ }
1158
+ }
1159
+ function findHtmlLiteralRanges(content, excludedRanges = []) {
1160
+ const ranges = [];
1161
+ const rawPattern = /<(script|style)(?=[\s/>])/g;
1162
+ let cursor = 0;
1163
+ while (cursor < content.length) {
1164
+ rawPattern.lastIndex = cursor;
1165
+ const rawMatch = rawPattern.exec(content);
1166
+ const commentStart = content.indexOf("<!--", cursor);
1167
+ const rawStart = rawMatch?.index ?? -1;
1168
+ const useComment = commentStart !== -1 && (rawStart === -1 || commentStart < rawStart);
1169
+ const start = useComment ? commentStart : rawStart;
1170
+ if (start === -1) break;
1171
+ if (isEscapedAt(content, start) || isInsideRange(start, excludedRanges)) {
1172
+ cursor = start + 1;
1173
+ continue;
1174
+ }
1175
+ if (useComment) {
1176
+ const closing = content.indexOf("-->", start + 4);
1177
+ const end = closing === -1 ? content.length : closing + 3;
1178
+ ranges.push({
1179
+ start,
1180
+ end
1181
+ });
1182
+ cursor = end;
1183
+ continue;
1184
+ }
1185
+ const name = rawMatch?.[1];
1186
+ if (!name) {
1187
+ cursor = start + 1;
1188
+ continue;
1189
+ }
1190
+ const opening = readGenericMdxJsxTag(content, start);
1191
+ if (!opening) {
1192
+ cursor = start + 1;
1193
+ continue;
1194
+ }
1195
+ if (opening.selfClosing) {
1196
+ cursor = opening.end;
1197
+ continue;
1198
+ }
1199
+ const closingPattern = new RegExp(`</${name}\\s*>`, "g");
1200
+ closingPattern.lastIndex = opening.end;
1201
+ if (!closingPattern.exec(content)) {
1202
+ ranges.push({
1203
+ start,
1204
+ end: content.length
1205
+ });
1206
+ break;
1207
+ }
1208
+ ranges.push({
1209
+ start,
1210
+ end: closingPattern.lastIndex
1211
+ });
1212
+ cursor = closingPattern.lastIndex;
1213
+ }
1214
+ return ranges;
1215
+ }
1216
+ function prepareMdxParserSource(content) {
1217
+ const baseExcludedRanges = findDelimiterExclusionRanges(content);
1218
+ const svelteDirectives = findSvelteDirectiveRanges(content, baseExcludedRanges);
1219
+ const ranges = [...findHtmlLiteralRanges(content, mergeProtectedRanges([...baseExcludedRanges, ...svelteDirectives])), ...svelteDirectives];
1220
+ const frontmatter = findLeadingFrontmatterRange(content);
1221
+ if (frontmatter) ranges.push(frontmatter);
1222
+ return maskRangesForMdxParser(content, mergeProtectedRanges(ranges));
1223
+ }
1224
+ function getExpressionLiteralString(value) {
1225
+ if (!value || typeof value !== "object") return void 0;
1226
+ const expression = value.data?.estree?.body?.[0]?.expression;
1227
+ return expression?.type === "Literal" && typeof expression.value === "string" ? expression.value : void 0;
1228
+ }
1229
+ function getMdxAudienceAttributeInfo(attributes) {
1230
+ const hasSpreadAttribute = attributes.some((attribute) => attribute.type === "mdxJsxExpressionAttribute");
1231
+ const onlyAttribute = [...attributes].reverse().find((attribute) => attribute.type === "mdxJsxAttribute" && attribute.name === "only");
1232
+ if (hasSpreadAttribute) return {
1233
+ hasOnlyAttribute: Boolean(onlyAttribute),
1234
+ hasSpreadAttribute,
1235
+ onlyKind: "dynamic"
1236
+ };
1237
+ if (!onlyAttribute) return {
1238
+ hasOnlyAttribute: false,
1239
+ hasSpreadAttribute: false,
1240
+ onlyKind: "missing"
1241
+ };
1242
+ const value = typeof onlyAttribute.value === "string" ? onlyAttribute.value : getExpressionLiteralString(onlyAttribute.value);
1243
+ if (value === "human" || value === "agent") return {
1244
+ only: value,
1245
+ hasOnlyAttribute: true,
1246
+ hasSpreadAttribute: false,
1247
+ onlyKind: "static"
1248
+ };
1249
+ return {
1250
+ hasOnlyAttribute: true,
1251
+ hasSpreadAttribute: false,
1252
+ onlyKind: typeof onlyAttribute.value === "object" ? "dynamic" : "invalid"
1253
+ };
1254
+ }
1255
+ function getEstreeAudienceAttributeInfo(attributes) {
1256
+ const records = attributes.filter((attribute) => Boolean(attribute && typeof attribute === "object"));
1257
+ const hasSpreadAttribute = records.some((attribute) => attribute.type === "JSXSpreadAttribute");
1258
+ const onlyAttribute = [...records].reverse().find((attribute) => {
1259
+ const name = attribute.name;
1260
+ return attribute.type === "JSXAttribute" && name?.type === "JSXIdentifier" && name.name === "only";
1261
+ });
1262
+ if (hasSpreadAttribute) return {
1263
+ hasOnlyAttribute: Boolean(onlyAttribute),
1264
+ hasSpreadAttribute,
1265
+ onlyKind: "dynamic"
1266
+ };
1267
+ if (!onlyAttribute) return {
1268
+ hasOnlyAttribute: false,
1269
+ hasSpreadAttribute: false,
1270
+ onlyKind: "missing"
1271
+ };
1272
+ const attributeValue = onlyAttribute.value;
1273
+ const value = attributeValue?.type === "Literal" ? attributeValue.value : attributeValue?.type === "JSXExpressionContainer" && attributeValue.expression?.type === "Literal" ? attributeValue.expression.value : void 0;
1274
+ if (value === "human" || value === "agent") return {
1275
+ only: value,
1276
+ hasOnlyAttribute: true,
1277
+ hasSpreadAttribute: false,
1278
+ onlyKind: "static"
1279
+ };
1280
+ return {
1281
+ hasOnlyAttribute: true,
1282
+ hasSpreadAttribute: false,
1283
+ onlyKind: attributeValue?.type === "JSXExpressionContainer" ? "dynamic" : "invalid"
1284
+ };
1285
+ }
1286
+ function getOpeningTagEnd(content, start, name, attributes) {
1287
+ const searchStart = Math.max(start + name.length + 1, ...attributes.map((attribute) => getOffset(attribute.position, "end") ?? 0));
1288
+ const closingBracket = content.indexOf(">", searchStart);
1289
+ return closingBracket === -1 ? void 0 : closingBracket + 1;
1290
+ }
1291
+ function addMdxAudienceElementTags(content, node, tags) {
1292
+ const name = node.name;
1293
+ const start = getOffset(node.position, "start");
1294
+ const nodeEnd = getOffset(node.position, "end");
1295
+ if (start === void 0 || nodeEnd === void 0) return;
1296
+ const attributes = node.attributes ?? [];
1297
+ const openingEnd = getOpeningTagEnd(content, start, name, attributes);
1298
+ if (openingEnd === void 0) return;
1299
+ const closingStart = content.lastIndexOf(`</${name}`, nodeEnd);
1300
+ const hasClosingTag = closingStart >= openingEnd;
1301
+ const attributeInfo = getMdxAudienceAttributeInfo(attributes);
1302
+ const rawAttributes = content.slice(start + name.length + 1, openingEnd - 1);
1303
+ tags.push({
1304
+ index: start,
1305
+ end: openingEnd,
1306
+ name,
1307
+ closing: false,
1308
+ selfClosing: !hasClosingTag,
1309
+ attributes: rawAttributes,
1310
+ only: name === "Agent" ? "agent" : name === "Human" ? "human" : attributeInfo.only,
1311
+ hasOnlyAttribute: attributeInfo.hasOnlyAttribute,
1312
+ hasSpreadAttribute: attributeInfo.hasSpreadAttribute,
1313
+ onlyKind: attributeInfo.onlyKind
1314
+ });
1315
+ if (hasClosingTag) tags.push({
1316
+ index: closingStart,
1317
+ end: nodeEnd,
1318
+ name,
1319
+ closing: true,
1320
+ selfClosing: false,
1321
+ attributes: ""
1322
+ });
1323
+ }
1324
+ function getEstreeJsxIdentifierName(value) {
1325
+ if (!value || typeof value !== "object") return void 0;
1326
+ const name = value;
1327
+ return name.type === "JSXIdentifier" && DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === name.name) ? name.name : void 0;
1328
+ }
1329
+ function addEstreeAudienceElementTags(content, node, tags, jsxChild) {
1330
+ const opening = node.openingElement;
1331
+ if (!opening) return;
1332
+ const name = getEstreeJsxIdentifierName(opening.name);
1333
+ const start = typeof opening.start === "number" ? opening.start : void 0;
1334
+ const openingEnd = typeof opening.end === "number" ? opening.end : void 0;
1335
+ const nodeEnd = typeof node.end === "number" ? node.end : void 0;
1336
+ if (!name || start === void 0 || openingEnd === void 0 || nodeEnd === void 0) return;
1337
+ const attributeInfo = getEstreeAudienceAttributeInfo(Array.isArray(opening.attributes) ? opening.attributes : []);
1338
+ const closing = node.closingElement;
1339
+ const closingStart = closing && typeof closing.start === "number" ? closing.start : void 0;
1340
+ const closingEnd = closing && typeof closing.end === "number" ? closing.end : void 0;
1341
+ tags.push({
1342
+ index: start,
1343
+ end: openingEnd,
1344
+ name,
1345
+ closing: false,
1346
+ selfClosing: closingStart === void 0,
1347
+ attributes: content.slice(start + name.length + 1, openingEnd - 1),
1348
+ only: name === "Agent" ? "agent" : name === "Human" ? "human" : attributeInfo.only,
1349
+ expression: true,
1350
+ jsxChild,
1351
+ hasOnlyAttribute: attributeInfo.hasOnlyAttribute,
1352
+ hasSpreadAttribute: attributeInfo.hasSpreadAttribute,
1353
+ onlyKind: attributeInfo.onlyKind
1354
+ });
1355
+ if (closingStart !== void 0 && closingEnd !== void 0) tags.push({
1356
+ index: closingStart,
1357
+ end: closingEnd,
1358
+ name,
1359
+ closing: true,
1360
+ selfClosing: false,
1361
+ attributes: "",
1362
+ expression: true,
1363
+ jsxChild
1364
+ });
1365
+ }
1366
+ function collectEstreeAudienceTags(content, value, tags, seen = /* @__PURE__ */ new WeakSet(), parent, parentKey) {
1367
+ if (!value || typeof value !== "object" || seen.has(value)) return;
1368
+ seen.add(value);
1369
+ const record = value;
1370
+ if (record.type === "JSXElement") {
1371
+ const opening = record.openingElement;
1372
+ if (getEstreeJsxIdentifierName(opening?.name)) {
1373
+ addEstreeAudienceElementTags(content, record, tags, parentKey === "children" && (parent?.type === "JSXElement" || parent?.type === "JSXFragment"));
1374
+ for (const child of Array.isArray(record.children) ? record.children : []) collectEstreeAudienceTags(content, child, tags, seen, record, "children");
1375
+ return;
1376
+ }
1377
+ }
1378
+ for (const [key, child] of Object.entries(record)) {
1379
+ if (key === "loc" || key === "range" || key === "comments") continue;
1380
+ if (Array.isArray(child)) for (const item of child) collectEstreeAudienceTags(content, item, tags, seen, record, key);
1381
+ else collectEstreeAudienceTags(content, child, tags, seen, record, key);
1382
+ }
1383
+ }
1384
+ function collectMdxAudienceTags(content, node, tags) {
1385
+ const isMdxJsxElement = node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
1386
+ if (isMdxJsxElement && (node.name === "script" || node.name === "style")) return;
1387
+ const isAudienceElement = Boolean(isMdxJsxElement && node.name && DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === node.name));
1388
+ if (isAudienceElement) addMdxAudienceElementTags(content, node, tags);
1389
+ if (node.type !== "mdxjsEsm") {
1390
+ if (node.type === "mdxFlowExpression" || node.type === "mdxTextExpression") collectEstreeAudienceTags(content, node.data?.estree, tags);
1391
+ if (isMdxJsxElement && !isAudienceElement) for (const attribute of node.attributes ?? []) {
1392
+ collectEstreeAudienceTags(content, attribute.data?.estree, tags);
1393
+ if (attribute.value && typeof attribute.value === "object") {
1394
+ const value = attribute.value;
1395
+ collectEstreeAudienceTags(content, value.data?.estree, tags);
1396
+ }
1397
+ }
1398
+ }
1399
+ for (const child of node.children ?? []) collectMdxAudienceTags(content, child, tags);
1400
+ }
1401
+ function findMdxAstAudienceTags(content) {
1402
+ try {
1403
+ const tree = docsAudienceMdxProcessor.parse(prepareMdxParserSource(content));
1404
+ const tags = [];
1405
+ collectMdxAudienceTags(content, tree, tags);
1406
+ return tags.sort((left, right) => left.index - right.index || left.end - right.end);
1407
+ } catch {
1408
+ return;
1409
+ }
1410
+ }
1411
+ /** Locate effective audience tags while excluding Markdown/MDX literal contexts. */
1412
+ function findDocsAudienceMdxTags(content) {
1413
+ if (!DOCS_AUDIENCE_TAG_CANDIDATE_PATTERN.test(content)) return [];
1414
+ return findMdxAstAudienceTags(content) ?? findAudienceTags(content, findProtectedRanges(content));
1415
+ }
1416
+ function isAudienceVisible(scopes, audience) {
1417
+ return scopes.every((scope) => resolveDocsAudienceExposure(scope.only, audience));
1418
+ }
1419
+ function mergeProtectedRanges(ranges) {
1420
+ const sorted = [...ranges].sort((left, right) => left.start - right.start || left.end - right.end);
1421
+ const merged = [];
1422
+ for (const range of sorted) {
1423
+ const previous = merged.at(-1);
1424
+ if (!previous || range.start > previous.end) {
1425
+ merged.push({ ...range });
1426
+ continue;
1427
+ }
1428
+ previous.end = Math.max(previous.end, range.end);
1429
+ }
1430
+ return merged;
1431
+ }
1432
+ function findMarkdownLiteralRanges(content) {
1433
+ try {
1434
+ const tree = docsAudienceMarkdownProcessor.parse(content);
1435
+ const ranges = [];
1436
+ const visit = (node) => {
1437
+ const start = getOffset(node.position, "start");
1438
+ const end = getOffset(node.position, "end");
1439
+ if (start !== void 0 && end !== void 0) {
1440
+ if (node.type === "code" || node.type === "inlineCode" || node.type === "definition") ranges.push({
1441
+ start,
1442
+ end
1443
+ });
1444
+ else if (node.type === "link" || node.type === "image") {
1445
+ const contentEnd = Math.max(start, ...(node.children ?? []).map((child) => getOffset(child.position, "end") ?? start));
1446
+ ranges.push({
1447
+ start: contentEnd,
1448
+ end
1449
+ });
1450
+ }
1451
+ }
1452
+ for (const child of node.children ?? []) visit(child);
1453
+ };
1454
+ visit(tree);
1455
+ return ranges;
1456
+ } catch {
1457
+ return [];
1458
+ }
1459
+ }
1460
+ function findMarkdownLinkDestinationRanges(content, protectedRanges) {
1461
+ const ranges = [];
1462
+ let cursor = 0;
1463
+ while (cursor < content.length) {
1464
+ const start = content.indexOf("](", cursor);
1465
+ if (start === -1) break;
1466
+ if (isEscapedAt(content, start) || isInsideRange(start, protectedRanges)) {
1467
+ cursor = start + 1;
1468
+ continue;
1469
+ }
1470
+ let end = start + 2;
1471
+ let parenthesisDepth = 1;
1472
+ let angleDestination = false;
1473
+ let quote;
1474
+ while (end < content.length && parenthesisDepth > 0) {
1475
+ const character = content[end];
1476
+ if (character === "\\") {
1477
+ end += 2;
1478
+ continue;
1479
+ }
1480
+ if (quote) {
1481
+ if (character === quote) quote = void 0;
1482
+ end += 1;
1483
+ continue;
1484
+ }
1485
+ if (character === "\"" || character === "'") quote = character;
1486
+ else if (character === "<" && parenthesisDepth === 1) {
1487
+ const closingAngle = content.indexOf(">", end + 1);
1488
+ const closingParenthesis = content.indexOf(")", end + 1);
1489
+ angleDestination = closingAngle !== -1 && closingAngle < closingParenthesis;
1490
+ } else if (character === ">" && angleDestination) angleDestination = false;
1491
+ else if (!angleDestination && character === "(") parenthesisDepth += 1;
1492
+ else if (!angleDestination && character === ")") parenthesisDepth -= 1;
1493
+ end += 1;
1494
+ }
1495
+ if (parenthesisDepth === 0) ranges.push({
1496
+ start: start + 1,
1497
+ end
1498
+ });
1499
+ cursor = Math.max(start + 1, end);
1500
+ }
1501
+ return ranges;
1502
+ }
1503
+ function findFenceRanges(content) {
1504
+ const ranges = [];
1505
+ let fence;
1506
+ let offset = 0;
1507
+ const stripBlockquoteContainers = (line) => {
1508
+ let value = line;
1509
+ while (/^ {0,3}>[\t ]?/.test(value)) value = value.replace(/^ {0,3}>[\t ]?/, "");
1510
+ return value;
1511
+ };
1512
+ const stripOpeningListContainers = (line) => {
1513
+ let value = line;
1514
+ while (/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/.test(value)) value = value.replace(/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/, "");
1515
+ return value;
1516
+ };
1517
+ for (const line of content.split(/(?<=\n)/)) {
1518
+ const containerRelativeLine = stripBlockquoteContainers(line.replace(/\r?\n$/, ""));
1519
+ const match = (fence ? containerRelativeLine : stripOpeningListContainers(containerRelativeLine)).match(/^[\t ]*(`{3,}|~{3,})(.*)$/);
1520
+ if (!fence && match?.[1]) fence = {
1521
+ marker: match[1][0],
1522
+ length: match[1].length,
1523
+ start: offset
1524
+ };
1525
+ else if (fence && match?.[1]?.[0] === fence.marker && match[1].length >= fence.length && /^[\t ]*$/.test(match[2] ?? "")) {
1526
+ ranges.push({
1527
+ start: fence.start,
1528
+ end: offset + line.length
1529
+ });
1530
+ fence = void 0;
1531
+ }
1532
+ offset += line.length;
1533
+ }
1534
+ if (fence) ranges.push({
1535
+ start: fence.start,
1536
+ end: content.length
1537
+ });
1538
+ return ranges;
1539
+ }
1540
+ function findSvelteDirectiveRanges(content, excludedRanges) {
1541
+ const ranges = [];
1542
+ let index = 0;
1543
+ while (index < content.length) {
1544
+ const start = content.indexOf("{", index);
1545
+ if (start === -1) break;
1546
+ const sigil = content[start + 1];
1547
+ if (!/[#/:@]/.test(sigil ?? "") || !/[A-Za-z]/.test(content[start + 2] ?? "") || isEscapedAt(content, start) || isInsideRange(start, excludedRanges)) {
1548
+ index = start + 1;
1549
+ continue;
1550
+ }
1551
+ let cursor = start + 2;
1552
+ let braceDepth = 1;
1553
+ let quote;
1554
+ let blockComment = false;
1555
+ let lineComment = false;
1556
+ let regex = false;
1557
+ let regexCharacterClass = false;
1558
+ while (cursor < content.length && braceDepth > 0) {
1559
+ const character = content[cursor];
1560
+ const next = content[cursor + 1];
1561
+ if (lineComment) {
1562
+ if (character === "\n") lineComment = false;
1563
+ cursor += 1;
1564
+ continue;
1565
+ }
1566
+ if (blockComment) {
1567
+ if (character === "*" && next === "/") {
1568
+ blockComment = false;
1569
+ cursor += 2;
1570
+ } else cursor += 1;
1571
+ continue;
1572
+ }
1573
+ if (quote) {
1574
+ if (character === "\\") {
1575
+ cursor += 2;
1576
+ continue;
1577
+ }
1578
+ if (character === quote) quote = void 0;
1579
+ cursor += 1;
1580
+ continue;
1581
+ }
1582
+ if (regex) {
1583
+ if (character === "\\") {
1584
+ cursor += 2;
1585
+ continue;
1586
+ }
1587
+ if (character === "[") regexCharacterClass = true;
1588
+ if (character === "]") regexCharacterClass = false;
1589
+ if (character === "/" && !regexCharacterClass) regex = false;
1590
+ cursor += 1;
1591
+ continue;
1592
+ }
1593
+ if (character === "/" && next === "*") {
1594
+ blockComment = true;
1595
+ cursor += 2;
1596
+ continue;
1597
+ }
1598
+ if (character === "/" && next === "/") {
1599
+ lineComment = true;
1600
+ cursor += 2;
1601
+ continue;
1602
+ }
1603
+ if (character === "\"" || character === "'" || character === "`") {
1604
+ quote = character;
1605
+ cursor += 1;
1606
+ continue;
1607
+ }
1608
+ if (character === "/") {
1609
+ if (canStartJavascriptRegex(content, cursor, start + 1)) {
1610
+ regex = true;
1611
+ cursor += 1;
1612
+ continue;
1613
+ }
1614
+ }
1615
+ if (character === "{") braceDepth += 1;
1616
+ if (character === "}") braceDepth -= 1;
1617
+ cursor += 1;
1618
+ }
1619
+ if (braceDepth === 0) ranges.push({
1620
+ start,
1621
+ end: cursor
1622
+ });
1623
+ index = Math.max(start + 1, cursor);
1624
+ }
1625
+ return ranges;
1626
+ }
1627
+ function scanMdxModuleLine(line, state) {
1628
+ for (let index = 0; index < line.length; index += 1) {
1629
+ const character = line[index];
1630
+ const next = line[index + 1];
1631
+ if (state.blockComment) {
1632
+ if (character === "*" && next === "/") {
1633
+ state.blockComment = false;
1634
+ index += 1;
1635
+ }
1636
+ continue;
1637
+ }
1638
+ if (state.quote) {
1639
+ if (character === "\\") {
1640
+ index += 1;
1641
+ continue;
1642
+ }
1643
+ if (character === state.quote) state.quote = void 0;
1644
+ continue;
1645
+ }
1646
+ if (character === "/" && next === "/") break;
1647
+ if (character === "/" && next === "*") {
1648
+ state.blockComment = true;
1649
+ index += 1;
1650
+ continue;
1651
+ }
1652
+ if (character === "\"" || character === "'" || character === "`") {
1653
+ state.quote = character;
1654
+ continue;
1655
+ }
1656
+ if (state.jsxTag) {
1657
+ if (character === "{") state.braceDepth += 1;
1658
+ else if (character === "}" && state.braceDepth > 0) state.braceDepth -= 1;
1659
+ else if (character === ">" && state.braceDepth === 0) {
1660
+ let previous = index - 1;
1661
+ while (previous >= 0 && /[\t ]/.test(line[previous] ?? "")) previous -= 1;
1662
+ const selfClosing = line[previous] === "/";
1663
+ let following = index + 1;
1664
+ while (following < line.length && /[\t ]/.test(line[following] ?? "")) following += 1;
1665
+ const genericTypeParameters = !state.jsxTag.closing && line[following] === "(";
1666
+ if (state.jsxTag.closing) state.jsxDepth = Math.max(0, state.jsxDepth - 1);
1667
+ else if (!selfClosing && !genericTypeParameters) state.jsxDepth += 1;
1668
+ state.jsxTag = void 0;
1669
+ }
1670
+ continue;
1671
+ }
1672
+ if (character === "<") {
1673
+ let previous = index - 1;
1674
+ while (previous >= 0 && /[\t ]/.test(line[previous] ?? "")) previous -= 1;
1675
+ const previousCharacter = line[previous];
1676
+ const atExpressionStart = previousCharacter === void 0 || /[=([{,:?!;]/.test(previousCharacter);
1677
+ const openingElement = (state.jsxDepth > 0 || atExpressionStart) && /[A-Za-z]/.test(next ?? "");
1678
+ const closingElement = state.jsxDepth > 0 && next === "/" && /[A-Za-z]/.test(line[index + 2] ?? "");
1679
+ const openingFragment = atExpressionStart && next === ">";
1680
+ const closingFragment = state.jsxDepth > 0 && next === "/" && line[index + 2] === ">";
1681
+ if (openingFragment) {
1682
+ state.jsxDepth += 1;
1683
+ index += 1;
1684
+ continue;
1685
+ }
1686
+ if (closingFragment) {
1687
+ state.jsxDepth = Math.max(0, state.jsxDepth - 1);
1688
+ index += 2;
1689
+ continue;
1690
+ }
1691
+ if (openingElement || closingElement) {
1692
+ state.jsxTag = { closing: closingElement };
1693
+ continue;
1694
+ }
1695
+ }
1696
+ if (character === "{") {
1697
+ state.braceDepth += 1;
1698
+ state.sawBlock = true;
1699
+ continue;
1700
+ }
1701
+ if (character === "}") state.braceDepth = Math.max(0, state.braceDepth - 1);
1702
+ else if (character === "[") state.bracketDepth += 1;
1703
+ else if (character === "]") state.bracketDepth = Math.max(0, state.bracketDepth - 1);
1704
+ else if (character === "(") state.parenthesisDepth += 1;
1705
+ else if (character === ")") state.parenthesisDepth = Math.max(0, state.parenthesisDepth - 1);
1706
+ }
1707
+ }
1708
+ function shouldContinueMdxModule(statement, state, nextSignificantLine) {
1709
+ if (state.quote || state.blockComment || state.braceDepth > 0 || state.bracketDepth > 0 || state.parenthesisDepth > 0 || state.jsxTag || state.jsxDepth > 0) return true;
1710
+ const trimmed = statement.trimEnd();
1711
+ if (/^\s*import\b(?!\s*[.(])/.test(statement)) {
1712
+ if (!(/^\s*import\s*(?:type\s+)?["'`]/.test(statement) || /\bfrom\s*["'`][\s\S]*["'`]\s*;?\s*$/.test(trimmed)) && !/;\s*$/.test(trimmed)) return true;
1713
+ }
1714
+ const isExportList = /^\s*export\s+(?:type\s+)?\{/.test(statement);
1715
+ const isExportAll = /^\s*export\s+\*/.test(statement);
1716
+ if ((isExportList || isExportAll) && !/\bfrom\s*["'`][\s\S]*["'`]\s*;?\s*$/.test(trimmed) && (isExportAll || /^\s*from\b/.test(nextSignificantLine ?? ""))) return true;
1717
+ if (/=>\s*$/.test(trimmed) || /[=([{,:.?+\-*/%&|^!]$/.test(trimmed)) return true;
1718
+ if (/\b(?:as|default|extends|from|implements|satisfies)$/.test(trimmed)) return true;
1719
+ return /^\s*export\s+(?:default\s+)?(?:(?:async\s+)?function|class|enum|interface|module|namespace)\b/.test(statement) && !state.sawBlock;
1720
+ }
1721
+ function isInsideRange(index, ranges) {
1722
+ return ranges.some((range) => index >= range.start && index < range.end);
1723
+ }
1724
+ function findMdxModuleRanges(content, protectedRanges) {
1725
+ const ranges = [];
1726
+ const lines = content.split(/(?<=\n)/);
1727
+ let offset = 0;
1728
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
1729
+ const line = lines[lineIndex] ?? "";
1730
+ const firstNonWhitespace = line.search(/\S/);
1731
+ if (/^\s*(?:import|export)\b/.test(line) && !isInsideRange(offset + Math.max(0, firstNonWhitespace), protectedRanges)) {
1732
+ const start = offset;
1733
+ const state = {
1734
+ braceDepth: 0,
1735
+ bracketDepth: 0,
1736
+ parenthesisDepth: 0,
1737
+ blockComment: false,
1738
+ sawBlock: false,
1739
+ jsxDepth: 0
1740
+ };
1741
+ let statement = "";
1742
+ while (lineIndex < lines.length) {
1743
+ const moduleLine = lines[lineIndex] ?? "";
1744
+ statement += moduleLine;
1745
+ scanMdxModuleLine(moduleLine, state);
1746
+ offset += moduleLine.length;
1747
+ const nextSignificantLine = lines.slice(lineIndex + 1).find((candidate) => candidate.trim().length > 0);
1748
+ if (!shouldContinueMdxModule(statement, state, nextSignificantLine)) break;
1749
+ lineIndex += 1;
1750
+ }
1751
+ ranges.push({
1752
+ start,
1753
+ end: offset
1754
+ });
1755
+ continue;
1756
+ }
1757
+ offset += line.length;
1758
+ }
1759
+ return ranges;
1760
+ }
1761
+ function findInlineCodeRanges(content, protectedRanges) {
1762
+ const ranges = [];
1763
+ let index = 0;
1764
+ while (index < content.length) {
1765
+ if (content[index] !== "`" || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1766
+ index += 1;
1767
+ continue;
1768
+ }
1769
+ let markerLength = 1;
1770
+ while (content[index + markerLength] === "`") markerLength += 1;
1771
+ let closingIndex = index + markerLength;
1772
+ while (closingIndex < content.length) {
1773
+ closingIndex = content.indexOf("`", closingIndex);
1774
+ if (closingIndex === -1) break;
1775
+ if (isInsideRange(closingIndex, protectedRanges)) {
1776
+ closingIndex += 1;
1777
+ continue;
1778
+ }
1779
+ let closingLength = 1;
1780
+ while (content[closingIndex + closingLength] === "`") closingLength += 1;
1781
+ if (closingLength === markerLength) break;
1782
+ closingIndex += closingLength;
1783
+ }
1784
+ if (closingIndex === -1) {
1785
+ index += markerLength;
1786
+ continue;
1787
+ }
1788
+ ranges.push({
1789
+ start: index,
1790
+ end: closingIndex + markerLength
1791
+ });
1792
+ index = closingIndex + markerLength;
1793
+ }
1794
+ return ranges;
1795
+ }
1796
+ function findMdxExpressionLiteralRanges(content, protectedRanges) {
1797
+ const ranges = [];
1798
+ let index = 0;
1799
+ while (index < content.length) {
1800
+ if (content[index] !== "{" || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1801
+ index += 1;
1802
+ continue;
1803
+ }
1804
+ let cursor = index + 1;
1805
+ let depth = 1;
1806
+ while (cursor < content.length && depth > 0) {
1807
+ if (isInsideRange(cursor, protectedRanges)) {
1808
+ cursor += 1;
1809
+ continue;
1810
+ }
1811
+ const character = content[cursor];
1812
+ const next = content[cursor + 1];
1813
+ if (character === "\"" || character === "'" || character === "`") {
1814
+ const quote = character;
1815
+ const start = cursor;
1816
+ cursor += 1;
1817
+ while (cursor < content.length) {
1818
+ if (content[cursor] === "\\") {
1819
+ cursor += 2;
1820
+ continue;
1821
+ }
1822
+ if (content[cursor] === quote) {
1823
+ cursor += 1;
1824
+ break;
1825
+ }
1826
+ cursor += 1;
1827
+ }
1828
+ ranges.push({
1829
+ start,
1830
+ end: cursor
1831
+ });
1832
+ continue;
1833
+ }
1834
+ if (character === "/" && next === "*") {
1835
+ const start = cursor;
1836
+ const end = content.indexOf("*/", cursor + 2);
1837
+ cursor = end === -1 ? content.length : end + 2;
1838
+ ranges.push({
1839
+ start,
1840
+ end: cursor
1841
+ });
1842
+ continue;
1843
+ }
1844
+ if (character === "/" && next === "/") {
1845
+ const start = cursor;
1846
+ const newline = content.indexOf("\n", cursor + 2);
1847
+ cursor = newline === -1 ? content.length : newline;
1848
+ ranges.push({
1849
+ start,
1850
+ end: cursor
1851
+ });
1852
+ continue;
1853
+ }
1854
+ if (character === "/") {
1855
+ if (canStartJavascriptRegex(content, cursor, index)) {
1856
+ const start = cursor;
1857
+ let inCharacterClass = false;
1858
+ cursor += 1;
1859
+ while (cursor < content.length) {
1860
+ if (content[cursor] === "\\") {
1861
+ cursor += 2;
1862
+ continue;
1863
+ }
1864
+ if (content[cursor] === "[") inCharacterClass = true;
1865
+ if (content[cursor] === "]") inCharacterClass = false;
1866
+ if (content[cursor] === "/" && !inCharacterClass) {
1867
+ cursor += 1;
1868
+ while (/[A-Za-z]/.test(content[cursor] ?? "")) cursor += 1;
1869
+ break;
1870
+ }
1871
+ if (content[cursor] === "\n") break;
1872
+ cursor += 1;
1873
+ }
1874
+ ranges.push({
1875
+ start,
1876
+ end: cursor
1877
+ });
1878
+ continue;
1879
+ }
1880
+ }
1881
+ if (character === "{") depth += 1;
1882
+ if (character === "}") depth -= 1;
1883
+ cursor += 1;
1884
+ }
1885
+ index = Math.max(index + 1, cursor);
1886
+ }
1887
+ return ranges;
1888
+ }
1889
+ function readGenericMdxJsxTag(content, index) {
1890
+ let cursor = index + 1;
1891
+ if (content[cursor] === "/") cursor += 1;
1892
+ if (!/[A-Za-z]/.test(content[cursor] ?? "")) return void 0;
1893
+ const nameStart = cursor;
1894
+ while (/[\w:.-]/.test(content[cursor] ?? "")) cursor += 1;
1895
+ const name = content.slice(nameStart, cursor);
1896
+ if (DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === name)) return void 0;
1897
+ if (!/[\s/>]/.test(content[cursor] ?? "")) return void 0;
1898
+ const literals = [];
1899
+ let braceDepth = 0;
1900
+ while (cursor < content.length) {
1901
+ const character = content[cursor];
1902
+ const next = content[cursor + 1];
1903
+ if (character === "\"" || character === "'" || character === "`") {
1904
+ const quote = character;
1905
+ const start = cursor;
1906
+ cursor += 1;
1907
+ while (cursor < content.length) {
1908
+ if (content[cursor] === "\\") {
1909
+ cursor += 2;
1910
+ continue;
1911
+ }
1912
+ if (content[cursor] === quote) {
1913
+ cursor += 1;
1914
+ break;
1915
+ }
1916
+ cursor += 1;
1917
+ }
1918
+ literals.push({
1919
+ start,
1920
+ end: cursor
1921
+ });
1922
+ continue;
1923
+ }
1924
+ if (braceDepth > 0 && character === "/" && next === "*") {
1925
+ const start = cursor;
1926
+ const end = content.indexOf("*/", cursor + 2);
1927
+ cursor = end === -1 ? content.length : end + 2;
1928
+ literals.push({
1929
+ start,
1930
+ end: cursor
1931
+ });
1932
+ continue;
1933
+ }
1934
+ if (braceDepth > 0 && character === "/" && next === "/") {
1935
+ const start = cursor;
1936
+ const newline = content.indexOf("\n", cursor + 2);
1937
+ cursor = newline === -1 ? content.length : newline;
1938
+ literals.push({
1939
+ start,
1940
+ end: cursor
1941
+ });
1942
+ continue;
1943
+ }
1944
+ if (character === "{") braceDepth += 1;
1945
+ else if (character === "}" && braceDepth > 0) braceDepth -= 1;
1946
+ else if (character === ">" && braceDepth === 0) {
1947
+ let previous = cursor - 1;
1948
+ while (previous >= index && /\s/.test(content[previous] ?? "")) previous -= 1;
1949
+ return {
1950
+ end: cursor + 1,
1951
+ literals,
1952
+ selfClosing: content[previous] === "/"
1953
+ };
1954
+ }
1955
+ cursor += 1;
1956
+ }
1957
+ }
1958
+ function findGenericMdxJsxLiteralRanges(content, protectedRanges) {
1959
+ const ranges = [];
1960
+ let cursor = 0;
1961
+ while (cursor < content.length) {
1962
+ const index = content.indexOf("<", cursor);
1963
+ if (index === -1) break;
1964
+ if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1965
+ cursor = index + 1;
1966
+ continue;
1967
+ }
1968
+ const tag = readGenericMdxJsxTag(content, index);
1969
+ if (!tag) {
1970
+ cursor = index + 1;
1971
+ continue;
1972
+ }
1973
+ ranges.push(...tag.literals);
1974
+ cursor = tag.end;
1975
+ }
1976
+ return ranges;
1977
+ }
1978
+ function findDelimiterExclusionRanges(content) {
1979
+ const markdownLiterals = findMarkdownLiteralRanges(content);
1980
+ const fences = findFenceRanges(content);
1981
+ const frontmatter = findLeadingFrontmatterRange(content);
1982
+ const literalBlocks = mergeProtectedRanges([
1983
+ ...markdownLiterals,
1984
+ ...fences,
1985
+ ...frontmatter ? [frontmatter] : []
1986
+ ]);
1987
+ const inlineCode = findInlineCodeRanges(content, literalBlocks);
1988
+ const markdownLinks = findMarkdownLinkDestinationRanges(content, literalBlocks);
1989
+ const nonModuleRanges = mergeProtectedRanges([
1990
+ ...literalBlocks,
1991
+ ...inlineCode,
1992
+ ...markdownLinks
1993
+ ]);
1994
+ const moduleRanges = findMdxModuleRanges(content, nonModuleRanges);
1995
+ const nonExpressionRanges = mergeProtectedRanges([...nonModuleRanges, ...moduleRanges]);
1996
+ const expressionLiterals = findMdxExpressionLiteralRanges(content, nonExpressionRanges);
1997
+ const nonJsxRanges = mergeProtectedRanges([...nonExpressionRanges, ...expressionLiterals]);
1998
+ return mergeProtectedRanges([...nonJsxRanges, ...findGenericMdxJsxLiteralRanges(content, nonJsxRanges)]);
1999
+ }
2000
+ function findProtectedRanges(content) {
2001
+ const baseExcludedRanges = findDelimiterExclusionRanges(content);
2002
+ const svelteDirectives = findSvelteDirectiveRanges(content, baseExcludedRanges);
2003
+ const excludedRanges = mergeProtectedRanges([...baseExcludedRanges, ...svelteDirectives]);
2004
+ const htmlLiterals = findHtmlLiteralRanges(content, excludedRanges);
2005
+ return mergeProtectedRanges([...excludedRanges, ...htmlLiterals]);
2006
+ }
2007
+ function normalizeProjectedWhitespace(content) {
2008
+ const protectedRanges = findProtectedRanges(content);
2009
+ return content.replace(/\n{3,}/g, (newlines, offset) => {
2010
+ const end = offset + newlines.length;
2011
+ return protectedRanges.some((range) => range.start < end && range.end > offset) ? newlines : "\n\n";
2012
+ }).trim();
2013
+ }
2014
+ /** Find audience declarations that cannot be projected consistently at build time. */
2015
+ function findDocsAudienceMdxIssues(content) {
2016
+ const issues = [];
2017
+ for (const tag of findDocsAudienceMdxTags(content)) {
2018
+ if (tag.closing) continue;
2019
+ const { attributes } = tag;
2020
+ const hasOnlyAttribute = tag.hasOnlyAttribute ?? /(?:^|\s)only\s*=/.test(attributes);
2021
+ const hasSpreadAttribute = tag.hasSpreadAttribute ?? /\{\s*\.\.\./.test(attributes);
2022
+ if ((tag.name === "Agent" || tag.name === "Human") && hasOnlyAttribute) {
2023
+ const shorthandAudience = tag.name === "Agent" ? "agent" : "human";
2024
+ issues.push({
2025
+ code: tag.name === "Agent" ? "ignored-agent-only" : "ignored-human-only",
2026
+ index: tag.index,
2027
+ message: `<${tag.name}> is always ${shorthandAudience}-only, so its \`only\` prop is ignored. Use <Audience only="${shorthandAudience}"> when you need the explicit form.`
2028
+ });
2029
+ continue;
2030
+ }
2031
+ if (tag.name !== "Audience") continue;
2032
+ if (hasSpreadAttribute) {
2033
+ issues.push({
2034
+ code: "dynamic-only",
2035
+ index: tag.index,
2036
+ message: "Audience spread props cannot be projected consistently. Remove the spread and use the static literal `only=\"human\"` or `only=\"agent\"`."
2037
+ });
2038
+ continue;
2039
+ }
2040
+ if (tag.only) continue;
2041
+ if (!hasOnlyAttribute) {
2042
+ issues.push({
2043
+ code: "missing-only",
2044
+ index: tag.index,
2045
+ message: "<Audience> requires the static literal `only=\"human\"` or `only=\"agent\"`."
2046
+ });
2047
+ continue;
2048
+ }
2049
+ const dynamicOnly = tag.onlyKind === "dynamic" || /(?:^|\s)only\s*=\s*\{/.test(attributes);
2050
+ issues.push({
2051
+ code: dynamicOnly ? "dynamic-only" : "invalid-only",
2052
+ index: tag.index,
2053
+ message: dynamicOnly ? "Dynamic Audience.only expressions cannot be projected consistently. Use the static literal `only=\"human\"` or `only=\"agent\"`." : "Audience.only must be the static literal `\"human\"` or `\"agent\"`."
2054
+ });
2055
+ }
2056
+ return issues;
2057
+ }
2058
+ /**
2059
+ * Resolve MDX into its human or agent projection.
2060
+ *
2061
+ * `<Agent>` is shorthand for `<Audience only="agent">`, while `<Human>` is
2062
+ * shorthand for `<Audience only="human">`. Unknown `Audience.only` values are
2063
+ * treated as shared content so an authoring typo never silently deletes content.
2064
+ * These primitives shape content for each surface; they are not an access-control boundary.
2065
+ */
2066
+ function resolveDocsAudienceMdxContent(content, audience) {
2067
+ const scopes = [];
2068
+ let output = "";
2069
+ let cursor = 0;
2070
+ let resolvedTag = false;
2071
+ for (const tag of findDocsAudienceMdxTags(content)) {
2072
+ const activeScope = scopes.at(-1);
2073
+ if (tag.closing && activeScope?.name !== tag.name) continue;
2074
+ resolvedTag = true;
2075
+ const visibleBeforeTag = isAudienceVisible(scopes, audience);
2076
+ if (visibleBeforeTag) output += content.slice(cursor, tag.index);
2077
+ cursor = tag.end;
2078
+ if (tag.closing) {
2079
+ if (tag.expression && visibleBeforeTag) output += "</>";
2080
+ scopes.pop();
2081
+ continue;
2082
+ }
2083
+ if (tag.selfClosing) {
2084
+ if (tag.expression && visibleBeforeTag) output += tag.jsxChild ? "{null}" : "null";
2085
+ continue;
2086
+ }
2087
+ scopes.push({
2088
+ name: tag.name,
2089
+ only: tag.only
2090
+ });
2091
+ if (tag.expression && visibleBeforeTag) output += isAudienceVisible(scopes, audience) ? "<>" : tag.jsxChild ? "{null}" : "null";
2092
+ }
2093
+ if (isAudienceVisible(scopes, audience)) output += content.slice(cursor);
2094
+ return resolvedTag ? normalizeProjectedWhitespace(output) : content;
2095
+ }
2096
+ /** Backwards-compatible name retained for existing integrations. */
2097
+ function resolveDocsAgentMdxContent(content, audience) {
2098
+ return resolveDocsAudienceMdxContent(content, audience);
2099
+ }
2100
+
2101
+ //#endregion
2102
+ //#region src/agent.ts
2103
+ const DEFAULT_DOCS_API_ROUTE = "/api/docs";
2104
+ const DEFAULT_DOCS_CONFIG_FORMAT = "docs-config-map.v1";
2105
+ const DEFAULT_DOCS_CONFIG_ROUTE = `${DEFAULT_DOCS_API_ROUTE}?format=config`;
2106
+ const DEFAULT_DOCS_DIAGNOSTICS_FORMAT = "docs-diagnostics.v1";
2107
+ const DEFAULT_DOCS_DIAGNOSTICS_ROUTE = `${DEFAULT_DOCS_API_ROUTE}?format=diagnostics`;
2108
+ const DEFAULT_OPENAPI_SCHEMA_ROUTE = `${DEFAULT_DOCS_API_ROUTE}?format=openapi`;
2109
+ const DEFAULT_AGENT_SPEC_ROUTE = "/api/docs/agent/spec";
2110
+ const DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE = "/.well-known/agent";
2111
+ const DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE = "/.well-known/agent.json";
2112
+ const DEFAULT_LLMS_TXT_ROUTE = "/llms.txt";
2113
+ const DEFAULT_LLMS_FULL_TXT_ROUTE = "/llms-full.txt";
2114
+ const DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms.txt";
2115
+ const DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms-full.txt";
2116
+ const DEFAULT_LLMS_TXT_MAX_CHARS = 5e4;
2117
+ const DEFAULT_SKILL_MD_ROUTE = "/skill.md";
2118
+ const DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE = "/.well-known/skill.md";
2119
+ const DEFAULT_AGENTS_MD_ROUTE = "/AGENTS.md";
2120
+ const DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE = "/.well-known/AGENTS.md";
2121
+ const DEFAULT_AGENT_MD_ROUTE = "/AGENT.md";
2122
+ const DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE = "/.well-known/AGENT.md";
2123
+ const DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE = "/robots.txt";
2124
+ const DEFAULT_AGENT_FEEDBACK_ROUTE = "/api/docs/agent/feedback";
2125
+ const DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA = {
2126
+ type: "object",
2127
+ additionalProperties: false,
2128
+ properties: {
2129
+ task: {
2130
+ type: "string",
2131
+ description: "Short description of what the agent was trying to do."
2132
+ },
2133
+ understanding: {
2134
+ type: "string",
2135
+ description: "How well the docs supported the task, e.g. \"partial\" or \"clear\"."
2136
+ },
2137
+ outcome: {
2138
+ type: "string",
2139
+ description: "What happened after reading the docs, e.g. \"implemented\" or \"blocked\"."
2140
+ },
2141
+ confidence: {
2142
+ type: "number",
2143
+ minimum: 0,
2144
+ maximum: 1,
2145
+ description: "Confidence score from 0 to 1."
2146
+ },
2147
+ neededCodeReading: {
2148
+ type: "boolean",
2149
+ description: "Whether the agent still needed to inspect repository code."
2150
+ },
2151
+ missingContext: {
2152
+ type: "array",
2153
+ items: { type: "string" },
2154
+ description: "Important details the docs did not provide clearly enough."
2155
+ },
2156
+ docIssues: {
2157
+ type: "array",
2158
+ items: { type: "string" },
2159
+ description: "Specific documentation problems encountered during the task."
2160
+ },
2161
+ suggestedImprovement: {
2162
+ type: "string",
2163
+ description: "Concrete suggestion for improving the docs page or examples."
2164
+ }
2165
+ },
2166
+ required: ["task", "outcome"]
2167
+ };
2168
+ const DEFAULT_DOCS_DIAGNOSTICS_MCP_TOOLS = {
2169
+ listDocs: true,
2170
+ listPages: true,
2171
+ readPage: true,
2172
+ listTasks: true,
2173
+ readTask: true,
2174
+ searchDocs: true,
2175
+ getNavigation: true,
2176
+ getCodeExamples: true,
2177
+ getConfigSchema: true,
2178
+ getContext: true
2179
+ };
2180
+ const DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER = "Signature-Agent";
2181
+ const DOCS_AI_AGENT_USER_AGENT_PATTERNS = [
2182
+ "claudebot",
2183
+ "claude-searchbot",
2184
+ "claude-user",
2185
+ "anthropic-ai",
2186
+ "claude-web",
2187
+ "chatgpt",
2188
+ "gptbot",
2189
+ "oai-searchbot",
2190
+ "openai",
2191
+ "gemini",
2192
+ "bard",
2193
+ "google-cloudvertexbot",
2194
+ "google-extended",
2195
+ "meta-externalagent",
2196
+ "meta-externalfetcher",
2197
+ "meta-webindexer",
2198
+ "perplexity",
2199
+ "youbot",
2200
+ "you.com",
2201
+ "deepseekbot",
2202
+ "cursor",
2203
+ "github-copilot",
2204
+ "codeium",
2205
+ "tabnine",
2206
+ "sourcegraph",
2207
+ "cohere-ai",
2208
+ "bytespider",
2209
+ "amazonbot",
2210
+ "ai2bot",
2211
+ "diffbot",
2212
+ "omgili",
2213
+ "omgilibot"
2214
+ ];
2215
+ const DOCS_TRADITIONAL_BOT_USER_AGENT_PATTERNS = [
2216
+ "googlebot",
2217
+ "bingbot",
2218
+ "yandexbot",
2219
+ "baiduspider",
2220
+ "duckduckbot",
2221
+ "slurp",
2222
+ "msnbot",
2223
+ "facebot",
2224
+ "twitterbot",
2225
+ "linkedinbot",
2226
+ "whatsapp",
2227
+ "telegrambot",
2228
+ "pingdom",
2229
+ "uptimerobot",
2230
+ "newrelic",
2231
+ "datadog",
2232
+ "statuspage",
2233
+ "site24x7",
2234
+ "applebot"
2235
+ ];
2236
+ const DOCS_BOT_LIKE_USER_AGENT_PATTERN = /bot|agent|fetch|crawl|spider|search/i;
2237
+ const DOCS_BOT_LIKE_USER_AGENT_TERMS = [
2238
+ "bot",
2239
+ "agent",
2240
+ "fetch",
2241
+ "crawl",
2242
+ "spider",
2243
+ "search"
2244
+ ];
2245
+ const DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN = buildDocsUserAgentHeaderPattern(DOCS_AI_AGENT_USER_AGENT_PATTERNS);
2246
+ const DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN = buildDocsUserAgentHeaderPattern(DOCS_TRADITIONAL_BOT_USER_AGENT_PATTERNS);
2247
+ const DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN = buildDocsUserAgentHeaderPattern(DOCS_BOT_LIKE_USER_AGENT_TERMS);
2248
+ const DOCS_LLMS_TXT_DIRECTIVE_LINE = "LLM index: /llms.txt";
2249
+ const DOCS_MCP_SERVICE_SUBDOMAIN_LABELS = new Set([
2250
+ "api",
2251
+ "developer",
2252
+ "developers",
2253
+ "dev",
2254
+ "docs",
2255
+ "help",
2256
+ "mcp",
2257
+ "reference"
2258
+ ]);
2259
+ const COMMON_SECOND_LEVEL_PUBLIC_SUFFIX_LABELS = new Set([
2260
+ "ac",
2261
+ "co",
2262
+ "com",
2263
+ "edu",
2264
+ "go",
2265
+ "gov",
2266
+ "mil",
2267
+ "ne",
2268
+ "net",
2269
+ "or",
2270
+ "org"
2271
+ ]);
2272
+ const DOCS_CONFIG_MAP_TOP_LEVEL_KEYS = [
2273
+ "entry",
2274
+ "docsPath",
2275
+ "contentDir",
2276
+ "i18n",
2277
+ "staticExport",
2278
+ "theme",
2279
+ "analytics",
2280
+ "telemetry",
2281
+ "cloud",
2282
+ "observability",
2283
+ "github",
2284
+ "nav",
2285
+ "themeToggle",
2286
+ "breadcrumb",
2287
+ "sidebar",
2288
+ "components",
2289
+ "onCopyClick",
2290
+ "codeBlocks",
2291
+ "feedback",
2292
+ "mcp",
2293
+ "icons",
2294
+ "pageActions",
2295
+ "search",
2296
+ "lastUpdated",
2297
+ "readingTime",
2298
+ "ai",
2299
+ "ordering",
2300
+ "llmsTxt",
2301
+ "sitemap",
2302
+ "robots",
2303
+ "changelog",
2304
+ "apiReference",
2305
+ "agent",
2306
+ "review",
2307
+ "metadata",
2308
+ "og"
2309
+ ];
2310
+ function normalizeDocsPathSegment(value) {
2311
+ return value.replace(/^\/+|\/+$/g, "");
2312
+ }
2313
+ function normalizeDocsUrlPath(value) {
2314
+ const normalized = value.replace(/\/+/g, "/");
2315
+ if (normalized === "/") return normalized;
2316
+ return normalized.replace(/\/+$/, "");
2317
+ }
2318
+ function isPlainObject(value) {
2319
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2320
+ }
2321
+ function isDocsConfigRequest(url) {
2322
+ return url.searchParams.get("format")?.trim() === "config";
2323
+ }
2324
+ function isDocsDiagnosticsRequest(url) {
2325
+ return url.searchParams.get("format")?.trim() === "diagnostics";
2326
+ }
2327
+ /** Prefer an explicitly configured API route; otherwise infer a query-form route from the request. */
2328
+ function resolveDocsRequestApiRoute(url, configuredApiRoute) {
2329
+ const configured = configuredApiRoute?.trim();
2330
+ if (configured) return resolveDocsDiscoveryApiRoute(configured);
2331
+ const fallback = resolveDocsDiscoveryApiRoute();
2332
+ const pathname = normalizeDocsUrlPath(url.pathname);
2333
+ const hasPublicRepresentationSuffix = /\.(?:md|txt|xml)$/i.test(pathname);
2334
+ if (pathname.startsWith("/.well-known/") || hasPublicRepresentationSuffix) return fallback;
2335
+ return Boolean(url.searchParams.get("format")?.trim()) || url.searchParams.get("agent")?.trim() === "spec" || url.searchParams.has("query") || url.searchParams.get("feedback")?.trim() === "agent" ? resolveDocsDiscoveryApiRoute(pathname) : fallback;
2336
+ }
2337
+ function buildDocsConfigMap(config, options = {}) {
2338
+ const pointers = {};
2339
+ const values = serializeDocsConfigMapValue(pickDocsConfigMapValues(config), [], /* @__PURE__ */ new WeakSet(), pointers);
2340
+ const mappedValues = isPlainObject(values) ? values : {};
2341
+ const language = containsDocsConfigKind(mappedValues, "jsx") ? "tsx" : "ts";
2342
+ return {
2343
+ schemaVersion: 1,
2344
+ format: DEFAULT_DOCS_CONFIG_FORMAT,
2345
+ source: {
2346
+ file: options.file ?? (language === "tsx" ? "docs.config.tsx" : "docs.config.ts"),
2347
+ language
2348
+ },
2349
+ serialization: {
2350
+ mode: "json-safe",
2351
+ redacted: "Scalar values under secret-like keys such as apiKey, token, secret, password, authorization, and credential are redacted unless the key ends with Env.",
2352
+ nonSerializable: "described"
2353
+ },
2354
+ values: mappedValues,
2355
+ pointers
2356
+ };
2357
+ }
2358
+ function buildDocsDiagnostics(config, options = {}) {
2359
+ const input = config;
2360
+ const entry = normalizeDocsPathSegment(stringConfigValue(input.entry) ?? options.entry ?? "docs");
2361
+ const docsRoute = routeFromConfigPath(stringConfigValue(input.docsPath) ?? entry);
2362
+ const cloud = isPlainObject(input.cloud) ? input.cloud : void 0;
2363
+ const apiRoute = resolveDocsDiscoveryApiRoute(options.apiRoute ?? stringConfigValue(cloud?.apiRoute));
2364
+ const apiQueryRoute = (query) => `${apiRoute}?${query}`;
2365
+ const staticExport = input.staticExport === true;
2366
+ const i18n = options.i18n ?? null;
2367
+ const localesEnabled = Boolean(i18n?.locales.length);
2368
+ const search = resolveDocsDiagnosticsSearch(input.search, staticExport);
2369
+ const ai = resolveDocsDiagnosticsAi(input.ai, staticExport);
2370
+ const llms = resolveDocsDiagnosticsLlms(input.llmsTxt);
2371
+ const apiCatalog = resolveDocsDiagnosticsApiCatalog(input.llmsTxt, staticExport, options.apiCatalog);
2372
+ const sitemapConfig = resolveDocsSitemapConfig(input.sitemap);
2373
+ const robotsEnabled = isRobotsDiscoveryEnabled(input.robots);
2374
+ const openapiConfig = resolveDocsOpenApiDiscoveryConfig(options.openapi ?? input.apiReference);
2375
+ const openapiUrl = resolveDocsOpenApiDiscoveryUrl(openapiConfig, apiRoute);
2376
+ const apiReferenceRoute = resolveDocsDiagnosticsApiReferenceRoute(input.apiReference);
2377
+ const mcp = options.mcp ?? resolveDocsDiagnosticsMcp(input.mcp);
2378
+ const feedback = options.feedback ?? resolveDocsAgentFeedbackConfig(input.feedback);
2379
+ const agentFeedbackEnabled = feedback.enabled === true;
2380
+ const agentFeedbackRoute = feedback.route ?? DEFAULT_AGENT_FEEDBACK_ROUTE;
2381
+ const agentFeedbackSchemaRoute = feedback.schemaRoute ?? `${agentFeedbackRoute}/schema`;
2382
+ const humanFeedback = isDocsDiagnosticsHumanFeedbackEnabled(input.feedback);
2383
+ const warnings = [];
2384
+ const errors = [];
2385
+ if (staticExport) warnings.push({
2386
+ severity: "warning",
2387
+ code: "static-export-runtime-api",
2388
+ path: "/staticExport",
2389
+ message: `staticExport is enabled; runtime API-backed capabilities at ${apiRoute} are unavailable in production static export builds.`
2390
+ });
2391
+ if (staticExport && ai.configured) errors.push({
2392
+ severity: "error",
2393
+ code: "ai-static-export",
2394
+ path: "/ai/enabled",
2395
+ message: `Ask AI requires the runtime ${apiRoute} POST handler and will not run in static export builds.`
2396
+ });
2397
+ if (ai.enabled && !search.enabled) warnings.push({
2398
+ severity: "warning",
2399
+ code: "ai-without-search",
2400
+ path: "/ai",
2401
+ message: "Ask AI is enabled while docs search is disabled, so retrieval context may be unavailable."
2402
+ });
2403
+ const adapter = options.adapter?.trim() || null;
2404
+ if (adapter && adapter !== "next") {
2405
+ if (!stringConfigValue(input.contentDir)) warnings.push({
2406
+ severity: "warning",
2407
+ code: "missing-content-dir",
2408
+ path: "/contentDir",
2409
+ message: `${adapter} docs usually need contentDir so the server can find markdown content.`
2410
+ });
2411
+ if (!isPlainObject(input.nav)) warnings.push({
2412
+ severity: "warning",
2413
+ code: "missing-nav",
2414
+ path: "/nav",
2415
+ message: `${adapter} docs usually need nav.title and nav.url for sidebar branding and root navigation.`
2416
+ });
2417
+ }
2418
+ validateDocsDiagnosticsSearchConfig(input.search, errors);
2419
+ return {
2420
+ schemaVersion: 1,
2421
+ format: DEFAULT_DOCS_DIAGNOSTICS_FORMAT,
2422
+ ok: errors.length === 0,
2423
+ adapter,
2424
+ routes: {
2425
+ docs: docsRoute,
2426
+ api: apiRoute,
2427
+ config: apiQueryRoute("format=config"),
2428
+ diagnostics: apiQueryRoute("format=diagnostics"),
2429
+ agentSpec: apiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : apiQueryRoute("agent=spec"),
2430
+ apiCatalog: apiCatalog.enabled ? DEFAULT_API_CATALOG_ROUTE : null,
2431
+ agentSkillsIndex: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
2432
+ agentSkillsArtifact: DEFAULT_AGENT_SKILLS_ROUTE_PATTERN,
2433
+ agents: apiQueryRoute("format=agents"),
2434
+ skill: apiQueryRoute("format=skill"),
2435
+ search: search.enabled ? apiQueryRoute("query={query}") : null,
2436
+ agentSearch: search.enabled ? apiQueryRoute("query={query}&audience=agent") : null,
2437
+ askAi: ai.enabled ? apiRoute : null,
2438
+ mcp: mcp.enabled ? mcp.route : null,
2439
+ llmsTxt: llms.enabled ? DEFAULT_LLMS_TXT_ROUTE : null,
2440
+ llmsFullTxt: llms.enabled ? DEFAULT_LLMS_FULL_TXT_ROUTE : null,
2441
+ sitemapXml: sitemapConfig.enabled && sitemapConfig.xml.enabled ? sitemapConfig.xml.route : null,
2442
+ sitemapMarkdown: sitemapConfig.enabled && sitemapConfig.markdown.enabled ? sitemapConfig.markdown.route : null,
2443
+ robots: robotsEnabled ? DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE : null,
2444
+ openapi: openapiConfig.enabled ? openapiUrl ?? apiQueryRoute("format=openapi") : null,
2445
+ apiReference: openapiConfig.enabled ? apiReferenceRoute : null
2446
+ },
2447
+ features: {
2448
+ staticExport: { status: staticExport ? "enabled" : "disabled" },
2449
+ config: {
2450
+ status: "enabled",
2451
+ route: apiQueryRoute("format=config")
2452
+ },
2453
+ diagnostics: {
2454
+ status: "enabled",
2455
+ route: apiQueryRoute("format=diagnostics")
2456
+ },
2457
+ apiCatalog: {
2458
+ status: apiCatalog.enabled ? "enabled" : "disabled",
2459
+ reason: apiCatalog.reason,
2460
+ route: apiCatalog.enabled ? DEFAULT_API_CATALOG_ROUTE : null,
2461
+ transport: "GET/HEAD"
2462
+ },
2463
+ search: {
2464
+ status: search.enabled ? "enabled" : "disabled",
2465
+ reason: search.reason,
2466
+ route: search.enabled ? apiQueryRoute("query={query}") : null,
2467
+ routes: {
2468
+ human: search.enabled ? apiQueryRoute("query={query}") : null,
2469
+ agent: search.enabled ? apiQueryRoute("query={query}&audience=agent") : null
2470
+ },
2471
+ agentEndpoint: search.enabled ? apiQueryRoute("query={query}&audience=agent") : null,
2472
+ audienceParam: "audience",
2473
+ defaultAudience: "human",
2474
+ supportedAudiences: ["human", "agent"],
2475
+ provider: search.provider,
2476
+ transport: "GET"
2477
+ },
2478
+ ai: {
2479
+ status: ai.enabled ? "enabled" : "disabled",
2480
+ reason: ai.reason,
2481
+ route: ai.enabled ? apiRoute : null,
2482
+ mode: ai.mode,
2483
+ transport: "POST"
2484
+ },
2485
+ mcp: {
2486
+ status: mcp.enabled ? "enabled" : "disabled",
2487
+ route: mcp.enabled ? mcp.route : null,
2488
+ transport: "GET/POST",
2489
+ tools: mcp.tools
2490
+ },
2491
+ feedback: {
2492
+ status: agentFeedbackEnabled || humanFeedback ? "enabled" : "disabled",
2493
+ human: humanFeedback,
2494
+ agent: agentFeedbackEnabled,
2495
+ routes: {
2496
+ agentSubmit: agentFeedbackEnabled ? agentFeedbackRoute : null,
2497
+ agentSchema: agentFeedbackEnabled ? agentFeedbackSchemaRoute : null
2498
+ }
2499
+ },
2500
+ llmsTxt: {
2501
+ status: llms.enabled ? "enabled" : "disabled",
2502
+ reason: llms.reason,
2503
+ routes: {
2504
+ txt: llms.enabled ? DEFAULT_LLMS_TXT_ROUTE : null,
2505
+ full: llms.enabled ? DEFAULT_LLMS_FULL_TXT_ROUTE : null,
2506
+ wellKnownTxt: llms.enabled ? DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE : null,
2507
+ wellKnownFull: llms.enabled ? DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE : null
2508
+ }
2509
+ },
2510
+ sitemap: {
2511
+ status: sitemapConfig.enabled ? "enabled" : "disabled",
2512
+ routes: {
2513
+ xml: sitemapConfig.enabled && sitemapConfig.xml.enabled ? sitemapConfig.xml.route : null,
2514
+ markdown: sitemapConfig.enabled && sitemapConfig.markdown.enabled ? sitemapConfig.markdown.route : null,
2515
+ docsMarkdown: sitemapConfig.enabled && sitemapConfig.markdown.enabled ? sitemapConfig.markdown.docsRoute ?? null : null,
2516
+ wellKnownMarkdown: sitemapConfig.enabled && sitemapConfig.markdown.enabled ? sitemapConfig.markdown.wellKnownRoute : null
2517
+ }
2518
+ },
2519
+ robots: {
2520
+ status: robotsEnabled ? "enabled" : "disabled",
2521
+ route: robotsEnabled ? DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE : null
2522
+ },
2523
+ apiReference: {
2524
+ status: openapiConfig.enabled ? "enabled" : "disabled",
2525
+ route: openapiConfig.enabled ? apiReferenceRoute : null,
2526
+ routes: { openapi: openapiConfig.enabled ? openapiUrl ?? apiQueryRoute("format=openapi") : null },
2527
+ provider: openapiConfig.source
2528
+ },
2529
+ agents: {
2530
+ status: "enabled",
2531
+ routes: {
2532
+ default: DEFAULT_AGENTS_MD_ROUTE,
2533
+ wellKnown: DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE,
2534
+ api: apiQueryRoute("format=agents")
2535
+ }
2536
+ },
2537
+ skills: {
2538
+ status: "enabled",
2539
+ transport: "GET/HEAD",
2540
+ routes: {
2541
+ default: DEFAULT_SKILL_MD_ROUTE,
2542
+ wellKnown: DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE,
2543
+ api: apiQueryRoute("format=skill"),
2544
+ index: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
2545
+ artifact: DEFAULT_AGENT_SKILLS_ROUTE_PATTERN
2546
+ }
2547
+ },
2548
+ locales: {
2549
+ status: localesEnabled ? "enabled" : "disabled",
2550
+ provider: localesEnabled ? "query-param" : void 0
2551
+ }
2552
+ },
2553
+ warnings,
2554
+ errors
2555
+ };
2556
+ }
2557
+ function pickDocsConfigMapValues(config) {
2558
+ const output = {};
2559
+ for (const key of DOCS_CONFIG_MAP_TOP_LEVEL_KEYS) if (Object.prototype.hasOwnProperty.call(config, key)) output[key] = config[key];
2560
+ return output;
2561
+ }
2562
+ function serializeDocsConfigMapValue(value, path, seen, pointers, depth = 0) {
2563
+ const key = path.at(-1) ?? "";
2564
+ const pointerPath = toDocsConfigJsonPointer(path);
2565
+ const setPointer = (kind) => {
2566
+ if (path.length > 0) pointers[pointerPath] = {
2567
+ path: toDocsConfigDotPath(path),
2568
+ kind
2569
+ };
2570
+ };
2571
+ if (value === void 0) return void 0;
2572
+ if (shouldRedactDocsConfigKey(key) && value !== null && typeof value !== "object") {
2573
+ setPointer("secret");
2574
+ return {
2575
+ $kind: "secret",
2576
+ value: "[redacted]"
2577
+ };
2578
+ }
2579
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
2580
+ setPointer(typeof value);
2581
+ return value;
2582
+ }
2583
+ if (typeof value === "number") {
2584
+ setPointer("number");
2585
+ return Number.isFinite(value) ? value : String(value);
2586
+ }
2587
+ if (typeof value === "bigint") {
2588
+ setPointer("bigint");
2589
+ return {
2590
+ $kind: "bigint",
2591
+ value: value.toString()
2592
+ };
2593
+ }
2594
+ if (typeof value === "symbol") {
2595
+ setPointer("symbol");
2596
+ return {
2597
+ $kind: "symbol",
2598
+ value: String(value)
2599
+ };
2600
+ }
2601
+ if (typeof value === "function") {
2602
+ setPointer("function");
2603
+ return {
2604
+ $kind: "function",
2605
+ name: getDocsConfigFunctionName(value)
2606
+ };
2607
+ }
2608
+ if (value instanceof Date) {
2609
+ setPointer("date");
2610
+ return {
2611
+ $kind: "date",
2612
+ value: value.toISOString()
2613
+ };
2614
+ }
2615
+ if (value instanceof URL) {
2616
+ setPointer("url");
2617
+ return value.toString();
2618
+ }
2619
+ if (depth >= 10) {
2620
+ setPointer("truncated");
2621
+ return {
2622
+ $kind: "truncated",
2623
+ reason: "Exceeded max depth of 10."
2624
+ };
2625
+ }
2626
+ if (Array.isArray(value)) {
2627
+ setPointer("array");
2628
+ return value.map((entry, index) => serializeDocsConfigMapValue(entry, [...path, String(index)], seen, pointers, depth + 1)).filter((entry) => entry !== void 0);
2629
+ }
2630
+ if (isDocsConfigReactElement(value)) {
2631
+ setPointer("jsx");
2632
+ return {
2633
+ $kind: "jsx",
2634
+ component: getDocsConfigReactElementName(value)
2635
+ };
2636
+ }
2637
+ if (seen.has(value)) {
2638
+ setPointer("circular");
2639
+ return { $kind: "circular" };
2640
+ }
2641
+ seen.add(value);
2642
+ const output = {};
2643
+ for (const [childKey, childValue] of Object.entries(value)) {
2644
+ const serialized = serializeDocsConfigMapValue(childValue, [...path, childKey], seen, pointers, depth + 1);
2645
+ if (serialized !== void 0) output[childKey] = serialized;
2646
+ }
2647
+ seen.delete(value);
2648
+ if (path.length === 1 && path[0] === "theme") {
2649
+ setPointer("theme");
2650
+ return {
2651
+ $kind: "theme",
2652
+ ...output
2653
+ };
2654
+ }
2655
+ setPointer("object");
2656
+ return output;
2657
+ }
2658
+ function shouldRedactDocsConfigKey(key) {
2659
+ const normalized = key.replace(/[-_]/g, "").toLowerCase();
2660
+ if (!normalized || normalized === "env" || normalized.endsWith("env")) return false;
2661
+ return normalized.includes("apikey") || normalized.includes("token") || normalized.includes("secret") || normalized.includes("password") || normalized.includes("authorization") || normalized.includes("credential");
2662
+ }
2663
+ function isDocsConfigReactElement(value) {
2664
+ if (!isPlainObject(value) || !("$$typeof" in value)) return false;
2665
+ return String(value.$$typeof).includes("react.");
2666
+ }
2667
+ function getDocsConfigReactElementName(value) {
2668
+ const type = value.type;
2669
+ if (typeof type === "string") return type;
2670
+ if (typeof type === "function") return getDocsConfigFunctionName(type);
2671
+ if (isPlainObject(type)) {
2672
+ const displayName = type.displayName;
2673
+ if (typeof displayName === "string") return displayName;
2674
+ const render = type.render;
2675
+ if (typeof render === "function") return getDocsConfigFunctionName(render);
2676
+ }
2677
+ return "unknown";
2678
+ }
2679
+ function getDocsConfigFunctionName(value) {
2680
+ const displayName = value.displayName;
2681
+ return typeof displayName === "string" ? displayName : value.name || "anonymous";
2682
+ }
2683
+ function toDocsConfigJsonPointer(path) {
2684
+ return path.length === 0 ? "" : `/${path.map(escapeDocsConfigJsonPointerPart).join("/")}`;
2685
+ }
2686
+ function escapeDocsConfigJsonPointerPart(value) {
2687
+ return value.replace(/~/g, "~0").replace(/\//g, "~1");
2688
+ }
2689
+ function toDocsConfigDotPath(path) {
2690
+ return path.map((part, index) => /^\d+$/.test(part) ? `[${part}]` : index === 0 ? part : `.${part}`).join("");
2691
+ }
2692
+ function containsDocsConfigKind(value, kind) {
2693
+ if (!isPlainObject(value)) {
2694
+ if (!Array.isArray(value)) return false;
2695
+ }
2696
+ if (Array.isArray(value)) return value.some((entry) => containsDocsConfigKind(entry, kind));
2697
+ if (value["$kind"] === kind) return true;
2698
+ return Object.values(value).some((entry) => containsDocsConfigKind(entry, kind));
2699
+ }
2700
+ function stringConfigValue(value) {
2701
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
2702
+ }
2703
+ function routeFromConfigPath(value) {
2704
+ const normalized = normalizeDocsPathSegment(value);
2705
+ return normalized ? `/${normalized}` : "/";
2706
+ }
2707
+ function resolveDocsDiagnosticsSearch(search, staticExport) {
2708
+ const provider = isPlainObject(search) ? stringConfigValue(search.provider) : "simple";
2709
+ const configured = search !== false && !(isPlainObject(search) && search.enabled === false);
2710
+ if (staticExport) return {
2711
+ enabled: false,
2712
+ configured,
2713
+ provider,
2714
+ reason: "static-export"
2715
+ };
2716
+ if (!configured) return {
2717
+ enabled: false,
2718
+ configured,
2719
+ provider,
2720
+ reason: "configured-disabled"
2721
+ };
2722
+ return {
2723
+ enabled: true,
2724
+ configured,
2725
+ provider
2726
+ };
2727
+ }
2728
+ function resolveDocsDiagnosticsAi(ai, staticExport) {
2729
+ const configured = isPlainObject(ai) && ai.enabled === true;
2730
+ const mode = isPlainObject(ai) ? stringConfigValue(ai.mode) : void 0;
2731
+ if (!configured) return {
2732
+ enabled: false,
2733
+ configured,
2734
+ reason: "not-configured"
2735
+ };
2736
+ if (staticExport) return {
2737
+ enabled: false,
2738
+ configured,
2739
+ mode,
2740
+ reason: "static-export"
2741
+ };
2742
+ return {
2743
+ enabled: true,
2744
+ configured,
2745
+ mode
2746
+ };
2747
+ }
2748
+ function resolveDocsDiagnosticsLlms(llmsTxt) {
2749
+ return llmsTxt !== false && !(isPlainObject(llmsTxt) && llmsTxt.enabled === false) ? { enabled: true } : {
2750
+ enabled: false,
2751
+ reason: "configured-disabled"
2752
+ };
2753
+ }
2754
+ function resolveDocsDiagnosticsApiCatalog(llmsTxt, staticExport, explicit) {
2755
+ if (staticExport) return {
2756
+ enabled: false,
2757
+ reason: "static-export"
2758
+ };
2759
+ if (explicit !== void 0) return explicit ? { enabled: true } : {
2760
+ enabled: false,
2761
+ reason: "configured-disabled"
2762
+ };
2763
+ if (isPlainObject(llmsTxt) && llmsTxt.apiCatalog === false) return {
2764
+ enabled: false,
2765
+ reason: "llms-txt-api-catalog-disabled"
2766
+ };
2767
+ return { enabled: true };
2768
+ }
2769
+ function resolveDocsDiagnosticsMcp(mcp) {
2770
+ const config = isPlainObject(mcp) ? mcp : {};
2771
+ const tools = isPlainObject(config.tools) ? config.tools : {};
2772
+ return {
2773
+ enabled: typeof mcp === "boolean" ? mcp : config.enabled !== false,
2774
+ route: normalizeDocsDiagnosticsMcpRoute(config.route),
2775
+ name: stringConfigValue(config.name) ?? "Documentation",
2776
+ version: stringConfigValue(config.version) ?? "0.0.0",
2777
+ tools: {
2778
+ ...DEFAULT_DOCS_DIAGNOSTICS_MCP_TOOLS,
2779
+ listDocs: tools.listDocs !== false,
2780
+ listPages: tools.listPages !== false,
2781
+ readPage: tools.readPage !== false,
2782
+ listTasks: tools.listTasks !== false,
2783
+ readTask: tools.readTask !== false,
2784
+ searchDocs: tools.searchDocs !== false,
2785
+ getNavigation: tools.getNavigation !== false,
2786
+ getCodeExamples: tools.getCodeExamples !== false,
2787
+ getConfigSchema: tools.getConfigSchema !== false,
2788
+ getContext: tools.getContext !== false
2789
+ }
2790
+ };
2791
+ }
2792
+ function normalizeDocsDiagnosticsMcpRoute(route) {
2793
+ const value = stringConfigValue(route);
2794
+ if (!value) return DEFAULT_MCP_ROUTE;
2795
+ const normalized = `/${value}`.replace(/\/+/g, "/");
2796
+ return normalized !== "/" ? normalized.replace(/\/+$/, "") : DEFAULT_MCP_ROUTE;
2797
+ }
2798
+ function isDocsDiagnosticsHumanFeedbackEnabled(feedback) {
2799
+ return feedback === true || isPlainObject(feedback) && feedback.enabled !== false;
2800
+ }
2801
+ function resolveDocsDiagnosticsApiReferenceRoute(apiReference) {
2802
+ if (isPlainObject(apiReference)) return routeFromConfigPath(stringConfigValue(apiReference.path) ?? "api-reference");
2803
+ return "/api-reference";
2804
+ }
2805
+ function validateDocsDiagnosticsSearchConfig(search, errors) {
2806
+ if (!isPlainObject(search) || search.enabled === false) return;
2807
+ const provider = stringConfigValue(search.provider) ?? "simple";
2808
+ const requireString = (key) => {
2809
+ if (!stringConfigValue(search[key])) errors.push({
2810
+ severity: "error",
2811
+ code: `missing-search-${key.replace(/[A-Z]/g, (value) => `-${value.toLowerCase()}`)}`,
2812
+ path: `/search/${key}`,
2813
+ message: `Search provider "${provider}" requires search.${key}.`
2814
+ });
2815
+ };
2816
+ if (provider === "algolia") {
2817
+ requireString("appId");
2818
+ requireString("indexName");
2819
+ requireString("searchApiKey");
2820
+ }
2821
+ if (provider === "typesense") {
2822
+ requireString("baseUrl");
2823
+ requireString("collection");
2824
+ requireString("apiKey");
2825
+ }
2826
+ if (provider === "mcp") requireString("endpoint");
2827
+ if (provider === "custom" && !("adapter" in search)) errors.push({
2828
+ severity: "error",
2829
+ code: "missing-search-adapter",
2830
+ path: "/search/adapter",
2831
+ message: "Search provider \"custom\" requires search.adapter."
2832
+ });
2833
+ }
2834
+ function normalizeDocsAgentFeedbackRoute(route, fallback = DEFAULT_AGENT_FEEDBACK_ROUTE) {
2835
+ if (!route || route.trim().length === 0) return fallback;
2836
+ const normalized = `/${route}`.replace(/\/+/g, "/");
2837
+ return normalized !== "/" ? normalized.replace(/\/+$/, "") : fallback;
2838
+ }
2839
+ function buildDocsAgentFeedbackSchema(payloadSchema) {
2840
+ return {
2841
+ type: "object",
2842
+ additionalProperties: false,
2843
+ properties: {
2844
+ context: {
2845
+ type: "object",
2846
+ additionalProperties: false,
2847
+ properties: {
2848
+ page: { type: "string" },
2849
+ url: { type: "string" },
2850
+ slug: { type: "string" },
2851
+ locale: { type: "string" },
2852
+ source: { type: "string" }
2853
+ }
2854
+ },
2855
+ payload: payloadSchema
2856
+ },
2857
+ required: ["payload"]
2858
+ };
2859
+ }
2860
+ function resolveDocsAgentFeedbackConfig(feedback) {
2861
+ const route = normalizeDocsAgentFeedbackRoute();
2862
+ const enabled = {
2863
+ enabled: true,
2864
+ route,
2865
+ schemaRoute: `${route}/schema`,
2866
+ payloadSchema: DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA,
2867
+ schema: buildDocsAgentFeedbackSchema(DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA)
2868
+ };
2869
+ const disabled = {
2870
+ enabled: false,
2871
+ route,
2872
+ schemaRoute: `${route}/schema`,
2873
+ payloadSchema: DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA,
2874
+ schema: buildDocsAgentFeedbackSchema(DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA)
2875
+ };
2876
+ if (feedback === false) return disabled;
2877
+ if (!feedback || feedback === true || typeof feedback !== "object") return enabled;
2878
+ const agent = feedback.agent;
2879
+ if (agent === false) return disabled;
2880
+ if (!agent) return enabled;
2881
+ if (agent === true) return enabled;
2882
+ const resolvedRoute = normalizeDocsAgentFeedbackRoute(agent.route, route);
2883
+ const resolvedSchemaRoute = normalizeDocsAgentFeedbackRoute(agent.schemaRoute, `${resolvedRoute}/schema`);
2884
+ const payloadSchema = agent.schema ?? DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA;
2885
+ return {
2886
+ enabled: agent.enabled !== false,
2887
+ route: resolvedRoute,
2888
+ schemaRoute: resolvedSchemaRoute,
2889
+ payloadSchema,
2890
+ schema: buildDocsAgentFeedbackSchema(payloadSchema),
2891
+ onFeedback: agent.onFeedback
2892
+ };
2893
+ }
2894
+ function resolveDocsAgentFeedbackRequest(url, feedback) {
2895
+ if (!feedback.enabled) return null;
2896
+ const feedbackMode = url.searchParams.get("feedback")?.trim();
2897
+ const schemaMode = url.searchParams.get("schema")?.trim();
2898
+ if (feedbackMode === "agent") return { kind: schemaMode === "1" || schemaMode === "true" ? "schema" : "submit" };
2899
+ const pathname = normalizeDocsUrlPath(url.pathname);
2900
+ if (pathname === feedback.schemaRoute) return { kind: "schema" };
2901
+ if (pathname === feedback.route) return { kind: "submit" };
2902
+ return null;
2903
+ }
2904
+ function normalizeDocsAgentFeedbackContext(value) {
2905
+ if (!isPlainObject(value)) return void 0;
2906
+ const context = {};
2907
+ if (typeof value.page === "string") context.page = value.page;
2908
+ if (typeof value.url === "string") context.url = value.url;
2909
+ if (typeof value.slug === "string") context.slug = value.slug;
2910
+ if (typeof value.locale === "string") context.locale = value.locale;
2911
+ if (typeof value.source === "string") context.source = value.source;
2912
+ return Object.keys(context).length > 0 ? context : void 0;
2913
+ }
2914
+ async function parseDocsAgentFeedbackData(request) {
2915
+ let body;
2916
+ try {
2917
+ body = await request.json();
2918
+ } catch {
2919
+ return {
2920
+ ok: false,
2921
+ response: Response.json({ error: "Agent feedback body must be valid JSON" }, { status: 400 })
2922
+ };
2923
+ }
2924
+ if (!isPlainObject(body)) return {
2925
+ ok: false,
2926
+ response: Response.json({ error: "Agent feedback body must be an object" }, { status: 400 })
2927
+ };
2928
+ if (!isPlainObject(body.payload)) return {
2929
+ ok: false,
2930
+ response: Response.json({ error: "Agent feedback body must include a payload object" }, { status: 400 })
2931
+ };
2932
+ return {
2933
+ ok: true,
2934
+ data: {
2935
+ context: normalizeDocsAgentFeedbackContext(body.context),
2936
+ payload: body.payload
2937
+ }
2938
+ };
2939
+ }
2940
+ function validateDocsAgentFeedbackPayload(value, schema, valuePath = "payload") {
2941
+ const schemaType = typeof schema.type === "string" ? schema.type : void 0;
2942
+ if (Array.isArray(schema.enum) && !schema.enum.some((entry) => Object.is(entry, value))) return `${valuePath} must be one of the configured enum values`;
2943
+ if (schemaType === "object" || !schemaType && (schema.properties || schema.required)) {
2944
+ if (!isPlainObject(value)) return `${valuePath} must be an object`;
2945
+ const properties = isPlainObject(schema.properties) ? schema.properties : {};
2946
+ const required = Array.isArray(schema.required) ? schema.required.filter((entry) => typeof entry === "string") : [];
2947
+ for (const key of required) if (!(key in value)) return `${valuePath}.${key} is required`;
2948
+ if (schema.additionalProperties === false) {
2949
+ for (const key of Object.keys(value)) if (!(key in properties)) return `${valuePath}.${key} is not allowed`;
2950
+ }
2951
+ for (const [key, propertySchema] of Object.entries(properties)) {
2952
+ if (!(key in value)) continue;
2953
+ if (!isPlainObject(propertySchema)) continue;
2954
+ const error = validateDocsAgentFeedbackPayload(value[key], propertySchema, `${valuePath}.${key}`);
2955
+ if (error) return error;
2956
+ }
2957
+ return;
2958
+ }
2959
+ if (schemaType === "array") {
2960
+ if (!Array.isArray(value)) return `${valuePath} must be an array`;
2961
+ if (!isPlainObject(schema.items)) return void 0;
2962
+ for (const [index, item] of value.entries()) {
2963
+ const error = validateDocsAgentFeedbackPayload(item, schema.items, `${valuePath}[${index}]`);
2964
+ if (error) return error;
2965
+ }
2966
+ return;
2967
+ }
2968
+ if (schemaType === "string") {
2969
+ if (typeof value !== "string") return `${valuePath} must be a string`;
2970
+ if (typeof schema.minLength === "number" && value.length < schema.minLength) return `${valuePath} must be at least ${schema.minLength} characters`;
2971
+ if (typeof schema.maxLength === "number" && value.length > schema.maxLength) return `${valuePath} must be at most ${schema.maxLength} characters`;
2972
+ return;
2973
+ }
2974
+ if (schemaType === "number") {
2975
+ if (typeof value !== "number" || !Number.isFinite(value)) return `${valuePath} must be a number`;
2976
+ if (typeof schema.minimum === "number" && value < schema.minimum) return `${valuePath} must be >= ${schema.minimum}`;
2977
+ if (typeof schema.maximum === "number" && value > schema.maximum) return `${valuePath} must be <= ${schema.maximum}`;
2978
+ return;
2979
+ }
2980
+ if (schemaType === "boolean") {
2981
+ if (typeof value !== "boolean") return `${valuePath} must be a boolean`;
2982
+ return;
2983
+ }
2984
+ }
2985
+ function toDocsMarkdownUrl(url, options = {}) {
2986
+ const [withoutHash, hash = ""] = url.split("#", 2);
2987
+ const [pathname, query = ""] = withoutHash.split("?", 2);
2988
+ const normalizedPath = normalizeDocsUrlPath(pathname || "/");
2989
+ const markdownPath = normalizedPath.endsWith(".md") ? normalizedPath : `${normalizedPath}.md`;
2990
+ const params = new URLSearchParams(query);
2991
+ if (options.locale && !params.has("lang")) params.set("lang", options.locale);
2992
+ const search = params.toString();
2993
+ return `${markdownPath}${search ? `?${search}` : ""}${hash ? `#${hash}` : ""}`;
2994
+ }
2995
+ function resolveDocsMarkdownCanonicalUrl({ origin, entry = "docs", requestedPath, locale }) {
2996
+ const pathname = normalizeRequestedMarkdownPath(normalizeDocsPathSegment(entry) || "docs", requestedPath);
2997
+ const canonicalUrl = new URL(pathname, origin);
2998
+ if (locale) canonicalUrl.searchParams.set("lang", locale);
2999
+ return canonicalUrl.toString();
3000
+ }
3001
+ function getDocsMarkdownCanonicalLinkHeader(options) {
3002
+ return `<${resolveDocsMarkdownCanonicalUrl(options)}>; rel="canonical"`;
3003
+ }
3004
+ function joinDocsPublicRoute(prefix, suffix) {
3005
+ const normalizedPrefix = normalizeDocsUrlPath(`/${normalizeDocsPathSegment(prefix)}`);
3006
+ const normalizedSuffix = `/${normalizeDocsPathSegment(suffix)}`;
3007
+ if (normalizedPrefix === "/") return normalizedSuffix;
3008
+ return normalizeDocsUrlPath(`${normalizedPrefix}${normalizedSuffix}`);
3009
+ }
3010
+ function normalizeLlmsTxtMatch(value) {
3011
+ const trimmed = value.trim();
3012
+ if (!trimmed) return "/";
3013
+ return normalizeDocsUrlPath(trimmed.startsWith("/") ? trimmed : `/${trimmed}`);
3014
+ }
3015
+ function llmsTxtMatchPrefix(value) {
3016
+ const normalized = normalizeLlmsTxtMatch(value);
3017
+ const wildcardIndex = normalized.indexOf("*");
3018
+ return normalizeDocsUrlPath((wildcardIndex >= 0 ? normalized.slice(0, wildcardIndex) : normalized).replace(/\/+$/, "") || "/");
3019
+ }
3020
+ function deriveLlmsTxtSectionRoute(match) {
3021
+ return joinDocsPublicRoute(llmsTxtMatchPrefix(match[0] ?? "/"), "llms.txt");
3022
+ }
3023
+ function deriveLlmsTxtSectionFullRoute(route) {
3024
+ const normalized = normalizeDocsUrlPath(route);
3025
+ if (normalized.endsWith("/llms.txt")) return `${normalized.slice(0, -9)}/llms-full.txt`;
3026
+ return joinDocsPublicRoute(normalized, "llms-full.txt");
3027
+ }
3028
+ function resolveDocsBaseLlmsTxtRoute(basePath) {
3029
+ if (!basePath) return null;
3030
+ return joinDocsPublicRoute(normalizeDocsPathSegment(basePath) || "docs", "llms.txt");
3031
+ }
3032
+ function resolveDocsBaseLlmsFullTxtRoute(basePath) {
3033
+ const route = resolveDocsBaseLlmsTxtRoute(basePath);
3034
+ return route ? deriveLlmsTxtSectionFullRoute(route) : null;
3035
+ }
3036
+ function normalizeLlmsTxtMaxChars(value, fallback) {
3037
+ const mode = value?.mode ?? fallback?.mode ?? "warn";
3038
+ const chars = value?.chars ?? fallback?.chars ?? DEFAULT_LLMS_TXT_MAX_CHARS;
3039
+ return {
3040
+ mode,
3041
+ chars: Number.isFinite(chars) && chars > 0 ? Math.floor(chars) : DEFAULT_LLMS_TXT_MAX_CHARS
3042
+ };
3043
+ }
3044
+ function resolveDocsLlmsTxtSections(llms) {
3045
+ if (!llms || typeof llms !== "object" || !Array.isArray(llms.sections)) return [];
3046
+ const rootMaxChars = normalizeLlmsTxtMaxChars(llms.maxChars);
3047
+ return llms.sections.flatMap((section) => {
3048
+ const match = (Array.isArray(section.match) ? section.match : [section.match]).map(normalizeLlmsTxtMatch).filter(Boolean);
3049
+ if (match.length === 0) return [];
3050
+ const route = deriveLlmsTxtSectionRoute(match);
3051
+ const resolved = {
3052
+ title: section.title,
3053
+ match,
3054
+ route,
3055
+ fullRoute: deriveLlmsTxtSectionFullRoute(route),
3056
+ maxChars: normalizeLlmsTxtMaxChars(section.maxChars, rootMaxChars)
3057
+ };
3058
+ if (section.description !== void 0) resolved.description = section.description;
3059
+ return [resolved];
3060
+ });
3061
+ }
3062
+ function matchesDocsLlmsTxtSection(pageUrl, section) {
3063
+ const pathname = normalizeDocsUrlPath(pageUrl.split(/[?#]/, 1)[0] || "/");
3064
+ return section.match.some((pattern) => {
3065
+ const normalized = normalizeLlmsTxtMatch(pattern);
3066
+ if (normalized.endsWith("/**")) {
3067
+ const prefix = normalizeDocsUrlPath(normalized.slice(0, -3) || "/");
3068
+ if (prefix === "/") return true;
3069
+ return pathname === prefix || pathname.startsWith(`${prefix}/`);
3070
+ }
3071
+ if (normalized.endsWith("/*")) {
3072
+ const prefix = normalizeDocsUrlPath(normalized.slice(0, -2) || "/");
3073
+ if (prefix === "/") {
3074
+ const directChild = pathname.slice(1);
3075
+ return directChild.length > 0 && !directChild.includes("/");
3076
+ }
3077
+ if (!pathname.startsWith(`${prefix}/`)) return false;
3078
+ return !pathname.slice(prefix.length + 1).includes("/");
3079
+ }
3080
+ return pathname === normalized;
3081
+ });
3082
+ }
3083
+ function resolveDocsLlmsTxtRequest(url, llms, basePath, options = {}) {
3084
+ const pathname = normalizeDocsUrlPath(url.pathname);
3085
+ const apiRoute = resolveDocsDiscoveryApiRoute(options.apiRoute);
3086
+ const sections = resolveDocsLlmsTxtSections(llms);
3087
+ for (const section of sections) {
3088
+ if (pathname === section.route) return {
3089
+ format: "llms",
3090
+ section
3091
+ };
3092
+ if (pathname === section.fullRoute) return {
3093
+ format: "llms-full",
3094
+ section
3095
+ };
3096
+ }
3097
+ const format = url.searchParams.get("format");
3098
+ if (pathname === apiRoute && (format === "llms" || format === "llms-full")) {
3099
+ const sectionRoute = url.searchParams.get("section")?.trim();
3100
+ const normalizedSectionRoute = sectionRoute ? normalizeDocsUrlPath(sectionRoute) : void 0;
3101
+ return {
3102
+ format,
3103
+ section: normalizedSectionRoute ? sections.find((candidate) => candidate.route === normalizedSectionRoute || candidate.fullRoute === normalizedSectionRoute) ?? {
3104
+ title: "",
3105
+ match: [],
3106
+ route: normalizedSectionRoute,
3107
+ fullRoute: normalizedSectionRoute,
3108
+ maxChars: normalizeLlmsTxtMaxChars(void 0)
3109
+ } : void 0
3110
+ };
3111
+ }
3112
+ if (pathname === DEFAULT_LLMS_TXT_ROUTE || pathname === DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE) return { format: "llms" };
3113
+ if (pathname === resolveDocsBaseLlmsTxtRoute(basePath)) return { format: "llms" };
3114
+ if (pathname === DEFAULT_LLMS_FULL_TXT_ROUTE || pathname === DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE) return { format: "llms-full" };
3115
+ if (pathname === resolveDocsBaseLlmsFullTxtRoute(basePath)) return { format: "llms-full" };
3116
+ return null;
3117
+ }
3118
+ function renderLlmsTxtPageList(pages, baseUrl) {
3119
+ let content = "";
3120
+ for (const page of pages) {
3121
+ content += `- [${page.title}](${baseUrl}${page.markdownUrl ?? toDocsMarkdownUrl(page.url)})`;
3122
+ if (page.description) content += `: ${page.description}`;
3123
+ content += "\n";
3124
+ }
3125
+ return content;
3126
+ }
3127
+ function resolveDocsResourceUrl(baseUrl, url) {
3128
+ if (/^[a-z][a-z0-9+.-]*:/i.test(url)) return url;
3129
+ return `${baseUrl}${url.startsWith("/") ? url : `/${url}`}`;
3130
+ }
3131
+ function renderLlmsFullTxtPages(pages, baseUrl) {
3132
+ let content = "";
3133
+ for (const page of pages) {
3134
+ content += `## ${page.title}\n\n`;
3135
+ content += `URL: ${baseUrl}${page.url}\n\n`;
3136
+ if (page.description) content += `${page.description}\n\n`;
3137
+ const agentContent = page.agentRawContent ?? page.agentFallbackRawContent ?? page.agentContent ?? page.agentFallbackContent ?? page.rawContent ?? page.content;
3138
+ content += `${agentContent}\n\n---\n\n`;
3139
+ }
3140
+ return content;
3141
+ }
3142
+ function renderDocsLlmsTxt(pages, options = {}) {
3143
+ const siteTitle = options.siteTitle ?? "Documentation";
3144
+ const siteDescription = options.siteDescription;
3145
+ const baseUrl = options.baseUrl ?? "";
3146
+ const maxChars = normalizeLlmsTxtMaxChars(options.maxChars);
3147
+ const apiCatalogEnabled = options.apiCatalog ?? true;
3148
+ const sections = resolveDocsLlmsTxtSections(options);
3149
+ const openapi = resolveDocsOpenApiDiscoveryConfig(options.openapi);
3150
+ const openapiUrl = resolveDocsOpenApiDiscoveryUrl(openapi, resolveDocsDiscoveryApiRoute(options.apiRoute));
3151
+ const matchedPageUrls = /* @__PURE__ */ new Set();
3152
+ const generatedSections = sections.map((section) => {
3153
+ const sectionPages = pages.filter((page) => matchesDocsLlmsTxtSection(page.url, section));
3154
+ for (const page of sectionPages) matchedPageUrls.add(normalizeDocsUrlPath(page.url));
3155
+ let llmsTxt = `# ${siteTitle} - ${section.title}\n\n`;
3156
+ if (section.description) llmsTxt += `> ${section.description}\n\n`;
3157
+ else if (siteDescription) llmsTxt += `> ${siteDescription}\n\n`;
3158
+ llmsTxt += "## Pages\n\n";
3159
+ llmsTxt += renderLlmsTxtPageList(sectionPages, baseUrl);
3160
+ let llmsFullTxt = `# ${siteTitle} - ${section.title}\n\n`;
3161
+ if (section.description) llmsFullTxt += `> ${section.description}\n\n`;
3162
+ else if (siteDescription) llmsFullTxt += `> ${siteDescription}\n\n`;
3163
+ llmsFullTxt += renderLlmsFullTxtPages(sectionPages, baseUrl);
3164
+ return {
3165
+ ...section,
3166
+ llmsTxt,
3167
+ llmsFullTxt
3168
+ };
3169
+ });
3170
+ const rootPages = generatedSections.length > 0 ? pages.filter((page) => !matchedPageUrls.has(normalizeDocsUrlPath(page.url))) : pages;
3171
+ let llmsTxt = `# ${siteTitle}\n\n`;
3172
+ if (siteDescription) llmsTxt += `> ${siteDescription}\n\n`;
3173
+ llmsTxt += "## Agent Discovery\n\n";
3174
+ llmsTxt += `- [Agent manifest](${resolveDocsResourceUrl(baseUrl, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE)}): Farming Labs discovery manifest\n`;
3175
+ if (apiCatalogEnabled) llmsTxt += `- [API catalog](${resolveDocsResourceUrl(baseUrl, DEFAULT_API_CATALOG_ROUTE)}): RFC 9727 API catalog\n`;
3176
+ llmsTxt += `- [Agent Skills index](${resolveDocsResourceUrl(baseUrl, DEFAULT_AGENT_SKILLS_INDEX_ROUTE)}): Hashed Agent Skills discovery\n\n`;
3177
+ if (generatedSections.length > 0) {
3178
+ llmsTxt += "## Sections\n\n";
3179
+ for (const section of generatedSections) {
3180
+ llmsTxt += `- [${section.title}](${baseUrl}${section.route})`;
3181
+ if (section.description) llmsTxt += `: ${section.description}`;
3182
+ llmsTxt += "\n";
3183
+ }
3184
+ llmsTxt += "\n";
3185
+ }
3186
+ if (openapi.enabled && openapiUrl) {
3187
+ llmsTxt += "## API Schemas\n\n";
3188
+ llmsTxt += `- [OpenAPI schema](${resolveDocsResourceUrl(baseUrl, openapiUrl)}): Machine-readable API schema for tool use and API clients`;
3189
+ if (openapi.apiReferencePath) llmsTxt += `; rendered API reference at ${resolveDocsResourceUrl(baseUrl, openapi.apiReferencePath)}`;
3190
+ llmsTxt += "\n\n";
3191
+ }
3192
+ if (rootPages.length > 0 || generatedSections.length === 0) {
3193
+ llmsTxt += "## Pages\n\n";
3194
+ llmsTxt += renderLlmsTxtPageList(rootPages, baseUrl);
3195
+ }
3196
+ let llmsFullTxt = `# ${siteTitle}\n\n`;
3197
+ if (siteDescription) llmsFullTxt += `> ${siteDescription}\n\n`;
3198
+ llmsFullTxt += renderLlmsFullTxtPages(pages, baseUrl);
3199
+ return {
3200
+ llmsTxt,
3201
+ llmsFullTxt,
3202
+ maxChars,
3203
+ sections: generatedSections
3204
+ };
3205
+ }
3206
+ function selectDocsLlmsTxtContent(content, request) {
3207
+ if (request.section) {
3208
+ const section = content.sections.find((candidate) => candidate.route === request.section?.route);
3209
+ if (!section) return null;
3210
+ return {
3211
+ content: request.format === "llms-full" ? section.llmsFullTxt : section.llmsTxt,
3212
+ label: request.format === "llms-full" ? section.fullRoute : section.route,
3213
+ maxChars: request.format === "llms-full" ? {
3214
+ ...section.maxChars,
3215
+ mode: "off"
3216
+ } : section.maxChars
3217
+ };
3218
+ }
3219
+ return {
3220
+ content: request.format === "llms-full" ? content.llmsFullTxt : content.llmsTxt,
3221
+ label: request.format === "llms-full" ? DEFAULT_LLMS_FULL_TXT_ROUTE : DEFAULT_LLMS_TXT_ROUTE,
3222
+ maxChars: request.format === "llms-full" ? {
3223
+ ...content.maxChars,
3224
+ mode: "off"
3225
+ } : content.maxChars
3226
+ };
3227
+ }
3228
+ function getDocsLlmsTxtMaxCharsIssue(label, content, maxChars) {
3229
+ if (maxChars.mode === "off" || content.length <= maxChars.chars) return null;
3230
+ return {
3231
+ mode: maxChars.mode,
3232
+ chars: maxChars.chars,
3233
+ actual: content.length,
3234
+ label,
3235
+ message: `${label} is ${content.length.toLocaleString()} chars, above the configured ${maxChars.chars.toLocaleString()} char llms.txt budget.`
3236
+ };
3237
+ }
3238
+ function resolveDocsStandardsOrigin(preferred, fallback) {
3239
+ for (const candidate of [preferred, fallback]) {
3240
+ if (!candidate) continue;
3241
+ try {
3242
+ const url = new URL(candidate);
3243
+ if (url.protocol === "http:" || url.protocol === "https:") return url.origin;
3244
+ } catch {}
3245
+ }
3246
+ return new URL(fallback).origin;
3247
+ }
3248
+ /** Build and serve standards-based discovery without replacing the custom agent manifest. */
3249
+ async function createDocsStandardsDiscoveryResponse({ request, preferredSkillDocument, fallbackSkillDocument, origin, entry = "docs", docsPath, apiCatalog: explicitApiCatalog, apiRoute, i18n: _i18n, search: _search, mcp, feedback, llms, sitemap, robots, openapi, markdown: _markdown, publishedSkills, agentCard }) {
3250
+ const url = new URL(request.url);
3251
+ const resolvedApiRoute = resolveDocsDiscoveryApiRoute(apiRoute);
3252
+ if (!isDocsStandardsDiscoveryRequest(url, { apiRoute: resolvedApiRoute })) return null;
3253
+ const normalizedEntry = normalizeDocsPathSegment(entry) || "docs";
3254
+ const normalizedDocsPath = normalizeDocsPathSegment(docsPath ?? normalizedEntry);
3255
+ const apiCatalogEnabled = explicitApiCatalog ?? llms?.apiCatalog ?? true;
3256
+ const catalogOrigin = resolveDocsStandardsOrigin(llms?.baseUrl, origin || url.origin);
3257
+ const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms?.baseUrl });
3258
+ const openapiConfig = resolveDocsOpenApiDiscoveryConfig(openapi);
3259
+ const openapiUrl = resolveDocsOpenApiDiscoveryUrl(openapiConfig, resolvedApiRoute);
3260
+ const feedbackRoute = feedback?.route ?? DEFAULT_AGENT_FEEDBACK_ROUTE;
3261
+ const feedbackSchemaRoute = feedback?.schemaRoute ?? `${feedbackRoute}/schema`;
3262
+ const llmsEnabled = llms?.enabled ?? true;
3263
+ const robotsEnabled = isRobotsDiscoveryEnabled(robots);
3264
+ const llmsSections = resolveDocsLlmsTxtSections(llms);
3265
+ const llmsRoutes = llmsEnabled ? [
3266
+ DEFAULT_LLMS_TXT_ROUTE,
3267
+ DEFAULT_LLMS_FULL_TXT_ROUTE,
3268
+ DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
3269
+ DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE,
3270
+ ...llmsSections.flatMap((section) => [section.route, section.fullRoute])
3271
+ ] : [];
3272
+ const sitemapRoutes = sitemapConfig.enabled ? [...sitemapConfig.xml.enabled ? [sitemapConfig.xml.route] : [], ...sitemapConfig.markdown.enabled ? [
3273
+ sitemapConfig.markdown.route,
3274
+ sitemapConfig.markdown.docsRoute,
3275
+ sitemapConfig.markdown.wellKnownRoute
3276
+ ].filter((route) => Boolean(route)) : []] : [];
3277
+ const protectedResourceMetadataRoutes = mcp.enabled && mcp.security?.authenticate && mcp.security.protectedResource ? getDocsMcpProtectedResourceMetadataRoutes(mcp.route) : [];
3278
+ return createDocsStandardsResponse({
3279
+ request,
3280
+ apiCatalogEnabled,
3281
+ apiRoute: resolvedApiRoute,
3282
+ preferredSkillDocument,
3283
+ fallbackSkillDocument,
3284
+ publishedSkills,
3285
+ agentCard,
3286
+ apiCatalog: apiCatalogEnabled ? buildDocsApiCatalog({
3287
+ origin: catalogOrigin,
3288
+ docsRoute: normalizedDocsPath ? `/${normalizedDocsPath}` : "/",
3289
+ apiRoute: resolvedApiRoute,
3290
+ configRoute: `${resolvedApiRoute}?format=config`,
3291
+ diagnosticsRoute: `${resolvedApiRoute}?format=diagnostics`,
3292
+ agentManifestRoute: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
3293
+ agentSkillsIndexRoute: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
3294
+ legacySkillsIndexRoute: DEFAULT_LEGACY_SKILLS_INDEX_ROUTE,
3295
+ agentCardRoute: agentCard ? DEFAULT_A2A_AGENT_CARD_ROUTE : null,
3296
+ agentsRoute: DEFAULT_AGENTS_MD_ROUTE,
3297
+ skillRoute: DEFAULT_SKILL_MD_ROUTE,
3298
+ markdownRootRoute: `/${normalizedEntry}.md`,
3299
+ llmsRoutes,
3300
+ sitemapRoutes,
3301
+ robotsRoute: robotsEnabled ? DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE : null,
3302
+ mcpRoute: mcp.enabled ? mcp.route : null,
3303
+ protectedResourceMetadataRoutes,
3304
+ feedbackRoutes: feedback?.enabled ? [feedbackRoute, feedbackSchemaRoute] : [],
3305
+ openapiRoute: openapiConfig.enabled ? openapiUrl ?? `${resolvedApiRoute}?format=openapi` : null,
3306
+ apiReferenceRoute: openapiConfig.enabled && openapiConfig.apiReferencePath ? openapiConfig.apiReferencePath : null
3307
+ }) : void 0
3308
+ });
3309
+ }
3310
+ function isDocsAgentDiscoveryRequest(url, options = {}) {
3311
+ const pathname = normalizeDocsUrlPath(url.pathname);
3312
+ if (pathname === resolveDocsDiscoveryApiRoute(options.apiRoute) && url.searchParams.get("agent")?.trim() === "spec") return true;
3313
+ return pathname === DEFAULT_AGENT_SPEC_ROUTE || pathname === DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE || pathname === DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE;
3314
+ }
3315
+ function buildDocsMcpEndpointCandidates(baseUrl, routes = [DEFAULT_MCP_PUBLIC_ROUTE, DEFAULT_MCP_WELL_KNOWN_ROUTE], options = {}) {
3316
+ const includeOriginFallback = options.includeOriginFallback !== false;
3317
+ const includeRootDomainFallback = options.includeRootDomainFallback !== false;
3318
+ const includeMcpSubdomainFallback = options.includeMcpSubdomainFallback !== false;
3319
+ const base = new URL(baseUrl);
3320
+ const primaryOrigin = base.origin;
3321
+ const seen = /* @__PURE__ */ new Set();
3322
+ const candidates = [];
3323
+ const addCandidate = (candidateBaseUrl, route) => {
3324
+ const resolved = resolveDocsMcpCandidateUrl(candidateBaseUrl, route);
3325
+ if (seen.has(resolved.url)) return;
3326
+ seen.add(resolved.url);
3327
+ candidates.push({
3328
+ ...resolved,
3329
+ label: formatDocsMcpCandidateLabel(resolved.url, primaryOrigin)
3330
+ });
3331
+ };
3332
+ for (const route of routes) addCandidate(baseUrl, route);
3333
+ const originBaseUrl = primaryOrigin;
3334
+ if (includeOriginFallback && originBaseUrl !== baseUrl.replace(/\/+$/, "")) for (const route of routes) addCandidate(originBaseUrl, route);
3335
+ if (includeRootDomainFallback) for (const rootDomainBaseUrl of toDocsRootDomainBaseUrls(base)) for (const route of routes) addCandidate(rootDomainBaseUrl, route);
3336
+ if (includeMcpSubdomainFallback) for (const mcpBaseUrl of toDocsMcpSubdomainBaseUrls(base)) {
3337
+ addCandidate(mcpBaseUrl, DEFAULT_MCP_PUBLIC_ROUTE);
3338
+ addCandidate(mcpBaseUrl, "/");
3339
+ }
3340
+ return candidates;
3341
+ }
3342
+ function resolveDocsMcpCandidateUrl(baseUrl, route) {
3343
+ if (/^https?:\/\//i.test(route)) {
3344
+ const parsed = new URL(route);
3345
+ const path = `${parsed.pathname || "/"}${parsed.search}`;
3346
+ return {
3347
+ baseUrl: parsed.origin,
3348
+ route: path,
3349
+ url: parsed.toString()
3350
+ };
3351
+ }
3352
+ const base = new URL(baseUrl);
3353
+ const basePath = base.pathname.replace(/\/+$/, "");
3354
+ const routePath = route.startsWith("/") ? route : `/${route}`;
3355
+ const parsed = new URL(`${basePath}${routePath}`, base.origin);
3356
+ return {
3357
+ baseUrl: parsed.origin,
3358
+ route: `${parsed.pathname}${parsed.search}`,
3359
+ url: parsed.toString()
3360
+ };
3361
+ }
3362
+ function formatDocsMcpCandidateLabel(url, primaryOrigin) {
3363
+ const parsed = new URL(url);
3364
+ const path = `${parsed.pathname}${parsed.search}`;
3365
+ return parsed.origin === primaryOrigin ? path : `${parsed.origin}${path}`;
3366
+ }
3367
+ function toDocsMcpSubdomainBaseUrls(base) {
3368
+ return getDocsMcpRootDomainCandidates(base.hostname).map((rootDomain) => `${base.protocol}//mcp.${rootDomain}${base.port ? `:${base.port}` : ""}`);
3369
+ }
3370
+ function toDocsRootDomainBaseUrls(base) {
3371
+ return getDocsMcpRootDomainCandidates(base.hostname).map((rootDomain) => `${base.protocol}//${rootDomain}${base.port ? `:${base.port}` : ""}`);
3372
+ }
3373
+ function getDocsMcpRootDomainCandidates(hostname) {
3374
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
3375
+ if (!normalized || !normalized.includes(".") || isDocsIpHostname(normalized)) return [];
3376
+ const labels = normalized.split(".").filter(Boolean);
3377
+ if (labels.length < 2) return [];
3378
+ const candidates = [];
3379
+ const addCandidate = (candidateLabels) => {
3380
+ if (candidateLabels.length < 2) return;
3381
+ const candidate = candidateLabels.join(".");
3382
+ if (!candidates.includes(candidate)) candidates.push(candidate);
3383
+ };
3384
+ if (labels.length >= 3 && DOCS_MCP_SERVICE_SUBDOMAIN_LABELS.has(labels[0] ?? "")) addCandidate(labels.slice(1));
3385
+ const tld = labels.at(-1) ?? "";
3386
+ const secondLevel = labels.at(-2) ?? "";
3387
+ if (labels.length >= 3 && tld.length === 2 && COMMON_SECOND_LEVEL_PUBLIC_SUFFIX_LABELS.has(secondLevel)) addCandidate(labels.slice(-3));
3388
+ else addCandidate(labels.slice(-2));
3389
+ return candidates;
3390
+ }
3391
+ function isDocsIpHostname(hostname) {
3392
+ return /^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) || hostname.includes(":");
3393
+ }
3394
+ function isDocsSkillRequest(url, options = {}) {
3395
+ const pathname = normalizeDocsUrlPath(url.pathname);
3396
+ if (pathname === DEFAULT_SKILL_MD_ROUTE || pathname === DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE) return true;
3397
+ return pathname === resolveDocsDiscoveryApiRoute(options.apiRoute) && resolveDocsSkillFormat(url) === "skill";
3398
+ }
3399
+ function resolveDocsSkillFormat(url) {
3400
+ return url.searchParams.get("format")?.trim() === "skill" ? "skill" : null;
3401
+ }
3402
+ function isDocsAgentsPath(pathname) {
3403
+ return pathname === DEFAULT_AGENTS_MD_ROUTE || pathname === DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE || pathname === DEFAULT_AGENT_MD_ROUTE || pathname === DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE;
3404
+ }
3405
+ function isDocsAgentsRequest(url, options = {}) {
3406
+ const pathname = normalizeDocsUrlPath(url.pathname);
3407
+ if (isDocsAgentsPath(pathname)) return true;
3408
+ return pathname === resolveDocsDiscoveryApiRoute(options.apiRoute) && resolveDocsAgentsFormat(url) === "agents";
3409
+ }
3410
+ function resolveDocsAgentsFormat(url) {
3411
+ return url.searchParams.get("format")?.trim() === "agents" ? "agents" : null;
3412
+ }
3413
+ function isDocsPublicGetRequest(entry, url, request, options = {}) {
3414
+ const pathname = normalizeDocsUrlPath(url.pathname);
3415
+ const apiRoute = resolveDocsDiscoveryApiRoute(options.apiRoute);
3416
+ if (pathname === apiRoute || pathname === DEFAULT_MCP_ROUTE) return false;
3417
+ return isDocsStandardsDiscoveryRequest(url, { apiRoute }) || isDocsAgentDiscoveryRequest(url, { apiRoute }) || isDocsAgentsRequest(url, { apiRoute }) || isDocsSkillRequest(url, { apiRoute }) || pathname === DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE && isRobotsDiscoveryEnabled(options.robots) || resolveDocsLlmsTxtRequest(url, options.llms, entry, { apiRoute }) !== null || resolveDocsSitemapRequest(url, options.sitemap, { apiRoute }) !== null || resolveDocsMarkdownRequest(entry, url, request, { apiRoute }) !== null;
3418
+ }
3419
+ function isDocsLlmsTxtPublicRequest(url, llms, basePath, options = {}) {
3420
+ const pathname = normalizeDocsUrlPath(url.pathname);
3421
+ const apiRoute = resolveDocsDiscoveryApiRoute(options.apiRoute);
3422
+ return pathname !== apiRoute && resolveDocsLlmsTxtRequest(url, llms, basePath, { apiRoute }) !== null;
3423
+ }
3424
+ function resolveDocsLlmsTxtFormat(url, basePath, options = {}) {
3425
+ return resolveDocsLlmsTxtRequest(url, void 0, basePath, options)?.format ?? null;
3426
+ }
3427
+ function resolveDocsMarkdownRequest(entry, url, request, options = {}) {
3428
+ const pathname = normalizeDocsUrlPath(url.pathname);
3429
+ const format = url.searchParams.get("format")?.trim();
3430
+ if (pathname === resolveDocsDiscoveryApiRoute(options.apiRoute) && format === "markdown") return { requestedPath: url.searchParams.get("path")?.trim() ?? "" };
3431
+ const normalizedEntry = `/${normalizeDocsPathSegment(entry) || "docs"}`;
3432
+ if (pathname === `${normalizedEntry}.md`) return { requestedPath: "" };
3433
+ const slugPrefix = `${normalizedEntry}/`;
3434
+ if (pathname.startsWith(slugPrefix) && pathname.endsWith(".md")) return { requestedPath: pathname.slice(slugPrefix.length, -3) };
3435
+ if (acceptsDocsMarkdown(request) || hasDocsMarkdownSignatureAgent(request) || detectDocsMarkdownAgentRequest(request).detected) {
3436
+ if (pathname === normalizedEntry) return { requestedPath: "" };
3437
+ if (pathname.startsWith(slugPrefix)) return { requestedPath: pathname.slice(slugPrefix.length) };
3438
+ }
3439
+ return null;
3440
+ }
3441
+ function hasDocsMarkdownSignatureAgent(request) {
3442
+ return Boolean(request.headers.get(DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER)?.trim());
3443
+ }
3444
+ function detectDocsMarkdownAgentRequest(request) {
3445
+ if (hasDocsMarkdownSignatureAgent(request)) return {
3446
+ detected: true,
3447
+ method: "signature_agent"
3448
+ };
3449
+ const userAgent = request.headers.get("user-agent")?.trim().toLowerCase() ?? "";
3450
+ if (!userAgent) return {
3451
+ detected: false,
3452
+ method: null
3453
+ };
3454
+ if (DOCS_AI_AGENT_USER_AGENT_PATTERNS.some((pattern) => userAgent.includes(pattern))) return {
3455
+ detected: true,
3456
+ method: "user_agent"
3457
+ };
3458
+ if (!request.headers.get("sec-fetch-mode") && DOCS_BOT_LIKE_USER_AGENT_PATTERN.test(userAgent)) {
3459
+ if (!DOCS_TRADITIONAL_BOT_USER_AGENT_PATTERNS.some((pattern) => userAgent.includes(pattern))) return {
3460
+ detected: true,
3461
+ method: "heuristic"
3462
+ };
3463
+ }
3464
+ return {
3465
+ detected: false,
3466
+ method: null
3467
+ };
3468
+ }
3469
+ function getDocsMarkdownVaryHeader(request) {
3470
+ const values = /* @__PURE__ */ new Set();
3471
+ if (acceptsDocsMarkdown(request)) values.add("Accept");
3472
+ if (hasDocsMarkdownSignatureAgent(request)) {
3473
+ values.add("Accept");
3474
+ values.add(DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER);
3475
+ }
3476
+ const agentDetection = detectDocsMarkdownAgentRequest(request);
3477
+ if (agentDetection.detected && agentDetection.method !== "signature_agent") {
3478
+ values.add("User-Agent");
3479
+ if (agentDetection.method === "heuristic") values.add("Sec-Fetch-Mode");
3480
+ }
3481
+ return values.size > 0 ? Array.from(values).join(", ") : null;
3482
+ }
3483
+ const DOCS_MARKDOWN_RECOVERY_MATCH_LIMIT = 5;
3484
+ const DOCS_MARKDOWN_RECOVERY_REDIRECT_CONFIDENCE = .99;
3485
+ const DOCS_MARKDOWN_RECOVERY_SLUG_MAX_LENGTH = 256;
3486
+ function normalizeDocsRecoveryText(value) {
3487
+ return value.toLowerCase().replace(/\.md$/i, "").replace(/[#?].*$/g, "").replace(/['"`]/g, "").replace(/[^a-z0-9]+/g, " ").trim();
3488
+ }
3489
+ function normalizeDocsRecoverySlug(entry, value) {
3490
+ const withoutHash = value.split("#", 1)[0] ?? value;
3491
+ const withoutMarkdown = (withoutHash.split("?", 1)[0] ?? withoutHash).replace(/\.md$/i, "");
3492
+ const normalizedPath = normalizeDocsUrlPath(withoutMarkdown.startsWith("/") ? withoutMarkdown : `/${withoutMarkdown}`);
3493
+ const normalizedEntry = `/${normalizeDocsPathSegment(entry) || "docs"}`;
3494
+ if (normalizedPath === normalizedEntry) return "";
3495
+ if (normalizedPath.startsWith(`${normalizedEntry}/`)) return normalizeDocsPathSegment(normalizedPath.slice(normalizedEntry.length + 1));
3496
+ return normalizeDocsPathSegment(normalizedPath);
3497
+ }
3498
+ function limitDocsRecoverySlug(value) {
3499
+ return value.slice(0, DOCS_MARKDOWN_RECOVERY_SLUG_MAX_LENGTH);
3500
+ }
3501
+ function tokenizeDocsRecoveryText(value) {
3502
+ return normalizeDocsRecoveryText(value).split(/\s+/).filter((token) => token.length > 1);
3503
+ }
3504
+ function levenshteinDistance(a, b) {
3505
+ if (a === b) return 0;
3506
+ if (!a) return b.length;
3507
+ if (!b) return a.length;
3508
+ let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
3509
+ let current = new Array(b.length + 1);
3510
+ for (let i = 1; i <= a.length; i += 1) {
3511
+ current[0] = i;
3512
+ for (let j = 1; j <= b.length; j += 1) {
3513
+ const substitution = previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1);
3514
+ current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, substitution);
3515
+ }
3516
+ [previous, current] = [current, previous];
3517
+ }
3518
+ return previous[b.length] ?? Math.max(a.length, b.length);
3519
+ }
3520
+ function normalizedEditSimilarity(a, b) {
3521
+ if (!a || !b) return 0;
3522
+ if (a === b) return 1;
3523
+ const maxLength = Math.max(a.length, b.length);
3524
+ if (maxLength === 0) return 1;
3525
+ return Math.max(0, 1 - levenshteinDistance(a, b) / maxLength);
3526
+ }
3527
+ function tokenOverlapScore(requestedTokens, candidateTokens) {
3528
+ if (requestedTokens.length === 0 || candidateTokens.length === 0) return 0;
3529
+ const candidates = new Set(candidateTokens);
3530
+ return requestedTokens.filter((token) => candidates.has(token)).length / requestedTokens.length;
3531
+ }
3532
+ function sameDocsRecoveryParent(a, b) {
3533
+ const aParts = a.split("/").filter(Boolean);
3534
+ const bParts = b.split("/").filter(Boolean);
3535
+ if (aParts.length !== bParts.length || aParts.length === 0) return false;
3536
+ return aParts.slice(0, -1).join("/") === bParts.slice(0, -1).join("/");
3537
+ }
3538
+ function scoreDocsMarkdownRecoveryMatch({ entry, requestedPath, page }) {
3539
+ const requestedSlug = limitDocsRecoverySlug(normalizeDocsRecoverySlug(entry, requestedPath));
3540
+ const pageSlug = limitDocsRecoverySlug(normalizeDocsRecoverySlug(entry, page.url));
3541
+ const requestedLast = requestedSlug.split("/").filter(Boolean).at(-1) ?? requestedSlug;
3542
+ const pageLast = pageSlug.split("/").filter(Boolean).at(-1) ?? pageSlug;
3543
+ const title = normalizeDocsRecoveryText(page.title);
3544
+ const requestedText = normalizeDocsRecoveryText(requestedSlug.replace(/\//g, " "));
3545
+ const requestedTokens = tokenizeDocsRecoveryText(requestedText);
3546
+ const candidateTokens = tokenizeDocsRecoveryText([
3547
+ pageSlug.replace(/\//g, " "),
3548
+ page.title,
3549
+ page.description ?? ""
3550
+ ].join(" "));
3551
+ const pathDistance = levenshteinDistance(requestedSlug, pageSlug);
3552
+ const segmentDistance = levenshteinDistance(requestedLast, pageLast);
3553
+ if (requestedSlug && pageSlug && (sameDocsRecoveryParent(requestedSlug, pageSlug) && segmentDistance <= 1 || pathDistance <= 1)) return .995;
3554
+ const pathSimilarity = normalizedEditSimilarity(requestedSlug, pageSlug);
3555
+ const segmentSimilarity = normalizedEditSimilarity(requestedLast, pageLast);
3556
+ const titleSimilarity = normalizedEditSimilarity(requestedText, title);
3557
+ const overlap = tokenOverlapScore(requestedTokens, candidateTokens);
3558
+ const substringBoost = requestedText && (pageSlug.includes(requestedSlug) || title.includes(requestedText) || requestedText.includes(title)) ? .12 : 0;
3559
+ return Math.min(.98, Math.max(pathSimilarity * .86, segmentSimilarity * .8, titleSimilarity * .72, overlap * .75) + substringBoost);
3560
+ }
3561
+ function resolveDocsMarkdownRecovery({ entry = "docs", requestedPath, pages = [] }) {
3562
+ const normalizedEntry = normalizeDocsPathSegment(entry) || "docs";
3563
+ const matches = pages.map((page) => ({
3564
+ page,
3565
+ confidence: scoreDocsMarkdownRecoveryMatch({
3566
+ entry: normalizedEntry,
3567
+ requestedPath,
3568
+ page
3569
+ })
3570
+ })).filter((item) => item.confidence >= .35).sort((a, b) => {
3571
+ if (b.confidence !== a.confidence) return b.confidence - a.confidence;
3572
+ return a.page.url.localeCompare(b.page.url);
3573
+ }).slice(0, DOCS_MARKDOWN_RECOVERY_MATCH_LIMIT).map(({ page, confidence }) => ({
3574
+ title: page.title,
3575
+ url: normalizeDocsUrlPath(page.url),
3576
+ markdownUrl: toDocsMarkdownUrl(page.url),
3577
+ description: page.description,
3578
+ confidence
3579
+ }));
3580
+ return {
3581
+ matches,
3582
+ redirect: matches[0] && matches[0].confidence >= DOCS_MARKDOWN_RECOVERY_REDIRECT_CONFIDENCE ? matches[0] : void 0
3583
+ };
3584
+ }
3585
+ function renderDocsMarkdownSitemapFooter(sitemap) {
3586
+ const sitemapConfig = resolveDocsSitemapConfig(sitemap);
3587
+ const lines = ["## Sitemap", ""];
3588
+ if (sitemapConfig.enabled && sitemapConfig.markdown.enabled) {
3589
+ lines.push(`See the full [sitemap](${sitemapConfig.markdown.route}) for all pages.`);
3590
+ if (sitemapConfig.markdown.docsRoute) lines.push(`Docs-scoped sitemap: [${sitemapConfig.markdown.docsRoute}](${sitemapConfig.markdown.docsRoute}).`);
3591
+ lines.push(`Well-known sitemap: [${sitemapConfig.markdown.wellKnownRoute}](${sitemapConfig.markdown.wellKnownRoute}).`);
3592
+ } else if (sitemapConfig.enabled && sitemapConfig.xml.enabled) lines.push(`See the XML [sitemap](${sitemapConfig.xml.route}) for all pages.`);
3593
+ else lines.push("Sitemap discovery is not enabled for this deployment.");
3594
+ return lines.join("\n");
3595
+ }
3596
+ function appendDocsMarkdownSitemapFooter(markdown, sitemap) {
3597
+ if (/^##\s+Sitemap\s*$/im.test(markdown)) return markdown;
3598
+ return `${markdown.replace(/\s+$/g, "")}\n\n${renderDocsMarkdownSitemapFooter(sitemap)}\n`;
3599
+ }
3600
+ function normalizeDocsMarkdownLastUpdated(value) {
3601
+ if (!value) return void 0;
3602
+ const trimmed = value.trim();
3603
+ const dateOnly = trimmed.match(/^\d{4}-\d{2}-\d{2}/)?.[0];
3604
+ if (dateOnly) return dateOnly;
3605
+ const date = new Date(trimmed);
3606
+ if (Number.isNaN(date.getTime())) return void 0;
3607
+ return date.toISOString().slice(0, 10);
3608
+ }
3609
+ function resolveDocsMarkdownMetadataUrl(value, origin) {
3610
+ if (!origin) return value;
3611
+ try {
3612
+ return new URL(value, origin).toString();
3613
+ } catch {
3614
+ return value;
3615
+ }
3616
+ }
3617
+ function renderDocsMarkdownFrontmatter({ title, description, canonicalUrl, markdownUrl, lastUpdated, agent }) {
3618
+ return [
3619
+ "---",
3620
+ `title: ${toYamlString(title)}`,
3621
+ ...description ? [`description: ${toYamlString(description)}`] : [],
3622
+ `canonical_url: ${toYamlString(canonicalUrl)}`,
3623
+ `markdown_url: ${toYamlString(markdownUrl)}`,
3624
+ ...lastUpdated ? [`last_updated: ${toYamlString(lastUpdated)}`] : [],
3625
+ ...renderPageAgentFrontmatterYamlLines(agent),
3626
+ "---"
3627
+ ].join("\n");
3628
+ }
3629
+ function hasDocsMarkdownFrontmatter(markdown) {
3630
+ return /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/.test(markdown);
3631
+ }
3632
+ function prependDocsMarkdownFrontmatter(markdown, metadata) {
3633
+ if (hasDocsMarkdownFrontmatter(markdown)) return markdown;
3634
+ return `${renderDocsMarkdownFrontmatter(metadata)}\n\n${markdown.replace(/^\r?\n+/, "")}`;
3635
+ }
3636
+ function resolveDocsMarkdownPageMetadata(page, options) {
3637
+ return {
3638
+ title: page.title,
3639
+ description: page.description,
3640
+ canonicalUrl: resolveDocsMarkdownMetadataUrl(page.url, options?.origin),
3641
+ markdownUrl: resolveDocsMarkdownMetadataUrl(page.markdownUrl ?? toDocsMarkdownUrl(page.url), options?.origin),
3642
+ lastUpdated: normalizeDocsMarkdownLastUpdated(page.lastmod ?? page.lastModified),
3643
+ agent: page.agent
3644
+ };
3645
+ }
3646
+ function renderDocsMarkdownNotFound({ entry = "docs", apiRoute, requestedPath, origin, pages, sitemap }) {
3647
+ const normalizedEntry = normalizeDocsPathSegment(entry) || "docs";
3648
+ const resolvedApiRoute = resolveDocsDiscoveryApiRoute(apiRoute);
3649
+ const agentSpecApiRoute = resolvedApiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : `${resolvedApiRoute}?agent=spec`;
3650
+ const normalizedRequest = normalizeRequestedMarkdownPath(normalizedEntry, requestedPath);
3651
+ const slugPrefix = `/${normalizedEntry}/`;
3652
+ const requestedSlug = normalizedRequest === `/${normalizedEntry}` ? "" : normalizedRequest.slice(slugPrefix.length);
3653
+ const encodedRequestedSlug = requestedSlug.split("/").map(encodeURIComponent).join("/");
3654
+ const requestedMarkdownRoute = toDocsMarkdownUrl(normalizedRequest);
3655
+ const requestedApiRoute = requestedSlug ? `${resolvedApiRoute}?format=markdown&path=${encodedRequestedSlug}` : `${resolvedApiRoute}?format=markdown`;
3656
+ const sitemapConfig = resolveDocsSitemapConfig(sitemap);
3657
+ const recovery = resolveDocsMarkdownRecovery({
3658
+ entry: normalizedEntry,
3659
+ requestedPath,
3660
+ pages
3661
+ });
3662
+ const lines = [
3663
+ "# Docs Page Not Found",
3664
+ "",
3665
+ `Could not find a markdown page for \`${requestedMarkdownRoute}\`.`
3666
+ ];
3667
+ if (recovery.matches.length > 0) {
3668
+ lines.push("", "## Closest Matches", "");
3669
+ for (const match of recovery.matches) {
3670
+ const confidence = `${Math.round(match.confidence * 1e3) / 10}%`;
3671
+ lines.push(`- [${match.title}](${match.markdownUrl}) (${confidence} confidence)${match.description ? ` - ${match.description}` : ""}`);
3672
+ }
3673
+ }
3674
+ lines.push("", "## Recovery", "", "- If a closest match looks right, fetch that markdown URL directly.", "- If the match is uncertain, search the docs first and then fetch the smallest page that answers the task.", "- Use the sitemap routes below to browse the full docs index before guessing another slug.", "", "## Discovery Routes", "", "Use these discovery routes to find the right page:", "", `- Agent discovery spec: \`${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}\``, `- Agent discovery fallback: \`${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}\``, `- Agent discovery API: \`${agentSpecApiRoute}\``, `- API catalog: \`${DEFAULT_API_CATALOG_ROUTE}\``, `- Agent Skills index: \`${DEFAULT_AGENT_SKILLS_INDEX_ROUTE}\``, `- Agent instructions: \`${DEFAULT_AGENTS_MD_ROUTE}\``, `- Agent search endpoint: \`${resolvedApiRoute}?query={query}&audience=agent\``, `- Docs index markdown: \`/${normalizedEntry}.md\``, `- Requested markdown API route: \`${requestedApiRoute}\``);
3675
+ if (sitemapConfig.enabled) {
3676
+ if (sitemapConfig.markdown.enabled) {
3677
+ lines.push(`- Semantic sitemap: \`${sitemapConfig.markdown.route}\``);
3678
+ if (sitemapConfig.markdown.docsRoute) lines.push(`- Docs-scoped sitemap alias: \`${sitemapConfig.markdown.docsRoute}\``);
3679
+ lines.push(`- Semantic sitemap well-known alias: \`${sitemapConfig.markdown.wellKnownRoute}\``);
3680
+ }
3681
+ if (sitemapConfig.xml.enabled) lines.push(`- XML sitemap: \`${sitemapConfig.xml.route}\``);
3682
+ } else lines.push(`- Sitemap discovery, if enabled: \`${DEFAULT_SITEMAP_MD_ROUTE}\`, \`${DEFAULT_SITEMAP_MD_DOCS_ROUTE}\`, \`${DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE}\`, or \`${DEFAULT_SITEMAP_XML_ROUTE}\``);
3683
+ lines.push("", "The agent discovery spec is the safest first step because it lists the active markdown, sitemap, robots, search, MCP, and feedback routes for this deployment.");
3684
+ return appendDocsMarkdownSitemapFooter(prependDocsMarkdownFrontmatter(lines.join("\n"), {
3685
+ title: "Docs Page Not Found",
3686
+ description: `Could not find a markdown page for ${requestedMarkdownRoute}.`,
3687
+ canonicalUrl: resolveDocsMarkdownMetadataUrl(normalizedRequest, origin),
3688
+ markdownUrl: resolveDocsMarkdownMetadataUrl(requestedMarkdownRoute, origin)
3689
+ }), sitemap);
3690
+ }
3691
+ function hashDocsMarkdownRepresentation(value) {
3692
+ let hash = 2166136261;
3693
+ for (let index = 0; index < value.length; index += 1) {
3694
+ hash ^= value.charCodeAt(index);
3695
+ hash = Math.imul(hash, 16777619);
3696
+ }
3697
+ return (hash >>> 0).toString(16).padStart(8, "0");
3698
+ }
3699
+ function createDocsMarkdownEtag(document) {
3700
+ return `W/"${document.length.toString(16)}-${hashDocsMarkdownRepresentation(document)}"`;
3701
+ }
3702
+ function normalizeDocsMarkdownEtag(value) {
3703
+ return value.trim().replace(/^W\//i, "");
3704
+ }
3705
+ function requestMatchesDocsMarkdownEtag(request, etag) {
3706
+ const header = request.headers.get("if-none-match");
3707
+ if (!header) return false;
3708
+ if (header.trim() === "*") return true;
3709
+ const expected = normalizeDocsMarkdownEtag(etag);
3710
+ return header.split(",").some((candidate) => normalizeDocsMarkdownEtag(candidate) === expected);
3711
+ }
3712
+ function resolveDocsMarkdownHttpDate(value) {
3713
+ if (!value) return void 0;
3714
+ if (typeof value === "string" && !/(?:T|\s)\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?/.test(value.trim())) return;
3715
+ const date = value instanceof Date ? value : new Date(value);
3716
+ if (Number.isNaN(date.getTime())) return void 0;
3717
+ return date.toUTCString();
3718
+ }
3719
+ function extractDocsMarkdownLastModified(document) {
3720
+ const frontmatter = document.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
3721
+ if (!frontmatter) return void 0;
3722
+ const raw = frontmatter.match(/^last_updated:\s*(.+?)\s*$/m)?.[1]?.trim();
3723
+ if (!raw) return void 0;
3724
+ if (raw.startsWith("\"") && raw.endsWith("\"") || raw.startsWith("'") && raw.endsWith("'")) return raw.slice(1, -1);
3725
+ return raw;
3726
+ }
3727
+ function requestHasFreshDocsMarkdownDate(request, lastModified) {
3728
+ if (!lastModified || request.headers.has("if-none-match")) return false;
3729
+ const ifModifiedSince = request.headers.get("if-modified-since");
3730
+ if (!ifModifiedSince) return false;
3731
+ const resourceTime = Date.parse(lastModified);
3732
+ const requestTime = Date.parse(ifModifiedSince);
3733
+ return Number.isFinite(resourceTime) && Number.isFinite(requestTime) && Math.floor(resourceTime / 1e3) <= Math.floor(requestTime / 1e3);
3734
+ }
3735
+ function resolveDocsMarkdownContentLocation(canonicalUrl) {
3736
+ const url = new URL(canonicalUrl);
3737
+ url.pathname = toDocsMarkdownUrl(url.pathname);
3738
+ return url.toString();
3739
+ }
3740
+ /** Build one standards-aware Markdown response for every framework adapter. */
3741
+ function createDocsMarkdownResponse(options) {
3742
+ const { request, document, entry = "docs", requestedPath, origin = new URL(request.url).origin, pages, sitemap, locale } = options;
3743
+ const canonicalUrl = options.canonicalUrl ?? resolveDocsMarkdownCanonicalUrl({
3744
+ origin,
3745
+ entry,
3746
+ requestedPath,
3747
+ locale
3748
+ });
3749
+ const contentLocation = options.contentLocation ?? resolveDocsMarkdownContentLocation(canonicalUrl);
3750
+ const varyHeader = getDocsMarkdownVaryHeader(request);
3751
+ const sharedHeaders = {
3752
+ "Content-Location": contentLocation,
3753
+ Link: `<${canonicalUrl}>; rel="canonical"`,
3754
+ "X-Robots-Tag": "noindex",
3755
+ ...locale ? { "Content-Language": locale } : {},
3756
+ ...varyHeader ? { Vary: varyHeader } : {}
3757
+ };
3758
+ if (!document) {
3759
+ const recovery = resolveDocsMarkdownRecovery({
3760
+ entry,
3761
+ requestedPath,
3762
+ pages,
3763
+ sitemap
3764
+ });
3765
+ if (recovery.redirect) return new Response(null, {
3766
+ status: 307,
3767
+ headers: {
3768
+ ...sharedHeaders,
3769
+ "Cache-Control": "no-store",
3770
+ Location: new URL(recovery.redirect.markdownUrl, request.url).toString()
3771
+ }
3772
+ });
3773
+ return new Response(renderDocsMarkdownNotFound({
3774
+ entry,
3775
+ apiRoute: options.apiRoute,
3776
+ requestedPath,
3777
+ origin,
3778
+ pages,
3779
+ sitemap
3780
+ }), {
3781
+ status: 404,
3782
+ headers: {
3783
+ ...sharedHeaders,
3784
+ "Cache-Control": "no-store",
3785
+ "Content-Type": "text/markdown; charset=utf-8"
3786
+ }
3787
+ });
3788
+ }
3789
+ const etag = createDocsMarkdownEtag(document);
3790
+ const lastModified = resolveDocsMarkdownHttpDate(options.lastModified ?? extractDocsMarkdownLastModified(document));
3791
+ const responseHeaders = {
3792
+ ...sharedHeaders,
3793
+ "Cache-Control": options.cacheControl ?? "public, max-age=0, s-maxage=3600",
3794
+ "Content-Type": "text/markdown; charset=utf-8",
3795
+ ETag: etag,
3796
+ ...lastModified ? { "Last-Modified": lastModified } : {}
3797
+ };
3798
+ if (requestMatchesDocsMarkdownEtag(request, etag) || requestHasFreshDocsMarkdownDate(request, lastModified)) {
3799
+ const { "Content-Type": _contentType, ...notModifiedHeaders } = responseHeaders;
3800
+ return new Response(null, {
3801
+ status: 304,
3802
+ headers: notModifiedHeaders
3803
+ });
3804
+ }
3805
+ return new Response(document, { headers: responseHeaders });
3806
+ }
3807
+ function findDocsMarkdownPage(entry, pages, requestedPath) {
3808
+ const normalizedRequest = normalizeRequestedMarkdownPath(entry, requestedPath);
3809
+ for (const page of pages) if (normalizeDocsUrlPath(page.url) === normalizedRequest) return page;
3810
+ const normalizedSlug = normalizeDocsPathSegment(requestedPath.replace(/^\//, "").replace(/\.md$/i, ""));
3811
+ for (const page of pages) if (page.slug !== void 0 && normalizeDocsPathSegment(page.slug) === normalizedSlug) return page;
3812
+ return null;
3813
+ }
3814
+ function shouldRenderLlmsDirective(options) {
3815
+ if (options?.llms === false) return false;
3816
+ if (options?.llms && typeof options.llms === "object" && options.llms.enabled === false) return false;
3817
+ return true;
3818
+ }
3819
+ function resolveDocsAgentDocumentContext({ entry = "docs", apiRoute, apiCatalog: explicitApiCatalog, search, mcp, feedback, llms, sitemap, robots, openapi, markdown }) {
3820
+ const feedbackRoute = feedback?.route ?? DEFAULT_AGENT_FEEDBACK_ROUTE;
3821
+ const resolvedApiRoute = resolveDocsDiscoveryApiRoute(apiRoute);
3822
+ const openapiConfig = resolveDocsOpenApiDiscoveryConfig(openapi);
3823
+ return {
3824
+ apiRoute: resolvedApiRoute,
3825
+ normalizedEntry: normalizeDocsPathSegment(entry) || "docs",
3826
+ siteTitle: compactSkillText(llms?.siteTitle ?? "Documentation"),
3827
+ siteDescription: llms?.siteDescription ? compactSkillText(llms.siteDescription) : void 0,
3828
+ llmsEnabled: llms?.enabled ?? true,
3829
+ searchEnabled: isSearchEnabled(search),
3830
+ mcpEnabled: mcp.enabled,
3831
+ feedbackEnabled: feedback?.enabled ?? false,
3832
+ sitemapConfig: resolveDocsSitemapConfig(sitemap),
3833
+ robotsEnabled: isRobotsDiscoveryEnabled(robots),
3834
+ openapiConfig: {
3835
+ ...openapiConfig,
3836
+ url: resolveDocsOpenApiDiscoveryUrl(openapiConfig, resolvedApiRoute)
3837
+ },
3838
+ feedbackRoute,
3839
+ feedbackSchemaRoute: feedback?.schemaRoute ?? `${feedbackRoute}/schema`,
3840
+ llmsSections: resolveDocsLlmsTxtSections(llms),
3841
+ markdownAcceptHeader: markdown?.acceptHeader === false ? null : "text/markdown",
3842
+ markdownSignatureAgentHeader: markdown?.signatureAgentHeader === false ? null : DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER,
3843
+ apiCatalogEnabled: explicitApiCatalog ?? llms?.apiCatalog ?? true
3844
+ };
3845
+ }
3846
+ function appendDocsMarkdownNegotiationStartLines(lines, context, variant) {
3847
+ if (context.markdownAcceptHeader) lines.push(variant === "skill" ? `- You can also request ${context.markdownAcceptHeader} from normal page URLs.` : `- Normal docs pages can return markdown with Accept: ${context.markdownAcceptHeader}.`);
3848
+ if (context.markdownSignatureAgentHeader) lines.push(variant === "skill" ? `- Requests with ${context.markdownSignatureAgentHeader} on normal page URLs receive markdown automatically.` : `- Normal docs pages can also return markdown when ${context.markdownSignatureAgentHeader} is present.`);
3849
+ }
3850
+ function appendDocsSearchStartLine(lines, context, variant) {
3851
+ if (!context.searchEnabled) return;
3852
+ lines.push(variant === "skill" ? `- Search with ${context.apiRoute}?query={query}&audience=agent when you do not know the page.` : `- Search with ${context.apiRoute}?query={query}&audience=agent when the route is unknown.`);
3853
+ }
3854
+ function appendDocsOpenApiStartLine(lines, context, variant) {
3855
+ if (!context.openapiConfig.enabled || !context.openapiConfig.url) return;
3856
+ lines.push(variant === "skill" ? `- Fetch ${context.openapiConfig.url} for the machine-readable OpenAPI schema before scraping API reference pages.` : `- Fetch ${context.openapiConfig.url} before scraping API reference pages; prefer schemas over prose.`);
3857
+ }
3858
+ function appendDocsLlmsStartLines(lines, context, variant) {
3859
+ if (!context.llmsEnabled) return;
3860
+ lines.push(variant === "skill" ? `- Use ${DEFAULT_LLMS_TXT_ROUTE} for a compact docs index.` : `- Use ${DEFAULT_LLMS_TXT_ROUTE} as the compact docs map.`, variant === "skill" ? `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} for full markdown context.` : `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} when you need the full markdown bundle.`);
3861
+ for (const section of context.llmsSections) lines.push(variant === "skill" ? `- Use ${section.route} for the ${section.title} llms.txt section.` : `- Use ${section.route} for the ${section.title} section map.`);
3862
+ }
3863
+ function appendDocsSitemapStartLines(lines, context, variant) {
3864
+ if (!context.sitemapConfig.enabled) return;
3865
+ if (variant === "skill") {
3866
+ if (context.sitemapConfig.xml.enabled) lines.push(`- Use ${context.sitemapConfig.xml.route} to check canonical page freshness.`);
3867
+ if (context.sitemapConfig.markdown.enabled) lines.push(`- Use ${context.sitemapConfig.markdown.route} for a semantic docs map.`);
3868
+ return;
3869
+ }
3870
+ if (context.sitemapConfig.markdown.enabled) lines.push(`- Use ${context.sitemapConfig.markdown.route} for a semantic sitemap with sections.`);
3871
+ if (context.sitemapConfig.xml.enabled) lines.push(`- Use ${context.sitemapConfig.xml.route} for canonical URLs and freshness metadata.`);
3872
+ }
3873
+ function appendDocsRobotsStartLine(lines, context, variant) {
3874
+ if (!context.robotsEnabled) return;
3875
+ lines.push(variant === "skill" ? `- Check ${DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE} for crawler and AI-agent access policy.` : `- Check ${DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE} before crawling broadly.`);
3876
+ }
3877
+ function appendDocsMcpStartLine(lines, context, variant) {
3878
+ if (!context.mcpEnabled) return;
3879
+ lines.push(variant === "skill" ? `- Use ${DEFAULT_MCP_WELL_KNOWN_ROUTE} or ${DEFAULT_MCP_PUBLIC_ROUTE} for MCP tools when your environment supports MCP.` : `- Use MCP at ${DEFAULT_MCP_PUBLIC_ROUTE} or ${DEFAULT_MCP_WELL_KNOWN_ROUTE} when your environment supports MCP tools.`);
3880
+ }
3881
+ function appendDocsFeedbackStartLine(lines, context, variant) {
3882
+ if (!context.feedbackEnabled) return;
3883
+ lines.push(variant === "skill" ? `- Read ${context.feedbackSchemaRoute} before posting agent feedback to ${context.feedbackRoute}.` : `- Read ${context.feedbackSchemaRoute} before posting feedback to ${context.feedbackRoute}.`);
3884
+ }
3885
+ function appendDocsAgentStartHereLines(lines, context, variant) {
3886
+ const agentSpecFallback = context.apiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : `${context.apiRoute}?agent=spec`;
3887
+ lines.push(variant === "skill" ? `- Fetch ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${agentSpecFallback}.` : `- Read ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE} first; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${agentSpecFallback}.`);
3888
+ if (context.apiCatalogEnabled) lines.push(variant === "skill" ? `- Use ${DEFAULT_API_CATALOG_ROUTE} for standards-based API discovery.` : `- Use ${DEFAULT_API_CATALOG_ROUTE} for RFC 9727 API discovery.`);
3889
+ lines.push(variant === "skill" ? `- Use ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE} for hashed skill discovery.` : `- Use ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE} for integrity-checked skills.`, variant === "skill" ? `- Fetch /${context.normalizedEntry}.md for the root docs page.` : `- Read /${context.normalizedEntry}.md for the root docs page.`, variant === "skill" ? `- Fetch /${context.normalizedEntry}/{slug}.md for page-specific context.` : `- Read /${context.normalizedEntry}/{slug}.md for page-specific context.`);
3890
+ if (variant === "skill") {
3891
+ appendDocsMarkdownNegotiationStartLines(lines, context, variant);
3892
+ appendDocsSearchStartLine(lines, context, variant);
3893
+ appendDocsOpenApiStartLine(lines, context, variant);
3894
+ appendDocsLlmsStartLines(lines, context, variant);
3895
+ appendDocsSitemapStartLines(lines, context, variant);
3896
+ appendDocsRobotsStartLine(lines, context, variant);
3897
+ appendDocsMcpStartLine(lines, context, variant);
3898
+ appendDocsFeedbackStartLine(lines, context, variant);
3899
+ return;
3900
+ }
3901
+ appendDocsLlmsStartLines(lines, context, variant);
3902
+ appendDocsSitemapStartLines(lines, context, variant);
3903
+ appendDocsRobotsStartLine(lines, context, variant);
3904
+ appendDocsSearchStartLine(lines, context, variant);
3905
+ appendDocsOpenApiStartLine(lines, context, variant);
3906
+ appendDocsMcpStartLine(lines, context, variant);
3907
+ appendDocsFeedbackStartLine(lines, context, variant);
3908
+ appendDocsMarkdownNegotiationStartLines(lines, context, variant);
3909
+ }
3910
+ function appendDocsLlmsRouteLines(lines, context) {
3911
+ if (!context.llmsEnabled) return;
3912
+ lines.push(`- llms.txt: ${DEFAULT_LLMS_TXT_ROUTE}`, `- llms-full.txt: ${DEFAULT_LLMS_FULL_TXT_ROUTE}`, `- llms well-known aliases: ${DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE}, ${DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE}`);
3913
+ for (const section of context.llmsSections) {
3914
+ lines.push(`- ${section.title} llms.txt: ${section.route}`);
3915
+ lines.push(`- ${section.title} llms-full.txt: ${section.fullRoute}`);
3916
+ }
3917
+ }
3918
+ function appendDocsOpenApiRouteLines(lines, context) {
3919
+ if (!context.openapiConfig.enabled || !context.openapiConfig.url) return;
3920
+ lines.push(`- OpenAPI schema: ${context.openapiConfig.url}`);
3921
+ if (context.openapiConfig.apiReferencePath) lines.push(`- API reference: ${context.openapiConfig.apiReferencePath}`);
3922
+ }
3923
+ function appendDocsSitemapRouteLines(lines, context) {
3924
+ if (!context.sitemapConfig.enabled) return;
3925
+ if (context.sitemapConfig.xml.enabled) lines.push(`- Sitemap XML: ${context.sitemapConfig.xml.route}`);
3926
+ if (context.sitemapConfig.markdown.enabled) lines.push(`- Sitemap Markdown: ${context.sitemapConfig.markdown.route}`, ...context.sitemapConfig.markdown.docsRoute ? [`- Sitemap docs alias: ${context.sitemapConfig.markdown.docsRoute}`] : [], `- Sitemap well-known alias: ${context.sitemapConfig.markdown.wellKnownRoute}`);
3927
+ }
3928
+ function appendDocsMcpRouteLines(lines, context) {
3929
+ if (!context.mcpEnabled) return;
3930
+ lines.push(`- MCP: ${DEFAULT_MCP_PUBLIC_ROUTE}, ${DEFAULT_MCP_WELL_KNOWN_ROUTE}`);
3931
+ }
3932
+ function appendDocsAgentPublicRouteLines(lines, context, variant) {
3933
+ if (variant === "skill") {
3934
+ lines.push(`- Agent instructions: ${DEFAULT_AGENTS_MD_ROUTE}`, `- Agent instructions well-known alias: ${DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE}`, `- Agent instructions API format: ${context.apiRoute}?format=agents`, `- Skill document: ${DEFAULT_SKILL_MD_ROUTE}`, `- Skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Skill API format: ${context.apiRoute}?format=skill`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`);
3935
+ if (context.apiCatalogEnabled) lines.push(`- API catalog (RFC 9727): ${DEFAULT_API_CATALOG_ROUTE}`);
3936
+ lines.push(`- Agent Skills index: ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE}`, `- Agent Skills artifacts: ${DEFAULT_AGENT_SKILLS_ROUTE_PATTERN}`, `- Markdown root: /${context.normalizedEntry}.md`, `- Markdown pages: /${context.normalizedEntry}/{slug}.md`);
3937
+ if (context.robotsEnabled) lines.push(`- Robots policy: ${DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE}`);
3938
+ appendDocsLlmsRouteLines(lines, context);
3939
+ appendDocsOpenApiRouteLines(lines, context);
3940
+ appendDocsSitemapRouteLines(lines, context);
3941
+ appendDocsMcpRouteLines(lines, context);
3942
+ return;
3943
+ }
3944
+ lines.push(`- Agent instructions: ${DEFAULT_AGENTS_MD_ROUTE}`, `- Agent instructions well-known alias: ${DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE}`, `- Agent instructions API format: ${context.apiRoute}?format=agents`, `- Agent instructions aliases: ${DEFAULT_AGENT_MD_ROUTE}, ${DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE}`, `- Site skill: ${DEFAULT_SKILL_MD_ROUTE}`, `- Site skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Site skill API format: ${context.apiRoute}?format=skill`, `- Markdown root: /${context.normalizedEntry}.md`, `- Markdown pages: /${context.normalizedEntry}/{slug}.md`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`);
3945
+ if (context.apiCatalogEnabled) lines.push(`- API catalog (RFC 9727): ${DEFAULT_API_CATALOG_ROUTE}`);
3946
+ lines.push(`- Agent Skills index: ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE}`, `- Agent Skills artifacts: ${DEFAULT_AGENT_SKILLS_ROUTE_PATTERN}`);
3947
+ appendDocsLlmsRouteLines(lines, context);
3948
+ if (context.robotsEnabled) lines.push(`- Robots policy: ${DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE}`);
3949
+ appendDocsSitemapRouteLines(lines, context);
3950
+ appendDocsOpenApiRouteLines(lines, context);
3951
+ appendDocsMcpRouteLines(lines, context);
3952
+ }
3953
+ function renderDocsMarkdownDocument(page, options) {
3954
+ const explicitAgentContent = page.agentRawContent ?? page.agentContent;
3955
+ if (explicitAgentContent !== void 0) return appendDocsMarkdownSitemapFooter(prependDocsMarkdownFrontmatter(upsertPageAgentContractMarkdown(explicitAgentContent, page.agent), resolveDocsMarkdownPageMetadata(page, options)), options?.sitemap);
3956
+ const relatedLines = renderDocsRelatedMarkdownLines(page.related);
3957
+ const lines = [`# ${page.title}`, `URL: ${page.url}`];
3958
+ if (shouldRenderLlmsDirective(options)) lines.push(DOCS_LLMS_TXT_DIRECTIVE_LINE);
3959
+ if (page.description) lines.push(`Description: ${page.description}`);
3960
+ lines.push(...relatedLines);
3961
+ lines.push("", upsertPageAgentContractMarkdown(page.agentFallbackRawContent ?? page.agentFallbackContent ?? page.rawContent ?? page.content, page.agent));
3962
+ return appendDocsMarkdownSitemapFooter(prependDocsMarkdownFrontmatter(lines.join("\n"), resolveDocsMarkdownPageMetadata(page, options)), options?.sitemap);
3963
+ }
3964
+ function renderDocsSkillDocument(options) {
3965
+ const { origin } = options;
3966
+ const context = resolveDocsAgentDocumentContext(options);
3967
+ const lines = [
3968
+ "---",
3969
+ "name: docs",
3970
+ `description: ${toYamlString(truncateSkillDescription(`Use ${context.siteTitle} through markdown routes, llms.txt, robots.txt, agent discovery, search, and MCP when available.`))}`,
3971
+ "---",
3972
+ "",
3973
+ `# ${context.siteTitle} Skill`,
3974
+ "",
3975
+ `Base URL: ${origin}`
3976
+ ];
3977
+ if (context.siteDescription) lines.push(`Description: ${context.siteDescription}`);
3978
+ lines.push("", "## When To Use", "Use this skill when you need to read or implement against this documentation site.", "", "## Start Here");
3979
+ appendDocsAgentStartHereLines(lines, context, "skill");
3980
+ lines.push("", "## Routes");
3981
+ appendDocsAgentPublicRouteLines(lines, context, "skill");
3982
+ lines.push("", "## Reusable Framework Skills", "For framework setup, CLI, page actions, Ask AI, or configuration work, install the reusable Farming Labs skills:", "", "```sh", "npx skills add farming-labs/docs", "```");
3983
+ return lines.join("\n");
3984
+ }
3985
+ function renderDocsAgentsDocument(options) {
3986
+ const { origin } = options;
3987
+ const context = resolveDocsAgentDocumentContext(options);
3988
+ const lines = [
3989
+ "# Agent Instructions",
3990
+ "",
3991
+ `Site: ${context.siteTitle}`,
3992
+ `Base URL: ${origin}`
3993
+ ];
3994
+ if (context.siteDescription) lines.push(`Description: ${context.siteDescription}`);
3995
+ lines.push("", "## Start Here");
3996
+ appendDocsAgentStartHereLines(lines, context, "agents");
3997
+ lines.push("", "## Working Rules", "- Prefer markdown routes, llms.txt, sitemap.md, OpenAPI schemas, and MCP tools over scraping rendered HTML.", "- Treat generated context files as discovery aids, then fetch the smallest page or section that answers the task.", "- Preserve canonical docs URLs when citing pages back to humans.", "- If a markdown route returns a recovery page, use its closest matches, sitemap, and discovery spec before guessing another slug.", "", "## Public Routes");
3998
+ appendDocsAgentPublicRouteLines(lines, context, "agents");
3999
+ lines.push("", "## Framework Maintenance", "- For @farming-labs/docs projects, keep the framework package current before debugging missing agent surfaces.", "", "```sh", "npx @farming-labs/docs@latest upgrade --latest", "```", "", "- For framework setup, configuration, CLI, Ask AI, page actions, or theme work, install the reusable Skills pack:", "", "```sh", "npx skills add farming-labs/docs", "```");
4000
+ return lines.join("\n");
4001
+ }
4002
+ /** Resolve only the task tools that the advertised MCP endpoint actually exposes. */
4003
+ function resolveDocsAgentContractMcpTools(mcp) {
4004
+ if (!mcp.enabled) return void 0;
4005
+ const tools = {};
4006
+ if (mcp.tools.listTasks !== false) tools.list = "list_tasks";
4007
+ if (mcp.tools.readTask !== false) tools.read = "read_task";
4008
+ return tools.list || tools.read ? tools : void 0;
4009
+ }
4010
+ function buildDocsAgentDiscoverySpec({ origin, entry = "docs", apiRoute, apiCatalog: explicitApiCatalog, i18n = null, search, mcp, feedback, llms, sitemap, robots, openapi, markdown, publishedSkills = [], agentCard }) {
4011
+ const normalizedEntry = normalizeDocsPathSegment(entry) || "docs";
4012
+ const resolvedApiRoute = resolveDocsDiscoveryApiRoute(apiRoute);
4013
+ const apiQueryRoute = (query) => `${resolvedApiRoute}?${query}`;
4014
+ const localesEnabled = i18n !== null;
4015
+ const searchEnabled = isSearchEnabled(search);
4016
+ const feedbackRoute = feedback?.route ?? DEFAULT_AGENT_FEEDBACK_ROUTE;
4017
+ const feedbackSchemaRoute = feedback?.schemaRoute ?? `${feedbackRoute}/schema`;
4018
+ const llmsEnabled = llms?.enabled ?? true;
4019
+ const llmsSections = resolveDocsLlmsTxtSections(llms);
4020
+ const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms?.baseUrl });
4021
+ const robotsEnabled = isRobotsDiscoveryEnabled(robots);
4022
+ const openapiConfig = resolveDocsOpenApiDiscoveryConfig(openapi);
4023
+ const defaultOpenapiRoute = apiQueryRoute("format=openapi");
4024
+ const openapiUrl = resolveDocsOpenApiDiscoveryUrl(openapiConfig, resolvedApiRoute);
4025
+ const agentContractMcpTools = resolveDocsAgentContractMcpTools(mcp);
4026
+ const apiCatalogEnabled = explicitApiCatalog ?? llms?.apiCatalog ?? true;
4027
+ const protectedResource = mcp.enabled && mcp.security?.authenticate ? mcp.security.protectedResource : void 0;
4028
+ const protectedResourceMetadataRoutes = protectedResource ? getDocsMcpProtectedResourceMetadataRoutes(mcp.route) : [];
4029
+ return {
4030
+ version: "1",
4031
+ name: "@farming-labs/docs",
4032
+ baseUrl: origin,
4033
+ site: {
4034
+ title: llms?.siteTitle ?? "Documentation",
4035
+ description: llms?.siteDescription,
4036
+ entry: normalizedEntry,
4037
+ baseUrl: llms?.baseUrl ?? origin
4038
+ },
4039
+ locales: {
4040
+ enabled: localesEnabled,
4041
+ available: i18n?.locales ?? [],
4042
+ default: i18n?.defaultLocale ?? null,
4043
+ queryParam: "lang",
4044
+ fallbackQueryParam: "locale"
4045
+ },
4046
+ capabilities: {
4047
+ markdownRoutes: true,
4048
+ agentMdOverrides: true,
4049
+ agentBlocks: true,
4050
+ structuredAgentContracts: true,
4051
+ agents: true,
4052
+ llms: llmsEnabled,
4053
+ skills: true,
4054
+ apiCatalog: apiCatalogEnabled,
4055
+ agentSkillsDiscovery: true,
4056
+ mcp: mcp.enabled,
4057
+ search: searchEnabled,
4058
+ sitemap: sitemapConfig.enabled,
4059
+ robots: robotsEnabled,
4060
+ structuredData: true,
4061
+ apiReference: openapiConfig.enabled,
4062
+ openapi: openapiConfig.enabled,
4063
+ agentFeedback: feedback?.enabled ?? false,
4064
+ locales: localesEnabled
4065
+ },
4066
+ api: {
4067
+ docs: resolvedApiRoute,
4068
+ config: apiQueryRoute("format=config"),
4069
+ diagnostics: apiQueryRoute("format=diagnostics"),
4070
+ agentSpec: resolvedApiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : apiQueryRoute("agent=spec"),
4071
+ agentSpecDefault: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
4072
+ agentSpecFallback: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
4073
+ agentSpecWellKnown: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
4074
+ agentSpecWellKnownJson: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
4075
+ agentSpecQuery: apiQueryRoute("agent=spec"),
4076
+ agents: apiQueryRoute("format=agents"),
4077
+ ...apiCatalogEnabled ? {
4078
+ apiCatalog: DEFAULT_API_CATALOG_ROUTE,
4079
+ apiCatalogQuery: apiQueryRoute(`format=${DEFAULT_API_CATALOG_FORMAT}`)
4080
+ } : {},
4081
+ agentSkillsIndex: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
4082
+ legacySkillsIndex: DEFAULT_LEGACY_SKILLS_INDEX_ROUTE,
4083
+ ...agentCard ? { agentCard: DEFAULT_A2A_AGENT_CARD_ROUTE } : {},
4084
+ openapi: defaultOpenapiRoute
4085
+ },
4086
+ apiCatalog: {
4087
+ enabled: apiCatalogEnabled,
4088
+ route: apiCatalogEnabled ? DEFAULT_API_CATALOG_ROUTE : null,
4089
+ api: apiCatalogEnabled ? apiQueryRoute(`format=${DEFAULT_API_CATALOG_FORMAT}`) : null,
4090
+ mediaType: API_CATALOG_MEDIA_TYPE,
4091
+ profile: API_CATALOG_PROFILE_URI
4092
+ },
4093
+ config: {
4094
+ format: DEFAULT_DOCS_CONFIG_FORMAT,
4095
+ endpoint: apiQueryRoute("format=config")
4096
+ },
4097
+ markdown: {
4098
+ enabled: true,
4099
+ acceptHeader: markdown?.acceptHeader === false ? null : "text/markdown",
4100
+ signatureAgentHeader: markdown?.signatureAgentHeader === false ? null : DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER,
4101
+ pagePattern: `/${normalizedEntry}/{slug}.md`,
4102
+ rootPage: `/${normalizedEntry}.md`,
4103
+ apiPattern: apiQueryRoute("format=markdown&path={slug}"),
4104
+ resolutionOrder: [
4105
+ "agent.md",
4106
+ "agent audience projection",
4107
+ "shared page markdown"
4108
+ ]
4109
+ },
4110
+ agentContract: {
4111
+ enabled: true,
4112
+ schemaVersion: "page-agent-contract.v1",
4113
+ source: "page-frontmatter",
4114
+ frontmatterPath: "agent",
4115
+ markdownSection: "Agent Contract",
4116
+ mcpField: "agent",
4117
+ ...agentContractMcpTools ? { mcpTools: agentContractMcpTools } : {},
4118
+ usefulContractFields: ["task", "outcome"],
4119
+ fields: PAGE_AGENT_CONTRACT_FIELD_SCHEMA
4120
+ },
4121
+ llms: {
4122
+ enabled: llmsEnabled,
4123
+ defaultTxt: DEFAULT_LLMS_TXT_ROUTE,
4124
+ defaultFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
4125
+ txt: apiQueryRoute("format=llms"),
4126
+ full: apiQueryRoute("format=llms-full"),
4127
+ publicTxt: DEFAULT_LLMS_TXT_ROUTE,
4128
+ publicFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
4129
+ wellKnownTxt: DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
4130
+ wellKnownFull: DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE,
4131
+ ...llmsSections.length > 0 ? { sections: llmsSections.map((section) => ({
4132
+ title: section.title,
4133
+ description: section.description,
4134
+ match: section.match,
4135
+ txt: section.route,
4136
+ full: section.fullRoute
4137
+ })) } : {}
4138
+ },
4139
+ sitemap: {
4140
+ enabled: sitemapConfig.enabled,
4141
+ xml: {
4142
+ enabled: sitemapConfig.xml.enabled,
4143
+ route: sitemapConfig.xml.route,
4144
+ api: apiQueryRoute("format=sitemap-xml"),
4145
+ defaultRoute: DEFAULT_SITEMAP_XML_ROUTE
4146
+ },
4147
+ markdown: {
4148
+ enabled: sitemapConfig.markdown.enabled,
4149
+ route: sitemapConfig.markdown.route,
4150
+ docsRoute: sitemapConfig.markdown.docsRoute,
4151
+ wellKnownRoute: sitemapConfig.markdown.wellKnownRoute,
4152
+ api: apiQueryRoute("format=sitemap-md"),
4153
+ defaultRoute: DEFAULT_SITEMAP_MD_ROUTE,
4154
+ defaultDocsRoute: DEFAULT_SITEMAP_MD_DOCS_ROUTE,
4155
+ defaultWellKnownRoute: DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE
4156
+ }
4157
+ },
4158
+ robots: {
4159
+ enabled: robotsEnabled,
4160
+ route: DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE,
4161
+ defaultRoute: DEFAULT_AGENT_DISCOVERY_ROBOTS_TXT_ROUTE
4162
+ },
4163
+ structuredData: {
4164
+ enabled: true,
4165
+ format: "application/ld+json",
4166
+ schema: "https://schema.org/TechArticle",
4167
+ fields: [
4168
+ "headline",
4169
+ "description",
4170
+ "url",
4171
+ "dateModified",
4172
+ "breadcrumb",
4173
+ "mainEntity"
4174
+ ],
4175
+ canonicalUrlField: "url",
4176
+ breadcrumbType: "BreadcrumbList",
4177
+ agentContractType: "HowTo"
4178
+ },
4179
+ openapi: {
4180
+ enabled: openapiConfig.enabled,
4181
+ url: openapiUrl ?? null,
4182
+ source: openapiConfig.source ?? null,
4183
+ specUrl: openapiConfig.specUrl ?? null,
4184
+ apiReferencePath: openapiConfig.apiReferencePath ?? null,
4185
+ format: "OpenAPI 3.1"
4186
+ },
4187
+ search: {
4188
+ enabled: searchEnabled,
4189
+ endpoint: apiQueryRoute("query={query}"),
4190
+ agentEndpoint: apiQueryRoute("query={query}&audience=agent"),
4191
+ method: "GET",
4192
+ queryParam: "query",
4193
+ localeParam: "lang",
4194
+ audienceParam: "audience",
4195
+ defaultAudience: "human",
4196
+ supportedAudiences: ["human", "agent"]
4197
+ },
4198
+ agents: {
4199
+ enabled: true,
4200
+ file: "AGENTS.md",
4201
+ route: DEFAULT_AGENTS_MD_ROUTE,
4202
+ wellKnown: DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE,
4203
+ api: apiQueryRoute("format=agents"),
4204
+ generatedFallback: true,
4205
+ aliases: [DEFAULT_AGENT_MD_ROUTE, DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE]
4206
+ },
4207
+ skills: {
4208
+ enabled: true,
4209
+ file: "skill.md",
4210
+ route: DEFAULT_SKILL_MD_ROUTE,
4211
+ wellKnown: DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE,
4212
+ api: apiQueryRoute("format=skill"),
4213
+ generatedFallback: true,
4214
+ registry: "skills.sh",
4215
+ install: "npx skills add farming-labs/docs",
4216
+ discovery: {
4217
+ schema: AGENT_SKILLS_DISCOVERY_SCHEMA_URI,
4218
+ index: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
4219
+ artifact: DEFAULT_AGENT_SKILLS_ROUTE_PATTERN,
4220
+ archive: DEFAULT_AGENT_SKILLS_ARCHIVE_ROUTE_PATTERN,
4221
+ file: `${DEFAULT_AGENT_SKILLS_ROUTE_PATTERN.replace("/SKILL.md", "/{path}")}`,
4222
+ legacyIndex: DEFAULT_LEGACY_SKILLS_INDEX_ROUTE,
4223
+ apiIndex: apiQueryRoute(`format=${DEFAULT_AGENT_SKILLS_INDEX_FORMAT}`),
4224
+ apiArtifact: apiQueryRoute("format=agent-skill&name={name}"),
4225
+ apiFile: apiQueryRoute("format=agent-skill-file&name={name}&path={path}"),
4226
+ digest: "sha256"
4227
+ },
4228
+ published: publishedSkills.map((skill) => ({
4229
+ name: skill.name,
4230
+ description: skill.description,
4231
+ type: skill.type,
4232
+ url: skill.url,
4233
+ digest: skill.digest,
4234
+ files: skill.files.map((file) => ({
4235
+ path: file.path,
4236
+ url: file.url,
4237
+ digest: file.digest
4238
+ }))
4239
+ })),
4240
+ recommended: [{
4241
+ name: "getting-started",
4242
+ description: "Use for installation, init, framework setup, theme CSS, and first docs.config wiring."
4243
+ }]
4244
+ },
4245
+ mcp: {
4246
+ enabled: mcp.enabled,
4247
+ endpoint: mcp.route,
4248
+ defaultEndpoint: DEFAULT_MCP_PUBLIC_ROUTE,
4249
+ publicEndpoint: DEFAULT_MCP_PUBLIC_ROUTE,
4250
+ wellKnownEndpoint: DEFAULT_MCP_WELL_KNOWN_ROUTE,
4251
+ publicEndpoints: [DEFAULT_MCP_PUBLIC_ROUTE, DEFAULT_MCP_WELL_KNOWN_ROUTE],
4252
+ canonicalEndpoint: mcp.route,
4253
+ name: mcp.name,
4254
+ version: mcp.version,
4255
+ tools: mcp.tools,
4256
+ ...protectedResource ? { protectedResource: {
4257
+ metadataEndpoints: protectedResourceMetadataRoutes,
4258
+ authorizationServers: protectedResource.authorizationServers,
4259
+ scopesSupported: protectedResource.scopesSupported,
4260
+ requiredScopes: protectedResource.requiredScopes
4261
+ } } : {}
4262
+ },
4263
+ feedback: {
4264
+ enabled: feedback?.enabled ?? false,
4265
+ schema: feedbackSchemaRoute,
4266
+ submit: feedbackRoute,
4267
+ schemaQuery: apiQueryRoute("feedback=agent&schema=1"),
4268
+ submitQuery: apiQueryRoute("feedback=agent")
4269
+ },
4270
+ instructions: {
4271
+ preferMarkdownRoutes: true,
4272
+ useMcpWhenAvailable: true,
4273
+ useOpenApiWhenAvailable: true,
4274
+ readFeedbackSchemaBeforeSubmitting: true,
4275
+ doNotAssumeFeedbackPayloadShape: true
4276
+ }
4277
+ };
4278
+ }
4279
+ function acceptsDocsMarkdown(request) {
4280
+ const accept = request.headers.get("accept");
4281
+ if (!accept) return false;
4282
+ const ranges = accept.split(",").map((value) => {
4283
+ const [rawMediaType = "", ...params] = value.split(";").map((part) => part.trim().toLowerCase());
4284
+ const qualityParam = params.find((param) => param.split("=", 1)[0]?.trim() === "q");
4285
+ const parsedQuality = qualityParam ? Number.parseFloat(qualityParam.slice(qualityParam.indexOf("=") + 1).trim()) : 1;
4286
+ return {
4287
+ mediaType: rawMediaType,
4288
+ quality: Number.isFinite(parsedQuality) ? Math.min(1, Math.max(0, parsedQuality)) : 0
4289
+ };
4290
+ });
4291
+ const qualityFor = (mediaType) => {
4292
+ const matches = ranges.filter((range) => range.mediaType === mediaType);
4293
+ return matches.length > 0 ? Math.max(...matches.map((range) => range.quality)) : void 0;
4294
+ };
4295
+ const markdownQuality = qualityFor("text/markdown");
4296
+ if (!markdownQuality || markdownQuality <= 0) return false;
4297
+ const htmlQuality = qualityFor("text/html") ?? qualityFor("text/*") ?? qualityFor("*/*");
4298
+ return htmlQuality === void 0 || htmlQuality <= markdownQuality;
4299
+ }
4300
+ function buildDocsUserAgentHeaderPattern(patterns) {
4301
+ return `.*(?:${patterns.map(toCaseInsensitiveHeaderPattern).join("|")}).*`;
4302
+ }
4303
+ function toCaseInsensitiveHeaderPattern(value) {
4304
+ return value.split("").map((char) => {
4305
+ if (/^[a-z]$/i.test(char)) return `[${char.toLowerCase()}${char.toUpperCase()}]`;
4306
+ return escapeRegex(char);
4307
+ }).join("");
4308
+ }
4309
+ function escapeRegex(value) {
4310
+ return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
4311
+ }
4312
+ function normalizeRequestedMarkdownPath(entry, requestedPath) {
4313
+ const normalizedEntry = `/${normalizeDocsPathSegment(entry) || "docs"}`;
4314
+ const trimmed = requestedPath.trim().replace(/\.md$/i, "");
4315
+ if (!trimmed) return normalizedEntry;
4316
+ const normalized = normalizeDocsUrlPath(trimmed.startsWith("/") ? trimmed : `/${trimmed}`);
4317
+ if (normalized === normalizedEntry || normalized.startsWith(`${normalizedEntry}/`)) return normalized;
4318
+ const slug = normalizeDocsPathSegment(trimmed);
4319
+ return slug ? normalizeDocsUrlPath(`${normalizedEntry}/${slug}`) : normalizedEntry;
4320
+ }
4321
+ function isSearchEnabled(search) {
4322
+ if (search === false) return false;
4323
+ if (search && typeof search === "object" && search.enabled === false) return false;
4324
+ return true;
4325
+ }
4326
+ function isRobotsDiscoveryEnabled(robots) {
4327
+ if (robots === false) return false;
4328
+ if (robots && typeof robots === "object" && robots.enabled === false) return false;
4329
+ return true;
4330
+ }
4331
+ function resolveDocsOpenApiDiscoveryConfig(openapi) {
4332
+ if (openapi === false || openapi === void 0) return { enabled: false };
4333
+ if (openapi === true) return {
4334
+ enabled: true,
4335
+ url: DEFAULT_OPENAPI_SCHEMA_ROUTE,
4336
+ urlSource: "default",
4337
+ source: "generated"
4338
+ };
4339
+ if (openapi.enabled === false) return { enabled: false };
4340
+ return {
4341
+ enabled: true,
4342
+ url: openapi.url ?? DEFAULT_OPENAPI_SCHEMA_ROUTE,
4343
+ urlSource: openapi.urlSource ?? (openapi.url === void 0 ? "default" : "configured"),
4344
+ source: openapi.source ?? "generated",
4345
+ specUrl: openapi.specUrl,
4346
+ apiReferencePath: openapi.apiReferencePath
4347
+ };
4348
+ }
4349
+ function resolveDocsOpenApiDiscoveryUrl(openapi, apiRoute) {
4350
+ return openapi.urlSource === "default" && openapi.url === DEFAULT_OPENAPI_SCHEMA_ROUTE ? `${apiRoute}?format=openapi` : openapi.url;
4351
+ }
4352
+ function compactSkillText(value) {
4353
+ return value.replace(/\s+/g, " ").trim();
4354
+ }
4355
+ function truncateSkillDescription(value) {
4356
+ const normalized = compactSkillText(value);
4357
+ if (normalized.length <= 1024) return normalized;
4358
+ return `${normalized.slice(0, 1021).trimEnd()}...`;
4359
+ }
4360
+ function toYamlString(value) {
4361
+ return JSON.stringify(value);
4362
+ }
4363
+
4364
+ //#endregion
4365
+ export { renderDocsAgentsDocument as $, DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE as $t, buildDocsAgentFeedbackSchema as A, buildDocsSitemapManifest as At, getDocsMarkdownVaryHeader as B, renderDocsRelatedMarkdownLines as Bt, DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN as C, resolveDocsAudienceExposure as Ct, DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN as D, DEFAULT_SITEMAP_MD_ROUTE as Dt, DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER as E, DEFAULT_SITEMAP_MD_DOCS_ROUTE as Et, createDocsStandardsDiscoveryResponse as F, resolveDocsSitemapConfig as Ft, isDocsDiagnosticsRequest as G, PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS as Gt, isDocsAgentDiscoveryRequest as H, PAGE_AGENT_CONTRACT_FIELDS as Ht, detectDocsMarkdownAgentRequest as I, resolveDocsSitemapPageLastmod as It, isDocsSkillRequest as J, normalizePageAgentFrontmatter as Jt, isDocsLlmsTxtPublicRequest as K, getPageAgentFrontmatterIssues as Kt, findDocsMarkdownPage as L, resolveDocsSitemapRequest as Lt, buildDocsDiagnostics as M, readDocsSitemapManifestFromContentMap as Mt, buildDocsMcpEndpointCandidates as N, renderDocsSitemapMarkdown as Nt, acceptsDocsMarkdown as O, DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE as Ot, createDocsMarkdownResponse as P, renderDocsSitemapXml as Pt, parseDocsAgentFeedbackData as Q, upsertPageAgentContractMarkdown as Qt, getDocsLlmsTxtMaxCharsIssue as R, toDocsSitemapMarkdownUrl as Rt, DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE as S, resolveDocsAgentMdxContent as St, DOCS_CONFIG_MAP_TOP_LEVEL_KEYS as T, DEFAULT_SITEMAP_MANIFEST_PATH as Tt, isDocsAgentsRequest as U, PAGE_AGENT_CONTRACT_FIELD_SCHEMA as Ut, hasDocsMarkdownSignatureAgent as V, PAGE_AGENT_CONTRACT_END_MARKER as Vt, isDocsConfigRequest as W, PAGE_AGENT_CONTRACT_START_MARKER as Wt, normalizeDocsPathSegment as X, renderPageAgentFrontmatterYamlLines as Xt, matchesDocsLlmsTxtSection as Y, renderPageAgentContractMarkdown as Yt, normalizeDocsUrlPath as Z, stripGeneratedPageAgentContractMarkdown as Zt, DEFAULT_LLMS_TXT_MAX_CHARS as _, selectDocsLlmsTxtContent as _t, DEFAULT_AGENT_MD_ROUTE as a, getDocsMcpResourcePaths as an, resolveDocsAgentFeedbackConfig as at, DEFAULT_OPENAPI_SCHEMA_ROUTE as b, findDocsAudienceMdxIssues as bt, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE as c, isDocsMcpProtectedResourceMetadataPath as cn, resolveDocsLlmsTxtFormat as ct, DEFAULT_DOCS_CONFIG_FORMAT as d, normalizeDocsMcpAuthorizationServerUrls as dn, resolveDocsMarkdownCanonicalUrl as dt, DEFAULT_MCP_PUBLIC_ROUTE as en, renderDocsLlmsTxt as et, DEFAULT_DOCS_CONFIG_ROUTE as f, normalizeDocsMcpEndpointPath as fn, resolveDocsMarkdownRecovery as ft, DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE as g, resolveDocsSkillFormat as gt, DEFAULT_LLMS_FULL_TXT_ROUTE as h, resolveDocsRequestApiRoute as ht, DEFAULT_AGENT_FEEDBACK_ROUTE as i, getDocsMcpProtectedResourceMetadataRoutes as in, resolveDocsAgentContractMcpTools as it, buildDocsConfigMap as j, createDocsSitemapResponse as jt, buildDocsAgentDiscoverySpec as k, DEFAULT_SITEMAP_XML_ROUTE as kt, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE as l, isDocsMcpRequest as ln, resolveDocsLlmsTxtRequest as lt, DEFAULT_DOCS_DIAGNOSTICS_ROUTE as m, resolveDocsMcpResourceLocation as mn, resolveDocsOpenApiDiscoveryConfig as mt, DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE as n, DEFAULT_MCP_WELL_KNOWN_ROUTE as nn, renderDocsMarkdownNotFound as nt, DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE as o, hasDocsMcpProtectedResourceConfig as on, resolveDocsAgentFeedbackRequest as ot, DEFAULT_DOCS_DIAGNOSTICS_FORMAT as p, resolveDocsMcpProtectedResourceMetadataLocation as pn, resolveDocsMarkdownRequest as pt, isDocsPublicGetRequest as q, hasStructuredPageAgentContract as qt, DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA as r, buildDocsMcpProtectedResourceMetadataRoute as rn, renderDocsSkillDocument as rt, DEFAULT_AGENT_SPEC_ROUTE as s, isDocsMcpOAuthScopeToken as sn, resolveDocsAgentsFormat as st, DEFAULT_AGENTS_MD_ROUTE as t, DEFAULT_MCP_ROUTE as tn, renderDocsMarkdownDocument as tt, DEFAULT_DOCS_API_ROUTE as u, isDocsMcpResourcePath as un, resolveDocsLlmsTxtSections as ut, DEFAULT_LLMS_TXT_ROUTE as v, toDocsMarkdownUrl as vt, DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN as w, resolveDocsAudienceMdxContent as wt, DEFAULT_SKILL_MD_ROUTE as x, findDocsAudienceMdxTags as xt, DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE as y, validateDocsAgentFeedbackPayload as yt, getDocsMarkdownCanonicalLinkHeader as z, normalizeDocsRelated as zt };