blodemd 0.0.13 → 0.0.15

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 (136) hide show
  1. package/README.md +1 -1
  2. package/dev-server/lib/local-runtime.tsx +12 -15
  3. package/dev-server/package.json +5 -1
  4. package/dist/cli.mjs +1211 -983
  5. package/dist/cli.mjs.map +1 -1
  6. package/docs/app/globals.css +1 -1
  7. package/docs/components/api/api-playground.tsx +2 -5
  8. package/docs/components/api/api-reference.tsx +29 -3
  9. package/docs/components/docs/contextual-menu.tsx +37 -33
  10. package/docs/components/docs/copy-page-menu.tsx +18 -0
  11. package/docs/components/docs/doc-header.tsx +4 -1
  12. package/docs/components/docs/doc-shell.tsx +48 -18
  13. package/docs/components/docs/doc-sidebar.tsx +131 -89
  14. package/docs/components/docs/doc-toc.tsx +1 -0
  15. package/docs/components/docs/mobile-nav.tsx +72 -68
  16. package/docs/components/docs/sidebar-active-highlight.tsx +34 -0
  17. package/docs/components/docs/sidebar-scroll-area.tsx +9 -4
  18. package/docs/components/git/repo-picker.tsx +5 -2
  19. package/docs/components/mdx/index.tsx +31 -21
  20. package/docs/components/posthog-provider.tsx +42 -0
  21. package/docs/components/tenant-analytics.tsx +49 -0
  22. package/docs/components/third-parties.tsx +4 -1
  23. package/docs/components/ui/copy-button.tsx +16 -2
  24. package/docs/components/ui/search-dialog.tsx +431 -0
  25. package/docs/components/ui/search.tsx +44 -427
  26. package/docs/components/web-mcp.tsx +115 -0
  27. package/docs/lib/agent-skills.ts +48 -0
  28. package/docs/lib/config.ts +4 -5
  29. package/docs/lib/docs-collection.ts +7 -22
  30. package/docs/lib/docs-runtime.tsx +160 -10
  31. package/docs/lib/llms-full.ts +82 -0
  32. package/docs/lib/marketing-markdown.ts +79 -0
  33. package/docs/lib/marketing-site.ts +31 -0
  34. package/docs/lib/mdx.ts +17 -6
  35. package/docs/lib/routes.ts +19 -3
  36. package/docs/lib/shiki.ts +4 -0
  37. package/docs/lib/tenancy.ts +15 -2
  38. package/docs/lib/tenant-headers.ts +29 -0
  39. package/docs/lib/tenant-static.ts +73 -99
  40. package/package.json +8 -5
  41. package/packages/@repo/common/package.json +1 -1
  42. package/packages/@repo/contracts/dist/analytics.d.ts +21 -0
  43. package/packages/@repo/contracts/dist/analytics.d.ts.map +1 -0
  44. package/packages/@repo/contracts/dist/analytics.js +18 -0
  45. package/packages/@repo/contracts/dist/deployment.js +1 -1
  46. package/packages/@repo/contracts/dist/git.js +2 -2
  47. package/packages/@repo/contracts/dist/ids.d.ts.map +1 -1
  48. package/packages/@repo/contracts/dist/ids.js +2 -1
  49. package/packages/@repo/contracts/dist/index.d.ts +1 -0
  50. package/packages/@repo/contracts/dist/index.d.ts.map +1 -1
  51. package/packages/@repo/contracts/dist/index.js +1 -0
  52. package/packages/@repo/contracts/dist/project.d.ts +18 -1
  53. package/packages/@repo/contracts/dist/project.d.ts.map +1 -1
  54. package/packages/@repo/contracts/dist/project.js +3 -1
  55. package/packages/@repo/contracts/dist/tenant.d.ts +36 -0
  56. package/packages/@repo/contracts/dist/tenant.d.ts.map +1 -1
  57. package/packages/@repo/contracts/dist/tenant.js +2 -0
  58. package/packages/@repo/contracts/package.json +1 -1
  59. package/packages/@repo/contracts/src/analytics.ts +33 -0
  60. package/packages/@repo/contracts/src/deployment.ts +1 -1
  61. package/packages/@repo/contracts/src/git.ts +2 -2
  62. package/packages/@repo/contracts/src/ids.ts +2 -1
  63. package/packages/@repo/contracts/src/index.ts +1 -0
  64. package/packages/@repo/contracts/src/project.ts +3 -1
  65. package/packages/@repo/contracts/src/tenant.ts +2 -0
  66. package/packages/@repo/models/dist/docs-config.d.ts +0 -198
  67. package/packages/@repo/models/dist/docs-config.d.ts.map +1 -1
  68. package/packages/@repo/models/dist/docs-config.js +3 -2
  69. package/packages/@repo/models/dist/tenant.d.ts +12 -0
  70. package/packages/@repo/models/dist/tenant.d.ts.map +1 -1
  71. package/packages/@repo/models/package.json +1 -1
  72. package/packages/@repo/models/src/docs-config.ts +3 -3
  73. package/packages/@repo/models/src/tenant.ts +15 -0
  74. package/packages/@repo/prebuild/dist/openapi.d.ts.map +1 -1
  75. package/packages/@repo/prebuild/dist/openapi.js +32 -4
  76. package/packages/@repo/prebuild/package.json +1 -1
  77. package/packages/@repo/prebuild/src/openapi.ts +42 -4
  78. package/packages/@repo/previewing/dist/blob-source.d.ts.map +1 -1
  79. package/packages/@repo/previewing/dist/blob-source.js +18 -5
  80. package/packages/@repo/previewing/dist/config-loader.d.ts +134 -0
  81. package/packages/@repo/previewing/dist/config-loader.d.ts.map +1 -0
  82. package/packages/@repo/previewing/dist/config-loader.js +231 -0
  83. package/packages/@repo/previewing/dist/constants.d.ts +15 -0
  84. package/packages/@repo/previewing/dist/constants.d.ts.map +1 -0
  85. package/packages/@repo/previewing/dist/constants.js +14 -0
  86. package/packages/@repo/previewing/dist/content-index.d.ts +7 -0
  87. package/packages/@repo/previewing/dist/content-index.d.ts.map +1 -0
  88. package/packages/@repo/previewing/dist/content-index.js +291 -0
  89. package/packages/@repo/previewing/dist/index.d.ts +13 -121
  90. package/packages/@repo/previewing/dist/index.d.ts.map +1 -1
  91. package/packages/@repo/previewing/dist/index.js +11 -1003
  92. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts +3 -0
  93. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts.map +1 -0
  94. package/packages/@repo/previewing/dist/markdown/agent-markdown.js +176 -0
  95. package/packages/@repo/previewing/dist/markdown/format.d.ts +8 -0
  96. package/packages/@repo/previewing/dist/markdown/format.d.ts.map +1 -0
  97. package/packages/@repo/previewing/dist/markdown/format.js +43 -0
  98. package/packages/@repo/previewing/dist/markdown/links.d.ts +3 -0
  99. package/packages/@repo/previewing/dist/markdown/links.d.ts.map +1 -0
  100. package/packages/@repo/previewing/dist/markdown/links.js +31 -0
  101. package/packages/@repo/previewing/dist/openapi-pages.d.ts +7 -0
  102. package/packages/@repo/previewing/dist/openapi-pages.d.ts.map +1 -0
  103. package/packages/@repo/previewing/dist/openapi-pages.js +200 -0
  104. package/packages/@repo/previewing/dist/search-index.d.ts +4 -0
  105. package/packages/@repo/previewing/dist/search-index.d.ts.map +1 -0
  106. package/packages/@repo/previewing/dist/search-index.js +23 -0
  107. package/packages/@repo/previewing/dist/serialization.d.ts +13 -0
  108. package/packages/@repo/previewing/dist/serialization.d.ts.map +1 -0
  109. package/packages/@repo/previewing/dist/serialization.js +108 -0
  110. package/packages/@repo/previewing/dist/toc-index.d.ts +5 -0
  111. package/packages/@repo/previewing/dist/toc-index.d.ts.map +1 -0
  112. package/packages/@repo/previewing/dist/toc-index.js +53 -0
  113. package/packages/@repo/previewing/dist/types.d.ts +92 -0
  114. package/packages/@repo/previewing/dist/types.d.ts.map +1 -0
  115. package/packages/@repo/previewing/dist/types.js +1 -0
  116. package/packages/@repo/previewing/dist/utility-index.d.ts +7 -0
  117. package/packages/@repo/previewing/dist/utility-index.d.ts.map +1 -0
  118. package/packages/@repo/previewing/dist/utility-index.js +201 -0
  119. package/packages/@repo/previewing/package.json +1 -1
  120. package/packages/@repo/previewing/src/blob-source.ts +20 -5
  121. package/packages/@repo/previewing/src/config-loader.ts +316 -0
  122. package/packages/@repo/previewing/src/constants.ts +16 -0
  123. package/packages/@repo/previewing/src/content-index.ts +384 -0
  124. package/packages/@repo/previewing/src/index.ts +69 -1515
  125. package/packages/@repo/previewing/src/markdown/agent-markdown.ts +254 -0
  126. package/packages/@repo/previewing/src/markdown/format.ts +63 -0
  127. package/packages/@repo/previewing/src/markdown/links.ts +46 -0
  128. package/packages/@repo/previewing/src/openapi-pages.ts +319 -0
  129. package/packages/@repo/previewing/src/search-index.ts +38 -0
  130. package/packages/@repo/previewing/src/serialization.ts +191 -0
  131. package/packages/@repo/previewing/src/toc-index.ts +72 -0
  132. package/packages/@repo/previewing/src/types.ts +105 -0
  133. package/packages/@repo/previewing/src/utility-index.ts +304 -0
  134. package/packages/@repo/validation/package.json +1 -1
  135. package/scripts/repo-packages.mjs +8 -0
  136. package/docs/components/ui/site-footer.tsx +0 -41
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toc-index.d.ts","sourceRoot":"","sources":["../src/toc-index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAMxD,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,KAAG,OAAO,EAoClD,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,OAAO,YAAY,EACnB,QAAQ,aAAa,KACpB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAoBhC,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { slugify } from "@repo/common";
2
+ import { NEWLINE_REGEX } from "./constants.js";
3
+ const HEADING_REGEX = /^(#{2,4})\s+(.*)$/;
4
+ // Matches ``` and ~~~ fenced blocks, requiring the same fence to close them.
5
+ const TOC_FENCE_REGEX = /(`{3,}|~{3,})[\s\S]*?\1/g;
6
+ export const extractToc = (source) => {
7
+ const withoutCode = source.replaceAll(TOC_FENCE_REGEX, "");
8
+ const lines = withoutCode.split(NEWLINE_REGEX);
9
+ const toc = [];
10
+ const emitted = new Set();
11
+ for (const line of lines) {
12
+ const match = HEADING_REGEX.exec(line.trim());
13
+ if (!match) {
14
+ continue;
15
+ }
16
+ const [, hashes = "", heading = ""] = match;
17
+ if (!(hashes && heading)) {
18
+ continue;
19
+ }
20
+ const baseId = slugify(heading.trim());
21
+ // Increment until the id is unique among the ids we have already emitted,
22
+ // so a suffixed id never collides with an explicit "foo-1" heading.
23
+ let id = baseId;
24
+ let count = 1;
25
+ while (emitted.has(id)) {
26
+ id = `${baseId}-${count}`;
27
+ count += 1;
28
+ }
29
+ emitted.add(id);
30
+ toc.push({
31
+ id,
32
+ level: hashes.length,
33
+ title: heading.trim(),
34
+ });
35
+ }
36
+ return toc;
37
+ };
38
+ export const buildTocIndex = async (index, source) => {
39
+ const itemsBySlug = new Map();
40
+ const results = await Promise.all(index.entries.map(async (entry) => {
41
+ if (entry.kind !== "entry") {
42
+ return null;
43
+ }
44
+ const rawContent = await source.readFile(entry.relativePath);
45
+ return { slug: entry.slug, toc: extractToc(rawContent) };
46
+ }));
47
+ for (const result of results) {
48
+ if (result) {
49
+ itemsBySlug.set(result.slug, result.toc);
50
+ }
51
+ }
52
+ return itemsBySlug;
53
+ };
@@ -0,0 +1,92 @@
1
+ import type { ContentType, DocsOpenApiSource, FrontmatterByType, PageMode, SiteConfig } from "@repo/models";
2
+ import type { OpenApiOperation, OpenApiSpec } from "@repo/prebuild";
3
+ export type SiteConfigResult = {
4
+ ok: true;
5
+ config: SiteConfig;
6
+ warnings: string[];
7
+ } | {
8
+ ok: false;
9
+ errors: string[];
10
+ };
11
+ export type ContentEntry = {
12
+ kind: "entry";
13
+ slug: string;
14
+ title: string;
15
+ description?: string;
16
+ hidden?: boolean;
17
+ type: ContentType;
18
+ collectionId: string;
19
+ sourcePath: string;
20
+ relativePath: string;
21
+ frontmatter: FrontmatterByType[ContentType];
22
+ } | {
23
+ kind: "index";
24
+ slug: string;
25
+ title: string;
26
+ description?: string;
27
+ type: ContentType;
28
+ collectionId: string;
29
+ };
30
+ export interface ContentIndex {
31
+ entries: ContentEntry[];
32
+ bySlug: Map<string, ContentEntry>;
33
+ byCollection: Map<string, ContentEntry[]>;
34
+ errors: string[];
35
+ }
36
+ export interface PageMetadata {
37
+ title?: string;
38
+ sidebarTitle?: string;
39
+ icon?: string;
40
+ iconType?: string;
41
+ tag?: string;
42
+ hidden?: boolean;
43
+ deprecated?: boolean;
44
+ url?: string;
45
+ mode?: PageMode;
46
+ noindex?: boolean;
47
+ hideFooterPagination?: boolean;
48
+ hideApiMarker?: boolean;
49
+ keywords?: string[];
50
+ }
51
+ export interface SearchIndexItem {
52
+ href?: string;
53
+ title: string;
54
+ path: string;
55
+ }
56
+ export interface TocItem {
57
+ id: string;
58
+ level: number;
59
+ title: string;
60
+ }
61
+ export interface UtilityPage {
62
+ content: string;
63
+ description?: string;
64
+ slug: string;
65
+ title: string;
66
+ }
67
+ export interface UtilitySegment {
68
+ pageSlugs: string[];
69
+ slug: string;
70
+ title: string;
71
+ }
72
+ export interface UtilityIndex {
73
+ description?: string;
74
+ name: string;
75
+ pages: UtilityPage[];
76
+ segments?: UtilitySegment[];
77
+ slug?: string;
78
+ }
79
+ export interface UtilityArtifact {
80
+ content: string;
81
+ contentType: string;
82
+ path: string;
83
+ }
84
+ export interface PrebuiltOpenApiEntry {
85
+ identifier: string;
86
+ operation: OpenApiOperation;
87
+ slug: string;
88
+ source: DocsOpenApiSource;
89
+ sourceKey: string;
90
+ spec: OpenApiSpec;
91
+ }
92
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { SiteConfig } from "@repo/models";
2
+ import type { ContentSource } from "./content-source.js";
3
+ import type { ContentIndex, UtilityArtifact, UtilityIndex } from "./types.js";
4
+ export declare const buildUtilityIndex: (index: ContentIndex, source: ContentSource, config: SiteConfig) => Promise<UtilityIndex>;
5
+ export declare const getPrebuiltUtilityLlmPagePath: (slug: string) => string;
6
+ export declare const buildUtilityArtifacts: (index: UtilityIndex) => UtilityArtifact[];
7
+ //# sourceMappingURL=utility-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utility-index.d.ts","sourceRoot":"","sources":["../src/utility-index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAmB/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EAGb,MAAM,YAAY,CAAC;AAoCpB,eAAO,MAAM,iBAAiB,GAC5B,OAAO,YAAY,EACnB,QAAQ,aAAa,EACrB,QAAQ,UAAU,KACjB,OAAO,CAAC,YAAY,CA8CtB,CAAC;AAqBF,eAAO,MAAM,6BAA6B,GAAI,MAAM,MAAM,WAGzD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,OAAO,YAAY,KAClB,eAAe,EAwJjB,CAAC"}
@@ -0,0 +1,201 @@
1
+ import { normalizePath, slugify } from "@repo/common";
2
+ import { getDocsCollectionWithNavigation, getDocsNavigation, } from "./config-loader.js";
3
+ import { PREBUILT_UTILITY_LLMS_FULL_PATH, PREBUILT_UTILITY_LLMS_PATH, PREBUILT_UTILITY_LLMS_SEGMENT_PREFIX, PREBUILT_UTILITY_SITEMAP_PATH, PREBUILT_UTILITY_SKILLS_INDEX_PATH, PREBUILT_UTILITY_SKILLS_MD_PREFIX, UTILITY_DOCS_ROOT_TOKEN, } from "./constants.js";
4
+ import { buildPageMetadataMap, shouldIncludeSearchEntry, } from "./content-index.js";
5
+ import { prepareLlmsFullContent, toAgentMarkdown, } from "./markdown/agent-markdown.js";
6
+ import { formatMarkdownPage, formatMarkdownPageSection, stripFrontmatter, } from "./markdown/format.js";
7
+ import { buildUtilityOpenApiPages } from "./openapi-pages.js";
8
+ const collectUtilitySegments = (config, pages) => {
9
+ const segments = new Map();
10
+ const addGroup = (group) => {
11
+ if (group.hidden || !group.group) {
12
+ return;
13
+ }
14
+ const pageSlugs = (group.pages ?? []).filter((page) => pages.has(page));
15
+ if (pageSlugs.length === 0) {
16
+ return;
17
+ }
18
+ const slug = slugify(group.group);
19
+ segments.set(slug, { pageSlugs, slug, title: group.group });
20
+ };
21
+ const navigation = getDocsNavigation(config);
22
+ for (const group of navigation?.groups ?? []) {
23
+ addGroup(group);
24
+ }
25
+ for (const tab of navigation?.tabs ?? []) {
26
+ for (const group of tab.groups ?? []) {
27
+ addGroup(group);
28
+ }
29
+ }
30
+ return [...segments.values()];
31
+ };
32
+ export const buildUtilityIndex = async (index, source, config) => {
33
+ const pageMetadataMap = buildPageMetadataMap(index);
34
+ const pages = new Map();
35
+ const contentPages = await Promise.all(index.entries.map(async (entry) => {
36
+ if (entry.kind !== "entry") {
37
+ return null;
38
+ }
39
+ if (!shouldIncludeSearchEntry(entry, pageMetadataMap, config)) {
40
+ return null;
41
+ }
42
+ const rawContent = await source.readFile(entry.relativePath);
43
+ return {
44
+ content: stripFrontmatter(rawContent),
45
+ description: entry.description,
46
+ slug: entry.slug,
47
+ title: entry.title,
48
+ };
49
+ }));
50
+ for (const page of contentPages) {
51
+ if (page) {
52
+ pages.set(page.slug, page);
53
+ }
54
+ }
55
+ for (const page of await buildUtilityOpenApiPages(config, getDocsCollectionWithNavigation(config), source)) {
56
+ pages.set(page.slug, page);
57
+ }
58
+ const sortedPages = [...pages.values()];
59
+ // oxlint-disable-next-line eslint-plugin-unicorn/no-array-sort
60
+ sortedPages.sort((left, right) => left.slug.localeCompare(right.slug));
61
+ return {
62
+ description: config.description,
63
+ name: config.name,
64
+ pages: sortedPages,
65
+ segments: collectUtilitySegments(config, pages),
66
+ slug: config.slug,
67
+ };
68
+ };
69
+ const toUtilityDocPath = (value) => {
70
+ const clean = normalizePath(value);
71
+ if (!clean || clean === "index") {
72
+ return "/";
73
+ }
74
+ return `/${clean}`;
75
+ };
76
+ const toUtilityTemplatedDocUrl = (value) => `${UTILITY_DOCS_ROOT_TOKEN}${toUtilityDocPath(value)}`;
77
+ const toUtilityTemplatedMarkdownDocUrl = (value) => {
78
+ const clean = normalizePath(value);
79
+ if (!clean || clean === "index") {
80
+ return `${UTILITY_DOCS_ROOT_TOKEN}/index.md`;
81
+ }
82
+ return `${UTILITY_DOCS_ROOT_TOKEN}/${clean}.md`;
83
+ };
84
+ export const getPrebuiltUtilityLlmPagePath = (slug) => {
85
+ const normalized = normalizePath(slug);
86
+ return `_utility/llms-pages/${normalized || "index"}.mdx`;
87
+ };
88
+ export const buildUtilityArtifacts = (index) => {
89
+ const segments = index.segments ?? [];
90
+ const segmentLines = segments.length > 0
91
+ ? [
92
+ "",
93
+ "## Segments",
94
+ ...segments.map((segment) => `- [${segment.title}](${UTILITY_DOCS_ROOT_TOKEN}/llms/${segment.slug}.txt)`),
95
+ ]
96
+ : [];
97
+ const llmsLines = [
98
+ `# ${index.name}`,
99
+ index.description ? `> ${index.description}` : null,
100
+ "",
101
+ `Sitemap: ${toUtilityTemplatedDocUrl("sitemap.xml")}`,
102
+ `Full content: ${UTILITY_DOCS_ROOT_TOKEN}/llms-full.txt`,
103
+ `Skills: ${UTILITY_DOCS_ROOT_TOKEN}/.well-known/skills/index.json`,
104
+ ...segmentLines,
105
+ "",
106
+ "## Docs",
107
+ ...index.pages.map((page) => {
108
+ const description = page.description ? `: ${page.description}` : "";
109
+ return `- [${page.title}](${toUtilityTemplatedMarkdownDocUrl(page.slug)})${description}`;
110
+ }),
111
+ ];
112
+ const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
113
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
114
+ ${index.pages
115
+ .map((page) => ` <url><loc>${toUtilityTemplatedDocUrl(page.slug)}</loc></url>`)
116
+ .join("\n")}
117
+ </urlset>`;
118
+ const llmsFull = index.pages
119
+ .map((page) => formatMarkdownPageSection(page.title, toUtilityTemplatedDocUrl(page.slug), prepareLlmsFullContent(page.content, UTILITY_DOCS_ROOT_TOKEN, ""), page.description))
120
+ .join("\n\n");
121
+ const skillSlug = index.slug ?? slugify(index.name);
122
+ const skillDescription = `${index.name} documentation. ${index.description ?? ""}`.trim();
123
+ const skillsIndex = JSON.stringify({
124
+ skills: [
125
+ {
126
+ description: skillDescription,
127
+ files: ["SKILL.md"],
128
+ name: skillSlug,
129
+ },
130
+ ],
131
+ }, null, 2);
132
+ const topPages = index.pages.slice(0, 20);
133
+ const skillMdLines = [
134
+ "---",
135
+ `name: ${skillSlug}`,
136
+ `description: ${skillDescription} Use when working with ${index.name}, answering questions about its features, or helping users follow its guides.`,
137
+ "---",
138
+ "",
139
+ `# ${index.name}`,
140
+ "",
141
+ index.description ? `${index.description}\n` : "",
142
+ "## Documentation",
143
+ "",
144
+ `- Full docs index: ${UTILITY_DOCS_ROOT_TOKEN}/llms.txt`,
145
+ `- Complete docs content: ${UTILITY_DOCS_ROOT_TOKEN}/llms-full.txt`,
146
+ "- Append `.md` to any page URL for raw markdown",
147
+ "",
148
+ "## Key Pages",
149
+ "",
150
+ ...topPages.map((page) => {
151
+ const desc = page.description ? ` - ${page.description}` : "";
152
+ return `- [${page.title}](${toUtilityTemplatedMarkdownDocUrl(page.slug)})${desc}`;
153
+ }),
154
+ ];
155
+ return [
156
+ {
157
+ content: sitemap,
158
+ contentType: "application/xml; charset=utf-8",
159
+ path: PREBUILT_UTILITY_SITEMAP_PATH,
160
+ },
161
+ {
162
+ content: llmsLines.filter((line) => line !== null).join("\n"),
163
+ contentType: "text/plain; charset=utf-8",
164
+ path: PREBUILT_UTILITY_LLMS_PATH,
165
+ },
166
+ {
167
+ content: llmsFull,
168
+ contentType: "text/plain; charset=utf-8",
169
+ path: PREBUILT_UTILITY_LLMS_FULL_PATH,
170
+ },
171
+ {
172
+ content: skillsIndex,
173
+ contentType: "application/json; charset=utf-8",
174
+ path: PREBUILT_UTILITY_SKILLS_INDEX_PATH,
175
+ },
176
+ {
177
+ content: skillMdLines.filter((line) => line !== null).join("\n"),
178
+ contentType: "text/markdown; charset=utf-8",
179
+ path: `${PREBUILT_UTILITY_SKILLS_MD_PREFIX}${skillSlug}/SKILL.md`,
180
+ },
181
+ ...segments.map((segment) => {
182
+ const segmentPages = index.pages.filter((page) => segment.pageSlugs.includes(page.slug));
183
+ const content = [
184
+ `# ${index.name} - ${segment.title}`,
185
+ `> Segment of ${UTILITY_DOCS_ROOT_TOKEN}/llms-full.txt`,
186
+ "",
187
+ ...segmentPages.map((page) => formatMarkdownPageSection(page.title, toUtilityTemplatedDocUrl(page.slug), prepareLlmsFullContent(page.content, UTILITY_DOCS_ROOT_TOKEN, ""), page.description)),
188
+ ].join("\n\n");
189
+ return {
190
+ content,
191
+ contentType: "text/plain; charset=utf-8",
192
+ path: `${PREBUILT_UTILITY_LLMS_SEGMENT_PREFIX}${segment.slug}.txt`,
193
+ };
194
+ }),
195
+ ...index.pages.map((page) => ({
196
+ content: formatMarkdownPage(page.title, toAgentMarkdown(page.content), page.description),
197
+ contentType: "text/markdown; charset=utf-8",
198
+ path: getPrebuiltUtilityLlmPagePath(page.slug),
199
+ })),
200
+ ];
201
+ };
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@repo/typescript-config": "*",
35
- "@types/node": "^22.19.15",
35
+ "@types/node": "^24.12.2",
36
36
  "oxfmt": "^0.42.0",
