create-zudo-doc 3.1.0 → 3.2.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/dist/preset.d.ts CHANGED
@@ -38,6 +38,7 @@ export interface PresetJson {
38
38
  features?: string[];
39
39
  githubUrl?: string;
40
40
  cjkFriendly?: boolean;
41
+ minifyHtml?: boolean;
41
42
  packageManager?: "pnpm" | "npm" | "yarn" | "bun";
42
43
  headerRightItems?: PresetHeaderRightItem[];
43
44
  metaTags?: PresetMetaTagsConfig;
package/dist/preset.js CHANGED
@@ -72,6 +72,9 @@ export function validatePreset(json) {
72
72
  if (p.cjkFriendly !== undefined && typeof p.cjkFriendly !== "boolean") {
73
73
  return `"cjkFriendly" must be a boolean in preset`;
74
74
  }
75
+ if (p.minifyHtml !== undefined && typeof p.minifyHtml !== "boolean") {
76
+ return `"minifyHtml" must be a boolean in preset`;
77
+ }
75
78
  if (p.headerRightItems !== undefined) {
76
79
  if (!Array.isArray(p.headerRightItems)) {
77
80
  return `"headerRightItems" must be an array in preset`;
@@ -177,6 +180,8 @@ export function presetToChoices(json) {
177
180
  choices.githubUrl = json.githubUrl;
178
181
  if (json.cjkFriendly !== undefined)
179
182
  choices.cjkFriendly = json.cjkFriendly;
183
+ if (json.minifyHtml !== undefined)
184
+ choices.minifyHtml = json.minifyHtml;
180
185
  if (json.headerRightItems !== undefined) {
181
186
  choices.headerRightItems = json.headerRightItems;
182
187
  }
package/dist/prompts.d.ts CHANGED
@@ -12,6 +12,7 @@ export interface UserChoices {
12
12
  explicitlyDisabledFeatures?: string[];
13
13
  githubUrl?: string;
14
14
  cjkFriendly?: boolean;
15
+ minifyHtml?: boolean;
15
16
  packageManager: "pnpm" | "npm" | "yarn" | "bun";
16
17
  headerRightItems?: PresetHeaderRightItem[];
17
18
  metaTags?: PresetMetaTagsConfig;
@@ -29,6 +30,7 @@ export interface PartialChoices {
29
30
  explicitlyDisabledFeatures?: string[];
30
31
  githubUrl?: string;
31
32
  cjkFriendly?: boolean;
33
+ minifyHtml?: boolean;
32
34
  packageManager?: "pnpm" | "npm" | "yarn" | "bun";
33
35
  headerRightItems?: PresetHeaderRightItem[];
34
36
  metaTags?: PresetMetaTagsConfig;
package/dist/prompts.js CHANGED
@@ -200,6 +200,7 @@ export async function runPrompts(prefilled = {}) {
200
200
  explicitlyDisabledFeatures: prefilled.explicitlyDisabledFeatures,
201
201
  githubUrl,
202
202
  cjkFriendly: prefilled.cjkFriendly,
203
+ minifyHtml: prefilled.minifyHtml,
203
204
  packageManager,
204
205
  headerRightItems: prefilled.headerRightItems,
205
206
  metaTags: prefilled.metaTags,
@@ -11,5 +11,5 @@ export { getSecondaryLang };
11
11
  *
12
12
  * Bumped in lockstep by scripts/release-create-zudo-doc.sh.
13
13
  */
14
- export declare const ZUDO_DOC_PIN = "^3.1.0";
14
+ export declare const ZUDO_DOC_PIN = "^3.2.0";
15
15
  export declare function scaffold(choices: UserChoices): Promise<void>;
package/dist/scaffold.js CHANGED
@@ -18,11 +18,11 @@ export { getSecondaryLang };
18
18
  *
19
19
  * Bumped in lockstep by scripts/release-create-zudo-doc.sh.
20
20
  */
21
- export const ZUDO_DOC_PIN = "^3.1.0";
21
+ export const ZUDO_DOC_PIN = "^3.2.0";
22
22
  /**
23
- * Files in `templates/base/**` that must never be copied into a generated
24
- * project. Each entry is matched against the path relative to `templates/base/`
25
- * (POSIX-style, forward slashes).
23
+ * Files in `templates/base/**` that must not be copied by the unconditional
24
+ * base mirror. Each entry is matched against the path relative to
25
+ * `templates/base/` (POSIX-style, forward slashes).
26
26
  *
27
27
  * W2 spec-lock Decision 5 (#1728) — `pages/api/**` is worker-only SSR
28
28
  * (uses `@takazudo/zfb-adapter-cloudflare`, `prerender = false`) and is
@@ -32,6 +32,7 @@ export const ZUDO_DOC_PIN = "^3.1.0";
32
32
  */
33
33
  const EXCLUDE_FROM_MIRROR = [
34
34
  /^pages\/api(\/|$)/,
35
+ /^scripts\/setup-doc-skill\.sh$/,
35
36
  ];
36
37
  /**
37
38
  * `fs.copy` filter for the `templates/base/` → target-dir copy. Returns
@@ -201,7 +202,7 @@ export async function scaffold(choices) {
201
202
  const templatesDir = path.join(pkgRoot, "templates");
202
203
  const baseDir = path.join(templatesDir, "base");
203
204
  const featuresDir = path.join(templatesDir, "features");
204
- // For skillSymlinker, we still need the monorepo root for the script
205
+ // Still needed for source-checkout-only assets such as Claude skills.
205
206
  const monorepoRoot = path.resolve(pkgRoot, "../..");
206
207
  await fs.ensureDir(targetDir);
207
208
  // 1. Copy base template
@@ -214,11 +215,9 @@ export async function scaffold(choices) {
214
215
  });
215
216
  // 2. Copy skill symlinker script when enabled
216
217
  if (choices.features.includes("skillSymlinker")) {
217
- const scriptSrc = path.join(monorepoRoot, "scripts/setup-doc-skill.sh");
218
+ const scriptSrc = path.join(baseDir, "scripts/setup-doc-skill.sh");
218
219
  const scriptDest = path.join(targetDir, "scripts/setup-doc-skill.sh");
219
- if (await fs.pathExists(scriptSrc)) {
220
- await fs.copy(scriptSrc, scriptDest);
221
- }
220
+ await fs.copy(scriptSrc, scriptDest);
222
221
  }
223
222
  // 2b. Copy user-facing Claude Code skills when enabled
224
223
  // Ships the curated zudo-doc-* skills (design-system, translate, version-bump)
@@ -497,14 +496,15 @@ function generatePackageJson(choices) {
497
496
  // pins. No consumer-facing / CLI change.
498
497
  // next.76: routine toolchain bump from next.75, adopted in
499
498
  // lockstep with the root package.json pins. No consumer-facing / CLI change.
500
- // next.77 (current pin): router persistence/history fixes and runtime
501
- // island remount support, adopted in lockstep with the root package.json
502
- // pins. No scaffold API change.
503
- "@takazudo/zfb": "0.1.0-next.77",
504
- "@takazudo/zfb-runtime": "0.1.0-next.77",
499
+ // next.77: router persistence/history fixes and runtime island remount
500
+ // support, adopted in lockstep with the root package.json pins. No
501
+ // scaffold API change. next.78 (current pin): production HTML minification
502
+ // support via minifyHtml, adopted as a zudo-doc default through settings.
503
+ "@takazudo/zfb": "0.1.0-next.78",
504
+ "@takazudo/zfb-runtime": "0.1.0-next.78",
505
505
  // zfb-adapter-cloudflare — required for any route with `prerender = false`.
506
506
  // Pinned in lockstep with @takazudo/zfb.
507
- "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.77",
507
+ "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.78",
508
508
  // @takazudo/zudo-doc — published from this monorepo via
509
509
  // .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
510
510
  // lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
@@ -587,7 +587,7 @@ function generatePackageJson(choices) {
587
587
  // @takazudo/zudo-doc/integrations/doc-history which in turn imports
588
588
  // @takazudo/zudo-doc-history-server/git-history. Without this dep the
589
589
  // plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
590
- deps["@takazudo/zudo-doc-history-server"] = "^3.1.0";
590
+ deps["@takazudo/zudo-doc-history-server"] = "^3.2.0";
591
591
  // tsx is no longer needed here: the relocated package plugin imports the
592
592
  // runner directly (no `tsx -e` spawn) since the package ships compiled
593
593
  // dist/ — package-first migration #2321 (#2337).
@@ -51,6 +51,7 @@ export function generateSettingsFile(choices) {
51
51
  lines.push(` siteDescription: "" as string,`);
52
52
  lines.push(` base: "/",`);
53
53
  lines.push(` trailingSlash: false as boolean,`);
54
+ lines.push(` minifyHtml: ${choices.minifyHtml ?? true} as boolean,`);
54
55
  lines.push(` noindex: ${choices.features.includes("noindex")} as boolean,`);
55
56
  lines.push(` editUrl: false as string | false,`);
56
57
  const rawGithubUrl = (choices.githubUrl ?? "").trim();
@@ -4,8 +4,8 @@ import type { UserChoices } from "./prompts.js";
4
4
  *
5
5
  * S5b (#2329): collapsed to the thin preset-based shape that mirrors the
6
6
  * showcase `zfb.config.ts` after S5a. All collection wiring, plugin
7
- * descriptors, markdown features, codeHighlight, resolveMarkdownLinks, and
8
- * trailingSlash are now owned by `zudoDocPreset()` in
7
+ * descriptors, markdown features, codeHighlight, resolveMarkdownLinks,
8
+ * trailingSlash, and minifyHtml are now owned by `zudoDocPreset()` in
9
9
  * `@takazudo/zudo-doc/preset`. The generated config spreads the preset
10
10
  * result into `defineConfig` and keeps only the project-owned shell fields
11
11
  * (`framework`, `port`, `tailwind`, `base`).
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * S5b (#2329): collapsed to the thin preset-based shape that mirrors the
5
5
  * showcase `zfb.config.ts` after S5a. All collection wiring, plugin
6
- * descriptors, markdown features, codeHighlight, resolveMarkdownLinks, and
7
- * trailingSlash are now owned by `zudoDocPreset()` in
6
+ * descriptors, markdown features, codeHighlight, resolveMarkdownLinks,
7
+ * trailingSlash, and minifyHtml are now owned by `zudoDocPreset()` in
8
8
  * `@takazudo/zudo-doc/preset`. The generated config spreads the preset
9
9
  * result into `defineConfig` and keeps only the project-owned shell fields
10
10
  * (`framework`, `port`, `tailwind`, `base`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zudo-doc",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Create a new zudo-doc documentation site",
5
5
  "license": "MIT",
6
6
  "author": "Takeshi Takatsudo",
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # ── setup-doc-skill.sh ─────────────────────────────────
5
+ # Creates an agent skill that exposes your zudo-doc
6
+ # documentation as a knowledge base, then symlinks it into
7
+ # the user-scope skills directory (~/.claude/skills/ and/or
8
+ # ~/.codex/skills/).
9
+ # ────────────────────────────────────────────────────────
10
+
11
+ TARGET_MODE="auto"
12
+
13
+ # Accept --silent (alias -y) for parity with the consuming-site convention:
14
+ # scaffolded sites expose `setup:doc-skill-silent` = `bash scripts/setup-doc-skill.sh
15
+ # --silent`. This script is already non-interactive (the skill name is deterministic
16
+ # — see below), so the flag is a no-op here; it is consumed only so it is never
17
+ # mistaken for the positional skill-name override (`$1`).
18
+ while [ $# -gt 0 ]; do
19
+ case "$1" in
20
+ --silent|-y) shift ;;
21
+ --target)
22
+ shift
23
+ if [ $# -eq 0 ]; then
24
+ echo "Error: --target requires one of: auto, claude, codex, both" >&2
25
+ exit 1
26
+ fi
27
+ TARGET_MODE="$1"
28
+ shift
29
+ ;;
30
+ --target=*)
31
+ TARGET_MODE="${1#--target=}"
32
+ shift
33
+ ;;
34
+ --) shift; break ;;
35
+ -*) echo "Error: unknown flag '$1'" >&2; exit 1 ;;
36
+ *) break ;;
37
+ esac
38
+ done
39
+
40
+ case "$TARGET_MODE" in
41
+ auto|claude|codex|both) ;;
42
+ *)
43
+ echo "Error: --target must be one of: auto, claude, codex, both" >&2
44
+ exit 1
45
+ ;;
46
+ esac
47
+
48
+ ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
49
+
50
+ # Read project name from package.json
51
+ PROJECT_NAME=$(node -e "console.log(require('$ROOT_DIR/package.json').name || 'my-project')")
52
+ DEFAULT_SKILL_NAME="${PROJECT_NAME}-wisdom"
53
+
54
+ echo ""
55
+ echo "=== zudo-doc Skill Setup ==="
56
+ echo ""
57
+
58
+ # Skill name is DETERMINISTIC: always `<projectName>-wisdom`. The scaffolded
59
+ # .gitignore (emitted by create-zudo-doc) hard-codes this exact name, so the
60
+ # generated skill directory must match it — an interactive prompt would let the
61
+ # name drift from the gitignore entry and leave the skill showing as untracked
62
+ # (zudolab/zudo-doc#2173). An explicit override is still allowed via the first
63
+ # CLI arg or the SKILL_NAME env var (consumers who override must also update
64
+ # their .gitignore), but never via an interactive prompt.
65
+ SKILL_NAME="${1:-${SKILL_NAME:-$DEFAULT_SKILL_NAME}}"
66
+
67
+ # Validate skill name (allow only alphanumeric, hyphens, underscores)
68
+ if [[ ! "$SKILL_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
69
+ echo "Error: Skill name may only contain letters, numbers, hyphens, and underscores."
70
+ exit 1
71
+ fi
72
+
73
+ # Resolve the main repo root (handles git worktrees correctly)
74
+ # Use the main worktree path so symlinks survive worktree removal
75
+ REPO_ROOT="$(git -C "$ROOT_DIR" worktree list | head -1 | awk '{print $1}')"
76
+
77
+ DOCS_DIR="$ROOT_DIR/src/content/docs"
78
+
79
+ # Validate docs directory exists
80
+ if [ ! -d "$DOCS_DIR" ]; then
81
+ echo "Error: Documentation directory not found at $DOCS_DIR"
82
+ exit 1
83
+ fi
84
+
85
+ # Helper: replace a symlink or file at the given path
86
+ ensure_symlink() {
87
+ local link_path="$1"
88
+ local target="$2"
89
+ if [ -L "$link_path" ] || [ -e "$link_path" ]; then
90
+ rm -rf "$link_path"
91
+ fi
92
+ ln -s "$target" "$link_path"
93
+ }
94
+
95
+ DOCS_JA_DIR="$ROOT_DIR/src/content/docs-ja"
96
+ HAS_JA=""
97
+ if [ -d "$DOCS_JA_DIR" ]; then
98
+ HAS_JA="true"
99
+ fi
100
+
101
+ # Discover top-level doc categories dynamically
102
+ DOC_TREE=""
103
+ for dir in "$DOCS_DIR"/*/; do
104
+ [ -d "$dir" ] || continue
105
+ dirname="$(basename "$dir")"
106
+ DOC_TREE="${DOC_TREE}- ${dirname}/
107
+ "
108
+ done
109
+
110
+ resolve_targets() {
111
+ case "$TARGET_MODE" in
112
+ claude) echo "claude" ;;
113
+ codex) echo "codex" ;;
114
+ both) echo "claude codex" ;;
115
+ auto)
116
+ local has_claude=""
117
+ local has_codex=""
118
+ [ -d "$HOME/.claude" ] && has_claude="true"
119
+ [ -d "$HOME/.codex" ] && has_codex="true"
120
+
121
+ if [ "$has_claude" = "true" ] && [ "$has_codex" = "true" ]; then
122
+ echo "claude codex"
123
+ elif [ "$has_codex" = "true" ]; then
124
+ echo "codex"
125
+ else
126
+ # Preserve the historical default for fresh machines and test homes.
127
+ echo "claude"
128
+ fi
129
+ ;;
130
+ esac
131
+ }
132
+
133
+ generate_skill() {
134
+ local target="$1"
135
+ local project_skills_dir="$ROOT_DIR/.$target/skills"
136
+ local skill_dir="$project_skills_dir/$SKILL_NAME"
137
+ local global_skills_dir="$HOME/.$target/skills"
138
+ local assistant_label
139
+
140
+ case "$target" in
141
+ claude) assistant_label="Claude Code" ;;
142
+ codex) assistant_label="Codex" ;;
143
+ *) echo "Error: unknown target '$target'" >&2; exit 1 ;;
144
+ esac
145
+
146
+ mkdir -p "$skill_dir"
147
+
148
+ ensure_symlink "$skill_dir/docs" "$REPO_ROOT/src/content/docs"
149
+ echo " [$target] Created docs symlink -> $REPO_ROOT/src/content/docs"
150
+
151
+ if [ "$HAS_JA" = "true" ]; then
152
+ ensure_symlink "$skill_dir/docs-ja" "$REPO_ROOT/src/content/docs-ja"
153
+ echo " [$target] Created docs-ja symlink -> $REPO_ROOT/src/content/docs-ja"
154
+ fi
155
+
156
+ cat > "$skill_dir/SKILL.md" << SKILLEOF
157
+ ---
158
+ name: $SKILL_NAME
159
+ description: >-
160
+ Search and reference documentation from the $PROJECT_NAME project.
161
+ Use when answering questions about $PROJECT_NAME features, configuration,
162
+ components, or usage patterns.
163
+ user-invocable: true
164
+ argument-hint: "[-u|--update] [topic keyword, e.g., 'configuration', 'sidebar', 'i18n']"
165
+ ---
166
+
167
+ # $PROJECT_NAME Documentation Reference
168
+
169
+ Look up documentation from the $PROJECT_NAME project for $assistant_label.
170
+ Documentation base path: \`src/content/docs\` (relative to repo root)
171
+
172
+ ## Mode Detection
173
+
174
+ Parse the argument string for flags:
175
+
176
+ - If args start with \`-u\` or \`--update\`: enter **Update mode** (see below)
177
+ - Otherwise: enter **Lookup mode** (default)
178
+
179
+ Strip the flag from the remaining argument to get the topic keyword.
180
+
181
+ ## Lookup Mode (default)
182
+
183
+ 1. Find the relevant article(s) from the \`docs/\` directory based on the topic
184
+ 2. Read ONLY the specific article(s) you need — do NOT load all articles at once
185
+ 3. Apply the information from the article when answering the user's question
186
+ 4. Mention the source article path so the user can find it for further reading
187
+
188
+ ## Update Mode (\`-u\` / \`--update\`)
189
+
190
+ The user has new information and wants to add or update documentation in this repo.
191
+
192
+ ### Workflow
193
+
194
+ 1. **Understand the new info**: Ask the user what they learned or want to
195
+ document. The topic keyword (if provided) hints at the subject area.
196
+ 2. **Find existing docs**: Search the \`docs/\` directory for articles related to
197
+ the topic. Read them to understand what is already covered.
198
+ 3. **Decide create vs update**: If an existing article covers the topic, update
199
+ it. Otherwise, create a new \`.mdx\` file in the appropriate subdirectory.
200
+ 4. **Write the content**: Follow the doc-authoring rules in the root CLAUDE.md:
201
+ - Required frontmatter: \`title\` (string). Always set \`sidebar_position\`.
202
+ Optional: \`description\`, \`sidebar_label\`, \`tags\`, etc.
203
+ - Do NOT use \`# h1\` in content — the frontmatter \`title\` renders as h1.
204
+ Start with \`## h2\` headings.
205
+ - Use available MDX components (\`<Note>\`, \`<Tip>\`, \`<Info>\`, \`<Warning>\`,
206
+ \`<Danger>\`, \`<HtmlPreview>\`) where appropriate.
207
+ - For live demos, use \`<HtmlPreview>\` with \`js\`/\`displayJs\` props.
208
+ - Link to other docs using relative paths with \`.mdx\` extension.
209
+ 5. **Update Japanese docs**: Create or update the corresponding file under
210
+ \`docs-ja/\` mirroring the English directory structure. Keep code blocks,
211
+ Mermaid diagrams, and \`<HtmlPreview>\` blocks identical — only translate
212
+ surrounding prose. Exception: pages with \`generated: true\` skip translation.
213
+ 6. **Format**: Run \`pnpm format:md\` to format the new/changed MDX files.
214
+ 7. **Verify**: Run \`pnpm build\` to confirm the site builds correctly.
215
+
216
+ ## Documentation Structure
217
+
218
+ The documentation is organized in MDX files under \`docs/\`:
219
+
220
+ \`\`\`
221
+ ${DOC_TREE}\`\`\`
222
+
223
+ Browse the \`docs/\` directory to discover available articles. Each \`.mdx\` file
224
+ has YAML frontmatter with \`title\` and \`description\` fields that help identify
225
+ the right article to read.
226
+ SKILLEOF
227
+
228
+ if [ "$HAS_JA" = "true" ]; then
229
+ cat >> "$skill_dir/SKILL.md" << JAEOF
230
+
231
+ ## Japanese Documentation
232
+
233
+ Japanese translations are available under \`docs-ja/\`. When the user is working
234
+ in Japanese or asks for Japanese content, prefer articles from \`docs-ja/\`.
235
+ JAEOF
236
+ fi
237
+
238
+ echo " [$target] Generated SKILL.md"
239
+
240
+ mkdir -p "$global_skills_dir"
241
+ ensure_symlink "$global_skills_dir/$SKILL_NAME" "$skill_dir"
242
+
243
+ echo " [$target] Project skill: $skill_dir"
244
+ echo " [$target] Global symlink: $global_skills_dir/$SKILL_NAME"
245
+ }
246
+
247
+ read -r -a TARGETS <<< "$(resolve_targets)"
248
+ echo "Target: $TARGET_MODE -> ${TARGETS[*]}"
249
+ echo ""
250
+
251
+ for target in "${TARGETS[@]}"; do
252
+ generate_skill "$target"
253
+ done
254
+
255
+ echo ""
256
+ echo "Done! Skill '$SKILL_NAME' is ready."
257
+ echo ""
258
+ echo "Use --target claude, --target codex, or --target both to override auto-detection."
259
+ echo "In Claude Code, use: /$SKILL_NAME <topic>"
260
+ echo "In Codex, mention the skill by name when asking about this documentation."
261
+ echo ""
@@ -152,6 +152,11 @@ declare module "zfb/config" {
152
152
  * haven't opted in.
153
153
  */
154
154
  trailingSlash?: boolean;
155
+ /**
156
+ * Minify production HTML output from `zfb build`.
157
+ * Mirrors `Config::minify_html` in crates/zfb/src/config.rs.
158
+ */
159
+ minifyHtml?: boolean;
155
160
  /**
156
161
  * Markdown / MDX pipeline options. Mirrors `Config::markdown` →
157
162
  * `MarkdownConfig` in crates/zfb/src/config.rs. zfb next.12 moved the