@takazudo/zudo-doc 0.1.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 (255) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -0
  3. package/dist/body-foot-util/body-foot-util-area.d.ts +55 -0
  4. package/dist/body-foot-util/body-foot-util-area.js +71 -0
  5. package/dist/body-foot-util/edit-link.d.ts +45 -0
  6. package/dist/body-foot-util/edit-link.js +42 -0
  7. package/dist/body-foot-util/index.d.ts +3 -0
  8. package/dist/body-foot-util/index.js +11 -0
  9. package/dist/breadcrumb/breadcrumb.d.ts +57 -0
  10. package/dist/breadcrumb/breadcrumb.js +113 -0
  11. package/dist/breadcrumb/find-path.d.ts +16 -0
  12. package/dist/breadcrumb/find-path.js +13 -0
  13. package/dist/breadcrumb/index.d.ts +4 -0
  14. package/dist/breadcrumb/index.js +7 -0
  15. package/dist/breadcrumb/types.d.ts +32 -0
  16. package/dist/breadcrumb/types.js +0 -0
  17. package/dist/code-syntax/code-block-enhancer-script.d.ts +3 -0
  18. package/dist/code-syntax/code-block-enhancer-script.js +165 -0
  19. package/dist/code-syntax/code-block-enhancer.d.ts +22 -0
  20. package/dist/code-syntax/code-block-enhancer.js +13 -0
  21. package/dist/code-syntax/index.d.ts +8 -0
  22. package/dist/code-syntax/index.js +29 -0
  23. package/dist/code-syntax/mermaid-init-script.d.ts +51 -0
  24. package/dist/code-syntax/mermaid-init-script.js +225 -0
  25. package/dist/code-syntax/mermaid-init.d.ts +48 -0
  26. package/dist/code-syntax/mermaid-init.js +14 -0
  27. package/dist/code-syntax/tabs-init-script.d.ts +3 -0
  28. package/dist/code-syntax/tabs-init-script.js +106 -0
  29. package/dist/code-syntax/tabs-init.d.ts +24 -0
  30. package/dist/code-syntax/tabs-init.js +10 -0
  31. package/dist/code-syntax/tabs.d.ts +36 -0
  32. package/dist/code-syntax/tabs.js +62 -0
  33. package/dist/content/component-map.d.ts +51 -0
  34. package/dist/content/component-map.js +29 -0
  35. package/dist/content/content-blockquote.d.ts +11 -0
  36. package/dist/content/content-blockquote.js +14 -0
  37. package/dist/content/content-code.d.ts +26 -0
  38. package/dist/content/content-code.js +39 -0
  39. package/dist/content/content-link.d.ts +12 -0
  40. package/dist/content/content-link.js +43 -0
  41. package/dist/content/content-ol.d.ts +11 -0
  42. package/dist/content/content-ol.js +15 -0
  43. package/dist/content/content-paragraph.d.ts +10 -0
  44. package/dist/content/content-paragraph.js +7 -0
  45. package/dist/content/content-strong.d.ts +11 -0
  46. package/dist/content/content-strong.js +14 -0
  47. package/dist/content/content-table.d.ts +11 -0
  48. package/dist/content/content-table.js +14 -0
  49. package/dist/content/content-ul.d.ts +11 -0
  50. package/dist/content/content-ul.js +15 -0
  51. package/dist/content/heading-h2.d.ts +14 -0
  52. package/dist/content/heading-h2.js +18 -0
  53. package/dist/content/heading-h3.d.ts +14 -0
  54. package/dist/content/heading-h3.js +18 -0
  55. package/dist/content/heading-h4.d.ts +14 -0
  56. package/dist/content/heading-h4.js +18 -0
  57. package/dist/content/index.d.ts +13 -0
  58. package/dist/content/index.js +27 -0
  59. package/dist/details/details.d.ts +26 -0
  60. package/dist/details/details.js +10 -0
  61. package/dist/details/index.d.ts +2 -0
  62. package/dist/details/index.js +4 -0
  63. package/dist/doclayout/anchors.d.ts +55 -0
  64. package/dist/doclayout/anchors.js +42 -0
  65. package/dist/doclayout/doc-layout-with-defaults.d.ts +83 -0
  66. package/dist/doclayout/doc-layout-with-defaults.js +159 -0
  67. package/dist/doclayout/doc-layout.d.ts +121 -0
  68. package/dist/doclayout/doc-layout.js +89 -0
  69. package/dist/doclayout/index.d.ts +6 -0
  70. package/dist/doclayout/index.js +17 -0
  71. package/dist/footer/footer.d.ts +42 -0
  72. package/dist/footer/footer.js +79 -0
  73. package/dist/footer/index.d.ts +3 -0
  74. package/dist/footer/index.js +4 -0
  75. package/dist/footer/types.d.ts +58 -0
  76. package/dist/footer/types.js +0 -0
  77. package/dist/head/doc-head.d.ts +33 -0
  78. package/dist/head/doc-head.js +90 -0
  79. package/dist/head/index.d.ts +5 -0
  80. package/dist/head/index.js +8 -0
  81. package/dist/head/og-tags.d.ts +25 -0
  82. package/dist/head/og-tags.js +16 -0
  83. package/dist/head/twitter-card.d.ts +21 -0
  84. package/dist/head/twitter-card.js +14 -0
  85. package/dist/head/types.d.ts +83 -0
  86. package/dist/head/types.js +0 -0
  87. package/dist/header/header.d.ts +158 -0
  88. package/dist/header/header.js +367 -0
  89. package/dist/header/index.d.ts +6 -0
  90. package/dist/header/index.js +18 -0
  91. package/dist/header/nav-active.d.ts +39 -0
  92. package/dist/header/nav-active.js +24 -0
  93. package/dist/header/nav-overflow-script.d.ts +3 -0
  94. package/dist/header/nav-overflow-script.js +169 -0
  95. package/dist/header/right-items.d.ts +38 -0
  96. package/dist/header/right-items.js +30 -0
  97. package/dist/header/types.d.ts +40 -0
  98. package/dist/header/types.js +0 -0
  99. package/dist/html-preview-wrapper/dedent.d.ts +10 -0
  100. package/dist/html-preview-wrapper/dedent.js +16 -0
  101. package/dist/html-preview-wrapper/highlighted-code.d.ts +18 -0
  102. package/dist/html-preview-wrapper/highlighted-code.js +53 -0
  103. package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +60 -0
  104. package/dist/html-preview-wrapper/html-preview-wrapper.js +36 -0
  105. package/dist/html-preview-wrapper/html-preview.d.ts +35 -0
  106. package/dist/html-preview-wrapper/html-preview.js +75 -0
  107. package/dist/html-preview-wrapper/index.d.ts +5 -0
  108. package/dist/html-preview-wrapper/index.js +12 -0
  109. package/dist/html-preview-wrapper/preflight.d.ts +13 -0
  110. package/dist/html-preview-wrapper/preflight.js +108 -0
  111. package/dist/html-preview-wrapper/preview-base.d.ts +29 -0
  112. package/dist/html-preview-wrapper/preview-base.js +127 -0
  113. package/dist/i18n-version/index.d.ts +5 -0
  114. package/dist/i18n-version/index.js +14 -0
  115. package/dist/i18n-version/language-switcher.d.ts +24 -0
  116. package/dist/i18n-version/language-switcher.js +25 -0
  117. package/dist/i18n-version/types.d.ts +43 -0
  118. package/dist/i18n-version/types.js +0 -0
  119. package/dist/i18n-version/version-banner.d.ts +30 -0
  120. package/dist/i18n-version/version-banner.js +21 -0
  121. package/dist/i18n-version/version-switcher.d.ts +112 -0
  122. package/dist/i18n-version/version-switcher.js +157 -0
  123. package/dist/index.d.ts +2 -0
  124. package/dist/index.js +0 -0
  125. package/dist/integrations/claude-resources/escape-for-mdx.d.ts +8 -0
  126. package/dist/integrations/claude-resources/escape-for-mdx.js +131 -0
  127. package/dist/integrations/claude-resources/generate.d.ts +13 -0
  128. package/dist/integrations/claude-resources/generate.js +404 -0
  129. package/dist/integrations/claude-resources/index.d.ts +46 -0
  130. package/dist/integrations/claude-resources/index.js +24 -0
  131. package/dist/integrations/doc-history/index.d.ts +137 -0
  132. package/dist/integrations/doc-history/index.js +138 -0
  133. package/dist/integrations/doc-history/pre-build.d.ts +58 -0
  134. package/dist/integrations/doc-history/pre-build.js +67 -0
  135. package/dist/integrations/llms-txt/dev-middleware.d.ts +40 -0
  136. package/dist/integrations/llms-txt/dev-middleware.js +76 -0
  137. package/dist/integrations/llms-txt/emit.d.ts +22 -0
  138. package/dist/integrations/llms-txt/emit.js +55 -0
  139. package/dist/integrations/llms-txt/generate.d.ts +26 -0
  140. package/dist/integrations/llms-txt/generate.js +36 -0
  141. package/dist/integrations/llms-txt/index.d.ts +7 -0
  142. package/dist/integrations/llms-txt/index.js +27 -0
  143. package/dist/integrations/llms-txt/load.d.ts +51 -0
  144. package/dist/integrations/llms-txt/load.js +83 -0
  145. package/dist/integrations/llms-txt/strip.d.ts +22 -0
  146. package/dist/integrations/llms-txt/strip.js +10 -0
  147. package/dist/integrations/llms-txt/types.d.ts +145 -0
  148. package/dist/integrations/llms-txt/types.js +0 -0
  149. package/dist/integrations/search-index/build-emitter.d.ts +30 -0
  150. package/dist/integrations/search-index/build-emitter.js +15 -0
  151. package/dist/integrations/search-index/collect.d.ts +12 -0
  152. package/dist/integrations/search-index/collect.js +48 -0
  153. package/dist/integrations/search-index/content-files.d.ts +32 -0
  154. package/dist/integrations/search-index/content-files.js +50 -0
  155. package/dist/integrations/search-index/dev-middleware.d.ts +16 -0
  156. package/dist/integrations/search-index/dev-middleware.js +30 -0
  157. package/dist/integrations/search-index/index.d.ts +5 -0
  158. package/dist/integrations/search-index/index.js +14 -0
  159. package/dist/integrations/search-index/types.d.ts +38 -0
  160. package/dist/integrations/search-index/types.js +6 -0
  161. package/dist/metainfo/doc-metainfo.d.ts +50 -0
  162. package/dist/metainfo/doc-metainfo.js +107 -0
  163. package/dist/metainfo/doc-tags.d.ts +66 -0
  164. package/dist/metainfo/doc-tags.js +53 -0
  165. package/dist/metainfo/frontmatter-preview.d.ts +95 -0
  166. package/dist/metainfo/frontmatter-preview.js +55 -0
  167. package/dist/metainfo/index.d.ts +4 -0
  168. package/dist/metainfo/index.js +28 -0
  169. package/dist/nav-indexing/category-nav.d.ts +28 -0
  170. package/dist/nav-indexing/category-nav.js +41 -0
  171. package/dist/nav-indexing/category-tree-nav.d.ts +27 -0
  172. package/dist/nav-indexing/category-tree-nav.js +49 -0
  173. package/dist/nav-indexing/doc-card-grid.d.ts +38 -0
  174. package/dist/nav-indexing/doc-card-grid.js +40 -0
  175. package/dist/nav-indexing/docs-sitemap.d.ts +25 -0
  176. package/dist/nav-indexing/docs-sitemap.js +40 -0
  177. package/dist/nav-indexing/index.d.ts +10 -0
  178. package/dist/nav-indexing/index.js +18 -0
  179. package/dist/nav-indexing/nav-card-grid.d.ts +31 -0
  180. package/dist/nav-indexing/nav-card-grid.js +43 -0
  181. package/dist/nav-indexing/site-tree-nav-demo.d.ts +39 -0
  182. package/dist/nav-indexing/site-tree-nav-demo.js +65 -0
  183. package/dist/nav-indexing/tag-nav.d.ts +38 -0
  184. package/dist/nav-indexing/tag-nav.js +96 -0
  185. package/dist/nav-indexing/types.d.ts +95 -0
  186. package/dist/nav-indexing/types.js +0 -0
  187. package/dist/nav-indexing/versions-page-content.d.ts +29 -0
  188. package/dist/nav-indexing/versions-page-content.js +76 -0
  189. package/dist/page-loading/index.d.ts +2 -0
  190. package/dist/page-loading/index.js +10 -0
  191. package/dist/page-loading/page-loading-overlay.d.ts +35 -0
  192. package/dist/page-loading/page-loading-overlay.js +50 -0
  193. package/dist/sidebar/index.d.ts +3 -0
  194. package/dist/sidebar/index.js +4 -0
  195. package/dist/sidebar/sidebar.d.ts +54 -0
  196. package/dist/sidebar/sidebar.js +35 -0
  197. package/dist/sidebar/types.d.ts +71 -0
  198. package/dist/sidebar/types.js +0 -0
  199. package/dist/sidebar-resizer/index.d.ts +14 -0
  200. package/dist/sidebar-resizer/index.js +165 -0
  201. package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +20 -0
  202. package/dist/sidebar-resizer/sidebar-resizer-init.js +119 -0
  203. package/dist/sidebar-tree/build-tree.d.ts +43 -0
  204. package/dist/sidebar-tree/build-tree.js +127 -0
  205. package/dist/sidebar-tree/category-meta.d.ts +19 -0
  206. package/dist/sidebar-tree/category-meta.js +63 -0
  207. package/dist/sidebar-tree/index.d.ts +3 -0
  208. package/dist/sidebar-tree/index.js +13 -0
  209. package/dist/sidebar-tree/types.d.ts +120 -0
  210. package/dist/sidebar-tree/types.js +0 -0
  211. package/dist/tab-item/index.d.ts +2 -0
  212. package/dist/tab-item/index.js +5 -0
  213. package/dist/tab-item/tab-item.d.ts +38 -0
  214. package/dist/tab-item/tab-item.js +25 -0
  215. package/dist/theme/color-scheme-provider.d.ts +32 -0
  216. package/dist/theme/color-scheme-provider.js +43 -0
  217. package/dist/theme/color-tweak-export-modal.d.ts +20 -0
  218. package/dist/theme/color-tweak-export-modal.js +138 -0
  219. package/dist/theme/design-token-serde.d.ts +136 -0
  220. package/dist/theme/design-token-serde.js +254 -0
  221. package/dist/theme/design-token-tweak-panel.d.ts +11 -0
  222. package/dist/theme/design-token-tweak-panel.js +10 -0
  223. package/dist/theme/design-token-types.d.ts +19 -0
  224. package/dist/theme/design-token-types.js +6 -0
  225. package/dist/theme/iframe-bridge.d.ts +44 -0
  226. package/dist/theme/iframe-bridge.js +70 -0
  227. package/dist/theme/index.d.ts +9 -0
  228. package/dist/theme/index.js +42 -0
  229. package/dist/theme/theme-toggle.d.ts +17 -0
  230. package/dist/theme/theme-toggle.js +91 -0
  231. package/dist/toc/cx.d.ts +16 -0
  232. package/dist/toc/cx.js +22 -0
  233. package/dist/toc/index.d.ts +5 -0
  234. package/dist/toc/index.js +9 -0
  235. package/dist/toc/mobile-toc.d.ts +46 -0
  236. package/dist/toc/mobile-toc.js +88 -0
  237. package/dist/toc/smart-break.d.ts +27 -0
  238. package/dist/toc/smart-break.js +36 -0
  239. package/dist/toc/toc-title.d.ts +10 -0
  240. package/dist/toc/toc-title.js +14 -0
  241. package/dist/toc/toc.d.ts +60 -0
  242. package/dist/toc/toc.js +56 -0
  243. package/dist/toc/types.d.ts +23 -0
  244. package/dist/toc/types.js +0 -0
  245. package/dist/toc/use-active-heading.d.ts +30 -0
  246. package/dist/toc/use-active-heading.js +106 -0
  247. package/dist/transitions/index.d.ts +1 -0
  248. package/dist/transitions/index.js +12 -0
  249. package/dist/transitions/page-events.d.ts +41 -0
  250. package/dist/transitions/page-events.js +20 -0
  251. package/dist/url-normalizer/index.d.ts +1 -0
  252. package/dist/url-normalizer/index.js +6 -0
  253. package/dist/url-normalizer/normalize.d.ts +104 -0
  254. package/dist/url-normalizer/normalize.js +22 -0
  255. package/package.json +186 -0
