@farming-labs/docs 0.2.55 → 0.2.56

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.
@@ -1,3 +1,5 @@
1
+ import { createProcessor } from "@mdx-js/mdx";
2
+
1
3
  //#region src/agent-contract.ts
2
4
  const PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS = [
3
5
  "task",
@@ -886,6 +888,1117 @@ function createDocsSitemapResponse({ request, sitemap, entry = "docs", siteTitle
886
888
  return new Response(body, { headers });
887
889
  }
888
890
 
891
+ //#endregion
892
+ //#region src/audience.ts
893
+ /** Resolve whether content with an optional audience restriction is visible. */
894
+ function resolveDocsAudienceExposure(only, audience) {
895
+ return only !== "human" && only !== "agent" || only === audience;
896
+ }
897
+ const DOCS_AUDIENCE_TAG_NAMES = [
898
+ "Audience",
899
+ "Agent",
900
+ "Human"
901
+ ];
902
+ const DOCS_AUDIENCE_TAG_CANDIDATE_PATTERN = /<\/?(?:Audience|Agent|Human)(?=[\s/>])/;
903
+ function parseAudienceOnly(attributes) {
904
+ if (/\{\s*\.\.\./.test(attributes)) return void 0;
905
+ const value = attributes.match(/(?:^|\s)only\s*=\s*(?:"(human|agent)"|'(human|agent)'|\{\s*"(human|agent)"\s*\}|\{\s*'(human|agent)'\s*\})/)?.slice(1).find(Boolean);
906
+ return value === "human" || value === "agent" ? value : void 0;
907
+ }
908
+ function isEscapedAt(content, index) {
909
+ let backslashes = 0;
910
+ for (let cursor = index - 1; cursor >= 0 && content[cursor] === "\\"; cursor -= 1) backslashes += 1;
911
+ return backslashes % 2 === 1;
912
+ }
913
+ const JAVASCRIPT_REGEX_PREFIX_KEYWORDS = new Set([
914
+ "await",
915
+ "case",
916
+ "delete",
917
+ "do",
918
+ "else",
919
+ "each",
920
+ "if",
921
+ "in",
922
+ "instanceof",
923
+ "key",
924
+ "new",
925
+ "of",
926
+ "return",
927
+ "throw",
928
+ "catch",
929
+ "const",
930
+ "debug",
931
+ "html",
932
+ "render",
933
+ "snippet",
934
+ "then",
935
+ "typeof",
936
+ "void",
937
+ "yield"
938
+ ]);
939
+ function canStartJavascriptRegex(content, cursor, boundary) {
940
+ let previous = cursor - 1;
941
+ while (previous > boundary && /\s/.test(content[previous] ?? "")) previous -= 1;
942
+ if (previous <= boundary || /[([{=,:;!?&|>]/.test(content[previous] ?? "")) return true;
943
+ const precedingWord = content.slice(boundary + 1, cursor).match(/([A-Za-z_$][\w$]*)\s*$/)?.[1];
944
+ return JAVASCRIPT_REGEX_PREFIX_KEYWORDS.has(precedingWord ?? "");
945
+ }
946
+ function readAudienceTagAt(content, index) {
947
+ let cursor = index + 1;
948
+ const closing = content[cursor] === "/";
949
+ if (closing) cursor += 1;
950
+ const name = DOCS_AUDIENCE_TAG_NAMES.find((candidate) => content.startsWith(candidate, cursor) && /[\s/>]/.test(content[cursor + candidate.length] ?? ""));
951
+ if (!name) return void 0;
952
+ cursor += name.length;
953
+ const attributesStart = cursor;
954
+ let braceDepth = 0;
955
+ let quote;
956
+ let blockComment = false;
957
+ let lineComment = false;
958
+ while (cursor < content.length) {
959
+ const character = content[cursor];
960
+ const next = content[cursor + 1];
961
+ if (lineComment) {
962
+ if (character === "\n") lineComment = false;
963
+ cursor += 1;
964
+ continue;
965
+ }
966
+ if (blockComment) {
967
+ if (character === "*" && next === "/") {
968
+ blockComment = false;
969
+ cursor += 2;
970
+ } else cursor += 1;
971
+ continue;
972
+ }
973
+ if (quote) {
974
+ if (character === "\\") {
975
+ cursor += 2;
976
+ continue;
977
+ }
978
+ if (character === quote) quote = void 0;
979
+ cursor += 1;
980
+ continue;
981
+ }
982
+ if (braceDepth > 0 && character === "/" && next === "*") {
983
+ blockComment = true;
984
+ cursor += 2;
985
+ continue;
986
+ }
987
+ if (braceDepth > 0 && character === "/" && next === "/") {
988
+ lineComment = true;
989
+ cursor += 2;
990
+ continue;
991
+ }
992
+ if (character === "\"" || character === "'" || character === "`") quote = character;
993
+ else if (character === "{") braceDepth += 1;
994
+ else if (character === "}" && braceDepth > 0) braceDepth -= 1;
995
+ else if (character === ">" && braceDepth === 0) {
996
+ let attributesEnd = cursor;
997
+ let slashIndex = cursor - 1;
998
+ while (slashIndex >= attributesStart && /\s/.test(content[slashIndex] ?? "")) slashIndex -= 1;
999
+ const selfClosing = content[slashIndex] === "/";
1000
+ if (selfClosing) attributesEnd = slashIndex;
1001
+ const attributes = content.slice(attributesStart, attributesEnd);
1002
+ return {
1003
+ index,
1004
+ end: cursor + 1,
1005
+ name,
1006
+ closing,
1007
+ selfClosing,
1008
+ attributes,
1009
+ only: name === "Agent" ? "agent" : name === "Human" ? "human" : parseAudienceOnly(attributes)
1010
+ };
1011
+ }
1012
+ cursor += 1;
1013
+ }
1014
+ }
1015
+ function findAudienceTags(content, protectedRanges) {
1016
+ const tags = [];
1017
+ let cursor = 0;
1018
+ while (cursor < content.length) {
1019
+ const index = content.indexOf("<", cursor);
1020
+ if (index === -1) break;
1021
+ if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1022
+ cursor = index + 1;
1023
+ continue;
1024
+ }
1025
+ const tag = readAudienceTagAt(content, index);
1026
+ if (tag) {
1027
+ tags.push(tag);
1028
+ cursor = tag.end;
1029
+ } else cursor = index + 1;
1030
+ }
1031
+ return tags;
1032
+ }
1033
+ const docsAudienceMdxProcessor = createProcessor({ format: "mdx" });
1034
+ const docsAudienceMarkdownProcessor = createProcessor({ format: "md" });
1035
+ function getOffset(position, edge) {
1036
+ const value = position?.[edge]?.offset;
1037
+ return typeof value === "number" ? value : void 0;
1038
+ }
1039
+ function maskRangesForMdxParser(content, ranges) {
1040
+ if (ranges.length === 0) return content;
1041
+ const characters = content.split("");
1042
+ for (const range of ranges) for (let index = range.start; index < range.end; index += 1) if (characters[index] !== "\n" && characters[index] !== "\r") characters[index] = " ";
1043
+ return characters.join("");
1044
+ }
1045
+ function findLeadingFrontmatterRange(content) {
1046
+ const bomLength = content.startsWith("") ? 1 : 0;
1047
+ const opening = content.slice(bomLength).match(/^(---|\+\+\+)[\t ]*(?:\r?\n|$)/);
1048
+ const marker = opening?.[1];
1049
+ if (!opening || !marker) return void 0;
1050
+ let offset = bomLength + opening[0].length;
1051
+ for (const line of content.slice(offset).split(/(?<=\n)/)) {
1052
+ offset += line.length;
1053
+ const value = line.replace(/\r?\n$/, "");
1054
+ if (marker === "---" ? /^(?:---|\.\.\.)[\t ]*$/.test(value) : /^\+\+\+[\t ]*$/.test(value)) return {
1055
+ start: 0,
1056
+ end: offset
1057
+ };
1058
+ }
1059
+ }
1060
+ function findHtmlLiteralRanges(content, excludedRanges = []) {
1061
+ const ranges = [];
1062
+ const rawPattern = /<(script|style)(?=[\s/>])/g;
1063
+ let cursor = 0;
1064
+ while (cursor < content.length) {
1065
+ rawPattern.lastIndex = cursor;
1066
+ const rawMatch = rawPattern.exec(content);
1067
+ const commentStart = content.indexOf("<!--", cursor);
1068
+ const rawStart = rawMatch?.index ?? -1;
1069
+ const useComment = commentStart !== -1 && (rawStart === -1 || commentStart < rawStart);
1070
+ const start = useComment ? commentStart : rawStart;
1071
+ if (start === -1) break;
1072
+ if (isEscapedAt(content, start) || isInsideRange(start, excludedRanges)) {
1073
+ cursor = start + 1;
1074
+ continue;
1075
+ }
1076
+ if (useComment) {
1077
+ const closing = content.indexOf("-->", start + 4);
1078
+ const end = closing === -1 ? content.length : closing + 3;
1079
+ ranges.push({
1080
+ start,
1081
+ end
1082
+ });
1083
+ cursor = end;
1084
+ continue;
1085
+ }
1086
+ const name = rawMatch?.[1];
1087
+ if (!name) {
1088
+ cursor = start + 1;
1089
+ continue;
1090
+ }
1091
+ const opening = readGenericMdxJsxTag(content, start);
1092
+ if (!opening) {
1093
+ cursor = start + 1;
1094
+ continue;
1095
+ }
1096
+ if (opening.selfClosing) {
1097
+ cursor = opening.end;
1098
+ continue;
1099
+ }
1100
+ const closingPattern = new RegExp(`</${name}\\s*>`, "g");
1101
+ closingPattern.lastIndex = opening.end;
1102
+ if (!closingPattern.exec(content)) {
1103
+ ranges.push({
1104
+ start,
1105
+ end: content.length
1106
+ });
1107
+ break;
1108
+ }
1109
+ ranges.push({
1110
+ start,
1111
+ end: closingPattern.lastIndex
1112
+ });
1113
+ cursor = closingPattern.lastIndex;
1114
+ }
1115
+ return ranges;
1116
+ }
1117
+ function prepareMdxParserSource(content) {
1118
+ const baseExcludedRanges = findDelimiterExclusionRanges(content);
1119
+ const svelteDirectives = findSvelteDirectiveRanges(content, baseExcludedRanges);
1120
+ const ranges = [...findHtmlLiteralRanges(content, mergeProtectedRanges([...baseExcludedRanges, ...svelteDirectives])), ...svelteDirectives];
1121
+ const frontmatter = findLeadingFrontmatterRange(content);
1122
+ if (frontmatter) ranges.push(frontmatter);
1123
+ return maskRangesForMdxParser(content, mergeProtectedRanges(ranges));
1124
+ }
1125
+ function getExpressionLiteralString(value) {
1126
+ if (!value || typeof value !== "object") return void 0;
1127
+ const expression = value.data?.estree?.body?.[0]?.expression;
1128
+ return expression?.type === "Literal" && typeof expression.value === "string" ? expression.value : void 0;
1129
+ }
1130
+ function getMdxAudienceAttributeInfo(attributes) {
1131
+ const hasSpreadAttribute = attributes.some((attribute) => attribute.type === "mdxJsxExpressionAttribute");
1132
+ const onlyAttribute = [...attributes].reverse().find((attribute) => attribute.type === "mdxJsxAttribute" && attribute.name === "only");
1133
+ if (hasSpreadAttribute) return {
1134
+ hasOnlyAttribute: Boolean(onlyAttribute),
1135
+ hasSpreadAttribute,
1136
+ onlyKind: "dynamic"
1137
+ };
1138
+ if (!onlyAttribute) return {
1139
+ hasOnlyAttribute: false,
1140
+ hasSpreadAttribute: false,
1141
+ onlyKind: "missing"
1142
+ };
1143
+ const value = typeof onlyAttribute.value === "string" ? onlyAttribute.value : getExpressionLiteralString(onlyAttribute.value);
1144
+ if (value === "human" || value === "agent") return {
1145
+ only: value,
1146
+ hasOnlyAttribute: true,
1147
+ hasSpreadAttribute: false,
1148
+ onlyKind: "static"
1149
+ };
1150
+ return {
1151
+ hasOnlyAttribute: true,
1152
+ hasSpreadAttribute: false,
1153
+ onlyKind: typeof onlyAttribute.value === "object" ? "dynamic" : "invalid"
1154
+ };
1155
+ }
1156
+ function getEstreeAudienceAttributeInfo(attributes) {
1157
+ const records = attributes.filter((attribute) => Boolean(attribute && typeof attribute === "object"));
1158
+ const hasSpreadAttribute = records.some((attribute) => attribute.type === "JSXSpreadAttribute");
1159
+ const onlyAttribute = [...records].reverse().find((attribute) => {
1160
+ const name = attribute.name;
1161
+ return attribute.type === "JSXAttribute" && name?.type === "JSXIdentifier" && name.name === "only";
1162
+ });
1163
+ if (hasSpreadAttribute) return {
1164
+ hasOnlyAttribute: Boolean(onlyAttribute),
1165
+ hasSpreadAttribute,
1166
+ onlyKind: "dynamic"
1167
+ };
1168
+ if (!onlyAttribute) return {
1169
+ hasOnlyAttribute: false,
1170
+ hasSpreadAttribute: false,
1171
+ onlyKind: "missing"
1172
+ };
1173
+ const attributeValue = onlyAttribute.value;
1174
+ const value = attributeValue?.type === "Literal" ? attributeValue.value : attributeValue?.type === "JSXExpressionContainer" && attributeValue.expression?.type === "Literal" ? attributeValue.expression.value : void 0;
1175
+ if (value === "human" || value === "agent") return {
1176
+ only: value,
1177
+ hasOnlyAttribute: true,
1178
+ hasSpreadAttribute: false,
1179
+ onlyKind: "static"
1180
+ };
1181
+ return {
1182
+ hasOnlyAttribute: true,
1183
+ hasSpreadAttribute: false,
1184
+ onlyKind: attributeValue?.type === "JSXExpressionContainer" ? "dynamic" : "invalid"
1185
+ };
1186
+ }
1187
+ function getOpeningTagEnd(content, start, name, attributes) {
1188
+ const searchStart = Math.max(start + name.length + 1, ...attributes.map((attribute) => getOffset(attribute.position, "end") ?? 0));
1189
+ const closingBracket = content.indexOf(">", searchStart);
1190
+ return closingBracket === -1 ? void 0 : closingBracket + 1;
1191
+ }
1192
+ function addMdxAudienceElementTags(content, node, tags) {
1193
+ const name = node.name;
1194
+ const start = getOffset(node.position, "start");
1195
+ const nodeEnd = getOffset(node.position, "end");
1196
+ if (start === void 0 || nodeEnd === void 0) return;
1197
+ const attributes = node.attributes ?? [];
1198
+ const openingEnd = getOpeningTagEnd(content, start, name, attributes);
1199
+ if (openingEnd === void 0) return;
1200
+ const closingStart = content.lastIndexOf(`</${name}`, nodeEnd);
1201
+ const hasClosingTag = closingStart >= openingEnd;
1202
+ const attributeInfo = getMdxAudienceAttributeInfo(attributes);
1203
+ const rawAttributes = content.slice(start + name.length + 1, openingEnd - 1);
1204
+ tags.push({
1205
+ index: start,
1206
+ end: openingEnd,
1207
+ name,
1208
+ closing: false,
1209
+ selfClosing: !hasClosingTag,
1210
+ attributes: rawAttributes,
1211
+ only: name === "Agent" ? "agent" : name === "Human" ? "human" : attributeInfo.only,
1212
+ hasOnlyAttribute: attributeInfo.hasOnlyAttribute,
1213
+ hasSpreadAttribute: attributeInfo.hasSpreadAttribute,
1214
+ onlyKind: attributeInfo.onlyKind
1215
+ });
1216
+ if (hasClosingTag) tags.push({
1217
+ index: closingStart,
1218
+ end: nodeEnd,
1219
+ name,
1220
+ closing: true,
1221
+ selfClosing: false,
1222
+ attributes: ""
1223
+ });
1224
+ }
1225
+ function getEstreeJsxIdentifierName(value) {
1226
+ if (!value || typeof value !== "object") return void 0;
1227
+ const name = value;
1228
+ return name.type === "JSXIdentifier" && DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === name.name) ? name.name : void 0;
1229
+ }
1230
+ function addEstreeAudienceElementTags(content, node, tags, jsxChild) {
1231
+ const opening = node.openingElement;
1232
+ if (!opening) return;
1233
+ const name = getEstreeJsxIdentifierName(opening.name);
1234
+ const start = typeof opening.start === "number" ? opening.start : void 0;
1235
+ const openingEnd = typeof opening.end === "number" ? opening.end : void 0;
1236
+ const nodeEnd = typeof node.end === "number" ? node.end : void 0;
1237
+ if (!name || start === void 0 || openingEnd === void 0 || nodeEnd === void 0) return;
1238
+ const attributeInfo = getEstreeAudienceAttributeInfo(Array.isArray(opening.attributes) ? opening.attributes : []);
1239
+ const closing = node.closingElement;
1240
+ const closingStart = closing && typeof closing.start === "number" ? closing.start : void 0;
1241
+ const closingEnd = closing && typeof closing.end === "number" ? closing.end : void 0;
1242
+ tags.push({
1243
+ index: start,
1244
+ end: openingEnd,
1245
+ name,
1246
+ closing: false,
1247
+ selfClosing: closingStart === void 0,
1248
+ attributes: content.slice(start + name.length + 1, openingEnd - 1),
1249
+ only: name === "Agent" ? "agent" : name === "Human" ? "human" : attributeInfo.only,
1250
+ expression: true,
1251
+ jsxChild,
1252
+ hasOnlyAttribute: attributeInfo.hasOnlyAttribute,
1253
+ hasSpreadAttribute: attributeInfo.hasSpreadAttribute,
1254
+ onlyKind: attributeInfo.onlyKind
1255
+ });
1256
+ if (closingStart !== void 0 && closingEnd !== void 0) tags.push({
1257
+ index: closingStart,
1258
+ end: closingEnd,
1259
+ name,
1260
+ closing: true,
1261
+ selfClosing: false,
1262
+ attributes: "",
1263
+ expression: true,
1264
+ jsxChild
1265
+ });
1266
+ }
1267
+ function collectEstreeAudienceTags(content, value, tags, seen = /* @__PURE__ */ new WeakSet(), parent, parentKey) {
1268
+ if (!value || typeof value !== "object" || seen.has(value)) return;
1269
+ seen.add(value);
1270
+ const record = value;
1271
+ if (record.type === "JSXElement") {
1272
+ const opening = record.openingElement;
1273
+ if (getEstreeJsxIdentifierName(opening?.name)) {
1274
+ addEstreeAudienceElementTags(content, record, tags, parentKey === "children" && (parent?.type === "JSXElement" || parent?.type === "JSXFragment"));
1275
+ for (const child of Array.isArray(record.children) ? record.children : []) collectEstreeAudienceTags(content, child, tags, seen, record, "children");
1276
+ return;
1277
+ }
1278
+ }
1279
+ for (const [key, child] of Object.entries(record)) {
1280
+ if (key === "loc" || key === "range" || key === "comments") continue;
1281
+ if (Array.isArray(child)) for (const item of child) collectEstreeAudienceTags(content, item, tags, seen, record, key);
1282
+ else collectEstreeAudienceTags(content, child, tags, seen, record, key);
1283
+ }
1284
+ }
1285
+ function collectMdxAudienceTags(content, node, tags) {
1286
+ const isMdxJsxElement = node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
1287
+ if (isMdxJsxElement && (node.name === "script" || node.name === "style")) return;
1288
+ const isAudienceElement = Boolean(isMdxJsxElement && node.name && DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === node.name));
1289
+ if (isAudienceElement) addMdxAudienceElementTags(content, node, tags);
1290
+ if (node.type !== "mdxjsEsm") {
1291
+ if (node.type === "mdxFlowExpression" || node.type === "mdxTextExpression") collectEstreeAudienceTags(content, node.data?.estree, tags);
1292
+ if (isMdxJsxElement && !isAudienceElement) for (const attribute of node.attributes ?? []) {
1293
+ collectEstreeAudienceTags(content, attribute.data?.estree, tags);
1294
+ if (attribute.value && typeof attribute.value === "object") {
1295
+ const value = attribute.value;
1296
+ collectEstreeAudienceTags(content, value.data?.estree, tags);
1297
+ }
1298
+ }
1299
+ }
1300
+ for (const child of node.children ?? []) collectMdxAudienceTags(content, child, tags);
1301
+ }
1302
+ function findMdxAstAudienceTags(content) {
1303
+ try {
1304
+ const tree = docsAudienceMdxProcessor.parse(prepareMdxParserSource(content));
1305
+ const tags = [];
1306
+ collectMdxAudienceTags(content, tree, tags);
1307
+ return tags.sort((left, right) => left.index - right.index || left.end - right.end);
1308
+ } catch {
1309
+ return;
1310
+ }
1311
+ }
1312
+ /** Locate effective audience tags while excluding Markdown/MDX literal contexts. */
1313
+ function findDocsAudienceMdxTags(content) {
1314
+ if (!DOCS_AUDIENCE_TAG_CANDIDATE_PATTERN.test(content)) return [];
1315
+ return findMdxAstAudienceTags(content) ?? findAudienceTags(content, findProtectedRanges(content));
1316
+ }
1317
+ function isAudienceVisible(scopes, audience) {
1318
+ return scopes.every((scope) => resolveDocsAudienceExposure(scope.only, audience));
1319
+ }
1320
+ function mergeProtectedRanges(ranges) {
1321
+ const sorted = [...ranges].sort((left, right) => left.start - right.start || left.end - right.end);
1322
+ const merged = [];
1323
+ for (const range of sorted) {
1324
+ const previous = merged.at(-1);
1325
+ if (!previous || range.start > previous.end) {
1326
+ merged.push({ ...range });
1327
+ continue;
1328
+ }
1329
+ previous.end = Math.max(previous.end, range.end);
1330
+ }
1331
+ return merged;
1332
+ }
1333
+ function findMarkdownLiteralRanges(content) {
1334
+ try {
1335
+ const tree = docsAudienceMarkdownProcessor.parse(content);
1336
+ const ranges = [];
1337
+ const visit = (node) => {
1338
+ const start = getOffset(node.position, "start");
1339
+ const end = getOffset(node.position, "end");
1340
+ if (start !== void 0 && end !== void 0) {
1341
+ if (node.type === "code" || node.type === "inlineCode" || node.type === "definition") ranges.push({
1342
+ start,
1343
+ end
1344
+ });
1345
+ else if (node.type === "link" || node.type === "image") {
1346
+ const contentEnd = Math.max(start, ...(node.children ?? []).map((child) => getOffset(child.position, "end") ?? start));
1347
+ ranges.push({
1348
+ start: contentEnd,
1349
+ end
1350
+ });
1351
+ }
1352
+ }
1353
+ for (const child of node.children ?? []) visit(child);
1354
+ };
1355
+ visit(tree);
1356
+ return ranges;
1357
+ } catch {
1358
+ return [];
1359
+ }
1360
+ }
1361
+ function findMarkdownLinkDestinationRanges(content, protectedRanges) {
1362
+ const ranges = [];
1363
+ let cursor = 0;
1364
+ while (cursor < content.length) {
1365
+ const start = content.indexOf("](", cursor);
1366
+ if (start === -1) break;
1367
+ if (isEscapedAt(content, start) || isInsideRange(start, protectedRanges)) {
1368
+ cursor = start + 1;
1369
+ continue;
1370
+ }
1371
+ let end = start + 2;
1372
+ let parenthesisDepth = 1;
1373
+ let angleDestination = false;
1374
+ let quote;
1375
+ while (end < content.length && parenthesisDepth > 0) {
1376
+ const character = content[end];
1377
+ if (character === "\\") {
1378
+ end += 2;
1379
+ continue;
1380
+ }
1381
+ if (quote) {
1382
+ if (character === quote) quote = void 0;
1383
+ end += 1;
1384
+ continue;
1385
+ }
1386
+ if (character === "\"" || character === "'") quote = character;
1387
+ else if (character === "<" && parenthesisDepth === 1) {
1388
+ const closingAngle = content.indexOf(">", end + 1);
1389
+ const closingParenthesis = content.indexOf(")", end + 1);
1390
+ angleDestination = closingAngle !== -1 && closingAngle < closingParenthesis;
1391
+ } else if (character === ">" && angleDestination) angleDestination = false;
1392
+ else if (!angleDestination && character === "(") parenthesisDepth += 1;
1393
+ else if (!angleDestination && character === ")") parenthesisDepth -= 1;
1394
+ end += 1;
1395
+ }
1396
+ if (parenthesisDepth === 0) ranges.push({
1397
+ start: start + 1,
1398
+ end
1399
+ });
1400
+ cursor = Math.max(start + 1, end);
1401
+ }
1402
+ return ranges;
1403
+ }
1404
+ function findFenceRanges(content) {
1405
+ const ranges = [];
1406
+ let fence;
1407
+ let offset = 0;
1408
+ const stripBlockquoteContainers = (line) => {
1409
+ let value = line;
1410
+ while (/^ {0,3}>[\t ]?/.test(value)) value = value.replace(/^ {0,3}>[\t ]?/, "");
1411
+ return value;
1412
+ };
1413
+ const stripOpeningListContainers = (line) => {
1414
+ let value = line;
1415
+ while (/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/.test(value)) value = value.replace(/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/, "");
1416
+ return value;
1417
+ };
1418
+ for (const line of content.split(/(?<=\n)/)) {
1419
+ const containerRelativeLine = stripBlockquoteContainers(line.replace(/\r?\n$/, ""));
1420
+ const match = (fence ? containerRelativeLine : stripOpeningListContainers(containerRelativeLine)).match(/^[\t ]*(`{3,}|~{3,})(.*)$/);
1421
+ if (!fence && match?.[1]) fence = {
1422
+ marker: match[1][0],
1423
+ length: match[1].length,
1424
+ start: offset
1425
+ };
1426
+ else if (fence && match?.[1]?.[0] === fence.marker && match[1].length >= fence.length && /^[\t ]*$/.test(match[2] ?? "")) {
1427
+ ranges.push({
1428
+ start: fence.start,
1429
+ end: offset + line.length
1430
+ });
1431
+ fence = void 0;
1432
+ }
1433
+ offset += line.length;
1434
+ }
1435
+ if (fence) ranges.push({
1436
+ start: fence.start,
1437
+ end: content.length
1438
+ });
1439
+ return ranges;
1440
+ }
1441
+ function findSvelteDirectiveRanges(content, excludedRanges) {
1442
+ const ranges = [];
1443
+ let index = 0;
1444
+ while (index < content.length) {
1445
+ const start = content.indexOf("{", index);
1446
+ if (start === -1) break;
1447
+ const sigil = content[start + 1];
1448
+ if (!/[#/:@]/.test(sigil ?? "") || !/[A-Za-z]/.test(content[start + 2] ?? "") || isEscapedAt(content, start) || isInsideRange(start, excludedRanges)) {
1449
+ index = start + 1;
1450
+ continue;
1451
+ }
1452
+ let cursor = start + 2;
1453
+ let braceDepth = 1;
1454
+ let quote;
1455
+ let blockComment = false;
1456
+ let lineComment = false;
1457
+ let regex = false;
1458
+ let regexCharacterClass = false;
1459
+ while (cursor < content.length && braceDepth > 0) {
1460
+ const character = content[cursor];
1461
+ const next = content[cursor + 1];
1462
+ if (lineComment) {
1463
+ if (character === "\n") lineComment = false;
1464
+ cursor += 1;
1465
+ continue;
1466
+ }
1467
+ if (blockComment) {
1468
+ if (character === "*" && next === "/") {
1469
+ blockComment = false;
1470
+ cursor += 2;
1471
+ } else cursor += 1;
1472
+ continue;
1473
+ }
1474
+ if (quote) {
1475
+ if (character === "\\") {
1476
+ cursor += 2;
1477
+ continue;
1478
+ }
1479
+ if (character === quote) quote = void 0;
1480
+ cursor += 1;
1481
+ continue;
1482
+ }
1483
+ if (regex) {
1484
+ if (character === "\\") {
1485
+ cursor += 2;
1486
+ continue;
1487
+ }
1488
+ if (character === "[") regexCharacterClass = true;
1489
+ if (character === "]") regexCharacterClass = false;
1490
+ if (character === "/" && !regexCharacterClass) regex = false;
1491
+ cursor += 1;
1492
+ continue;
1493
+ }
1494
+ if (character === "/" && next === "*") {
1495
+ blockComment = true;
1496
+ cursor += 2;
1497
+ continue;
1498
+ }
1499
+ if (character === "/" && next === "/") {
1500
+ lineComment = true;
1501
+ cursor += 2;
1502
+ continue;
1503
+ }
1504
+ if (character === "\"" || character === "'" || character === "`") {
1505
+ quote = character;
1506
+ cursor += 1;
1507
+ continue;
1508
+ }
1509
+ if (character === "/") {
1510
+ if (canStartJavascriptRegex(content, cursor, start + 1)) {
1511
+ regex = true;
1512
+ cursor += 1;
1513
+ continue;
1514
+ }
1515
+ }
1516
+ if (character === "{") braceDepth += 1;
1517
+ if (character === "}") braceDepth -= 1;
1518
+ cursor += 1;
1519
+ }
1520
+ if (braceDepth === 0) ranges.push({
1521
+ start,
1522
+ end: cursor
1523
+ });
1524
+ index = Math.max(start + 1, cursor);
1525
+ }
1526
+ return ranges;
1527
+ }
1528
+ function scanMdxModuleLine(line, state) {
1529
+ for (let index = 0; index < line.length; index += 1) {
1530
+ const character = line[index];
1531
+ const next = line[index + 1];
1532
+ if (state.blockComment) {
1533
+ if (character === "*" && next === "/") {
1534
+ state.blockComment = false;
1535
+ index += 1;
1536
+ }
1537
+ continue;
1538
+ }
1539
+ if (state.quote) {
1540
+ if (character === "\\") {
1541
+ index += 1;
1542
+ continue;
1543
+ }
1544
+ if (character === state.quote) state.quote = void 0;
1545
+ continue;
1546
+ }
1547
+ if (character === "/" && next === "/") break;
1548
+ if (character === "/" && next === "*") {
1549
+ state.blockComment = true;
1550
+ index += 1;
1551
+ continue;
1552
+ }
1553
+ if (character === "\"" || character === "'" || character === "`") {
1554
+ state.quote = character;
1555
+ continue;
1556
+ }
1557
+ if (state.jsxTag) {
1558
+ if (character === "{") state.braceDepth += 1;
1559
+ else if (character === "}" && state.braceDepth > 0) state.braceDepth -= 1;
1560
+ else if (character === ">" && state.braceDepth === 0) {
1561
+ let previous = index - 1;
1562
+ while (previous >= 0 && /[\t ]/.test(line[previous] ?? "")) previous -= 1;
1563
+ const selfClosing = line[previous] === "/";
1564
+ let following = index + 1;
1565
+ while (following < line.length && /[\t ]/.test(line[following] ?? "")) following += 1;
1566
+ const genericTypeParameters = !state.jsxTag.closing && line[following] === "(";
1567
+ if (state.jsxTag.closing) state.jsxDepth = Math.max(0, state.jsxDepth - 1);
1568
+ else if (!selfClosing && !genericTypeParameters) state.jsxDepth += 1;
1569
+ state.jsxTag = void 0;
1570
+ }
1571
+ continue;
1572
+ }
1573
+ if (character === "<") {
1574
+ let previous = index - 1;
1575
+ while (previous >= 0 && /[\t ]/.test(line[previous] ?? "")) previous -= 1;
1576
+ const previousCharacter = line[previous];
1577
+ const atExpressionStart = previousCharacter === void 0 || /[=([{,:?!;]/.test(previousCharacter);
1578
+ const openingElement = (state.jsxDepth > 0 || atExpressionStart) && /[A-Za-z]/.test(next ?? "");
1579
+ const closingElement = state.jsxDepth > 0 && next === "/" && /[A-Za-z]/.test(line[index + 2] ?? "");
1580
+ const openingFragment = atExpressionStart && next === ">";
1581
+ const closingFragment = state.jsxDepth > 0 && next === "/" && line[index + 2] === ">";
1582
+ if (openingFragment) {
1583
+ state.jsxDepth += 1;
1584
+ index += 1;
1585
+ continue;
1586
+ }
1587
+ if (closingFragment) {
1588
+ state.jsxDepth = Math.max(0, state.jsxDepth - 1);
1589
+ index += 2;
1590
+ continue;
1591
+ }
1592
+ if (openingElement || closingElement) {
1593
+ state.jsxTag = { closing: closingElement };
1594
+ continue;
1595
+ }
1596
+ }
1597
+ if (character === "{") {
1598
+ state.braceDepth += 1;
1599
+ state.sawBlock = true;
1600
+ continue;
1601
+ }
1602
+ if (character === "}") state.braceDepth = Math.max(0, state.braceDepth - 1);
1603
+ else if (character === "[") state.bracketDepth += 1;
1604
+ else if (character === "]") state.bracketDepth = Math.max(0, state.bracketDepth - 1);
1605
+ else if (character === "(") state.parenthesisDepth += 1;
1606
+ else if (character === ")") state.parenthesisDepth = Math.max(0, state.parenthesisDepth - 1);
1607
+ }
1608
+ }
1609
+ function shouldContinueMdxModule(statement, state, nextSignificantLine) {
1610
+ if (state.quote || state.blockComment || state.braceDepth > 0 || state.bracketDepth > 0 || state.parenthesisDepth > 0 || state.jsxTag || state.jsxDepth > 0) return true;
1611
+ const trimmed = statement.trimEnd();
1612
+ if (/^\s*import\b(?!\s*[.(])/.test(statement)) {
1613
+ if (!(/^\s*import\s*(?:type\s+)?["'`]/.test(statement) || /\bfrom\s*["'`][\s\S]*["'`]\s*;?\s*$/.test(trimmed)) && !/;\s*$/.test(trimmed)) return true;
1614
+ }
1615
+ const isExportList = /^\s*export\s+(?:type\s+)?\{/.test(statement);
1616
+ const isExportAll = /^\s*export\s+\*/.test(statement);
1617
+ if ((isExportList || isExportAll) && !/\bfrom\s*["'`][\s\S]*["'`]\s*;?\s*$/.test(trimmed) && (isExportAll || /^\s*from\b/.test(nextSignificantLine ?? ""))) return true;
1618
+ if (/=>\s*$/.test(trimmed) || /[=([{,:.?+\-*/%&|^!]$/.test(trimmed)) return true;
1619
+ if (/\b(?:as|default|extends|from|implements|satisfies)$/.test(trimmed)) return true;
1620
+ return /^\s*export\s+(?:default\s+)?(?:(?:async\s+)?function|class|enum|interface|module|namespace)\b/.test(statement) && !state.sawBlock;
1621
+ }
1622
+ function isInsideRange(index, ranges) {
1623
+ return ranges.some((range) => index >= range.start && index < range.end);
1624
+ }
1625
+ function findMdxModuleRanges(content, protectedRanges) {
1626
+ const ranges = [];
1627
+ const lines = content.split(/(?<=\n)/);
1628
+ let offset = 0;
1629
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
1630
+ const line = lines[lineIndex] ?? "";
1631
+ const firstNonWhitespace = line.search(/\S/);
1632
+ if (/^\s*(?:import|export)\b/.test(line) && !isInsideRange(offset + Math.max(0, firstNonWhitespace), protectedRanges)) {
1633
+ const start = offset;
1634
+ const state = {
1635
+ braceDepth: 0,
1636
+ bracketDepth: 0,
1637
+ parenthesisDepth: 0,
1638
+ blockComment: false,
1639
+ sawBlock: false,
1640
+ jsxDepth: 0
1641
+ };
1642
+ let statement = "";
1643
+ while (lineIndex < lines.length) {
1644
+ const moduleLine = lines[lineIndex] ?? "";
1645
+ statement += moduleLine;
1646
+ scanMdxModuleLine(moduleLine, state);
1647
+ offset += moduleLine.length;
1648
+ const nextSignificantLine = lines.slice(lineIndex + 1).find((candidate) => candidate.trim().length > 0);
1649
+ if (!shouldContinueMdxModule(statement, state, nextSignificantLine)) break;
1650
+ lineIndex += 1;
1651
+ }
1652
+ ranges.push({
1653
+ start,
1654
+ end: offset
1655
+ });
1656
+ continue;
1657
+ }
1658
+ offset += line.length;
1659
+ }
1660
+ return ranges;
1661
+ }
1662
+ function findInlineCodeRanges(content, protectedRanges) {
1663
+ const ranges = [];
1664
+ let index = 0;
1665
+ while (index < content.length) {
1666
+ if (content[index] !== "`" || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1667
+ index += 1;
1668
+ continue;
1669
+ }
1670
+ let markerLength = 1;
1671
+ while (content[index + markerLength] === "`") markerLength += 1;
1672
+ let closingIndex = index + markerLength;
1673
+ while (closingIndex < content.length) {
1674
+ closingIndex = content.indexOf("`", closingIndex);
1675
+ if (closingIndex === -1) break;
1676
+ if (isInsideRange(closingIndex, protectedRanges)) {
1677
+ closingIndex += 1;
1678
+ continue;
1679
+ }
1680
+ let closingLength = 1;
1681
+ while (content[closingIndex + closingLength] === "`") closingLength += 1;
1682
+ if (closingLength === markerLength) break;
1683
+ closingIndex += closingLength;
1684
+ }
1685
+ if (closingIndex === -1) {
1686
+ index += markerLength;
1687
+ continue;
1688
+ }
1689
+ ranges.push({
1690
+ start: index,
1691
+ end: closingIndex + markerLength
1692
+ });
1693
+ index = closingIndex + markerLength;
1694
+ }
1695
+ return ranges;
1696
+ }
1697
+ function findMdxExpressionLiteralRanges(content, protectedRanges) {
1698
+ const ranges = [];
1699
+ let index = 0;
1700
+ while (index < content.length) {
1701
+ if (content[index] !== "{" || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1702
+ index += 1;
1703
+ continue;
1704
+ }
1705
+ let cursor = index + 1;
1706
+ let depth = 1;
1707
+ while (cursor < content.length && depth > 0) {
1708
+ if (isInsideRange(cursor, protectedRanges)) {
1709
+ cursor += 1;
1710
+ continue;
1711
+ }
1712
+ const character = content[cursor];
1713
+ const next = content[cursor + 1];
1714
+ if (character === "\"" || character === "'" || character === "`") {
1715
+ const quote = character;
1716
+ const start = cursor;
1717
+ cursor += 1;
1718
+ while (cursor < content.length) {
1719
+ if (content[cursor] === "\\") {
1720
+ cursor += 2;
1721
+ continue;
1722
+ }
1723
+ if (content[cursor] === quote) {
1724
+ cursor += 1;
1725
+ break;
1726
+ }
1727
+ cursor += 1;
1728
+ }
1729
+ ranges.push({
1730
+ start,
1731
+ end: cursor
1732
+ });
1733
+ continue;
1734
+ }
1735
+ if (character === "/" && next === "*") {
1736
+ const start = cursor;
1737
+ const end = content.indexOf("*/", cursor + 2);
1738
+ cursor = end === -1 ? content.length : end + 2;
1739
+ ranges.push({
1740
+ start,
1741
+ end: cursor
1742
+ });
1743
+ continue;
1744
+ }
1745
+ if (character === "/" && next === "/") {
1746
+ const start = cursor;
1747
+ const newline = content.indexOf("\n", cursor + 2);
1748
+ cursor = newline === -1 ? content.length : newline;
1749
+ ranges.push({
1750
+ start,
1751
+ end: cursor
1752
+ });
1753
+ continue;
1754
+ }
1755
+ if (character === "/") {
1756
+ if (canStartJavascriptRegex(content, cursor, index)) {
1757
+ const start = cursor;
1758
+ let inCharacterClass = false;
1759
+ cursor += 1;
1760
+ while (cursor < content.length) {
1761
+ if (content[cursor] === "\\") {
1762
+ cursor += 2;
1763
+ continue;
1764
+ }
1765
+ if (content[cursor] === "[") inCharacterClass = true;
1766
+ if (content[cursor] === "]") inCharacterClass = false;
1767
+ if (content[cursor] === "/" && !inCharacterClass) {
1768
+ cursor += 1;
1769
+ while (/[A-Za-z]/.test(content[cursor] ?? "")) cursor += 1;
1770
+ break;
1771
+ }
1772
+ if (content[cursor] === "\n") break;
1773
+ cursor += 1;
1774
+ }
1775
+ ranges.push({
1776
+ start,
1777
+ end: cursor
1778
+ });
1779
+ continue;
1780
+ }
1781
+ }
1782
+ if (character === "{") depth += 1;
1783
+ if (character === "}") depth -= 1;
1784
+ cursor += 1;
1785
+ }
1786
+ index = Math.max(index + 1, cursor);
1787
+ }
1788
+ return ranges;
1789
+ }
1790
+ function readGenericMdxJsxTag(content, index) {
1791
+ let cursor = index + 1;
1792
+ if (content[cursor] === "/") cursor += 1;
1793
+ if (!/[A-Za-z]/.test(content[cursor] ?? "")) return void 0;
1794
+ const nameStart = cursor;
1795
+ while (/[\w:.-]/.test(content[cursor] ?? "")) cursor += 1;
1796
+ const name = content.slice(nameStart, cursor);
1797
+ if (DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === name)) return void 0;
1798
+ if (!/[\s/>]/.test(content[cursor] ?? "")) return void 0;
1799
+ const literals = [];
1800
+ let braceDepth = 0;
1801
+ while (cursor < content.length) {
1802
+ const character = content[cursor];
1803
+ const next = content[cursor + 1];
1804
+ if (character === "\"" || character === "'" || character === "`") {
1805
+ const quote = character;
1806
+ const start = cursor;
1807
+ cursor += 1;
1808
+ while (cursor < content.length) {
1809
+ if (content[cursor] === "\\") {
1810
+ cursor += 2;
1811
+ continue;
1812
+ }
1813
+ if (content[cursor] === quote) {
1814
+ cursor += 1;
1815
+ break;
1816
+ }
1817
+ cursor += 1;
1818
+ }
1819
+ literals.push({
1820
+ start,
1821
+ end: cursor
1822
+ });
1823
+ continue;
1824
+ }
1825
+ if (braceDepth > 0 && character === "/" && next === "*") {
1826
+ const start = cursor;
1827
+ const end = content.indexOf("*/", cursor + 2);
1828
+ cursor = end === -1 ? content.length : end + 2;
1829
+ literals.push({
1830
+ start,
1831
+ end: cursor
1832
+ });
1833
+ continue;
1834
+ }
1835
+ if (braceDepth > 0 && character === "/" && next === "/") {
1836
+ const start = cursor;
1837
+ const newline = content.indexOf("\n", cursor + 2);
1838
+ cursor = newline === -1 ? content.length : newline;
1839
+ literals.push({
1840
+ start,
1841
+ end: cursor
1842
+ });
1843
+ continue;
1844
+ }
1845
+ if (character === "{") braceDepth += 1;
1846
+ else if (character === "}" && braceDepth > 0) braceDepth -= 1;
1847
+ else if (character === ">" && braceDepth === 0) {
1848
+ let previous = cursor - 1;
1849
+ while (previous >= index && /\s/.test(content[previous] ?? "")) previous -= 1;
1850
+ return {
1851
+ end: cursor + 1,
1852
+ literals,
1853
+ selfClosing: content[previous] === "/"
1854
+ };
1855
+ }
1856
+ cursor += 1;
1857
+ }
1858
+ }
1859
+ function findGenericMdxJsxLiteralRanges(content, protectedRanges) {
1860
+ const ranges = [];
1861
+ let cursor = 0;
1862
+ while (cursor < content.length) {
1863
+ const index = content.indexOf("<", cursor);
1864
+ if (index === -1) break;
1865
+ if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
1866
+ cursor = index + 1;
1867
+ continue;
1868
+ }
1869
+ const tag = readGenericMdxJsxTag(content, index);
1870
+ if (!tag) {
1871
+ cursor = index + 1;
1872
+ continue;
1873
+ }
1874
+ ranges.push(...tag.literals);
1875
+ cursor = tag.end;
1876
+ }
1877
+ return ranges;
1878
+ }
1879
+ function findDelimiterExclusionRanges(content) {
1880
+ const markdownLiterals = findMarkdownLiteralRanges(content);
1881
+ const fences = findFenceRanges(content);
1882
+ const frontmatter = findLeadingFrontmatterRange(content);
1883
+ const literalBlocks = mergeProtectedRanges([
1884
+ ...markdownLiterals,
1885
+ ...fences,
1886
+ ...frontmatter ? [frontmatter] : []
1887
+ ]);
1888
+ const inlineCode = findInlineCodeRanges(content, literalBlocks);
1889
+ const markdownLinks = findMarkdownLinkDestinationRanges(content, literalBlocks);
1890
+ const nonModuleRanges = mergeProtectedRanges([
1891
+ ...literalBlocks,
1892
+ ...inlineCode,
1893
+ ...markdownLinks
1894
+ ]);
1895
+ const moduleRanges = findMdxModuleRanges(content, nonModuleRanges);
1896
+ const nonExpressionRanges = mergeProtectedRanges([...nonModuleRanges, ...moduleRanges]);
1897
+ const expressionLiterals = findMdxExpressionLiteralRanges(content, nonExpressionRanges);
1898
+ const nonJsxRanges = mergeProtectedRanges([...nonExpressionRanges, ...expressionLiterals]);
1899
+ return mergeProtectedRanges([...nonJsxRanges, ...findGenericMdxJsxLiteralRanges(content, nonJsxRanges)]);
1900
+ }
1901
+ function findProtectedRanges(content) {
1902
+ const baseExcludedRanges = findDelimiterExclusionRanges(content);
1903
+ const svelteDirectives = findSvelteDirectiveRanges(content, baseExcludedRanges);
1904
+ const excludedRanges = mergeProtectedRanges([...baseExcludedRanges, ...svelteDirectives]);
1905
+ const htmlLiterals = findHtmlLiteralRanges(content, excludedRanges);
1906
+ return mergeProtectedRanges([...excludedRanges, ...htmlLiterals]);
1907
+ }
1908
+ function normalizeProjectedWhitespace(content) {
1909
+ const protectedRanges = findProtectedRanges(content);
1910
+ return content.replace(/\n{3,}/g, (newlines, offset) => {
1911
+ const end = offset + newlines.length;
1912
+ return protectedRanges.some((range) => range.start < end && range.end > offset) ? newlines : "\n\n";
1913
+ }).trim();
1914
+ }
1915
+ /** Find audience declarations that cannot be projected consistently at build time. */
1916
+ function findDocsAudienceMdxIssues(content) {
1917
+ const issues = [];
1918
+ for (const tag of findDocsAudienceMdxTags(content)) {
1919
+ if (tag.closing) continue;
1920
+ const { attributes } = tag;
1921
+ const hasOnlyAttribute = tag.hasOnlyAttribute ?? /(?:^|\s)only\s*=/.test(attributes);
1922
+ const hasSpreadAttribute = tag.hasSpreadAttribute ?? /\{\s*\.\.\./.test(attributes);
1923
+ if ((tag.name === "Agent" || tag.name === "Human") && hasOnlyAttribute) {
1924
+ const shorthandAudience = tag.name === "Agent" ? "agent" : "human";
1925
+ issues.push({
1926
+ code: tag.name === "Agent" ? "ignored-agent-only" : "ignored-human-only",
1927
+ index: tag.index,
1928
+ message: `<${tag.name}> is always ${shorthandAudience}-only, so its \`only\` prop is ignored. Use <Audience only="${shorthandAudience}"> when you need the explicit form.`
1929
+ });
1930
+ continue;
1931
+ }
1932
+ if (tag.name !== "Audience") continue;
1933
+ if (hasSpreadAttribute) {
1934
+ issues.push({
1935
+ code: "dynamic-only",
1936
+ index: tag.index,
1937
+ message: "Audience spread props cannot be projected consistently. Remove the spread and use the static literal `only=\"human\"` or `only=\"agent\"`."
1938
+ });
1939
+ continue;
1940
+ }
1941
+ if (tag.only) continue;
1942
+ if (!hasOnlyAttribute) {
1943
+ issues.push({
1944
+ code: "missing-only",
1945
+ index: tag.index,
1946
+ message: "<Audience> requires the static literal `only=\"human\"` or `only=\"agent\"`."
1947
+ });
1948
+ continue;
1949
+ }
1950
+ const dynamicOnly = tag.onlyKind === "dynamic" || /(?:^|\s)only\s*=\s*\{/.test(attributes);
1951
+ issues.push({
1952
+ code: dynamicOnly ? "dynamic-only" : "invalid-only",
1953
+ index: tag.index,
1954
+ 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\"`."
1955
+ });
1956
+ }
1957
+ return issues;
1958
+ }
1959
+ /**
1960
+ * Resolve MDX into its human or agent projection.
1961
+ *
1962
+ * `<Agent>` is shorthand for `<Audience only="agent">`, while `<Human>` is
1963
+ * shorthand for `<Audience only="human">`. Unknown `Audience.only` values are
1964
+ * treated as shared content so an authoring typo never silently deletes content.
1965
+ * These primitives shape content for each surface; they are not an access-control boundary.
1966
+ */
1967
+ function resolveDocsAudienceMdxContent(content, audience) {
1968
+ const scopes = [];
1969
+ let output = "";
1970
+ let cursor = 0;
1971
+ let resolvedTag = false;
1972
+ for (const tag of findDocsAudienceMdxTags(content)) {
1973
+ const activeScope = scopes.at(-1);
1974
+ if (tag.closing && activeScope?.name !== tag.name) continue;
1975
+ resolvedTag = true;
1976
+ const visibleBeforeTag = isAudienceVisible(scopes, audience);
1977
+ if (visibleBeforeTag) output += content.slice(cursor, tag.index);
1978
+ cursor = tag.end;
1979
+ if (tag.closing) {
1980
+ if (tag.expression && visibleBeforeTag) output += "</>";
1981
+ scopes.pop();
1982
+ continue;
1983
+ }
1984
+ if (tag.selfClosing) {
1985
+ if (tag.expression && visibleBeforeTag) output += tag.jsxChild ? "{null}" : "null";
1986
+ continue;
1987
+ }
1988
+ scopes.push({
1989
+ name: tag.name,
1990
+ only: tag.only
1991
+ });
1992
+ if (tag.expression && visibleBeforeTag) output += isAudienceVisible(scopes, audience) ? "<>" : tag.jsxChild ? "{null}" : "null";
1993
+ }
1994
+ if (isAudienceVisible(scopes, audience)) output += content.slice(cursor);
1995
+ return resolvedTag ? normalizeProjectedWhitespace(output) : content;
1996
+ }
1997
+ /** Backwards-compatible name retained for existing integrations. */
1998
+ function resolveDocsAgentMdxContent(content, audience) {
1999
+ return resolveDocsAudienceMdxContent(content, audience);
2000
+ }
2001
+
889
2002
  //#endregion
890
2003
  //#region src/agent.ts
891
2004
  const DEFAULT_DOCS_API_ROUTE = "/api/docs";
@@ -1873,7 +2986,8 @@ function renderLlmsFullTxtPages(pages, baseUrl) {
1873
2986
  content += `## ${page.title}\n\n`;
1874
2987
  content += `URL: ${baseUrl}${page.url}\n\n`;
1875
2988
  if (page.description) content += `${page.description}\n\n`;
1876
- content += `${page.content}\n\n---\n\n`;
2989
+ const agentContent = page.agentRawContent ?? page.agentFallbackRawContent ?? page.agentContent ?? page.agentFallbackContent ?? page.rawContent ?? page.content;
2990
+ content += `${agentContent}\n\n---\n\n`;
1877
2991
  }
1878
2992
  return content;
1879
2993
  }
@@ -2595,13 +3709,14 @@ function appendDocsAgentPublicRouteLines(lines, context, variant) {
2595
3709
  appendDocsMcpRouteLines(lines, context);
2596
3710
  }
2597
3711
  function renderDocsMarkdownDocument(page, options) {
2598
- if (page.agentRawContent !== void 0) return appendDocsMarkdownSitemapFooter(prependDocsMarkdownFrontmatter(upsertPageAgentContractMarkdown(page.agentRawContent, page.agent), resolveDocsMarkdownPageMetadata(page, options)), options?.sitemap);
3712
+ const explicitAgentContent = page.agentRawContent ?? page.agentContent;
3713
+ if (explicitAgentContent !== void 0) return appendDocsMarkdownSitemapFooter(prependDocsMarkdownFrontmatter(upsertPageAgentContractMarkdown(explicitAgentContent, page.agent), resolveDocsMarkdownPageMetadata(page, options)), options?.sitemap);
2599
3714
  const relatedLines = renderDocsRelatedMarkdownLines(page.related);
2600
3715
  const lines = [`# ${page.title}`, `URL: ${page.url}`];
2601
3716
  if (shouldRenderLlmsDirective(options)) lines.push(DOCS_LLMS_TXT_DIRECTIVE_LINE);
2602
3717
  if (page.description) lines.push(`Description: ${page.description}`);
2603
3718
  lines.push(...relatedLines);
2604
- lines.push("", upsertPageAgentContractMarkdown(page.agentFallbackRawContent ?? page.rawContent ?? page.content, page.agent));
3719
+ lines.push("", upsertPageAgentContractMarkdown(page.agentFallbackRawContent ?? page.agentFallbackContent ?? page.rawContent ?? page.content, page.agent));
2605
3720
  return appendDocsMarkdownSitemapFooter(prependDocsMarkdownFrontmatter(lines.join("\n"), resolveDocsMarkdownPageMetadata(page, options)), options?.sitemap);
2606
3721
  }
2607
3722
  function renderDocsSkillDocument(options) {
@@ -2642,53 +3757,6 @@ function renderDocsAgentsDocument(options) {
2642
3757
  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", "```");
2643
3758
  return lines.join("\n");
2644
3759
  }
2645
- function resolveDocsAgentMdxContent(content, audience) {
2646
- const lines = content.split("\n");
2647
- const output = [];
2648
- let fenceMarker = null;
2649
- let agentDepth = 0;
2650
- for (const line of lines) {
2651
- const trimmed = line.trim();
2652
- const fenceMatch = trimmed.match(/^(`{3,}|~{3,})/);
2653
- if (fenceMatch) {
2654
- if (!fenceMarker) fenceMarker = fenceMatch[1];
2655
- else if (trimmed.startsWith(fenceMarker)) fenceMarker = null;
2656
- if (audience === "agent" || agentDepth === 0) output.push(line);
2657
- continue;
2658
- }
2659
- if (!fenceMarker) {
2660
- if (/^<Agent(?:\s[^>]*)?\/>$/.test(trimmed)) continue;
2661
- const singleLineMatch = line.match(/^(\s*)<Agent(?:\s[^>]*)?>([\s\S]*?)<\/Agent>\s*$/);
2662
- if (singleLineMatch) {
2663
- if (audience === "agent" && singleLineMatch[2]) output.push(`${singleLineMatch[1]}${singleLineMatch[2]}`);
2664
- continue;
2665
- }
2666
- if (line.match(/^(\s*)<Agent(?:\s[^>]*)?>\s*$/)) {
2667
- agentDepth += 1;
2668
- continue;
2669
- }
2670
- const openWithContentMatch = line.match(/^(\s*)<Agent(?:\s[^>]*)?>(.*)$/);
2671
- if (openWithContentMatch) {
2672
- agentDepth += 1;
2673
- if (audience === "agent" && openWithContentMatch[2]) output.push(`${openWithContentMatch[1]}${openWithContentMatch[2]}`);
2674
- continue;
2675
- }
2676
- const closeWithContentMatch = line.match(/^(.*)<\/Agent>\s*$/);
2677
- if (closeWithContentMatch && agentDepth > 0) {
2678
- if (audience === "agent" && closeWithContentMatch[1].trim()) output.push(closeWithContentMatch[1]);
2679
- agentDepth = Math.max(0, agentDepth - 1);
2680
- continue;
2681
- }
2682
- if (/^<\/Agent>\s*$/.test(trimmed) && agentDepth > 0) {
2683
- agentDepth = Math.max(0, agentDepth - 1);
2684
- continue;
2685
- }
2686
- }
2687
- if (agentDepth > 0 && audience === "human") continue;
2688
- output.push(line);
2689
- }
2690
- return output.join("\n").replace(/\n{3,}/g, "\n\n").trim();
2691
- }
2692
3760
  /** Resolve only the task tools that the advertised MCP endpoint actually exposes. */
2693
3761
  function resolveDocsAgentContractMcpTools(mcp) {
2694
3762
  if (!mcp.enabled) return void 0;
@@ -2770,8 +3838,8 @@ function buildDocsAgentDiscoverySpec({ origin, entry = "docs", i18n = null, sear
2770
3838
  apiPattern: `${DEFAULT_DOCS_API_ROUTE}?format=markdown&path={slug}`,
2771
3839
  resolutionOrder: [
2772
3840
  "agent.md",
2773
- "Agent blocks",
2774
- "page markdown"
3841
+ "agent audience projection",
3842
+ "shared page markdown"
2775
3843
  ]
2776
3844
  },
2777
3845
  agentContract: {
@@ -2990,4 +4058,4 @@ function toYamlString(value) {
2990
4058
  }
2991
4059
 
2992
4060
  //#endregion
2993
- export { normalizeDocsPathSegment as $, DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN as A, readDocsSitemapManifestFromContentMap as At, getDocsLlmsTxtMaxCharsIssue as B, PAGE_AGENT_CONTRACT_FIELDS as Bt, DEFAULT_OPENAPI_SCHEMA_ROUTE as C, DEFAULT_SITEMAP_MANIFEST_PATH as Ct, DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN as D, DEFAULT_SITEMAP_XML_ROUTE as Dt, DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN as E, DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE as Et, buildDocsDiagnostics as F, resolveDocsSitemapRequest as Ft, isDocsAgentsRequest as G, hasStructuredPageAgentContract as Gt, getDocsMarkdownVaryHeader as H, PAGE_AGENT_CONTRACT_START_MARKER as Ht, buildDocsMcpEndpointCandidates as I, toDocsSitemapMarkdownUrl as It, isDocsLlmsTxtPublicRequest as J, renderPageAgentFrontmatterYamlLines as Jt, isDocsConfigRequest as K, normalizePageAgentFrontmatter as Kt, createDocsMarkdownResponse as L, normalizeDocsRelated as Lt, buildDocsAgentDiscoverySpec as M, renderDocsSitemapXml as Mt, buildDocsAgentFeedbackSchema as N, resolveDocsSitemapConfig as Nt, DOCS_CONFIG_MAP_TOP_LEVEL_KEYS as O, buildDocsSitemapManifest as Ot, buildDocsConfigMap as P, resolveDocsSitemapPageLastmod as Pt, matchesDocsLlmsTxtSection as Q, detectDocsMarkdownAgentRequest as R, renderDocsRelatedMarkdownLines as Rt, DEFAULT_MCP_WELL_KNOWN_ROUTE as S, validateDocsAgentFeedbackPayload as St, DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE as T, DEFAULT_SITEMAP_MD_ROUTE as Tt, hasDocsMarkdownSignatureAgent as U, PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS as Ut, getDocsMarkdownCanonicalLinkHeader as V, PAGE_AGENT_CONTRACT_FIELD_SCHEMA as Vt, isDocsAgentDiscoveryRequest as W, getPageAgentFrontmatterIssues as Wt, isDocsPublicGetRequest as X, upsertPageAgentContractMarkdown as Xt, isDocsMcpRequest as Y, stripGeneratedPageAgentContractMarkdown as Yt, isDocsSkillRequest as Z, DEFAULT_LLMS_TXT_MAX_CHARS as _, resolveDocsMarkdownRequest as _t, DEFAULT_AGENT_MD_ROUTE as a, renderDocsMarkdownNotFound as at, DEFAULT_MCP_PUBLIC_ROUTE as b, selectDocsLlmsTxtContent as bt, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE as c, resolveDocsAgentFeedbackConfig as ct, DEFAULT_DOCS_CONFIG_FORMAT as d, resolveDocsAgentsFormat as dt, normalizeDocsUrlPath as et, DEFAULT_DOCS_CONFIG_ROUTE as f, resolveDocsLlmsTxtFormat as ft, DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE as g, resolveDocsMarkdownRecovery as gt, DEFAULT_LLMS_FULL_TXT_ROUTE as h, resolveDocsMarkdownCanonicalUrl as ht, DEFAULT_AGENT_FEEDBACK_ROUTE as i, renderDocsMarkdownDocument as it, acceptsDocsMarkdown as j, renderDocsSitemapMarkdown as jt, DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER as k, createDocsSitemapResponse as kt, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE as l, resolveDocsAgentFeedbackRequest as lt, DEFAULT_DOCS_DIAGNOSTICS_ROUTE as m, resolveDocsLlmsTxtSections as mt, DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE as n, renderDocsAgentsDocument as nt, DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE as o, renderDocsSkillDocument as ot, DEFAULT_DOCS_DIAGNOSTICS_FORMAT as p, resolveDocsLlmsTxtRequest as pt, isDocsDiagnosticsRequest as q, renderPageAgentContractMarkdown as qt, DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA as r, renderDocsLlmsTxt as rt, DEFAULT_AGENT_SPEC_ROUTE as s, resolveDocsAgentContractMcpTools as st, DEFAULT_AGENTS_MD_ROUTE as t, parseDocsAgentFeedbackData as tt, DEFAULT_DOCS_API_ROUTE as u, resolveDocsAgentMdxContent as ut, DEFAULT_LLMS_TXT_ROUTE as v, resolveDocsOpenApiDiscoveryConfig as vt, DEFAULT_SKILL_MD_ROUTE as w, DEFAULT_SITEMAP_MD_DOCS_ROUTE as wt, DEFAULT_MCP_ROUTE as x, toDocsMarkdownUrl as xt, DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE as y, resolveDocsSkillFormat as yt, findDocsMarkdownPage as z, PAGE_AGENT_CONTRACT_END_MARKER as zt };
4061
+ export { normalizeDocsPathSegment as $, stripGeneratedPageAgentContractMarkdown as $t, DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN as A, DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE as At, getDocsLlmsTxtMaxCharsIssue as B, toDocsSitemapMarkdownUrl as Bt, DEFAULT_OPENAPI_SCHEMA_ROUTE as C, findDocsAudienceMdxTags as Ct, DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN as D, DEFAULT_SITEMAP_MANIFEST_PATH as Dt, DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN as E, resolveDocsAudienceMdxContent as Et, buildDocsDiagnostics as F, renderDocsSitemapMarkdown as Ft, isDocsAgentsRequest as G, PAGE_AGENT_CONTRACT_FIELD_SCHEMA as Gt, getDocsMarkdownVaryHeader as H, renderDocsRelatedMarkdownLines as Ht, buildDocsMcpEndpointCandidates as I, renderDocsSitemapXml as It, isDocsLlmsTxtPublicRequest as J, getPageAgentFrontmatterIssues as Jt, isDocsConfigRequest as K, PAGE_AGENT_CONTRACT_START_MARKER as Kt, createDocsMarkdownResponse as L, resolveDocsSitemapConfig as Lt, buildDocsAgentDiscoverySpec as M, buildDocsSitemapManifest as Mt, buildDocsAgentFeedbackSchema as N, createDocsSitemapResponse as Nt, DOCS_CONFIG_MAP_TOP_LEVEL_KEYS as O, DEFAULT_SITEMAP_MD_DOCS_ROUTE as Ot, buildDocsConfigMap as P, readDocsSitemapManifestFromContentMap as Pt, matchesDocsLlmsTxtSection as Q, renderPageAgentFrontmatterYamlLines as Qt, detectDocsMarkdownAgentRequest as R, resolveDocsSitemapPageLastmod as Rt, DEFAULT_MCP_WELL_KNOWN_ROUTE as S, findDocsAudienceMdxIssues as St, DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE as T, resolveDocsAudienceExposure as Tt, hasDocsMarkdownSignatureAgent as U, PAGE_AGENT_CONTRACT_END_MARKER as Ut, getDocsMarkdownCanonicalLinkHeader as V, normalizeDocsRelated as Vt, isDocsAgentDiscoveryRequest as W, PAGE_AGENT_CONTRACT_FIELDS as Wt, isDocsPublicGetRequest as X, normalizePageAgentFrontmatter as Xt, isDocsMcpRequest as Y, hasStructuredPageAgentContract as Yt, isDocsSkillRequest as Z, renderPageAgentContractMarkdown as Zt, DEFAULT_LLMS_TXT_MAX_CHARS as _, resolveDocsOpenApiDiscoveryConfig as _t, DEFAULT_AGENT_MD_ROUTE as a, renderDocsMarkdownNotFound as at, DEFAULT_MCP_PUBLIC_ROUTE as b, toDocsMarkdownUrl as bt, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE as c, resolveDocsAgentFeedbackConfig as ct, DEFAULT_DOCS_CONFIG_FORMAT as d, resolveDocsLlmsTxtFormat as dt, upsertPageAgentContractMarkdown as en, normalizeDocsUrlPath as et, DEFAULT_DOCS_CONFIG_ROUTE as f, resolveDocsLlmsTxtRequest as ft, DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE as g, resolveDocsMarkdownRequest as gt, DEFAULT_LLMS_FULL_TXT_ROUTE as h, resolveDocsMarkdownRecovery as ht, DEFAULT_AGENT_FEEDBACK_ROUTE as i, renderDocsMarkdownDocument as it, acceptsDocsMarkdown as j, DEFAULT_SITEMAP_XML_ROUTE as jt, DOCS_MARKDOWN_SIGNATURE_AGENT_HEADER as k, DEFAULT_SITEMAP_MD_ROUTE as kt, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE as l, resolveDocsAgentFeedbackRequest as lt, DEFAULT_DOCS_DIAGNOSTICS_ROUTE as m, resolveDocsMarkdownCanonicalUrl as mt, DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE as n, renderDocsAgentsDocument as nt, DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE as o, renderDocsSkillDocument as ot, DEFAULT_DOCS_DIAGNOSTICS_FORMAT as p, resolveDocsLlmsTxtSections as pt, isDocsDiagnosticsRequest as q, PAGE_AGENT_STRUCTURED_CONTRACT_FIELDS as qt, DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA as r, renderDocsLlmsTxt as rt, DEFAULT_AGENT_SPEC_ROUTE as s, resolveDocsAgentContractMcpTools as st, DEFAULT_AGENTS_MD_ROUTE as t, parseDocsAgentFeedbackData as tt, DEFAULT_DOCS_API_ROUTE as u, resolveDocsAgentsFormat as ut, DEFAULT_LLMS_TXT_ROUTE as v, resolveDocsSkillFormat as vt, DEFAULT_SKILL_MD_ROUTE as w, resolveDocsAgentMdxContent as wt, DEFAULT_MCP_ROUTE as x, validateDocsAgentFeedbackPayload as xt, DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE as y, selectDocsLlmsTxtContent as yt, findDocsMarkdownPage as z, resolveDocsSitemapRequest as zt };