@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.
- package/LICENSE +21 -0
- package/README.md +18 -0
- package/dist/body-foot-util/body-foot-util-area.d.ts +55 -0
- package/dist/body-foot-util/body-foot-util-area.js +71 -0
- package/dist/body-foot-util/edit-link.d.ts +45 -0
- package/dist/body-foot-util/edit-link.js +42 -0
- package/dist/body-foot-util/index.d.ts +3 -0
- package/dist/body-foot-util/index.js +11 -0
- package/dist/breadcrumb/breadcrumb.d.ts +57 -0
- package/dist/breadcrumb/breadcrumb.js +113 -0
- package/dist/breadcrumb/find-path.d.ts +16 -0
- package/dist/breadcrumb/find-path.js +13 -0
- package/dist/breadcrumb/index.d.ts +4 -0
- package/dist/breadcrumb/index.js +7 -0
- package/dist/breadcrumb/types.d.ts +32 -0
- package/dist/breadcrumb/types.js +0 -0
- package/dist/code-syntax/code-block-enhancer-script.d.ts +3 -0
- package/dist/code-syntax/code-block-enhancer-script.js +165 -0
- package/dist/code-syntax/code-block-enhancer.d.ts +22 -0
- package/dist/code-syntax/code-block-enhancer.js +13 -0
- package/dist/code-syntax/index.d.ts +8 -0
- package/dist/code-syntax/index.js +29 -0
- package/dist/code-syntax/mermaid-init-script.d.ts +51 -0
- package/dist/code-syntax/mermaid-init-script.js +225 -0
- package/dist/code-syntax/mermaid-init.d.ts +48 -0
- package/dist/code-syntax/mermaid-init.js +14 -0
- package/dist/code-syntax/tabs-init-script.d.ts +3 -0
- package/dist/code-syntax/tabs-init-script.js +106 -0
- package/dist/code-syntax/tabs-init.d.ts +24 -0
- package/dist/code-syntax/tabs-init.js +10 -0
- package/dist/code-syntax/tabs.d.ts +36 -0
- package/dist/code-syntax/tabs.js +62 -0
- package/dist/content/component-map.d.ts +51 -0
- package/dist/content/component-map.js +29 -0
- package/dist/content/content-blockquote.d.ts +11 -0
- package/dist/content/content-blockquote.js +14 -0
- package/dist/content/content-code.d.ts +26 -0
- package/dist/content/content-code.js +39 -0
- package/dist/content/content-link.d.ts +12 -0
- package/dist/content/content-link.js +43 -0
- package/dist/content/content-ol.d.ts +11 -0
- package/dist/content/content-ol.js +15 -0
- package/dist/content/content-paragraph.d.ts +10 -0
- package/dist/content/content-paragraph.js +7 -0
- package/dist/content/content-strong.d.ts +11 -0
- package/dist/content/content-strong.js +14 -0
- package/dist/content/content-table.d.ts +11 -0
- package/dist/content/content-table.js +14 -0
- package/dist/content/content-ul.d.ts +11 -0
- package/dist/content/content-ul.js +15 -0
- package/dist/content/heading-h2.d.ts +14 -0
- package/dist/content/heading-h2.js +18 -0
- package/dist/content/heading-h3.d.ts +14 -0
- package/dist/content/heading-h3.js +18 -0
- package/dist/content/heading-h4.d.ts +14 -0
- package/dist/content/heading-h4.js +18 -0
- package/dist/content/index.d.ts +13 -0
- package/dist/content/index.js +27 -0
- package/dist/details/details.d.ts +26 -0
- package/dist/details/details.js +10 -0
- package/dist/details/index.d.ts +2 -0
- package/dist/details/index.js +4 -0
- package/dist/doclayout/anchors.d.ts +55 -0
- package/dist/doclayout/anchors.js +42 -0
- package/dist/doclayout/doc-layout-with-defaults.d.ts +83 -0
- package/dist/doclayout/doc-layout-with-defaults.js +159 -0
- package/dist/doclayout/doc-layout.d.ts +121 -0
- package/dist/doclayout/doc-layout.js +89 -0
- package/dist/doclayout/index.d.ts +6 -0
- package/dist/doclayout/index.js +17 -0
- package/dist/footer/footer.d.ts +42 -0
- package/dist/footer/footer.js +79 -0
- package/dist/footer/index.d.ts +3 -0
- package/dist/footer/index.js +4 -0
- package/dist/footer/types.d.ts +58 -0
- package/dist/footer/types.js +0 -0
- package/dist/head/doc-head.d.ts +33 -0
- package/dist/head/doc-head.js +90 -0
- package/dist/head/index.d.ts +5 -0
- package/dist/head/index.js +8 -0
- package/dist/head/og-tags.d.ts +25 -0
- package/dist/head/og-tags.js +16 -0
- package/dist/head/twitter-card.d.ts +21 -0
- package/dist/head/twitter-card.js +14 -0
- package/dist/head/types.d.ts +83 -0
- package/dist/head/types.js +0 -0
- package/dist/header/header.d.ts +158 -0
- package/dist/header/header.js +367 -0
- package/dist/header/index.d.ts +6 -0
- package/dist/header/index.js +18 -0
- package/dist/header/nav-active.d.ts +39 -0
- package/dist/header/nav-active.js +24 -0
- package/dist/header/nav-overflow-script.d.ts +3 -0
- package/dist/header/nav-overflow-script.js +169 -0
- package/dist/header/right-items.d.ts +38 -0
- package/dist/header/right-items.js +30 -0
- package/dist/header/types.d.ts +40 -0
- package/dist/header/types.js +0 -0
- package/dist/html-preview-wrapper/dedent.d.ts +10 -0
- package/dist/html-preview-wrapper/dedent.js +16 -0
- package/dist/html-preview-wrapper/highlighted-code.d.ts +18 -0
- package/dist/html-preview-wrapper/highlighted-code.js +53 -0
- package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +60 -0
- package/dist/html-preview-wrapper/html-preview-wrapper.js +36 -0
- package/dist/html-preview-wrapper/html-preview.d.ts +35 -0
- package/dist/html-preview-wrapper/html-preview.js +75 -0
- package/dist/html-preview-wrapper/index.d.ts +5 -0
- package/dist/html-preview-wrapper/index.js +12 -0
- package/dist/html-preview-wrapper/preflight.d.ts +13 -0
- package/dist/html-preview-wrapper/preflight.js +108 -0
- package/dist/html-preview-wrapper/preview-base.d.ts +29 -0
- package/dist/html-preview-wrapper/preview-base.js +127 -0
- package/dist/i18n-version/index.d.ts +5 -0
- package/dist/i18n-version/index.js +14 -0
- package/dist/i18n-version/language-switcher.d.ts +24 -0
- package/dist/i18n-version/language-switcher.js +25 -0
- package/dist/i18n-version/types.d.ts +43 -0
- package/dist/i18n-version/types.js +0 -0
- package/dist/i18n-version/version-banner.d.ts +30 -0
- package/dist/i18n-version/version-banner.js +21 -0
- package/dist/i18n-version/version-switcher.d.ts +112 -0
- package/dist/i18n-version/version-switcher.js +157 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +0 -0
- package/dist/integrations/claude-resources/escape-for-mdx.d.ts +8 -0
- package/dist/integrations/claude-resources/escape-for-mdx.js +131 -0
- package/dist/integrations/claude-resources/generate.d.ts +13 -0
- package/dist/integrations/claude-resources/generate.js +404 -0
- package/dist/integrations/claude-resources/index.d.ts +46 -0
- package/dist/integrations/claude-resources/index.js +24 -0
- package/dist/integrations/doc-history/index.d.ts +137 -0
- package/dist/integrations/doc-history/index.js +138 -0
- package/dist/integrations/doc-history/pre-build.d.ts +58 -0
- package/dist/integrations/doc-history/pre-build.js +67 -0
- package/dist/integrations/llms-txt/dev-middleware.d.ts +40 -0
- package/dist/integrations/llms-txt/dev-middleware.js +76 -0
- package/dist/integrations/llms-txt/emit.d.ts +22 -0
- package/dist/integrations/llms-txt/emit.js +55 -0
- package/dist/integrations/llms-txt/generate.d.ts +26 -0
- package/dist/integrations/llms-txt/generate.js +36 -0
- package/dist/integrations/llms-txt/index.d.ts +7 -0
- package/dist/integrations/llms-txt/index.js +27 -0
- package/dist/integrations/llms-txt/load.d.ts +51 -0
- package/dist/integrations/llms-txt/load.js +83 -0
- package/dist/integrations/llms-txt/strip.d.ts +22 -0
- package/dist/integrations/llms-txt/strip.js +10 -0
- package/dist/integrations/llms-txt/types.d.ts +145 -0
- package/dist/integrations/llms-txt/types.js +0 -0
- package/dist/integrations/search-index/build-emitter.d.ts +30 -0
- package/dist/integrations/search-index/build-emitter.js +15 -0
- package/dist/integrations/search-index/collect.d.ts +12 -0
- package/dist/integrations/search-index/collect.js +48 -0
- package/dist/integrations/search-index/content-files.d.ts +32 -0
- package/dist/integrations/search-index/content-files.js +50 -0
- package/dist/integrations/search-index/dev-middleware.d.ts +16 -0
- package/dist/integrations/search-index/dev-middleware.js +30 -0
- package/dist/integrations/search-index/index.d.ts +5 -0
- package/dist/integrations/search-index/index.js +14 -0
- package/dist/integrations/search-index/types.d.ts +38 -0
- package/dist/integrations/search-index/types.js +6 -0
- package/dist/metainfo/doc-metainfo.d.ts +50 -0
- package/dist/metainfo/doc-metainfo.js +107 -0
- package/dist/metainfo/doc-tags.d.ts +66 -0
- package/dist/metainfo/doc-tags.js +53 -0
- package/dist/metainfo/frontmatter-preview.d.ts +95 -0
- package/dist/metainfo/frontmatter-preview.js +55 -0
- package/dist/metainfo/index.d.ts +4 -0
- package/dist/metainfo/index.js +28 -0
- package/dist/nav-indexing/category-nav.d.ts +28 -0
- package/dist/nav-indexing/category-nav.js +41 -0
- package/dist/nav-indexing/category-tree-nav.d.ts +27 -0
- package/dist/nav-indexing/category-tree-nav.js +49 -0
- package/dist/nav-indexing/doc-card-grid.d.ts +38 -0
- package/dist/nav-indexing/doc-card-grid.js +40 -0
- package/dist/nav-indexing/docs-sitemap.d.ts +25 -0
- package/dist/nav-indexing/docs-sitemap.js +40 -0
- package/dist/nav-indexing/index.d.ts +10 -0
- package/dist/nav-indexing/index.js +18 -0
- package/dist/nav-indexing/nav-card-grid.d.ts +31 -0
- package/dist/nav-indexing/nav-card-grid.js +43 -0
- package/dist/nav-indexing/site-tree-nav-demo.d.ts +39 -0
- package/dist/nav-indexing/site-tree-nav-demo.js +65 -0
- package/dist/nav-indexing/tag-nav.d.ts +38 -0
- package/dist/nav-indexing/tag-nav.js +96 -0
- package/dist/nav-indexing/types.d.ts +95 -0
- package/dist/nav-indexing/types.js +0 -0
- package/dist/nav-indexing/versions-page-content.d.ts +29 -0
- package/dist/nav-indexing/versions-page-content.js +76 -0
- package/dist/page-loading/index.d.ts +2 -0
- package/dist/page-loading/index.js +10 -0
- package/dist/page-loading/page-loading-overlay.d.ts +35 -0
- package/dist/page-loading/page-loading-overlay.js +50 -0
- package/dist/sidebar/index.d.ts +3 -0
- package/dist/sidebar/index.js +4 -0
- package/dist/sidebar/sidebar.d.ts +54 -0
- package/dist/sidebar/sidebar.js +35 -0
- package/dist/sidebar/types.d.ts +71 -0
- package/dist/sidebar/types.js +0 -0
- package/dist/sidebar-resizer/index.d.ts +14 -0
- package/dist/sidebar-resizer/index.js +165 -0
- package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +20 -0
- package/dist/sidebar-resizer/sidebar-resizer-init.js +119 -0
- package/dist/sidebar-tree/build-tree.d.ts +43 -0
- package/dist/sidebar-tree/build-tree.js +127 -0
- package/dist/sidebar-tree/category-meta.d.ts +19 -0
- package/dist/sidebar-tree/category-meta.js +63 -0
- package/dist/sidebar-tree/index.d.ts +3 -0
- package/dist/sidebar-tree/index.js +13 -0
- package/dist/sidebar-tree/types.d.ts +120 -0
- package/dist/sidebar-tree/types.js +0 -0
- package/dist/tab-item/index.d.ts +2 -0
- package/dist/tab-item/index.js +5 -0
- package/dist/tab-item/tab-item.d.ts +38 -0
- package/dist/tab-item/tab-item.js +25 -0
- package/dist/theme/color-scheme-provider.d.ts +32 -0
- package/dist/theme/color-scheme-provider.js +43 -0
- package/dist/theme/color-tweak-export-modal.d.ts +20 -0
- package/dist/theme/color-tweak-export-modal.js +138 -0
- package/dist/theme/design-token-serde.d.ts +136 -0
- package/dist/theme/design-token-serde.js +254 -0
- package/dist/theme/design-token-tweak-panel.d.ts +11 -0
- package/dist/theme/design-token-tweak-panel.js +10 -0
- package/dist/theme/design-token-types.d.ts +19 -0
- package/dist/theme/design-token-types.js +6 -0
- package/dist/theme/iframe-bridge.d.ts +44 -0
- package/dist/theme/iframe-bridge.js +70 -0
- package/dist/theme/index.d.ts +9 -0
- package/dist/theme/index.js +42 -0
- package/dist/theme/theme-toggle.d.ts +17 -0
- package/dist/theme/theme-toggle.js +91 -0
- package/dist/toc/cx.d.ts +16 -0
- package/dist/toc/cx.js +22 -0
- package/dist/toc/index.d.ts +5 -0
- package/dist/toc/index.js +9 -0
- package/dist/toc/mobile-toc.d.ts +46 -0
- package/dist/toc/mobile-toc.js +88 -0
- package/dist/toc/smart-break.d.ts +27 -0
- package/dist/toc/smart-break.js +36 -0
- package/dist/toc/toc-title.d.ts +10 -0
- package/dist/toc/toc-title.js +14 -0
- package/dist/toc/toc.d.ts +60 -0
- package/dist/toc/toc.js +56 -0
- package/dist/toc/types.d.ts +23 -0
- package/dist/toc/types.js +0 -0
- package/dist/toc/use-active-heading.d.ts +30 -0
- package/dist/toc/use-active-heading.js +106 -0
- package/dist/transitions/index.d.ts +1 -0
- package/dist/transitions/index.js +12 -0
- package/dist/transitions/page-events.d.ts +41 -0
- package/dist/transitions/page-events.js +20 -0
- package/dist/url-normalizer/index.d.ts +1 -0
- package/dist/url-normalizer/index.js +6 -0
- package/dist/url-normalizer/normalize.d.ts +104 -0
- package/dist/url-normalizer/normalize.js +22 -0
- 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 };
|