@takazudo/zudo-doc 5.8.0 → 5.10.0

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 (104) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -1
  3. package/dist/chrome/derive.d.ts +1 -1
  4. package/dist/chrome/derive.js +24 -2
  5. package/dist/config-assertions/index.d.ts +30 -0
  6. package/dist/config-assertions/index.js +41 -1
  7. package/dist/config.d.ts +18 -0
  8. package/dist/config.js +1 -0
  9. package/dist/doc-content-header/index.js +6 -0
  10. package/dist/doc-metainfo-area/index.js +1 -14
  11. package/dist/doc-page-renderer/index.d.ts +3 -3
  12. package/dist/doc-page-renderer/index.js +1 -1
  13. package/dist/doc-page-shell/index.d.ts +6 -0
  14. package/dist/doc-pager/index.d.ts +6 -0
  15. package/dist/doc-pager/index.js +5 -2
  16. package/dist/docs-schema/index.d.ts +11 -0
  17. package/dist/docs-schema/index.js +8 -1
  18. package/dist/format-date/index.d.ts +12 -0
  19. package/dist/format-date/index.js +64 -0
  20. package/dist/frontmatter-preview-defaults/index.js +6 -1
  21. package/dist/header/header.js +9 -1
  22. package/dist/home-page/index.js +3 -1
  23. package/dist/html-preview-wrapper/highlight-runtime.d.ts +7 -7
  24. package/dist/html-preview-wrapper/highlight-runtime.js +1 -1
  25. package/dist/i18n-defaults/index.js +3 -0
  26. package/dist/integrations/changelog/emit.js +19 -2
  27. package/dist/mdx-components/index.d.ts +4 -1
  28. package/dist/mdx-components/index.js +3 -1
  29. package/dist/nav-indexing/index.d.ts +2 -0
  30. package/dist/nav-indexing/index.js +2 -0
  31. package/dist/nav-indexing/note-tray-index.d.ts +29 -0
  32. package/dist/nav-indexing/note-tray-index.js +120 -0
  33. package/dist/note-tray-index/index.d.ts +45 -0
  34. package/dist/note-tray-index/index.js +52 -0
  35. package/dist/note-tray-model/index.d.ts +31 -0
  36. package/dist/note-tray-model/index.js +74 -0
  37. package/dist/plugins/codex-resources.d.ts +4 -0
  38. package/dist/plugins/codex-resources.js +31 -0
  39. package/dist/plugins/internal/claude-resources/generate.js +20 -291
  40. package/dist/plugins/internal/codex-resources/agents-md.d.ts +6 -0
  41. package/dist/plugins/internal/codex-resources/agents-md.js +70 -0
  42. package/dist/plugins/internal/codex-resources/agents.d.ts +7 -0
  43. package/dist/plugins/internal/codex-resources/agents.js +104 -0
  44. package/dist/plugins/internal/codex-resources/config.d.ts +6 -0
  45. package/dist/plugins/internal/codex-resources/config.js +111 -0
  46. package/dist/plugins/internal/codex-resources/generate.d.ts +20 -0
  47. package/dist/plugins/internal/codex-resources/generate.js +34 -0
  48. package/dist/plugins/internal/codex-resources/hooks.d.ts +6 -0
  49. package/dist/plugins/internal/codex-resources/hooks.js +174 -0
  50. package/dist/plugins/internal/codex-resources/index.d.ts +24 -0
  51. package/dist/plugins/internal/codex-resources/index.js +21 -0
  52. package/dist/plugins/internal/codex-resources/overview.d.ts +10 -0
  53. package/dist/plugins/internal/codex-resources/overview.js +33 -0
  54. package/dist/plugins/internal/codex-resources/rules.d.ts +6 -0
  55. package/dist/plugins/internal/codex-resources/rules.js +255 -0
  56. package/dist/plugins/internal/codex-resources/skills.d.ts +2 -0
  57. package/dist/plugins/internal/codex-resources/skills.js +84 -0
  58. package/dist/plugins/internal/codex-resources/utils.d.ts +14 -0
  59. package/dist/plugins/internal/codex-resources/utils.js +80 -0
  60. package/dist/plugins/internal/resource-docs-shared/fs.d.ts +3 -0
  61. package/dist/plugins/internal/resource-docs-shared/fs.js +19 -0
  62. package/dist/plugins/internal/resource-docs-shared/index.d.ts +7 -0
  63. package/dist/plugins/internal/resource-docs-shared/index.js +44 -0
  64. package/dist/plugins/internal/resource-docs-shared/links.d.ts +22 -0
  65. package/dist/plugins/internal/resource-docs-shared/links.js +44 -0
  66. package/dist/plugins/internal/resource-docs-shared/markdown-structure.d.ts +9 -0
  67. package/dist/plugins/internal/resource-docs-shared/markdown-structure.js +22 -0
  68. package/dist/plugins/internal/resource-docs-shared/mdx.d.ts +23 -0
  69. package/dist/plugins/internal/resource-docs-shared/mdx.js +63 -0
  70. package/dist/plugins/internal/resource-docs-shared/skills.d.ts +37 -0
  71. package/dist/plugins/internal/resource-docs-shared/skills.js +318 -0
  72. package/dist/plugins/internal/resource-docs-shared/walk.d.ts +20 -0
  73. package/dist/plugins/internal/resource-docs-shared/walk.js +41 -0
  74. package/dist/preset.d.ts +19 -0
  75. package/dist/preset.js +16 -1
  76. package/dist/safelist.css +1 -1
  77. package/dist/settings.d.ts +5 -0
  78. package/dist/sidebar/types.d.ts +6 -0
  79. package/dist/sidebar-tree/build-tree.js +8 -0
  80. package/dist/sidebar-tree/types.d.ts +12 -0
  81. package/dist/sidebar-tree-island/index.js +175 -1
  82. package/dist/sidebar-utils/index.d.ts +6 -0
  83. package/dist/site-schema/doc-route-entries.js +2 -0
  84. package/dist/site-schema/index.d.ts +1 -0
  85. package/dist/site-schema/index.js +3 -1
  86. package/dist/site-schema/nav-tree.js +17 -2
  87. package/dist/site-schema/note-tray-validate.d.ts +7 -0
  88. package/dist/site-schema/note-tray-validate.js +94 -0
  89. package/dist/site-schema/types.d.ts +11 -0
  90. package/dist/site-tree-nav-island/index.d.ts +5 -1
  91. package/dist/site-tree-nav-island/index.js +119 -12
  92. package/dist/theme-packs/drift/pack.css +6 -1
  93. package/dist/theme-packs/hearth/pack.css +5 -0
  94. package/dist/theme-packs/sakura/pack.css +6 -0
  95. package/dist/theme-packs/scandi/pack.css +7 -7
  96. package/dist/theme-packs/timberline/pack.css +5 -0
  97. package/eject/doc-pager/index.tsx +9 -0
  98. package/eject/header/header.tsx +26 -1
  99. package/eject/sidebar/types.ts +6 -0
  100. package/eject/sidebar-tree-island/index.tsx +238 -6
  101. package/eject/site-tree-nav-island/index.tsx +166 -16
  102. package/package.json +25 -8
  103. /package/dist/plugins/internal/{claude-resources → resource-docs-shared}/escape-for-mdx.d.ts +0 -0
  104. /package/dist/plugins/internal/{claude-resources → resource-docs-shared}/escape-for-mdx.js +0 -0