37
37
  "oxlint": "^1.57.0",
38
38
  "typescript": "6.0.2",
@@ -116,12 +116,27 @@ export class BlobContentSource implements ContentSource {
116
116
  const manifest = await this.loadManifest();
117
117
  const prefix = normalizeDirectory(directory);
118
118
 
119
- const files = [...manifest.keys()].filter((file) => {
120
- if (shouldIgnoreRootDocsFile(file)) {
121
- return false;
119
+ const files: string[] = [];
120
+ for (const file of manifest.keys()) {
121
+ if (prefix && !file.startsWith(prefix)) {
122
+ continue;
122
123
  }
123
- return prefix ? file.startsWith(prefix) : true;
124
- });
124
+ // Return paths relative to the listed directory, matching
125
+ // FsContentSource so callers can join them onto the collection root.
126
+ const relativePath = prefix ? file.slice(prefix.length) : file;
127
+ if (!relativePath) {
128
+ continue;
129
+ }
130
+ // Only top-level entries of the listed directory are subject to the
131
+ // root-docs-file ignore list, again matching FsContentSource.
132
+ if (
133
+ !relativePath.includes("/") &&
134
+ shouldIgnoreRootDocsFile(relativePath)
135
+ ) {
136
+ continue;
137
+ }
138
+ files.push(relativePath);
139
+ }
125
140
  // oxlint-disable-next-line eslint-plugin-unicorn/no-array-sort
126
141
  files.sort();
127
142
  return files;