@@ -0,0 +1,404 @@
1
+ import fs from "node:fs";
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, '\\"');
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 writeCategoryMeta(outputDir, label, position, description, noPage = true) {
29
+ const meta = { label, position, description };
30
+ if (noPage) meta.noPage = true;
31
+ fs.writeFileSync(
32
+ path.join(outputDir, "_category_.json"),
33
+ JSON.stringify(meta, null, 2) + "\n"
34
+ );
35
+ }
36
+ function findClaudeMdFiles(dir, excludeDirs) {
37
+ const results = [];
38
+ if (!fs.existsSync(dir)) return results;
39
+ for (const item of fs.readdirSync(dir)) {
40
+ if (item === "node_modules") continue;
41
+ if (item.startsWith(".")) continue;
42
+ const itemPath = path.join(dir, item);
43
+ if (excludeDirs.some((d) => itemPath.startsWith(d))) continue;
44
+ let stat;
45
+ try {
46
+ stat = fs.lstatSync(itemPath);
47
+ } catch {
48
+ continue;
49
+ }
50
+ if (stat.isDirectory()) {
51
+ results.push(...findClaudeMdFiles(itemPath, excludeDirs));
52
+ } else if (stat.isFile() && item === "CLAUDE.md") {
53
+ results.push(itemPath);
54
+ }
55
+ }
56
+ return results;
57
+ }
58
+ function generateClaudemdDocs(config) {
59
+ const projectRoot = config.projectRoot ?? path.dirname(config.claudeDir);
60
+ const outputDir = path.join(config.docsDir, "claude-md");
61
+ cleanDir(outputDir);
62
+ const excludeDirs = [
63
+ path.join(projectRoot, ".git"),
64
+ path.join(projectRoot, "node_modules"),
65
+ path.join(projectRoot, "worktrees"),
66
+ path.join(projectRoot, "dist"),
67
+ path.join(projectRoot, "out"),
68
+ path.join(projectRoot, "public"),
69
+ path.join(projectRoot, "__inbox"),
70
+ path.join(projectRoot, "test-results"),
71
+ path.join(projectRoot, "e2e", "fixtures"),
72
+ path.join(config.docsDir)
73
+ ];
74
+ const files = findClaudeMdFiles(projectRoot, excludeDirs);
75
+ if (files.length === 0) return [];
76
+ ensureDir(outputDir);
77
+ const items = [];
78
+ for (const filePath of files) {
79
+ const content = fs.readFileSync(filePath, "utf8");
80
+ const relPath = path.relative(projectRoot, filePath);
81
+ const displayPath = `/${relPath}`;
82
+ const dirPart = path.dirname(relPath);
83
+ const slug = dirPart === "." ? "root" : dirPart.replace(/\//g, "--");
84
+ items.push({ displayPath, slug, relPath });
85
+ const pos = items.length + 1;
86
+ const mdx = `---
87
+ title: "${escapeTitle(displayPath)}"
88
+ description: "CLAUDE.md at ${escapeTitle(displayPath)}"
89
+ sidebar_position: ${pos}
90
+ sidebar_label: "${escapeTitle(relPath)}"
91
+ generated: true
92
+ ---
93
+
94
+ **Path:** \`${relPath}\`
95
+
96
+ ${escapeForMdx(content.trim())}
97
+ `;
98
+ fs.writeFileSync(path.join(outputDir, `${slug}.mdx`), mdx);
99
+ }
100
+ items.sort((a, b) => {
101
+ if (a.slug === "root") return -1;
102
+ if (b.slug === "root") return 1;
103
+ return a.displayPath.localeCompare(b.displayPath);
104
+ });
105
+ writeCategoryMeta(outputDir, "CLAUDE.md", 900, "Project-specific instructions");
106
+ return items;
107
+ }
108
+ function generateCommandsDocs(config) {
109
+ const commandsDir = path.join(config.claudeDir, "commands");
110
+ const outputDir = path.join(config.docsDir, "claude-commands");
111
+ cleanDir(outputDir);
112
+ if (!fs.existsSync(commandsDir)) return [];
113
+ const files = fs.readdirSync(commandsDir).filter((f) => f.endsWith(".md"));
114
+ if (files.length === 0) return [];
115
+ ensureDir(outputDir);
116
+ const items = [];
117
+ for (const file of files) {
118
+ const content = fs.readFileSync(path.join(commandsDir, file), "utf8");
119
+ const parsed = parseFrontmatter(content);
120
+ if (!parsed) continue;
121
+ const name = file.replace(/\.md$/, "");
122
+ const description = parsed.data.description || "";
123
+ items.push({ name, description });
124
+ const mdx = `---
125
+ title: "${escapeTitle(name)}"
126
+ description: "${escapeTitle(description)}"
127
+ sidebar_label: "${escapeTitle(name)}"
128
+ generated: true
129
+ ---
130
+
131
+ ${escapeForMdx(parsed.content.trim())}
132
+ `;
133
+ fs.writeFileSync(path.join(outputDir, `${name}.mdx`), mdx);
134
+ }
135
+ items.sort((a, b) => a.name.localeCompare(b.name));
136
+ writeCategoryMeta(outputDir, "Commands", 901, "Custom slash commands");
137
+ return items;
138
+ }
139
+ function getSkillFileTree(skillDir, subDirs) {
140
+ const lines = [`${skillDir}/`];
141
+ const entries = [{ isDir: false, name: "SKILL.md" }];
142
+ for (const sub of subDirs) {
143
+ entries.push({ isDir: true, name: sub.name, children: sub.files });
144
+ }
145
+ for (let i = 0; i < entries.length; i++) {
146
+ const entry = entries[i];
147
+ const isLast = i === entries.length - 1;
148
+ const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
149
+ if (!entry.isDir) {
150
+ lines.push(`${prefix}${entry.name}`);
151
+ } else {
152
+ lines.push(`${prefix}${entry.name}/`);
153
+ for (let j = 0; j < entry.children.length; j++) {
154
+ const child = entry.children[j];
155
+ const childIsLast = j === entry.children.length - 1;
156
+ const continuation = isLast ? " " : "\u2502 ";
157
+ const childPrefix = childIsLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
158
+ lines.push(`${continuation}${childPrefix}${child}`);
159
+ }
160
+ }
161
+ }
162
+ return lines.join("\n");
163
+ }
164
+ function getScriptDescription(filePath) {
165
+ try {
166
+ const topLines = fs.readFileSync(filePath, "utf8").split("\n", 2);
167
+ const commentLine = topLines[0].startsWith("#!") ? topLines[1] || "" : topLines[0];
168
+ const match = commentLine.match(/^(?:#|\/\/)\s*(.+)/);
169
+ return match ? ` \u2014 ${match[1]}` : "";
170
+ } catch {
171
+ return "";
172
+ }
173
+ }
174
+ function getSkillReferences(skillsDir, skillDir) {
175
+ const refsDir = path.join(skillsDir, skillDir, "references");
176
+ if (!fs.existsSync(refsDir)) return [];
177
+ return fs.readdirSync(refsDir).filter((f) => f.endsWith(".md")).map((f) => {
178
+ const content = fs.readFileSync(path.join(refsDir, f), "utf8");
179
+ const name = f.replace(/\.md$/, "");
180
+ const h1Match = content.match(/^#\s+(.+)$/m);
181
+ const title = h1Match ? h1Match[1] : name;
182
+ return { name, title, content };
183
+ }).sort((a, b) => a.name.localeCompare(b.name));
184
+ }
185
+ function generateSkillsDocs(config) {
186
+ const skillsDir = path.join(config.claudeDir, "skills");
187
+ const outputDir = path.join(config.docsDir, "claude-skills");
188
+ cleanDir(outputDir);
189
+ if (!fs.existsSync(skillsDir)) return [];
190
+ const dirs = fs.readdirSync(skillsDir).filter((d) => {
191
+ const skillPath = path.join(skillsDir, d);
192
+ return fs.statSync(skillPath).isDirectory() && fs.existsSync(path.join(skillPath, "SKILL.md"));
193
+ });
194
+ if (dirs.length === 0) return [];
195
+ ensureDir(outputDir);
196
+ const items = [];
197
+ for (const dir of dirs) {
198
+ const content = fs.readFileSync(
199
+ path.join(skillsDir, dir, "SKILL.md"),
200
+ "utf8"
201
+ );
202
+ const parsed = parseFrontmatter(content);
203
+ if (!parsed) continue;
204
+ const name = parsed.data.name || dir;
205
+ const description = parsed.data.description || "";
206
+ const references = getSkillReferences(skillsDir, dir);
207
+ items.push({ name, dir, description, references });
208
+ const scriptFiles = listFiles(path.join(skillsDir, dir, "scripts"));
209
+ const assetFiles = listFiles(path.join(skillsDir, dir, "assets"));
210
+ const refFiles = references.map((r) => `${r.name}.md`);
211
+ const subDirs = [];
212
+ if (scriptFiles.length > 0) subDirs.push({ name: "scripts", files: scriptFiles });
213
+ if (refFiles.length > 0) subDirs.push({ name: "references", files: refFiles });
214
+ if (assetFiles.length > 0) subDirs.push({ name: "assets", files: assetFiles });
215
+ let fileStructureSection = "";
216
+ if (subDirs.length > 0) {
217
+ const tree = `\`\`\`
218
+ ${getSkillFileTree(dir, subDirs)}
219
+ \`\`\``;
220
+ const links = [];
221
+ for (const ref of references) {
222
+ links.push(`- [references/${ref.name}.md](./ref-${ref.name})`);
223
+ }
224
+ for (const f of scriptFiles.filter((s) => s.endsWith(".md"))) {
225
+ const slug = f.replace(/\.md$/, "");
226
+ links.push(`- [scripts/${f}](./script-${slug})`);
227
+ }
228
+ for (const f of assetFiles.filter((a) => a.endsWith(".md"))) {
229
+ const slug = f.replace(/\.md$/, "");
230
+ links.push(`- [assets/${f}](./asset-${slug})`);
231
+ }
232
+ const linkList = links.length > 0 ? `
233
+
234
+ ${links.join("\n")}` : "";
235
+ fileStructureSection = `## File Structure
236
+
237
+ ${tree}${linkList}`;
238
+ }
239
+ const shortDesc = description.length > 200 ? description.substring(0, 200) + "..." : description;
240
+ let skillBody = parsed.content.trim();
241
+ skillBody = skillBody.replace(/\]\(references\/([^)]+)\.md\)/g, "](./ref-$1)").replace(/\]\(scripts\/([^)]+)\.md\)/g, "](./script-$1)").replace(/\]\(assets\/([^)]+)\.md\)/g, "](./asset-$1)");
242
+ const body = [
243
+ fileStructureSection,
244
+ escapeForMdx(skillBody)
245
+ ].filter(Boolean).join("\n\n");
246
+ const mdx = `---
247
+ title: "${escapeTitle(name)}"
248
+ description: "${escapeTitle(shortDesc)}"
249
+ sidebar_label: "${escapeTitle(name)}"
250
+ generated: true
251
+ ---
252
+
253
+ ${body}`;
254
+ fs.writeFileSync(path.join(outputDir, `${dir}.mdx`), mdx);
255
+ const skillSlugBase = `claude-skills/${dir}`;
256
+ for (const ref of references) {
257
+ const subSlug = `${skillSlugBase}/ref-${ref.name}`;
258
+ const refMdx = `---
259
+ title: "${escapeTitle(ref.title)}"
260
+ slug: "${subSlug}"
261
+ unlisted: true
262
+ generated: true
263
+ ---
264
+
265
+ ${escapeForMdx(ref.content.trim())}
266
+ `;
267
+ fs.writeFileSync(path.join(outputDir, `${dir}--ref-${ref.name}.mdx`), refMdx);
268
+ }
269
+ for (const f of scriptFiles.filter((s) => s.endsWith(".md"))) {
270
+ const slug = f.replace(/\.md$/, "");
271
+ const subSlug = `${skillSlugBase}/script-${slug}`;
272
+ const raw = fs.readFileSync(
273
+ path.join(skillsDir, dir, "scripts", f),
274
+ "utf8"
275
+ );
276
+ const h1Match = raw.match(/^#\s+(.+)$/m);
277
+ const title = h1Match ? h1Match[1] : slug;
278
+ fs.writeFileSync(
279
+ path.join(outputDir, `${dir}--script-${slug}.mdx`),
280
+ `---
281
+ title: "${escapeTitle(title)}"
282
+ slug: "${subSlug}"
283
+ unlisted: true
284
+ generated: true
285
+ ---
286
+
287
+ ${escapeForMdx(raw.trim())}
288
+ `
289
+ );
290
+ }
291
+ for (const f of assetFiles.filter((a) => a.endsWith(".md"))) {
292
+ const slug = f.replace(/\.md$/, "");
293
+ const subSlug = `${skillSlugBase}/asset-${slug}`;
294
+ const raw = fs.readFileSync(
295
+ path.join(skillsDir, dir, "assets", f),
296
+ "utf8"
297
+ );
298
+ const h1Match = raw.match(/^#\s+(.+)$/m);
299
+ const title = h1Match ? h1Match[1] : slug;
300
+ fs.writeFileSync(
301
+ path.join(outputDir, `${dir}--asset-${slug}.mdx`),
302
+ `---
303
+ title: "${escapeTitle(title)}"
304
+ slug: "${subSlug}"
305
+ unlisted: true
306
+ generated: true
307
+ ---
308
+
309
+ ${escapeForMdx(raw.trim())}
310
+ `
311
+ );
312
+ }
313
+ }
314
+ items.sort((a, b) => a.name.localeCompare(b.name));
315
+ writeCategoryMeta(outputDir, "Skills", 902, "Skill packages");
316
+ return items;
317
+ }
318
+ function generateAgentsDocs(config) {
319
+ const agentsDir = path.join(config.claudeDir, "agents");
320
+ const outputDir = path.join(config.docsDir, "claude-agents");
321
+ cleanDir(outputDir);
322
+ if (!fs.existsSync(agentsDir)) return [];
323
+ const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md"));
324
+ if (files.length === 0) return [];
325
+ ensureDir(outputDir);
326
+ const items = [];
327
+ for (const file of files) {
328
+ const content = fs.readFileSync(path.join(agentsDir, file), "utf8");
329
+ const parsed = parseFrontmatter(content);
330
+ if (!parsed) continue;
331
+ const name = parsed.data.name || file.replace(/\.md$/, "");
332
+ const description = parsed.data.description || "";
333
+ const model = parsed.data.model || "";
334
+ const fileSlug = file.replace(/\.md$/, "");
335
+ items.push({ name, file: fileSlug, description, model });
336
+ const modelBadge = model ? `**Model:** \`${model}\`
337
+ ` : "";
338
+ const mdx = `---
339
+ title: "${escapeTitle(name)}"
340
+ description: "${escapeTitle(description)}"
341
+ sidebar_label: "${escapeTitle(name)}"
342
+ generated: true
343
+ ---
344
+
345
+ ${modelBadge}
346
+ ${escapeForMdx(parsed.content.trim())}
347
+ `;
348
+ fs.writeFileSync(path.join(outputDir, `${fileSlug}.mdx`), mdx);
349
+ }
350
+ items.sort((a, b) => a.name.localeCompare(b.name));
351
+ writeCategoryMeta(outputDir, "Agents", 903, "Custom subagents");
352
+ return items;
353
+ }
354
+ function generateOverviewIndex(config, {
355
+ hasCommands,
356
+ hasSkills,
357
+ hasAgents,
358
+ hasClaudemd
359
+ }) {
360
+ const outputDir = path.join(config.docsDir, "claude");
361
+ cleanDir(outputDir);
362
+ ensureDir(outputDir);
363
+ const categorySlugs = [];
364
+ if (hasClaudemd) categorySlugs.push("claude-md");
365
+ if (hasSkills) categorySlugs.push("claude-skills");
366
+ if (hasAgents) categorySlugs.push("claude-agents");
367
+ if (hasCommands) categorySlugs.push("claude-commands");
368
+ const categoriesAttr = JSON.stringify(categorySlugs);
369
+ const index = `---
370
+ title: "Claude"
371
+ description: "Claude Code configuration reference."
372
+ sidebar_position: 899
373
+ generated: true
374
+ ---
375
+
376
+ Claude Code configuration reference.
377
+
378
+ ## Resources
379
+
380
+ <CategoryNav categories={${categoriesAttr}} />
381
+ `;
382
+ fs.writeFileSync(path.join(outputDir, "index.mdx"), index);
383
+ }
384
+ function generateClaudeResourcesDocs(config) {
385
+ const claudemds = generateClaudemdDocs(config);
386
+ const commands = generateCommandsDocs(config);
387
+ const skills = generateSkillsDocs(config);
388
+ const agents = generateAgentsDocs(config);
389
+ generateOverviewIndex(config, {
390
+ hasClaudemd: claudemds.length > 0,
391
+ hasCommands: commands.length > 0,
392
+ hasSkills: skills.length > 0,
393
+ hasAgents: agents.length > 0
394
+ });
395
+ return {
396
+ claudemd: claudemds.length,
397
+ commands: commands.length,
398
+ skills: skills.length,
399
+ agents: agents.length
400
+ };
401
+ }
402
+ export {
403
+ generateClaudeResourcesDocs
404
+ };
@@ -0,0 +1,46 @@
1
+ import { generateClaudeResourcesDocs } from './generate.js';
2
+ export { ClaudeResourcesConfig } from './generate.js';
3
+
4
+ interface ZfbPluginConfig {
5
+ name: string;
6
+ options?: Record<string, unknown>;
7
+ }
8
+ declare const CLAUDE_RESOURCES_PLUGIN_NAME = "@takazudo/zudo-doc-claude-resources";
9
+ /** Options accepted by both the plugin entry and the imperative runner. */
10
+ interface ClaudeResourcesPluginOptions {
11
+ /**
12
+ * Path to the project's `.claude/` directory holding `commands/`,
13
+ * `skills/`, `agents/`. Resolved against `projectRoot` when relative.
14
+ */
15
+ claudeDir: string;
16
+ /**
17
+ * Project root used both as the search root for `CLAUDE.md` discovery
18
+ * and to anchor relative paths. Defaults to `process.cwd()`.
19
+ */
20
+ projectRoot?: string;
21
+ /**
22
+ * Output directory for generated MDX pages, resolved against
23
+ * `projectRoot` when relative. Defaults to `src/content/docs` to
24
+ * match the existing Astro integration's behaviour.
25
+ */
26
+ docsDir?: string;
27
+ }
28
+ /**
29
+ * Declarative plugin entry for `zfb.config.ts`. Returns the
30
+ * `{ name, options }` shape that zfb's plugins array consumes.
31
+ *
32
+ * v0 note: zfb does not yet invoke plugin lifecycles, so registering the
33
+ * plugin alone does not run generation today. Pair it with a call to
34
+ * `runClaudeResourcesPreStep` from a `prebuild`-style script until the
35
+ * lifecycle hook lands. The plugin entry itself is forward-compatible.
36
+ */
37
+ declare function claudeResourcesPlugin(options: ClaudeResourcesPluginOptions): ZfbPluginConfig;
38
+ /**
39
+ * Imperative pre-step runner. Resolves relative paths against
40
+ * `projectRoot` (defaults to `process.cwd()`) and invokes the underlying
41
+ * generator. Output is byte-equivalent to the Astro integration when
42
+ * given the same inputs.
43
+ */
44
+ declare function runClaudeResourcesPreStep(options: ClaudeResourcesPluginOptions): ReturnType<typeof generateClaudeResourcesDocs>;
45
+
46
+ export { CLAUDE_RESOURCES_PLUGIN_NAME, type ClaudeResourcesPluginOptions, type ZfbPluginConfig, claudeResourcesPlugin, generateClaudeResourcesDocs, runClaudeResourcesPreStep };
@@ -0,0 +1,24 @@
1
+ import path from "node:path";
2
+ import {
3
+ generateClaudeResourcesDocs
4
+ } from "./generate.js";
5
+ const CLAUDE_RESOURCES_PLUGIN_NAME = "@takazudo/zudo-doc-claude-resources";
6
+ function claudeResourcesPlugin(options) {
7
+ return {
8
+ name: CLAUDE_RESOURCES_PLUGIN_NAME,
9
+ options: { ...options }
10
+ };
11
+ }
12
+ function runClaudeResourcesPreStep(options) {
13
+ const projectRoot = path.resolve(options.projectRoot ?? process.cwd());
14
+ const claudeDir = path.isAbsolute(options.claudeDir) ? options.claudeDir : path.resolve(projectRoot, options.claudeDir);
15
+ const docsDirInput = options.docsDir ?? "src/content/docs";
16
+ const docsDir = path.isAbsolute(docsDirInput) ? docsDirInput : path.resolve(projectRoot, docsDirInput);
17
+ return generateClaudeResourcesDocs({ claudeDir, projectRoot, docsDir });
18
+ }
19
+ export {
20
+ CLAUDE_RESOURCES_PLUGIN_NAME,
21
+ claudeResourcesPlugin,
22
+ generateClaudeResourcesDocs,
23
+ runClaudeResourcesPreStep
24
+ };
@@ -0,0 +1,137 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ export { DocHistoryMetaEntry, DocHistoryMetaLocaleConfig, DocHistoryMetaManifest, DocHistoryMetaVersionConfig, RunDocHistoryMetaOptions, runDocHistoryMetaStep } from './pre-build.js';
3
+
4
+ /** A single non-default locale entry; mirrors `settings.locales[*]`. */
5
+ interface DocHistoryLocaleConfig {
6
+ /** Absolute or project-relative directory holding this locale's MDX content. */
7
+ dir: string;
8
+ }
9
+ /** Build-time + dev-time options for the doc-history integration. */
10
+ interface DocHistoryOptions {
11
+ /** Default-locale content directory (e.g. `src/content/docs`). */
12
+ docsDir: string;
13
+ /** Optional non-default locales, keyed by locale code (e.g. `{ ja: { dir: "src/content/docs-ja" } }`). */
14
+ locales?: Record<string, DocHistoryLocaleConfig>;
15
+ /**
16
+ * Port the standalone `@takazudo/zudo-doc-history-server` listens on.
17
+ * Defaults to `4322` to match the server's CLI default. Only used by
18
+ * the dev proxy.
19
+ */
20
+ serverPort?: number;
21
+ /**
22
+ * Maximum number of git history entries to record per file. Defaults
23
+ * to `50`, matching `@takazudo/zudo-doc-history-server`'s CLI default.
24
+ * Only used by the post-build hook.
25
+ */
26
+ maxEntries?: number;
27
+ }
28
+ /** zfb v0 plugin descriptor — mirrors `PluginConfig` in `zfb/config`. */
29
+ interface DocHistoryPluginDescriptor {
30
+ /** Stable plugin id used by the future zfb plugin runtime to dispatch hooks. */
31
+ name: "doc-history";
32
+ /** Options forwarded verbatim into the zfb config; must be JSON-serialisable. */
33
+ options: DocHistoryOptions;
34
+ }
35
+ /** Default doc-history-server port — matches `@takazudo/zudo-doc-history-server`. */
36
+ declare const DEFAULT_SERVER_PORT = 4322;
37
+ /** Default git history depth — matches `@takazudo/zudo-doc-history-server`. */
38
+ declare const DEFAULT_MAX_ENTRIES = 50;
39
+ /** Public route prefix the dev middleware and the standalone server agree on. */
40
+ declare const DOC_HISTORY_ROUTE_PREFIX = "/doc-history/";
41
+ /** Subdirectory within the build output that receives the generated JSON files. */
42
+ declare const DOC_HISTORY_OUTPUT_DIRNAME = "doc-history";
43
+ /** CLI bin name exposed by `@takazudo/zudo-doc-history-server` for inline generation. */
44
+ declare const DOC_HISTORY_GENERATE_BIN = "doc-history-generate";
45
+ /**
46
+ * Build the zfb config-side descriptor. Add the return value to the
47
+ * `plugins: [...]` array in `zfb.config.ts`.
48
+ *
49
+ * The shape is intentionally limited to `{ name, options }` because
50
+ * that is the only thing today's zfb config loader consumes (see the
51
+ * Rust `PluginConfig` struct in zfb's `config.rs`). Runtime wiring is
52
+ * done through the sibling helpers in this module.
53
+ */
54
+ declare function docHistoryPlugin(options: DocHistoryOptions): DocHistoryPluginDescriptor;
55
+ /** Connect-style middleware signature — works as a Vite plugin middleware. */
56
+ type ConnectMiddleware = (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void;
57
+ /** Minimal logger surface used by the middleware on proxy failure. */
58
+ interface MiddlewareLogger {
59
+ warn(msg: string): void;
60
+ }
61
+ /**
62
+ * Connect-style middleware that proxies any URL containing
63
+ * `/doc-history/` to the standalone `@takazudo/zudo-doc-history-server`.
64
+ * Behaviour matches the legacy Astro integration byte-for-byte:
65
+ *
66
+ * - request URLs without the `/doc-history/` segment fall through
67
+ * to `next()` unchanged,
68
+ * - the path slice from `/doc-history/` onward is preserved (so a
69
+ * site `base` prefix like `/docs/doc-history/foo.json` still
70
+ * reaches the right server route),
71
+ * - a successful upstream response copies status + content-type and
72
+ * streams the body as text,
73
+ * - on upstream failure the proxy returns `502 application/json`
74
+ * with a stable error envelope so the client island can render a
75
+ * graceful empty state.
76
+ */
77
+ declare function createDocHistoryDevMiddleware(options: DocHistoryOptions, logger?: MiddlewareLogger): ConnectMiddleware;
78
+ /** Minimal logger surface used by the post-build hook. */
79
+ interface PostBuildLogger {
80
+ info(msg: string): void;
81
+ warn(msg: string): void;
82
+ }
83
+ /** Invocation context for the post-build hook. */
84
+ interface PostBuildContext {
85
+ /** Absolute path to the build output directory (zfb `outDir`). */
86
+ outDir: string;
87
+ /** Optional logger; falls back to silent no-ops when omitted. */
88
+ logger?: PostBuildLogger;
89
+ }
90
+ /**
91
+ * Post-build hook. Spawns the `doc-history-generate` CLI from
92
+ * `@takazudo/zudo-doc-history-server` to write per-page git history JSON
93
+ * files into `<outDir>/doc-history/`.
94
+ *
95
+ * Returns early when `SKIP_DOC_HISTORY=1` is set in the environment;
96
+ * the CI `build-history` job uses that flag because it generates the
97
+ * same output as a separate parallel artifact. Local `pnpm build`
98
+ * runs leave the flag unset so the inline path is taken.
99
+ *
100
+ * The CLI is spawned through the platform shell so that the
101
+ * `node_modules/.bin/doc-history-generate` symlink (created by pnpm /
102
+ * npm at install time) resolves naturally. Output is inherited so
103
+ * progress and warnings surface in the user's terminal exactly as
104
+ * they do in CI.
105
+ */
106
+ declare function runDocHistoryPostBuild(options: DocHistoryOptions, ctx: PostBuildContext): Promise<void>;
107
+ /**
108
+ * Build the argv passed to `doc-history-generate`. Exposed for unit
109
+ * tests; the CLI surface is documented in
110
+ * `packages/doc-history-server/src/args.ts`.
111
+ */
112
+ declare function buildGenerateCliArgs(options: DocHistoryOptions, outDir: string): string[];
113
+ /**
114
+ * Resolve the absolute path of the `doc-history-generate` script
115
+ * shipped by `@takazudo/zudo-doc-history-server`.
116
+ *
117
+ * Reading `bin` out of the dependency's `package.json` and joining it
118
+ * to that file's directory avoids two pitfalls:
119
+ *
120
+ * 1. **Shell injection.** Spawning the CLI as
121
+ * `spawn(node, [absoluteCliPath, ...flagArgs], { shell: false })`
122
+ * means CLI flag values (which may include user-controlled
123
+ * content directory paths) are never interpolated into a shell
124
+ * command line.
125
+ * 2. **PATH ambiguity.** Resolving via `node_modules/.bin` only
126
+ * works when that directory is on `PATH`, which depends on how
127
+ * the build is invoked. Reading the package's own `bin` map
128
+ * eliminates the dependency on shell PATH lookup.
129
+ *
130
+ * `package.json` is reachable via `require.resolve` regardless of
131
+ * the package's `exports` field (the spec carves out `./package.json`
132
+ * unconditionally), so this is safe even if the package later
133
+ * tightens its exports surface.
134
+ */
135
+ declare function resolveDocHistoryGenerateBin(): string;
136
+
137
+ export { type ConnectMiddleware, DEFAULT_MAX_ENTRIES, DEFAULT_SERVER_PORT, DOC_HISTORY_GENERATE_BIN, DOC_HISTORY_OUTPUT_DIRNAME, DOC_HISTORY_ROUTE_PREFIX, type DocHistoryLocaleConfig, type DocHistoryOptions, type DocHistoryPluginDescriptor, type MiddlewareLogger, type PostBuildContext, type PostBuildLogger, buildGenerateCliArgs, createDocHistoryDevMiddleware, docHistoryPlugin, resolveDocHistoryGenerateBin, runDocHistoryPostBuild };