@@ -1,133 +1,17 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import matter from "gray-matter";
4
- import { escapeForMdx } from "./escape-for-mdx.js";
5
- function ensureDir(dir) {
6
- if (!fs.existsSync(dir)) {
7
- fs.mkdirSync(dir, { recursive: true });
8
- }
9
- }
10
- function cleanDir(dir) {
11
- if (!fs.existsSync(dir)) return;
12
- fs.rmSync(dir, { recursive: true, force: true });
13
- }
14
- function parseFrontmatter(content) {
15
- try {
16
- return matter(content);
17
- } catch {
18
- return null;
19
- }
20
- }
21
- function escapeTitle(s) {
22
- return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
23
- }
24
- function listFiles(dir) {
25
- if (!fs.existsSync(dir)) return [];
26
- return fs.readdirSync(dir, { withFileTypes: true }).filter((d) => d.isFile()).map((d) => d.name).sort();
27
- }
28
- function writeCategoryIndex(outputDir, label, position, description) {
29
- const mdx = `---
30
- title: "${escapeTitle(label)}"
31
- description: "${escapeTitle(description)}"
32
- sidebar_position: ${position}
33
- category_no_page: true
34
- generated: true
35
- ---
36
- `;
37
- fs.writeFileSync(path.join(outputDir, "index.mdx"), mdx);
38
- }
39
- function writeUnlistedSubPage(outputPath, title, body) {
40
- fs.writeFileSync(
41
- outputPath,
42
- `---
43
- title: "${escapeTitle(title)}"
44
- unlisted: true
45
- generated: true
46
- ---
47
-
48
- ${body}
49
- `
50
- );
51
- }
52
- function assertNotIndexReserved(nameOrSlug, errorMessage) {
53
- if (nameOrSlug === "index") {
54
- throw new Error(errorMessage);
55
- }
56
- }
57
- function isRepoRelativeLink(url) {
58
- const trimmed = url.trim();
59
- if (trimmed === "") return false;
60
- if (trimmed.startsWith("#")) return false;
61
- if (trimmed.startsWith("/")) return false;
62
- if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return false;
63
- return true;
64
- }
65
- function downgradeRepoRelativeLinks(content) {
66
- const blockPlaceholder = "\0CRLINK_BLOCK_";
67
- const inlinePlaceholder = "\0CRLINK_INLINE_";
68
- const codeBlocks = [];
69
- const withBlocks = content.replace(/(`{3,}|~{3,})[^\n]*\n[\s\S]*?\1/g, (match) => {
70
- codeBlocks.push(match);
71
- return `${blockPlaceholder}${codeBlocks.length - 1}\0`;
72
- });
73
- const transformed = withBlocks.split(new RegExp(`(${blockPlaceholder}\\d+\0)`, "g")).map((part) => {
74
- if (new RegExp(`^${blockPlaceholder}\\d+\0$`).test(part)) return part;
75
- const inlineCodes = [];
76
- const withInline = part.replace(
77
- /(`{1,3})(?!`)([\s\S]*?[^`])\1(?!`)/g,
78
- (match) => {
79
- inlineCodes.push(match);
80
- return `${inlinePlaceholder}${inlineCodes.length - 1}\0`;
81
- }
82
- );
83
- const rewritten = withInline.replace(
84
- /!?\[([^\]]*)\]\(([^)]+)\)/g,
85
- (match, text, url) => isRepoRelativeLink(url) ? `\`${text}\`` : match
86
- );
87
- return rewritten.replace(
88
- new RegExp(`${inlinePlaceholder}(\\d+)\0`, "g"),
89
- (_, idx) => inlineCodes[Number(idx)] ?? ""
90
- );
91
- }).join("");
92
- return transformed.replace(
93
- new RegExp(`${blockPlaceholder}(\\d+)\0`, "g"),
94
- (_, idx) => codeBlocks[Number(idx)] ?? ""
95
- );
96
- }
97
- const EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([
98
- "node_modules",
99
- "worktrees",
100
- "dist",
101
- "out",
102
- "public",
103
- "__inbox",
104
- "test-results"
105
- ]);
106
- function findClaudeMdFiles(dir, excludeDirs) {
107
- const results = [];
108
- if (!fs.existsSync(dir)) return results;
109
- const excludes = excludeDirs.map(
110
- (d) => d.endsWith(path.sep) ? d.slice(0, -path.sep.length) : d
111
- );
112
- for (const item of fs.readdirSync(dir)) {
113
- if (EXCLUDED_DIR_NAMES.has(item)) continue;
114
- if (item.startsWith(".")) continue;
115
- const itemPath = path.join(dir, item);
116
- if (excludes.some((d) => itemPath === d || itemPath.startsWith(d + path.sep))) continue;
117
- let stat;
118
- try {
119
- stat = fs.lstatSync(itemPath);
120
- } catch {
121
- continue;
122
- }
123
- if (stat.isDirectory()) {
124
- results.push(...findClaudeMdFiles(itemPath, excludes));
125
- } else if (stat.isFile() && item === "CLAUDE.md") {
126
- results.push(itemPath);
127
- }
128
- }
129
- return results;
130
- }
3
+ import {
4
+ assertNotIndexReserved,
5
+ cleanDir,
6
+ downgradeRepoRelativeLinks,
7
+ ensureDir,
8
+ escapeForMdx,
9
+ escapeTitle,
10
+ findNamedFiles,
11
+ generateSkillsCategory,
12
+ parseFrontmatter,
13
+ writeCategoryIndex
14
+ } from "../resource-docs-shared/index.js";
131
15
  function generateClaudemdDocs(config) {
132
16
  const projectRoot = config.projectRoot ?? config.claudeDir;
133
17
  const scanRoot = config.scanRoot ?? projectRoot;
@@ -138,7 +22,7 @@ function generateClaudemdDocs(config) {
138
22
  path.join(projectRoot, "e2e", "fixtures"),
139
23
  path.join(config.docsDir)
140
24
  ];
141
- const files = findClaudeMdFiles(scanRoot, excludeDirs);
25
+ const files = findNamedFiles(scanRoot, excludeDirs, ["CLAUDE.md"]);
142
26
  if (files.length === 0) return [];
143
27
  ensureDir(outputDir);
144
28
  const items = [];
@@ -220,170 +104,15 @@ ${escapeForMdx(parsed.content.trim())}
220
104
  writeCategoryIndex(outputDir, "Commands", 901, "Custom slash commands");
221
105
  return items;
222
106
  }
