@farming-labs/docs 0.2.119 → 0.2.121

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 (188) hide show
  1. package/README.md +8 -0
  2. package/dist/access.d.mts +13 -0
  3. package/dist/access.mjs +56 -0
  4. package/dist/agent-conformance.d.mts +60 -0
  5. package/dist/agent-conformance.mjs +538 -0
  6. package/dist/agent-contract.d.mts +47 -0
  7. package/dist/agent-contract.mjs +645 -0
  8. package/dist/agent-detection.d.mts +6 -0
  9. package/dist/agent-detection.mjs +83 -0
  10. package/dist/agent-evals.d.mts +224 -0
  11. package/dist/{agent-evals-BLNLvXbG.mjs → agent-evals.mjs} +7 -565
  12. package/dist/agent-feedback-evaluations-node.mjs +38 -0
  13. package/dist/agent-feedback-evaluations.d.mts +91 -0
  14. package/dist/{agent-feedback-evaluations-CcMGlgsO.mjs → agent-feedback-evaluations.mjs} +2 -2
  15. package/dist/agent-feedback-loop.d.mts +45 -0
  16. package/dist/{agent-feedback-loop-CcZL_sb1.mjs → agent-feedback-loop.mjs} +1 -1
  17. package/dist/agent-maintenance.d.mts +71 -0
  18. package/dist/{agent-maintenance-CuZ7iAKq.mjs → agent-maintenance.mjs} +1 -1
  19. package/dist/agent-provenance.d.mts +23 -0
  20. package/dist/agent-provenance.mjs +77 -0
  21. package/dist/agent-scope.mjs +321 -0
  22. package/dist/agent-skills-archive.mjs +86 -0
  23. package/dist/agent-skills-bundle.d.mts +1 -1
  24. package/dist/{agent-skills-progressive-disclosure-PjPtTYL-.mjs → agent-skills-progressive-disclosure.mjs} +2 -2
  25. package/dist/{agent-skills-server-CTNWr23x.d.mts → agent-skills-server.d.mts} +3 -3
  26. package/dist/{agent-skills-server-BC7md56k.mjs → agent-skills-server.mjs} +2 -2
  27. package/dist/agent-skills-vite.d.mts +3 -3
  28. package/dist/agent-skills-vite.mjs +1 -2
  29. package/dist/agent-surface-drift.mjs +236 -0
  30. package/dist/{golden-evaluations-CLUViycJ.mjs → agent-usefulness.mjs} +5 -290
  31. package/dist/{content-change-hydration-CvHJadhE.d.mts → agent.d.mts} +10 -411
  32. package/dist/agent.mjs +2729 -0
  33. package/dist/{analytics-B8RZiKUt.d.mts → analytics.d.mts} +2 -2
  34. package/dist/{analytics-p8Vhhu2P.mjs → analytics.mjs} +2 -2
  35. package/dist/{sitemap-server-C9r22_06.d.mts → api-reference.d.mts} +3 -6
  36. package/dist/api-reference.mjs +1481 -0
  37. package/dist/{audience-exposure-DBrFWULA.d.mts → audience-exposure.d.mts} +1 -1
  38. package/dist/audience-exposure.mjs +8 -0
  39. package/dist/audience.d.mts +44 -0
  40. package/dist/audience.mjs +1654 -0
  41. package/dist/authoring-mcp.d.mts +44 -0
  42. package/dist/{authoring-mcp-CiCUQe3o.mjs → authoring-mcp.mjs} +3 -3
  43. package/dist/browser.d.mts +6 -4
  44. package/dist/browser.mjs +6 -7
  45. package/dist/build.d.mts +8 -0
  46. package/dist/build.mjs +8 -0
  47. package/dist/changelog.d.mts +20 -0
  48. package/dist/changelog.mjs +39 -0
  49. package/dist/{agent-export-Cxljt6RP.mjs → cli/agent-export.mjs} +19 -45
  50. package/dist/{agent-CYk2DxY7.mjs → cli/agent.mjs} +6 -35
  51. package/dist/{agents-jtn256sz.mjs → cli/agents.mjs} +5 -18
  52. package/dist/cli/api-doctor.mjs +206 -0
  53. package/dist/{authoring-C2ymvYWl.mjs → cli/authoring.mjs} +2 -8
  54. package/dist/{cloud-6eKrlmKd.mjs → cli/cloud.mjs} +3 -3
  55. package/dist/{codeblocks-CHpgAwY-.mjs → cli/codeblocks.mjs} +2 -2
  56. package/dist/cli/config.d.mts +11 -0
  57. package/dist/{config-BZnKAj_Y.mjs → cli/config.mjs} +1 -1
  58. package/dist/cli/dev-banner.mjs +58 -0
  59. package/dist/{dev-Bnn-NUNa.mjs → cli/dev.mjs} +3 -57
  60. package/dist/{doctor-CUMgbglt.mjs → cli/doctor.mjs} +41 -226
  61. package/dist/{downgrade-CHMta85e.mjs → cli/downgrade.mjs} +2 -2
  62. package/dist/cli/errors.d.mts +4 -0
  63. package/dist/{errors-BtnVLhNF.mjs → cli/errors.mjs} +1 -1
  64. package/dist/{feedback-evals-DMilg9pY.mjs → cli/feedback-evals.mjs} +3 -36
  65. package/dist/{feedback-DL4T5oIO.mjs → cli/feedback.mjs} +1 -1
  66. package/dist/cli/git-dates.mjs +35 -0
  67. package/dist/cli/golden-evaluations.mjs +52 -0
  68. package/dist/cli/index.d.mts +2 -3
  69. package/dist/cli/index.mjs +38 -38
  70. package/dist/{init-K0LmXDZ5.mjs → cli/init.mjs} +3 -3
  71. package/dist/{mcp-Bvha6_mG.mjs → cli/mcp.mjs} +7 -19
  72. package/dist/{openapi-diff-BOESBfnP.mjs → cli/openapi-diff.mjs} +2 -7
  73. package/dist/{openapi-sdk-DJutz2AC.mjs → cli/openapi-sdk.mjs} +2 -7
  74. package/dist/{openapi-source-CiX3hwFp.mjs → cli/openapi-source.mjs} +2 -2
  75. package/dist/{package-version-HJhYeq4M.mjs → cli/package-version.mjs} +2 -2
  76. package/dist/{propose-JmUv_BTt.mjs → cli/propose.mjs} +1 -1
  77. package/dist/{review-C6EmbV0l.mjs → cli/review.mjs} +16 -15
  78. package/dist/{robots-DteZB8vl.mjs → cli/robots.mjs} +3 -7
  79. package/dist/{search-DKcdZgGx.mjs → cli/search.mjs} +7 -20
  80. package/dist/{sitemap-CBQoERNz.mjs → cli/sitemap.mjs} +7 -42
  81. package/dist/{skills-a90P31sJ.mjs → cli/skills.mjs} +5 -19
  82. package/dist/{templates-BuQ8YsGv.mjs → cli/templates.mjs} +1 -1
  83. package/dist/{upgrade-DlQMOFV1.mjs → cli/upgrade.mjs} +2 -2
  84. package/dist/{utils-C7KDrPpA.mjs → cli/utils.mjs} +1 -1
  85. package/dist/client/react.d.mts +2 -18
  86. package/dist/client/react.mjs +1 -157
  87. package/dist/{cloud-analytics-D14HplI7.mjs → cloud-analytics.mjs} +1 -1
  88. package/dist/{cloud-ask-ai-BOahlsIZ.d.mts → cloud-ask-ai.d.mts} +2 -2
  89. package/dist/{cloud-ask-ai-BqKhjpS5.mjs → cloud-ask-ai.mjs} +3 -3
  90. package/dist/code-blocks.d.mts +51 -0
  91. package/dist/{code-blocks-GYdvS3BH.mjs → code-blocks.mjs} +2 -2
  92. package/dist/code-group-mdx.d.mts +11 -0
  93. package/dist/code-group-mdx.mjs +57 -0
  94. package/dist/content-change-hydration.d.mts +87 -0
  95. package/dist/{openapi-mcp-BIOTLiA7.mjs → content-change-hydration.mjs} +5 -210
  96. package/dist/content-changes.d.mts +47 -0
  97. package/dist/content-changes.mjs +216 -0
  98. package/dist/create-theme.d.mts +48 -0
  99. package/dist/create-theme.mjs +57 -0
  100. package/dist/date.d.mts +5 -0
  101. package/dist/date.mjs +17 -0
  102. package/dist/define-docs.d.mts +9 -0
  103. package/dist/define-docs.mjs +46 -0
  104. package/dist/docs-cloud-client.d.mts +18 -0
  105. package/dist/docs-cloud-client.mjs +161 -0
  106. package/dist/docs-cloud-server.d.mts +2 -2
  107. package/dist/docs-cloud-server.mjs +2 -3
  108. package/dist/heading-toc.d.mts +10 -0
  109. package/dist/heading-toc.mjs +23 -0
  110. package/dist/http-body.d.mts +14 -0
  111. package/dist/{http-body-DkAPk6D5.mjs → http-body.mjs} +1 -1
  112. package/dist/http-cache.d.mts +25 -0
  113. package/dist/http-cache.mjs +140 -0
  114. package/dist/http-link.mjs +81 -0
  115. package/dist/i18n.d.mts +18 -0
  116. package/dist/{i18n-B1gJ9EW0.mjs → i18n.mjs} +1 -1
  117. package/dist/index.d.mts +43 -675
  118. package/dist/index.mjs +40 -14
  119. package/dist/markdown-rendering.mjs +1 -1
  120. package/dist/markdown-section-cache.mjs +49 -0
  121. package/dist/markdown-sections.d.mts +47 -0
  122. package/dist/{markdown-sections-9Oxr33b-.mjs → markdown-sections.mjs} +29 -703
  123. package/dist/mcp-auth.d.mts +14 -0
  124. package/dist/mcp-auth.mjs +99 -0
  125. package/dist/mcp.d.mts +5 -3
  126. package/dist/mcp.mjs +39 -9
  127. package/dist/mdx.d.mts +6 -0
  128. package/dist/mdx.mjs +7 -0
  129. package/dist/metadata.d.mts +60 -0
  130. package/dist/{metadata-BOHn0Y5K.mjs → metadata.mjs} +2 -2
  131. package/dist/native-api-reference.mjs +968 -0
  132. package/dist/okf.d.mts +42 -0
  133. package/dist/okf.mjs +145 -0
  134. package/dist/openapi-contract.mjs +154 -0
  135. package/dist/{openapi-mcp-node-C4jUpZG6.mjs → openapi-mcp-node.mjs} +1 -1
  136. package/dist/openapi-mcp.d.mts +26 -0
  137. package/dist/openapi-mcp.mjs +132 -0
  138. package/dist/openapi-operations.d.mts +71 -0
  139. package/dist/{openapi-operations-DFpaqOqA.mjs → openapi-operations.mjs} +1 -1
  140. package/dist/openapi-overlays.mjs +221 -0
  141. package/dist/openapi-references.mjs +233 -0
  142. package/dist/pagination.d.mts +7 -0
  143. package/dist/pagination.mjs +100 -0
  144. package/dist/prompt-references.d.mts +12 -0
  145. package/dist/prompt-references.mjs +132 -0
  146. package/dist/prompt-utils.d.mts +36 -0
  147. package/dist/{prompt-utils-B5g-bv7o.mjs → prompt-utils.mjs} +1 -57
  148. package/dist/reading-time.d.mts +23 -0
  149. package/dist/reading-time.mjs +58 -0
  150. package/dist/related.d.mts +7 -0
  151. package/dist/related.mjs +50 -0
  152. package/dist/retrieval-digest.d.mts +16 -0
  153. package/dist/{retrieval-digest-CT-eIEcp.mjs → retrieval-digest.mjs} +1 -1
  154. package/dist/review.d.mts +69 -0
  155. package/dist/review.mjs +562 -0
  156. package/dist/robots.d.mts +54 -0
  157. package/dist/{robots-BYJAVeI6.mjs → robots.mjs} +5 -3
  158. package/dist/runtime.d.mts +3 -3
  159. package/dist/runtime.mjs +3 -9
  160. package/dist/search.d.mts +210 -0
  161. package/dist/search.mjs +3401 -0
  162. package/dist/server.d.mts +22 -198
  163. package/dist/server.mjs +21 -19
  164. package/dist/sidebar.d.mts +15 -0
  165. package/dist/sidebar.mjs +73 -0
  166. package/dist/sitemap-server.d.mts +7 -0
  167. package/dist/{sitemap-server-Lg3YhUx4.mjs → sitemap-server.mjs} +2 -2
  168. package/dist/{sitemap-DafdOrxK.d.mts → sitemap.d.mts} +3 -3
  169. package/dist/sitemap.mjs +254 -0
  170. package/dist/{standards-discovery-1fiUVDAo.d.mts → standards-discovery.d.mts} +2 -2
  171. package/dist/{standards-discovery-sSEojU80.mjs → standards-discovery.mjs} +3 -139
  172. package/dist/telemetry-runtime.d.mts +42 -0
  173. package/dist/telemetry-runtime.mjs +238 -0
  174. package/dist/telemetry.d.mts +15 -0
  175. package/dist/telemetry.mjs +117 -0
  176. package/dist/{types-BncG8J3g.d.mts → types.d.mts} +21 -3
  177. package/dist/urls.d.mts +7 -0
  178. package/dist/urls.mjs +21 -0
  179. package/dist/utils.d.mts +8 -0
  180. package/dist/utils.mjs +22 -0
  181. package/package.json +21 -3
  182. package/dist/agent-DkAidqtV.mjs +0 -9026
  183. package/dist/api-reference-By_LokQ-.mjs +0 -3033
  184. package/dist/prompt-references-DMgbu_dz.mjs +0 -1082
  185. package/dist/retrieval-digest-DLAQsQmx.d.mts +0 -367
  186. package/dist/sidebar-C2LKcU7n.d.mts +0 -63
  187. package/dist/sidebar-CFHBj29f.mjs +0 -421
  188. /package/dist/{openapi-CfCzX_a1.mjs → cli/openapi.mjs} +0 -0