223
- function getSkillFileTree(skillDir, subDirs) {
224
- const lines = [`${skillDir}/`];
225
- const entries = [{ isDir: false, name: "SKILL.md" }];
226
- for (const sub of subDirs) {
227
- entries.push({ isDir: true, name: sub.name, children: sub.files });
228
- }
229
- for (let i = 0; i < entries.length; i++) {
230
- const entry = entries[i];
231
- if (!entry) continue;
232
- const isLast = i === entries.length - 1;
233
- const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
234
- if (!entry.isDir) {
235
- lines.push(`${prefix}${entry.name}`);
236
- } else {
237
- lines.push(`${prefix}${entry.name}/`);
238
- for (let j = 0; j < entry.children.length; j++) {
239
- const child = entry.children[j];
240
- if (!child) continue;
241
- const childIsLast = j === entry.children.length - 1;
242
- const continuation = isLast ? " " : "\u2502 ";
243
- const childPrefix = childIsLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
244
- lines.push(`${continuation}${childPrefix}${child}`);
245
- }
246
- }
247
- }
248
- return lines.join("\n");
249
- }
250
- function getScriptDescription(filePath) {
251
- try {
252
- const topLines = fs.readFileSync(filePath, "utf8").split("\n", 2);
253
- const firstLine = topLines[0] ?? "";
254
- const commentLine = firstLine.startsWith("#!") ? topLines[1] ?? "" : firstLine;
255
- const match = commentLine.match(/^(?:#|\/\/)\s*(.+)/);
256
- return match ? ` \u2014 ${match[1]}` : "";
257
- } catch {
258
- return "";
259
- }
260
- }
261
- function getSkillReferences(skillsDir, skillDir) {
262
- const refsDir = path.join(skillsDir, skillDir, "references");
263
- if (!fs.existsSync(refsDir)) return [];
264
- return fs.readdirSync(refsDir).filter((f) => f.endsWith(".md")).map((f) => {
265
- const content = fs.readFileSync(path.join(refsDir, f), "utf8");
266
- const name = f.replace(/\.md$/, "");
267
- const h1Match = content.match(/^#\s+(.+)$/m);
268
- const title = h1Match?.[1] ?? name;
269
- return { name, title, content };
270
- }).sort((a, b) => a.name.localeCompare(b.name));
271
- }
272
107
  function generateSkillsDocs(config) {
273
- const skillsDir = path.join(config.claudeDir, "skills");
274
- const outputDir = path.join(config.docsDir, "claude-skills");
275
- cleanDir(outputDir);
276
- if (!fs.existsSync(skillsDir)) return [];
277
- const dirs = fs.readdirSync(skillsDir).filter((d) => {
278
- const skillPath = path.join(skillsDir, d);
279
- return fs.statSync(skillPath).isDirectory() && fs.existsSync(path.join(skillPath, "SKILL.md"));
108
+ return generateSkillsCategory({
109
+ skillsDirs: [path.join(config.claudeDir, "skills")],
110
+ outputDir: path.join(config.docsDir, "claude-skills"),
111
+ label: "Skills",
112
+ position: 902,
113
+ description: "Skill packages",
114
+ sourceLabel: ".claude/skills"
280
115
  });
281
- if (dirs.length === 0) return [];
282
- ensureDir(outputDir);
283
- const items = [];
284
- for (const dir of dirs) {
285
- assertNotIndexReserved(
286
- dir,
287
- `claude-resources: skill directory ".claude/skills/index/" uses the reserved name "index", which is used for the category metadata file. Rename the skill directory to resolve the conflict.`
288
- );
289
- const content = fs.readFileSync(
290
- path.join(skillsDir, dir, "SKILL.md"),
291
- "utf8"
292
- );
293
- const parsed = parseFrontmatter(content);
294
- if (!parsed) continue;
295
- const name = parsed.data.name || dir;
296
- const description = parsed.data.description || "";
297
- const references = getSkillReferences(skillsDir, dir);
298
- items.push({ name, dir, description, references });
299
- const scriptFiles = listFiles(path.join(skillsDir, dir, "scripts"));
300
- const assetFiles = listFiles(path.join(skillsDir, dir, "assets"));
301
- const refFiles = references.map((r) => `${r.name}.md`);
302
- const subDirs = [];
303
- if (scriptFiles.length > 0) subDirs.push({ name: "scripts", files: scriptFiles });
304
- if (refFiles.length > 0) subDirs.push({ name: "references", files: refFiles });
305
- if (assetFiles.length > 0) subDirs.push({ name: "assets", files: assetFiles });
306
- let fileStructureSection = "";
307
- if (subDirs.length > 0) {
308
- const tree = `\`\`\`
309
- ${getSkillFileTree(dir, subDirs)}
310
- \`\`\``;
311
- const links = [];
312
- for (const ref of references) {
313
- links.push(`- [references/${ref.name}.md](./ref-${ref.name})`);
314
- }
315
- for (const f of scriptFiles.filter((s) => s.endsWith(".md"))) {
316
- const slug = f.replace(/\.md$/, "");
317
- links.push(`- [scripts/${f}](./script-${slug})`);
318
- }
319
- for (const f of assetFiles.filter((a) => a.endsWith(".md"))) {
320
- const slug = f.replace(/\.md$/, "");
321
- links.push(`- [assets/${f}](./asset-${slug})`);
322
- }
323
- const linkList = links.length > 0 ? `
324
-
325
- ${links.join("\n")}` : "";
326
- fileStructureSection = `## File Structure
327
-
328
- ${tree}${linkList}`;
329
- }
330
- const shortDesc = description.length > 200 ? description.substring(0, 200) + "..." : description;
331
- let skillBody = parsed.content.trim();
332
- skillBody = skillBody.replace(/\]\(references\/([^)]+)\.md\)/g, "](./ref-$1)").replace(/\]\(scripts\/([^)]+)\.md\)/g, "](./script-$1)").replace(/\]\(assets\/([^)]+)\.md\)/g, "](./asset-$1)");
333
- const body = [
334
- fileStructureSection,
335
- escapeForMdx(skillBody)
336
- ].filter(Boolean).join("\n\n");
337
- const mdx = `---
338
- title: "${escapeTitle(name)}"
339
- description: "${escapeTitle(shortDesc)}"
340
- sidebar_label: "${escapeTitle(name)}"
341
- generated: true
342
- ---
343
-
344
- ${body}`;
345
- const skillDirOut = path.join(outputDir, dir);
346
- ensureDir(skillDirOut);
347
- fs.writeFileSync(path.join(skillDirOut, "index.mdx"), mdx);
348
- for (const ref of references) {
349
- writeUnlistedSubPage(
350
- path.join(skillDirOut, `ref-${ref.name}.mdx`),
351
- ref.title,
352
- escapeForMdx(ref.content.trim())
353
- );
354
- }
355
- for (const f of scriptFiles.filter((s) => s.endsWith(".md"))) {
356
- const slug = f.replace(/\.md$/, "");
357
- const raw = fs.readFileSync(
358
- path.join(skillsDir, dir, "scripts", f),
359
- "utf8"
360
- );
361
- const h1Match = raw.match(/^#\s+(.+)$/m);
362
- const title = h1Match?.[1] ?? slug;
363
- writeUnlistedSubPage(
364
- path.join(skillDirOut, `script-${slug}.mdx`),
365
- title,
366
- escapeForMdx(raw.trim())
367
- );
368
- }
369
- for (const f of assetFiles.filter((a) => a.endsWith(".md"))) {
370
- const slug = f.replace(/\.md$/, "");
371
- const raw = fs.readFileSync(
372
- path.join(skillsDir, dir, "assets", f),
373
- "utf8"
374
- );
375
- const h1Match = raw.match(/^#\s+(.+)$/m);
376
- const title = h1Match?.[1] ?? slug;
377
- writeUnlistedSubPage(
378
- path.join(skillDirOut, `asset-${slug}.mdx`),
379
- title,
380
- escapeForMdx(raw.trim())
381
- );
382
- }
383
- }
384
- items.sort((a, b) => a.name.localeCompare(b.name));
385
- writeCategoryIndex(outputDir, "Skills", 902, "Skill packages");
386
- return items;
387
116
  }
388
117
  function generateAgentsDocs(config) {
389
118
  const agentsDir = path.join(config.claudeDir, "agents");
@@ -0,0 +1,6 @@
1
+ import type { CodexResourcesConfig } from "./generate.js";
2
+ export interface AgentsMdItem {
3
+ relPath: string;
4
+ slug: string;
5
+ }
6
+ export declare function generateAgentsMdCategory(config: CodexResourcesConfig): AgentsMdItem[];
@@ -0,0 +1,70 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {
4
+ formatFrontmatterString,
5
+ cleanDir,
6
+ downgradeRepoRelativeLinks,
7
+ ensureDir,
8
+ escapeForMdx,
9
+ escapeMarkdownTableCell,
10
+ findNamedFiles,
11
+ writeCategoryIndex
12
+ } from "../resource-docs-shared/index.js";
13
+ import { assertUniqueSlug, writeGeneratedPage } from "./utils.js";
14
+ function generateAgentsMdCategory(config) {
15
+ const projectRoot = config.projectRoot ?? config.codexDir;
16
+ const scanRoot = config.scanRoot ?? projectRoot;
17
+ const outputDir = path.join(config.docsDir, "codex-agents-md");
18
+ cleanDir(outputDir);
19
+ const excludeDirs = [
20
+ path.join(scanRoot, "e2e", "fixtures"),
21
+ path.join(projectRoot, "e2e", "fixtures"),
22
+ config.docsDir
23
+ ];
24
+ const files = findNamedFiles(scanRoot, excludeDirs, [
25
+ "AGENTS.md",
26
+ "AGENTS.override.md"
27
+ ]);
28
+ if (files.length === 0) return [];
29
+ const items = files.map((absPath) => {
30
+ const relPath = path.relative(scanRoot, absPath);
31
+ const dirPart = path.dirname(relPath);
32
+ const baseSlug = dirPart === "." ? "root" : dirPart.split(path.sep).join("--");
33
+ const slug = path.basename(absPath) === "AGENTS.override.md" ? `${baseSlug}--override` : baseSlug;
34
+ return { absPath, relPath, slug };
35
+ });
36
+ items.sort((a, b) => {
37
+ if (a.slug === "root") return -1;
38
+ if (b.slug === "root") return 1;
39
+ return a.relPath.localeCompare(b.relPath);
40
+ });
41
+ ensureDir(outputDir);
42
+ const emitted = /* @__PURE__ */ new Map();
43
+ items.forEach((item, index) => {
44
+ assertUniqueSlug("AGENTS.md", item.slug, item.relPath, emitted);
45
+ const content = fs.readFileSync(item.absPath, "utf8");
46
+ writeGeneratedPage({
47
+ outputPath: path.join(outputDir, `${item.slug}.mdx`),
48
+ title: `/${item.relPath}`,
49
+ description: `Codex instructions at /${item.relPath}`,
50
+ sidebarPosition: index + 1,
51
+ sidebarLabel: item.relPath,
52
+ body: `**Path:** ${escapeMarkdownTableCell(item.relPath)}
53
+
54
+ ${escapeForMdx(
55
+ downgradeRepoRelativeLinks(content.trim())
56
+ )}`
57
+ });
58
+ });
59
+ writeCategoryIndex(
60
+ outputDir,
61
+ "AGENTS.md",
62
+ 905,
63
+ "Project instructions for Codex",
64
+ formatFrontmatterString
65
+ );
66
+ return items.map(({ relPath, slug }) => ({ relPath, slug }));
67
+ }
68
+ export {
69
+ generateAgentsMdCategory
70
+ };
@@ -0,0 +1,7 @@
1
+ import type { CodexResourcesConfig } from "./generate.js";
2
+ export interface AgentItem {
3
+ filename: string;
4
+ slug: string;
5
+ name: string;
6
+ }
7
+ export declare function generateAgentsCategory(config: CodexResourcesConfig): AgentItem[];
@@ -0,0 +1,104 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { parse } from "smol-toml";
4
+ import {
5
+ formatFrontmatterString,
6
+ cleanDir,
7
+ ensureDir,
8
+ escapeForMdx,
9
+ escapeMarkdownTableCell,
10
+ renderCodeFence,
11
+ writeCategoryIndex
12
+ } from "../resource-docs-shared/index.js";
13
+ import {
14
+ assertUniqueSlug,
15
+ filenameSlug,
16
+ isRecord,
17
+ warn,
18
+ writeGeneratedPage
19
+ } from "./utils.js";
20
+ function optionalString(record, field, filePath) {
21
+ const value = record[field];
22
+ if (value === void 0) return void 0;
23
+ if (typeof value === "string") return value;
24
+ warn(filePath, `${field} must be a string; omitting it`);
25
+ return void 0;
26
+ }
27
+ function generateAgentsCategory(config) {
28
+ const agentsDir = path.join(config.codexDir, "agents");
29
+ const outputDir = path.join(config.docsDir, "codex-agents");
30
+ cleanDir(outputDir);
31
+ if (!fs.existsSync(agentsDir)) return [];
32
+ let files;
33
+ try {
34
+ files = fs.readdirSync(agentsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".toml")).map((entry) => entry.name).sort();
35
+ } catch (error) {
36
+ warn(agentsDir, `unable to read agents directory: ${String(error)}`);
37
+ return [];
38
+ }
39
+ if (files.length === 0) return [];
40
+ ensureDir(outputDir);
41
+ const items = [];
42
+ const emitted = /* @__PURE__ */ new Map();
43
+ for (const filename of files) {
44
+ const filePath = path.join(agentsDir, filename);
45
+ let source;
46
+ let parsed;
47
+ try {
48
+ source = fs.readFileSync(filePath, "utf8");
49
+ parsed = parse(source);
50
+ } catch (error) {
51
+ warn(filePath, `unable to parse TOML, skipping file: ${String(error)}`);
52
+ continue;
53
+ }
54
+ if (!isRecord(parsed)) {
55
+ warn(filePath, "parsed TOML root was not an object, skipping file");
56
+ continue;
57
+ }
58
+ const slug = filenameSlug(filename.replace(/\.toml$/, ""));
59
+ assertUniqueSlug("agent", slug, filename, emitted);
60
+ const name = optionalString(parsed, "name", filePath) ?? slug;
61
+ const description = optionalString(parsed, "description", filePath) ?? "";
62
+ const model = optionalString(parsed, "model", filePath);
63
+ const reasoning = optionalString(parsed, "model_reasoning_effort", filePath);
64
+ const sandbox = optionalString(parsed, "sandbox_mode", filePath);
65
+ const instructions = optionalString(parsed, "developer_instructions", filePath);
66
+ const badges = [
67
+ model ? `**Model:** ${escapeMarkdownTableCell(model)}` : "",
68
+ reasoning ? `**Reasoning effort:** ${escapeMarkdownTableCell(reasoning)}` : "",
69
+ sandbox ? `**Sandbox:** ${escapeMarkdownTableCell(sandbox)}` : ""
70
+ ].filter(Boolean);
71
+ const sections = [badges.join("\n")];
72
+ if (instructions !== void 0) {
73
+ sections.push(
74
+ `## Developer instructions
75
+
76
+ ${escapeForMdx(instructions.trim())}`
77
+ );
78
+ }
79
+ sections.push(`## Source
80
+
81
+ ${renderCodeFence(source, "toml")}`);
82
+ writeGeneratedPage({
83
+ outputPath: path.join(outputDir, `${slug}.mdx`),
84
+ title: name,
85
+ description,
86
+ sidebarLabel: name,
87
+ body: sections.filter(Boolean).join("\n\n")
88
+ });
89
+ items.push({ filename, slug, name });
90
+ }
91
+ if (items.length > 0) {
92
+ writeCategoryIndex(
93
+ outputDir,
94
+ "Agents",
95
+ 907,
96
+ "Custom subagents",
97
+ formatFrontmatterString
98
+ );
99
+ }
100
+ return items;
101
+ }
102
+ export {
103
+ generateAgentsCategory
104
+ };
@@ -0,0 +1,6 @@
1
+ import type { CodexResourcesConfig } from "./generate.js";
2
+ export interface ConfigItem {
3
+ filename: string;
4
+ slug: string;
5
+ }
6
+ export declare function generateConfigCategory(config: CodexResourcesConfig): ConfigItem[];
@@ -0,0 +1,111 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { parse, TomlDate } from "smol-toml";
4
+ import {
5
+ formatFrontmatterString,
6
+ cleanDir,
7
+ ensureDir,
8
+ escapeMarkdownTableCell,
9
+ renderCodeFence,
10
+ writeCategoryIndex
11
+ } from "../resource-docs-shared/index.js";
12
+ import {
13
+ assertUniqueSlug,
14
+ filenameSlug,
15
+ isRecord,
16
+ renderTableRow,
17
+ warn,
18
+ writeGeneratedPage
19
+ } from "./utils.js";
20
+ function configFiles(codexDir) {
21
+ try {
22
+ return fs.readdirSync(codexDir, { withFileTypes: true }).filter(
23
+ (entry) => entry.isFile() && (entry.name === "config.toml" || entry.name === "config.toml.example" || entry.name.endsWith(".config.toml"))
24
+ ).map((entry) => entry.name).sort((a, b) => {
25
+ if (a === "config.toml") return -1;
26
+ if (b === "config.toml") return 1;
27
+ return a.localeCompare(b);
28
+ });
29
+ } catch (error) {
30
+ warn(codexDir, `unable to read config files: ${String(error)}`);
31
+ return [];
32
+ }
33
+ }
34
+ function renderValue(value) {
35
+ if (typeof value === "string") return value;
36
+ if (typeof value === "number" || typeof value === "boolean") {
37
+ return String(value);
38
+ }
39
+ if (Array.isArray(value)) return JSON.stringify(value);
40
+ if (value instanceof TomlDate) return value.toISOString();
41
+ return String(value);
42
+ }
43
+ function generateConfigCategory(config) {
44
+ const outputDir = path.join(config.docsDir, "codex-config");
45
+ cleanDir(outputDir);
46
+ if (!fs.existsSync(config.codexDir)) return [];
47
+ const files = configFiles(config.codexDir);
48
+ if (files.length === 0) return [];
49
+ ensureDir(outputDir);
50
+ const items = [];
51
+ const emitted = /* @__PURE__ */ new Map();
52
+ for (const filename of files) {
53
+ const filePath = path.join(config.codexDir, filename);
54
+ let source;
55
+ let parsed;
56
+ try {
57
+ source = fs.readFileSync(filePath, "utf8");
58
+ parsed = parse(source);
59
+ } catch (error) {
60
+ warn(filePath, `unable to parse TOML, skipping file: ${String(error)}`);
61
+ continue;
62
+ }
63
+ if (!isRecord(parsed)) {
64
+ warn(filePath, "parsed TOML root was not an object, skipping file");
65
+ continue;
66
+ }
67
+ const slug = filenameSlug(filename);
68
+ assertUniqueSlug("config", slug, filename, emitted);
69
+ const settings = Object.entries(parsed).filter(([, value]) => !isRecord(value) || value instanceof TomlDate).map(([key, value]) => renderTableRow([key, renderValue(value)]));
70
+ const sections = source.match(/^\s*\[\[?[^\]]+\]\]?/gm) ?? [];
71
+ const sectionList = sections.length === 0 ? "\u2014" : sections.map(
72
+ (section) => `- ${escapeMarkdownTableCell(section.trim())}`
73
+ ).join("\n");
74
+ const body = [
75
+ "## Settings",
76
+ "",
77
+ "| Key | Value |",
78
+ "| --- | --- |",
79
+ ...settings.length > 0 ? settings : [renderTableRow([void 0, void 0])],
80
+ "",
81
+ "## Sections",
82
+ "",
83
+ sectionList,
84
+ "",
85
+ "## Source",
86
+ "",
87
+ renderCodeFence(source, "toml")
88
+ ].join("\n");
89
+ writeGeneratedPage({
90
+ outputPath: path.join(outputDir, `${slug}.mdx`),
91
+ title: filename,
92
+ description: `Codex configuration from ${filename}`,
93
+ sidebarLabel: filename,
94
+ body
95
+ });
96
+ items.push({ filename, slug });
97
+ }
98
+ if (items.length > 0) {
99
+ writeCategoryIndex(
100
+ outputDir,
101
+ "Config",
102
+ 906,
103
+ "config.toml and profiles",
104
+ formatFrontmatterString
105
+ );
106
+ }
107
+ return items;
108
+ }
109
+ export {
110
+ generateConfigCategory
111
+ };
@@ -0,0 +1,20 @@
1
+ export interface CodexResourcesConfig {
2
+ codexDir: string;
3
+ /** The doc site's own root and the default value of `scanRoot`. */
4
+ projectRoot?: string;
5
+ /**
6
+ * Repo-wide discovery root for both the AGENTS.md walk and the repo-level
7
+ * `.agents/skills/` root. Also serves as the relative-path base for the
8
+ * generated AGENTS.md titles and slugs. Defaults to `projectRoot`.
9
+ */
10
+ scanRoot?: string;
11
+ docsDir: string;
12
+ }
13
+ export declare function generateCodexResourcesDocs(config: CodexResourcesConfig): {
14
+ agentsMd: number;
15
+ config: number;
16
+ agents: number;
17
+ hooks: number;
18
+ rules: number;
19
+ skills: number;
20
+ };