@@ -1,707 +1,16 @@
1
+ import { PAGE_AGENT_CONTRACT_END_MARKER, PAGE_AGENT_CONTRACT_START_MARKER } from "./agent-contract.mjs";
2
+ import { createDocsMarkdownSectionCache } from "./markdown-section-cache.mjs";
1
3
  import { createProcessor } from "@mdx-js/mdx";
2
4
  import { slug } from "github-slugger";
3
5
  import { parseEntities } from "parse-entities";
4
6
  import remarkGfm from "remark-gfm";
5
7
 
6
- //#region src/access.ts
7
- function isRecord$1(value) {
8
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9
- }
10
- function normalizeStrings(value) {
11
- if (!Array.isArray(value)) return void 0;
12
- const strings = Array.from(new Set(value.flatMap((item) => typeof item === "string" && item.trim() ? [item.trim()] : [])));
13
- return strings.length > 0 ? strings : void 0;
14
- }
15
- function normalizeClaimValue(value) {
16
- if (typeof value === "string") return value.trim() || void 0;
17
- if (typeof value === "number" && Number.isFinite(value)) return value;
18
- if (typeof value === "boolean") return value;
19
- return normalizeStrings(value);
20
- }
21
- function normalizeDocsPageAccessPolicy(value) {
22
- if (!isRecord$1(value)) return void 0;
23
- const visibility = value.visibility === "public" || value.visibility === "authenticated" ? value.visibility : void 0;
24
- const scopes = normalizeStrings(value.scopes);
25
- const rawClaims = isRecord$1(value.claims) ? value.claims : void 0;
26
- const claims = rawClaims ? Object.fromEntries(Object.entries(rawClaims).flatMap(([name, rawValue]) => {
27
- const normalizedName = name.trim();
28
- const normalizedValue = normalizeClaimValue(rawValue);
29
- return normalizedName && normalizedValue !== void 0 ? [[normalizedName, normalizedValue]] : [];
30
- })) : void 0;
31
- const normalizedClaims = claims && Object.keys(claims).length > 0 ? claims : void 0;
32
- if (!visibility && !scopes && !normalizedClaims) return void 0;
33
- return {
34
- ...visibility ? { visibility } : {},
35
- ...scopes ? { scopes } : {},
36
- ...normalizedClaims ? { claims: normalizedClaims } : {}
37
- };
38
- }
39
- function claimMatches(expected, actual) {
40
- const expectedValues = Array.isArray(expected) ? expected : [expected];
41
- const actualValues = Array.isArray(actual) ? actual : [actual];
42
- return expectedValues.some((expectedValue) => actualValues.some((actualValue) => actualValue === expectedValue));
43
- }
44
- function isDocsPageAccessAllowed(policy, principal) {
45
- if (!policy) return true;
46
- if (!(policy.visibility !== "public" || Boolean(policy.scopes?.length) || Boolean(policy.claims && Object.keys(policy.claims).length > 0))) return true;
47
- if (!principal) return false;
48
- const scopes = new Set(principal.scopes ?? []);
49
- if (policy.scopes?.some((scope) => !scopes.has(scope))) return false;
50
- for (const [name, expected] of Object.entries(policy.claims ?? {})) if (!claimMatches(expected, principal.claims?.[name])) return false;
51
- return true;
52
- }
53
- function isDocsAgentPageAccessible(page, principal) {
54
- return isDocsPageAccessAllowed(page.agent?.access, principal);
55
- }
56
- function filterDocsPagesByAccess(pages, principal) {
57
- return pages.filter((page) => isDocsAgentPageAccessible(page, principal));
58
- }
59
-
60
- //#endregion
61
- //#region src/agent-contract.ts
62
- const PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS = [
63
- "task",
64
- "outcome",
65
- "appliesTo",
66
- "prerequisites",
67
- "files",
68
- "commands",
69
- "sideEffects",
70
- "verification",
71
- "rollback",
72
- "failureModes"
73
- ];
74
- const PAGE_AGENT_CONTRACT_FIELDS = [
75
- "tokenBudget",
76
- "access",
77
- ...PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS
78
- ];
79
- const PAGE_AGENT_CONTRACT_FIELD_SCHEMA = {
80
- tokenBudget: "number",
81
- access: "{visibility?,scopes?,claims?}",
82
- task: "string",
83
- outcome: "string",
84
- appliesTo: {
85
- framework: "string|string[]",
86
- version: "string|string[]",
87
- package: "string|string[]"
88
- },
89
- prerequisites: "string[]",
90
- files: "string[]",
91
- commands: "Array<string|{run,cwd?,description?}>",
92
- sideEffects: "string[]",
93
- verification: "Array<string|{description?,run?,expect?}>",
94
- rollback: "string[]",
95
- failureModes: "Array<string|{symptom,resolution?}>"
96
- };
97
- const APPLIES_TO_FIELDS = [
98
- "framework",
99
- "version",
100
- "package"
101
- ];
102
- const COMMAND_FIELDS = [
103
- "run",
104
- "cwd",
105
- "description"
106
- ];
107
- const VERIFICATION_FIELDS = [
108
- "description",
109
- "run",
110
- "expect"
111
- ];
112
- const FAILURE_MODE_FIELDS = ["symptom", "resolution"];
113
- const ACCESS_FIELDS = [
114
- "visibility",
115
- "scopes",
116
- "claims"
117
- ];
118
- const PAGE_AGENT_CONTRACT_START_MARKER = "<!-- farming-labs:agent-contract:start -->";
119
- const PAGE_AGENT_CONTRACT_END_MARKER = "<!-- farming-labs:agent-contract:end -->";
120
- function isRecord(value) {
121
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
122
- }
123
- function normalizeString(value) {
124
- if (typeof value !== "string") return void 0;
125
- return value.trim() || void 0;
126
- }
127
- function normalizeStringList(value) {
128
- if (!Array.isArray(value)) return void 0;
129
- const seen = /* @__PURE__ */ new Set();
130
- const normalized = [];
131
- for (const item of value) {
132
- const text = normalizeString(item);
133
- if (!text || seen.has(text)) continue;
134
- seen.add(text);
135
- normalized.push(text);
136
- }
137
- return normalized.length > 0 ? normalized : void 0;
138
- }
139
- function normalizeStringOrList(value) {
140
- const single = normalizeString(value);
141
- if (single) return [single];
142
- return normalizeStringList(value);
143
- }
144
- function normalizeAppliesTo(value) {
145
- if (!isRecord(value)) return void 0;
146
- const framework = normalizeStringOrList(value.framework);
147
- const version = normalizeStringOrList(value.version);
148
- const packageNames = normalizeStringOrList(value.package);
149
- if (!framework && !version && !packageNames) return void 0;
150
- return {
151
- ...framework ? { framework } : {},
152
- ...version ? { version } : {},
153
- ...packageNames ? { package: packageNames } : {}
154
- };
155
- }
156
- function normalizeCommands(value) {
157
- if (!Array.isArray(value)) return void 0;
158
- const commands = [];
159
- for (const item of value) {
160
- const shorthand = normalizeString(item);
161
- if (shorthand) {
162
- commands.push(shorthand);
163
- continue;
164
- }
165
- if (!isRecord(item)) continue;
166
- const run = normalizeString(item.run);
167
- if (!run) continue;
168
- const cwd = normalizeString(item.cwd);
169
- const description = normalizeString(item.description);
170
- commands.push({
171
- run,
172
- ...cwd ? { cwd } : {},
173
- ...description ? { description } : {}
174
- });
175
- }
176
- return commands.length > 0 ? commands : void 0;
177
- }
178
- function normalizeVerification(value) {
179
- if (!Array.isArray(value)) return void 0;
180
- const verification = [];
181
- for (const item of value) {
182
- const shorthand = normalizeString(item);
183
- if (shorthand) {
184
- verification.push(shorthand);
185
- continue;
186
- }
187
- if (!isRecord(item)) continue;
188
- const description = normalizeString(item.description);
189
- const run = normalizeString(item.run);
190
- const expect = normalizeString(item.expect);
191
- if (!description && !run && !expect) continue;
192
- verification.push({
193
- ...description ? { description } : {},
194
- ...run ? { run } : {},
195
- ...expect ? { expect } : {}
196
- });
197
- }
198
- return verification.length > 0 ? verification : void 0;
199
- }
200
- function normalizeFailureModes(value) {
201
- if (!Array.isArray(value)) return void 0;
202
- const failureModes = [];
203
- for (const item of value) {
204
- const shorthand = normalizeString(item);
205
- if (shorthand) {
206
- failureModes.push(shorthand);
207
- continue;
208
- }
209
- if (!isRecord(item)) continue;
210
- const symptom = normalizeString(item.symptom);
211
- if (!symptom) continue;
212
- const resolution = normalizeString(item.resolution);
213
- failureModes.push({
214
- symptom,
215
- ...resolution ? { resolution } : {}
216
- });
217
- }
218
- return failureModes.length > 0 ? failureModes : void 0;
219
- }
220
- function normalizeTokenBudget(value) {
221
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
222
- return Math.ceil(value);
223
- }
224
- /**
225
- * Normalize untrusted page frontmatter into the stable agent contract shape.
226
- * Invalid fields are omitted so malformed author input cannot break page delivery.
227
- */
228
- function normalizePageAgentFrontmatter(value) {
229
- if (!isRecord(value)) return void 0;
230
- const tokenBudget = normalizeTokenBudget(value.tokenBudget);
231
- const access = "access" in value ? normalizeDocsPageAccessPolicy(value.access) ?? { visibility: "authenticated" } : void 0;
232
- const task = normalizeString(value.task);
233
- const outcome = normalizeString(value.outcome);
234
- const appliesTo = normalizeAppliesTo(value.appliesTo);
235
- const prerequisites = normalizeStringList(value.prerequisites);
236
- const files = normalizeStringList(value.files);
237
- const commands = normalizeCommands(value.commands);
238
- const sideEffects = normalizeStringList(value.sideEffects);
239
- const verification = normalizeVerification(value.verification);
240
- const rollback = normalizeStringList(value.rollback);
241
- const failureModes = normalizeFailureModes(value.failureModes);
242
- const normalized = {
243
- ...tokenBudget !== void 0 ? { tokenBudget } : {},
244
- ...access ? { access } : {},
245
- ...task ? { task } : {},
246
- ...outcome ? { outcome } : {},
247
- ...appliesTo ? { appliesTo } : {},
248
- ...prerequisites ? { prerequisites } : {},
249
- ...files ? { files } : {},
250
- ...commands ? { commands } : {},
251
- ...sideEffects ? { sideEffects } : {},
252
- ...verification ? { verification } : {},
253
- ...rollback ? { rollback } : {},
254
- ...failureModes ? { failureModes } : {}
255
- };
256
- return Object.keys(normalized).length > 0 ? normalized : void 0;
257
- }
258
- function hasStructuredPageAgentContract(value) {
259
- const normalized = normalizePageAgentFrontmatter(value);
260
- if (!normalized) return false;
261
- return PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS.some((field) => normalized[field] !== void 0);
262
- }
263
- function addStringIssue(issues, object, field) {
264
- if (!(field in object)) return;
265
- if (!normalizeString(object[field])) issues.push({
266
- path: `agent.${field}`,
267
- message: "must be a non-empty string"
268
- });
269
- }
270
- function addStringListIssues(issues, object, field) {
271
- if (!(field in object)) return;
272
- const value = object[field];
273
- if (!Array.isArray(value) || value.length === 0) {
274
- issues.push({
275
- path: `agent.${field}`,
276
- message: "must be a non-empty string array"
277
- });
278
- return;
279
- }
280
- value.forEach((item, index) => {
281
- if (!normalizeString(item)) issues.push({
282
- path: `agent.${field}[${index}]`,
283
- message: "must be a non-empty string"
284
- });
285
- });
286
- }
287
- function editDistance(left, right) {
288
- const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
289
- for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
290
- const current = [leftIndex];
291
- 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));
292
- previous.splice(0, previous.length, ...current);
293
- }
294
- return previous[right.length] ?? 0;
295
- }
296
- function closestKnownField(field, allowed) {
297
- const closest = allowed.map((candidate) => ({
298
- candidate,
299
- distance: editDistance(field, candidate)
300
- })).sort((left, right) => left.distance - right.distance || left.candidate.localeCompare(right.candidate))[0];
301
- if (!closest) return void 0;
302
- const threshold = Math.max(1, Math.min(3, Math.floor(closest.candidate.length / 3)));
303
- return closest.distance <= threshold ? closest.candidate : void 0;
304
- }
305
- function addUnknownKeyIssues(issues, object, allowed, path) {
306
- for (const field of Object.keys(object)) {
307
- if (allowed.includes(field)) continue;
308
- const suggestion = closestKnownField(field, allowed);
309
- issues.push({
310
- path: `${path}.${field}`,
311
- message: suggestion ? `is not recognized; did you mean "${path}.${suggestion}"?` : "is not recognized"
312
- });
313
- }
314
- }
315
- /** Return author-facing validation issues without throwing. */
316
- function getPageAgentFrontmatterIssues(value) {
317
- if (value === void 0) return [];
318
- if (!isRecord(value)) return [{
319
- path: "agent",
320
- message: "must be an object"
321
- }];
322
- const issues = [];
323
- addUnknownKeyIssues(issues, value, PAGE_AGENT_CONTRACT_FIELDS, "agent");
324
- if ("tokenBudget" in value && (typeof value.tokenBudget !== "number" || !Number.isFinite(value.tokenBudget) || value.tokenBudget <= 0)) issues.push({
325
- path: "agent.tokenBudget",
326
- message: "must be a positive finite number"
327
- });
328
- if ("access" in value) if (!isRecord(value.access)) issues.push({
329
- path: "agent.access",
330
- message: "must be an object"
331
- });
332
- else {
333
- addUnknownKeyIssues(issues, value.access, ACCESS_FIELDS, "agent.access");
334
- if ("visibility" in value.access && value.access.visibility !== "public" && value.access.visibility !== "authenticated") issues.push({
335
- path: "agent.access.visibility",
336
- message: "must be \"public\" or \"authenticated\""
337
- });
338
- if ("scopes" in value.access && !normalizeStringList(value.access.scopes)) issues.push({
339
- path: "agent.access.scopes",
340
- message: "must be a non-empty string array"
341
- });
342
- if ("claims" in value.access) {
343
- if (!isRecord(value.access.claims) || Object.keys(value.access.claims).length === 0) issues.push({
344
- path: "agent.access.claims",
345
- message: "must be a non-empty object"
346
- });
347
- else for (const [name, claim] of Object.entries(value.access.claims)) if (!name.trim() || normalizeDocsPageAccessPolicy({ claims: { [name]: claim } }) === void 0) issues.push({
348
- path: `agent.access.claims.${name || "<empty>"}`,
349
- message: "must be a string, number, boolean, or non-empty string array"
350
- });
351
- }
352
- if (!normalizeDocsPageAccessPolicy(value.access)) issues.push({
353
- path: "agent.access",
354
- message: "must include a valid visibility, scope, or claim"
355
- });
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.access) {
515
- lines.push(`${child}access:`);
516
- const accessIndent = `${child} `;
517
- if (agent.access.visibility) lines.push(`${accessIndent}visibility: ${agent.access.visibility}`);
518
- if (agent.access.scopes) renderYamlStringList(lines, accessIndent, "scopes", [...agent.access.scopes]);
519
- if (agent.access.claims) {
520
- lines.push(`${accessIndent}claims:`);
521
- const claimsIndent = `${accessIndent} `;
522
- for (const [name, claim] of Object.entries(agent.access.claims).sort(([left], [right]) => left.localeCompare(right))) if (Array.isArray(claim)) renderYamlStringList(lines, claimsIndent, yamlString(name), [...claim]);
523
- else lines.push(`${claimsIndent}${yamlString(name)}: ${typeof claim === "string" ? yamlString(claim) : claim}`);
524
- }
525
- }
526
- if (agent.task) lines.push(`${child}task: ${yamlString(agent.task)}`);
527
- if (agent.outcome) lines.push(`${child}outcome: ${yamlString(agent.outcome)}`);
528
- if (agent.appliesTo) {
529
- lines.push(`${child}appliesTo:`);
530
- const appliesIndent = `${child} `;
531
- for (const field of [
532
- "framework",
533
- "version",
534
- "package"
535
- ]) {
536
- const values = normalizeStringOrList(agent.appliesTo[field]);
537
- if (values) renderYamlStringList(lines, appliesIndent, field, values);
538
- }
539
- }
540
- if (agent.prerequisites) renderYamlStringList(lines, child, "prerequisites", agent.prerequisites);
541
- if (agent.files) renderYamlStringList(lines, child, "files", agent.files);
542
- if (agent.commands) renderYamlObjectList(lines, child, "commands", agent.commands, [
543
- "run",
544
- "cwd",
545
- "description"
546
- ]);
547
- if (agent.sideEffects) renderYamlStringList(lines, child, "sideEffects", agent.sideEffects);
548
- if (agent.verification) renderYamlObjectList(lines, child, "verification", agent.verification, [
549
- "description",
550
- "run",
551
- "expect"
552
- ]);
553
- if (agent.rollback) renderYamlStringList(lines, child, "rollback", agent.rollback);
554
- if (agent.failureModes) renderYamlObjectList(lines, child, "failureModes", agent.failureModes, ["symptom", "resolution"]);
555
- return lines;
556
- }
557
- function inlineCode(value) {
558
- const longestRun = Math.max(0, ...[...value.matchAll(/`+/g)].map((match) => match[0].length));
559
- const fence = "`".repeat(longestRun + 1);
560
- const padding = value.startsWith("`") || value.endsWith("`") ? " " : "";
561
- return `${fence}${padding}${value}${padding}${fence}`;
562
- }
563
- function renderTextList(lines, title, values, code = false) {
564
- lines.push("", `### ${title}`, "");
565
- for (const value of values) lines.push(`- ${code ? inlineCode(value) : value}`);
566
- }
567
- /** Render the structured contract as deterministic, compact machine-readable Markdown. */
568
- function renderPageAgentContractMarkdown(value) {
569
- const agent = normalizePageAgentFrontmatter(value);
570
- if (!agent || !hasStructuredPageAgentContract(agent)) return "";
571
- const lines = [PAGE_AGENT_CONTRACT_START_MARKER, "## Agent Contract"];
572
- if (agent.task) lines.push("", `Task: ${agent.task}`);
573
- if (agent.outcome) lines.push(`Outcome: ${agent.outcome}`);
574
- if (agent.appliesTo) {
575
- lines.push("", "### Applies To", "");
576
- for (const [label, field] of [
577
- ["Framework", "framework"],
578
- ["Version", "version"],
579
- ["Package", "package"]
580
- ]) {
581
- const values = normalizeStringOrList(agent.appliesTo[field]);
582
- if (values) lines.push(`- ${label}: ${values.map(inlineCode).join(", ")}`);
583
- }
584
- }
585
- if (agent.prerequisites) renderTextList(lines, "Prerequisites", agent.prerequisites);
586
- if (agent.files) renderTextList(lines, "Files", agent.files, true);
587
- if (agent.commands) {
588
- lines.push("", "### Commands", "");
589
- for (const command of agent.commands) {
590
- if (typeof command === "string") {
591
- lines.push(`- ${inlineCode(command)}`);
592
- continue;
593
- }
594
- const details = [command.cwd ? `cwd ${inlineCode(command.cwd)}` : void 0, command.description].filter(Boolean);
595
- lines.push(`- ${inlineCode(command.run)}${details.length ? ` — ${details.join("; ")}` : ""}`);
596
- }
597
- }
598
- if (agent.sideEffects) renderTextList(lines, "Side Effects", agent.sideEffects);
599
- if (agent.verification) {
600
- lines.push("", "### Verification", "");
601
- for (const step of agent.verification) {
602
- if (typeof step === "string") {
603
- lines.push(`- ${step}`);
604
- continue;
605
- }
606
- const summary = step.description ?? (step.run ? `Run ${inlineCode(step.run)}` : step.expect ?? "Verification step");
607
- lines.push(`- ${summary}`);
608
- if (step.run && step.description) lines.push(` - Run: ${inlineCode(step.run)}`);
609
- if (step.expect && step.expect !== summary) lines.push(` - Expected: ${step.expect}`);
610
- }
611
- }
612
- if (agent.rollback) renderTextList(lines, "Rollback", agent.rollback);
613
- if (agent.failureModes) {
614
- lines.push("", "### Failure Modes", "");
615
- for (const mode of agent.failureModes) {
616
- if (typeof mode === "string") {
617
- lines.push(`- ${mode}`);
618
- continue;
619
- }
620
- lines.push(`- ${mode.symptom}${mode.resolution ? ` — Recovery: ${mode.resolution}` : ""}`);
621
- }
622
- }
623
- lines.push(PAGE_AGENT_CONTRACT_END_MARKER);
624
- return lines.join("\n");
625
- }
626
- /** Remove generated contract blocks while preserving handwritten guidance. */
627
- function stripGeneratedPageAgentContractMarkdown(markdown) {
628
- const newline = markdown.includes("\r\n") ? "\r\n" : "\n";
629
- const output = [];
630
- let fence;
631
- let pendingBlock;
632
- let skipEmptySeparator = false;
633
- for (const line of markdown.split(/\r?\n/)) {
634
- if (pendingBlock) {
635
- pendingBlock.push(line);
636
- if (isGeneratedAgentContractMarker(line, PAGE_AGENT_CONTRACT_END_MARKER)) {
637
- pendingBlock = void 0;
638
- skipEmptySeparator = true;
639
- }
640
- continue;
641
- }
642
- if (!fence && isGeneratedAgentContractMarker(line, PAGE_AGENT_CONTRACT_START_MARKER)) {
643
- pendingBlock = [line];
644
- continue;
645
- }
646
- if (skipEmptySeparator && line.length === 0) continue;
647
- skipEmptySeparator = false;
648
- output.push(line);
649
- fence = advanceMarkdownFence(line, fence);
650
- }
651
- if (pendingBlock) output.push(...pendingBlock);
652
- while (output[0] === "") output.shift();
653
- return output.join(newline);
654
- }
655
- function isGeneratedAgentContractMarker(line, marker) {
656
- if (line.trim() !== marker) return false;
657
- const markerIndex = line.indexOf(marker);
658
- return markerIndex <= 3 && /^ *$/.test(line.slice(0, markerIndex));
659
- }
660
- function advanceMarkdownFence(line, fence) {
661
- if (fence) {
662
- const closing = /^ {0,3}(`+|~+)[\t ]*$/.exec(line)?.[1];
663
- if (closing?.[0] === fence.character && closing.length >= fence.length) return;
664
- return fence;
665
- }
666
- const opening = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
667
- if (!opening?.[1]) return void 0;
668
- if (opening[1][0] === "`" && opening[2]?.includes("`")) return void 0;
669
- return {
670
- character: opening[1][0],
671
- length: opening[1].length
672
- };
673
- }
674
- function isAgentContractHeadingText(value) {
675
- return value.trim().toLowerCase() === "agent contract";
676
- }
677
- function hasPageAgentContractHeading(markdown) {
678
- let fence;
679
- let previousLine;
680
- for (const line of markdown.split(/\r?\n/)) {
681
- const nextFence = advanceMarkdownFence(line, fence);
682
- if (fence || nextFence) {
683
- fence = nextFence;
684
- previousLine = void 0;
685
- continue;
686
- }
687
- const atxText = /^ {0,3}#{1,6}(?:[\t ]+|$)(.*)$/.exec(line)?.[1]?.replace(/[\t ]+#+[\t ]*$/, "").trim();
688
- if (atxText && isAgentContractHeadingText(atxText)) return true;
689
- if (previousLine && /^ {0,3}(?:=+|-+)[\t ]*$/.test(line) && isAgentContractHeadingText(previousLine)) return true;
690
- previousLine = line.trim().length > 0 && !/^ {4}/.test(line) && !/^ {0,3}\t/.test(line) ? line : void 0;
691
- }
692
- return false;
693
- }
694
- /** Insert one generated contract unless the document already has handwritten contract guidance. */
695
- function upsertPageAgentContractMarkdown(markdown, value) {
696
- const cleaned = stripGeneratedPageAgentContractMarkdown(markdown);
697
- const contract = renderPageAgentContractMarkdown(value);
698
- if (!contract || hasPageAgentContractHeading(cleaned)) return cleaned;
699
- return cleaned ? `${contract}\n\n${cleaned.replace(/^\r?\n+/, "")}` : contract;
700
- }
701
-
702
- //#endregion
703
8
  //#region src/markdown-sections.ts
704
- const docsMarkdownMdxProcessor = createProcessor({ remarkPlugins: [remarkGfm] });
9
+ let docsMarkdownMdxProcessor;
10
+ const docsMarkdownSections = createDocsMarkdownSectionCache();
11
+ function getDocsMarkdownMdxProcessor() {
12
+ return docsMarkdownMdxProcessor ??= createProcessor({ remarkPlugins: [remarkGfm] });
13
+ }
705
14
  function isDocsMarkdownLiteralPrompt(node) {
706
15
  return (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && node.name === "Prompt";
707
16
  }
@@ -1440,6 +749,17 @@ function stripDocsGeneratedAgentContractMarkers(markdown, location) {
1440
749
  function isDocsMarkdownLineInRanges(line, ranges) {
1441
750
  return ranges.some((range) => line >= range.start && line <= range.end);
1442
751
  }
752
+ /** Close each section at the next heading of the same or a shallower level. */
753
+ function resolveDocsMarkdownSectionEnds(headings, lineCount) {
754
+ const ends = headings.map(() => lineCount);
755
+ const open = [];
756
+ for (let index = 0; index < headings.length; index += 1) {
757
+ const heading = headings[index];
758
+ while (open.length > 0 && headings[open[open.length - 1]].level >= heading.level) ends[open.pop()] = heading.start;
759
+ open.push(index);
760
+ }
761
+ return ends;
762
+ }
1443
763
  /**
1444
764
  * Parse heading sections once for search, Ask AI hydration, and MCP tools.
1445
765
  * Supports CommonMark ATX indentation, Setext headings, fenced-code exclusion,
@@ -1524,8 +844,9 @@ function parseDocsMarkdownSectionsFallback(markdown, generatedContractRanges) {
1524
844
  const resolveHeadingAnchor = createDocsMarkdownHeadingAnchorResolverWithReferences(definedReferences);
1525
845
  const orderedHeadings = [...headings.filter((heading) => !isDocsMarkdownLineInRanges(heading.start, generatedContractRanges)), ...headings.filter((heading) => isDocsMarkdownLineInRanges(heading.start, generatedContractRanges))];
1526
846
  for (const heading of orderedHeadings) heading.resolved = resolveHeadingAnchor(heading.source);
847
+ const ends = resolveDocsMarkdownSectionEnds(headings, lines.length);
1527
848
  return headings.map((heading, index) => {
1528
- const end = headings.slice(index + 1).find((candidate) => candidate.level <= heading.level)?.start ?? lines.length;
849
+ const end = ends[index];
1529
850
  const resolved = heading.resolved;
1530
851
  if (!resolved) throw new Error("Failed to resolve a Markdown heading anchor.");
1531
852
  return {
@@ -1545,7 +866,7 @@ function stripDocsMarkdownSectionFrontmatter(markdown) {
1545
866
  function parseDocsMarkdownAstSections(markdown, generatedContractRanges) {
1546
867
  let root;
1547
868
  try {
1548
- root = docsMarkdownMdxProcessor.parse(markdown);
869
+ root = getDocsMarkdownMdxProcessor().parse(markdown);
1549
870
  } catch {
1550
871
  return;
1551
872
  }
@@ -1562,8 +883,9 @@ function parseDocsMarkdownAstSections(markdown, generatedContractRanges) {
1562
883
  }];
1563
884
  });
1564
885
  const lines = markdown.split(/\r?\n/u);
886
+ const ends = resolveDocsMarkdownSectionEnds(headings, lines.length);
1565
887
  return headings.map((heading, index) => {
1566
- const end = headings.slice(index + 1).find((candidate) => candidate.level <= heading.level)?.start ?? lines.length;
888
+ const end = ends[index];
1567
889
  return {
1568
890
  title: heading.title,
1569
891
  anchor: heading.anchor,
@@ -1577,8 +899,12 @@ function parseDocsMarkdownAstSections(markdown, generatedContractRanges) {
1577
899
  }
1578
900
  function parseDocsMarkdownSections(markdown) {
1579
901
  const body = stripDocsMarkdownSectionFrontmatter(markdown);
902
+ const cached = docsMarkdownSections.get(body);
903
+ if (cached) return cached;
1580
904
  const generatedContractRanges = collectGeneratedAgentContractRanges(body);
1581
- return parseDocsMarkdownAstSections(body, generatedContractRanges) ?? parseDocsMarkdownSectionsFallback(body, generatedContractRanges);
905
+ const sections = parseDocsMarkdownAstSections(body, generatedContractRanges) ?? parseDocsMarkdownSectionsFallback(body, generatedContractRanges);
906
+ docsMarkdownSections.set(body, sections);
907
+ return sections;
1582
908
  }
1583
909
  function findDocsMarkdownSection(markdown, requestedSection) {
1584
910
  const sections = parseDocsMarkdownSections(markdown);
@@ -1597,4 +923,4 @@ function findDocsMarkdownSection(markdown, requestedSection) {
1597
923
  }
1598
924
 
1599
925
  //#endregion
1600
- export { filterDocsPagesByAccess as C, normalizeDocsPageAccessPolicy as E, upsertPageAgentContractMarkdown as S, isDocsPageAccessAllowed as T, hasStructuredPageAgentContract as _, findDocsGeneratedAgentContractRanges as a, renderPageAgentFrontmatterYamlLines as b, slugifyDocsMarkdownHeading as c, PAGE_AGENT_CONTRACT_END_MARKER as d, PAGE_AGENT_CONTRACT_FIELDS as f, getPageAgentFrontmatterIssues as g, PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS as h, createDocsRenderedHeadingAnchorResolver as i, stripDocsGeneratedAgentContractMarkers as l, PAGE_AGENT_CONTRACT_START_MARKER as m, cleanDocsRenderedHeadingLabel as n, findDocsMarkdownSection as o, PAGE_AGENT_CONTRACT_FIELD_SCHEMA as p, createDocsMarkdownHeadingAnchorResolver as r, parseDocsMarkdownSections as s, applyDocsMarkdownHeadingAnchors as t, withDocsMarkdownRenderableHeadings as u, normalizePageAgentFrontmatter as v, isDocsAgentPageAccessible as w, stripGeneratedPageAgentContractMarkdown as x, renderPageAgentContractMarkdown as y };
926
+ export { applyDocsMarkdownHeadingAnchors, cleanDocsRenderedHeadingLabel, createDocsMarkdownHeadingAnchorResolver, createDocsRenderedHeadingAnchorResolver, findDocsGeneratedAgentContractRanges, findDocsMarkdownSection, parseDocsMarkdownSections, slugifyDocsMarkdownHeading, stripDocsGeneratedAgentContractMarkers, withDocsMarkdownRenderableHeadings };