l-update-generator
Detect and fix drift between the main zudo-doc project and the create-zudo-doc generator CLI. Use when adding/removing features, or to verify the generator stays in sync. Also triggered by "update generator", "sync generator", "l-update-generator", "l-sync-create-zudo-doc".
- License 许可
- MIT
- 所属仓库
- zudolab/zudo-doc
- 最近更新
- 2026-11-14
- Stars
- ★ 1
- Forks
- 0
01 前言 Front Matter
- name
- l-update-generator
- description
- Detect and fix drift between the main zudo-doc project and the create-zudo-doc generator CLI. Use when adding/removing features, or to verify the generator stays in sync. Also triggered by "update generator", "sync generator", "l-update-generator", "l-sync-create-zudo-doc".
03 SKILL.md 正文
Update create-zudo-doc Generator
Detect and fix drift between the main zudo-doc project and the create-zudo-doc CLI generator.
Architecture Overview (minimal-scaffold, epic zudolab/zudo-doc#2651)
The generator emits the locked ~12-file minimal manifest — one config
file (zfb.config.ts, zudoDoc({ ...only fields the user chose })) plus
markdown content plus a handful of unavoidable root files. Everything else
(layout, chrome, islands, default :root tokens, even the doc ROUTES
themselves via packageOwnedRoutes) ships from @takazudo/zudo-doc in
node_modules. There is no more copy-then-strip and no more @slot:
injection anchors:
- Copy the minimal base template (
templates/base/) — 10 files, no injection anchors:pages/index.tsx,pages/docs/[[...slug]].tsx,src/styles/global.css,tsconfig.json,scripts/setup-doc-skill.sh,scripts/check-links.js, and fourpublic/favicon files (the last is excluded from the unconditional mirror and copied only whenskillSymlinkeris selected — seescaffold.ts'sEXCLUDE_FROM_MIRROR). - Generate the ONE
zfb.config.tsprogrammatically (zfb-config-gen.ts) — diff-from-defaults: only fields whose value differs from the matchingZudoDocConfig@defaultare emitted (siteNameis always emitted). There is no moresettings-gen.tsand no moresrc/config/settings.tsin a fresh scaffold. - Compose selected features (
compose.ts+src/features/*.ts) — most feature modules are now pure settings-field emission (injections: [], nopostProcess) because the corresponding UI/behavior is entirely package-owned (package-first migration, epics #2321/#2344/#2356). Only a handful still do real work:- Genuine file copies:
i18n(locale doc-route stub),tagGovernance(one explicitsrc/config/tag-vocabulary.tsCLI/config module),skillSymlinker(scripts/setup-doc-skill.sh, copied inscaffold.tsdirectly, not atemplates/features/dir),claudeSkills(copies curatedzudo-doc-*Claude Code skills from the monorepo, also inscaffold.tsdirectly),claudeSkillsWriting(copies thezudo-doc-writingwriting/navigation-guide skill, also inscaffold.tsdirectly). postProcesspatches (small, targeted string patches to an already-generated file — never new files):docHistory(patches the doc-route stub(s) to statically import the realDocHistoryand thread it throughcreateChrome),designTokenPanel(inserts the one conditional@import "@takazudo/zdtp/styles.css";line intoglobal.css— the one thing that can't ship unconditionally from@takazudo/zudo-doc/theme.css, since it pulls in zdtp's own bytes),tagGovernance(writes the explicittag-vocabulary.tsmodule).- Retired features:
tauri/tauriDevwere removed (#4758). Do not treat their absence as drift; positive flags and preset/API feature names must keep failing before any write, and--no-tauri/--no-tauri-dev/--tauri=false/--tauri-dev=falsestay accepted as unadvertised no-ops.
- Genuine file copies:
tagGovernance passes its module explicitly to the package-owned
tags-audit/tags-suggest bins with --config; there are no project-side CLI
shims and no duplicate settings module.
When to Use
- After adding or removing a feature from zudo-doc
- When the drift-detection test fails
- Periodically to verify generator health
- User says "update generator", "sync generator", "check generator drift", "l-update-generator", or the old name "l-sync-create-zudo-doc"
Quick pre-check: Run pnpm check:template-drift first to get an automated summary of base template drift. Then proceed with the full workflow below for the config census, dependency, and feature composition drift.
Step 1: Analyze Drift
Compare the main project's source files with what the generator produces.
1a. Settings/config-field drift
The field census now lives in ONE place — the package, not this repo's own
src/config/settings.ts:
- Census (source of truth):
packages/zudo-doc/src/config.ts—ZudoDocConfig(the documented field surface, every field carries a@defaultJSDoc) and browser-safesettings-defaults.ts(the actualDEFAULT_SETTINGS, re-exported byconfig.ts). - Generator:
packages/create-zudo-doc/src/zfb-config-gen.ts—DEFAULT_MIRROR(a hand-kept local copy ofDEFAULT_SETTINGS, only for fields the generator can ever set — it can'timportthe package, see the file's header comment for why) +buildDesiredConfig()(user-choice → field mapping) +FIELD_ORDER(cosmetic emission order).
Compare field names between ZudoDocConfig and zfb-config-gen.ts's
DEFAULT_MIRROR/FIELD_ORDER/buildDesiredConfig(). A field the generator
can plausibly set (has a CLI flag or prompt) but is missing from
DEFAULT_MIRROR/FIELD_ORDER is drift. A field DEFAULT_MIRROR carries
whose default value no longer matches DEFAULT_SETTINGS is also drift
(stale mirror).
This repo's OWN src/config/settings.ts (the showcase's real settings
object, spread into zfb.config.ts's zudoDoc({ ...settings, ... })) is a
secondary, informal cross-check — useful for spotting a field the showcase
demonstrates but the generator never learned to emit — but it is NOT the
census. Don't chase drift against it that isn't also drift against
ZudoDocConfig.
1b. Dependency drift
Compare dependencies:
- Main:
package.json— root dependencies - Generator:
packages/create-zudo-doc/src/scaffold.tsgeneratePackageJson()— generated deps
Check for packages used in base template files and feature files that are not included in the generated package.json. Read generatePackageJson() for the actual dependency branches: zfb family pins stay aligned; zod is required; zdtp is feature-selected, and 0.9.0 has no Preact dependency, so no generated project declares Preact. diff and katex remain optional runtime peers. No preact-render-to-string or React compatibility dependency is needed for owned JSX.
1c. zfb config / preset drift
Compare the main project's zfb.config.ts (zudoDoc({ ...settings, chromeBindingsModule: "./src/chrome-bindings" })) with what the generator produces:
- Main:
zfb.config.ts— spreadssettingsfromsrc/config/settings.tsintozudoDoc({...}) - Generator:
packages/create-zudo-doc/src/zfb-config-gen.ts— programmatic diff-from-defaults generation, samezudoDoc()entry point
Both sides go through the SAME zudoDoc() function
(packages/zudo-doc/src/config.ts), so there is no separate "integration
wiring" to check field-by-field anymore — zudoDocPreset() (the internal
fragment builder zudoDoc() calls) is the one place collections/plugins/
markdown logic lives. Only check packages/zudo-doc/src/preset.ts when a
NEW plugin or collection needs wiring from a settings field (see 1d).
1d. Feature composition drift
Check that features in the main project have corresponding feature modules:
- Main: does the showcase demonstrate a behavior with no
ZudoDocConfigfield and no generator feature module backing it? - Generator:
packages/create-zudo-doc/src/features/*.ts— feature modules (mostly settings-field emission now; injections/postProcess only for the handful of genuine gaps listed in "Architecture Overview" above) - Templates:
packages/create-zudo-doc/templates/features/*/files/— feature-specific files (onlyi18nhas one;claudeSkills/claudeSkillsWritingdirectories are copied fromscaffold.ts)
For each feature-gated behavior in the main project, verify:
- A feature module exists in
src/features/and is registered insrc/features/index.ts - If the feature ships genuine files, they exist in
templates/features/<name>/files/ - If the feature introduces a new plugin/collection,
packages/zudo-doc/src/preset.ts'szudoDocPreset()wires it from the matching settings field — NOT the generator (the generator only ever emits the field value) - If the feature has a
postProcesshook, verify the string patch it applies still matches the current shape of the file it patches (e.g.docHistory's patch targets the exactcreateChrome(routeCtx);/import { createChrome } from "@takazudo/zudo-doc/chrome";lines in the doc-route stub — a stub rewrite elsewhere breaks this silently since the patch is a literal string match, not an AST edit)
1e. Base template drift
Compare the 6 source-code base template files against their showcase / package counterparts (the four favicon files are byte-identical assets; most showcase behavior is package-owned, not template-mirrored):
templates/base/pages/index.tsx— 1-line re-exporttemplates/base/pages/docs/[[...slug]].tsx— self-contained doc-route stub (compare against the showcase'spages/docs/[[...slug]].tsx, which the.template-drift-allowlistallows to diverge — the showcase addschromeBindingsModulewiring the minimal stub doesn't need)templates/base/src/styles/global.css— fixed ~20-line@importchain (compare against the showcase'ssrc/styles/global.css, also allowlisted — the showcase's is a superset)templates/base/tsconfig.json— 5-line extends form (compare against the showcase'stsconfig.json, allowlisted — the showcase addsnoUncheckedIndexedAccess,types, and extraincludepaths, while both staybaseUrl-free with relative alias targets — see "Owned JSX and project-local aliases" inpackages/zudo-doc/CLAUDE.md)templates/base/scripts/setup-doc-skill.sh— should be byte-identical to the rootscripts/setup-doc-skill.sh(the root copy IS the source template; not allowlisted, must match exactly)templates/base/scripts/check-links.js— source-first counterpart to the showcase checker; allowlisted because generated projects read literal settings fromzfb.config.tsinstead of the showcase'ssrc/config/settings.ts, so validation-core changes require manual parity review
Automated first check: Run pnpm check:template-drift before doing manual analysis. This runs scripts/check-template-drift.sh and quickly identifies files that differ between the main project and the base template.
Allowlist note: The base-template pairs in .template-drift-allowlist (global.css, tsconfig.json, pages/index.tsx, the two doc-route stubs, and scripts/check-links.js) are skipped by the automated script's whole-file content check because they intentionally differ (the showcase carries wiring the minimal template doesn't need). These files still require manual review — check that validation-core or other relevant changes in the main project are reflected in the template counterpart. global.css also has a dedicated automated guard (check_global_css_legacy_tokens in scripts/check-template-drift.sh) that fails if the template regresses to a pre-ramp-restructure token or drops the @import "@takazudo/zudo-doc/theme.css" line — that one drift class stays automated even though the rest of the file needs manual review.
Step 2: Report Findings
Present a clear drift report:
## Config-Field Drift
- Missing in generator: fieldA, fieldB (present in ZudoDocConfig, absent from DEFAULT_MIRROR/FIELD_ORDER)
- Stale default in DEFAULT_MIRROR: fieldC (generator default no longer matches DEFAULT_SETTINGS)
## Dependency Drift
- Missing from generated package.json: packageX (used unconditionally, or by featureY)
- Unnecessary in generated package.json: packageZ (feature disabled / no longer needed)
## Preset Drift
- Missing plugin wiring: pluginX in packages/zudo-doc/src/preset.ts for settings.fieldY
## Feature Composition Drift
- Missing feature module: feature "X" has a ZudoDocConfig field but no src/features/<name>.ts
- Missing template files: feature "X" module exists but templates/features/X/files/ is missing a file it should copy
- Stale postProcess patch: feature "X"'s string-replace target no longer exists in the file it patches
## Base Template Drift
- Stale file: templates/base/<path> differs from its showcase/package counterpart
## No Drift Detected
(if everything is in sync)
Step 3: Apply Fixes
For each drift item found:
- Config-field drift → Update
zfb-config-gen.ts'sDEFAULT_MIRROR+buildDesiredConfig()+FIELD_ORDER. If the field doesn't exist yet onZudoDocConfig, add it there first (with a@defaultJSDoc — enforced byconfig-jsdoc.test.ts) and tosettings-defaults.ts'sDEFAULT_SETTINGS. - Dependency drift → Update
scaffold.tsgeneratePackageJson()to add/remove deps - Preset drift → Update
packages/zudo-doc/src/preset.ts'szudoDocPreset()to wire the plugin/collection from the settings field - Feature composition drift → Create/update feature module in
src/features/, register it insrc/features/index.ts, add template files only if there's a genuine gap (check whether@takazudo/zudo-docalready ships the behavior first) - Base template drift → Update the stale file in
templates/base/
After fixes:
- Run
cd packages/create-zudo-doc && pnpm buildto verify TypeScript compiles - Run
cd packages/create-zudo-doc && pnpm testto verify tests pass (including the settings-drift guard, which assertsZudoDocConfigis a subset ofFIELD_ORDER∪ a reasoned allowlist) - Commit with message:
fix(create-zudo-doc): sync generator with main project
Key Files
| File | Role |
|---|---|
packages/zudo-doc/src/config.ts |
Canonical field census — ZudoDocConfig (documented, @default-tagged); browser-safe settings-defaults.ts owns DEFAULT_SETTINGS. Source of truth for every generated project's field surface. |
src/config/settings.ts |
This repo's own showcase settings (informal cross-check only — see Step 1a) |
zfb.config.ts |
Main project zfb config — zudoDoc({ ...settings, chromeBindingsModule: "./src/chrome-bindings" }) |
packages/create-zudo-doc/src/zfb-config-gen.ts |
The SINGLE config generator — emits defineConfig(zudoDoc({...})), diff-from-defaults against DEFAULT_MIRROR (a local, hand-kept copy of DEFAULT_SETTINGS) |
packages/create-zudo-doc/src/compose.ts |
Composition engine (injection system mostly unused — ANCHOR_FILES is []; kept as infra), feature resolution |
packages/create-zudo-doc/src/features/*.ts |
Feature modules — settings-field emission via zfb-config-gen.ts, plus a handful of genuine file copies / postProcess patches |
packages/create-zudo-doc/src/features/index.ts |
Registers every feature module |
packages/create-zudo-doc/src/scaffold.ts |
Orchestrates generation pipeline, generates package.json, .gitignore, .npmrc, seeds starter content |
packages/create-zudo-doc/src/claude-md-gen.ts |
Generates the per-project CLAUDE.md |
packages/create-zudo-doc/templates/base/ |
The locked ~21-file (barebone) minimal manifest's static half — 10 files, no @slot: anchors |
packages/create-zudo-doc/templates/features/ |
Feature-specific files copied when a feature is enabled — only i18n has one (claudeSkills/claudeSkillsWriting directories are copied from scaffold.ts) |
packages/zudo-doc/src/preset.ts |
zudoDocPreset() — wires plugins/collections/markdown from settings fields; the generator never wires plugins directly |
packages/create-zudo-doc/src/__tests__/scaffold.test.ts |
Manifest-shape assertions (exact 12-file barebone list, exact all-on list, settings-drift guard) |
packages/create-zudo-doc/src/__tests__/zfb-config-gen.test.ts |
Field-mapping / diff-from-defaults unit tests |
04 同仓库更多 Skills
zudo-doc-writing
Doc-writing and navigation-structure guide for this zudo-doc project. Consult BEFORE creating pages, adding categories, designing header navigation, or writing/editing mdx content under src/content/. Covers: reading the AUTHORING.md editorial policy and its four placement questions, when to run a structure review, plan-the-nav-tree-first workflow, tree vs note-tray categories, the recommended 3-level hierarchy (header → sidebar → nested), filesystem navigation as the default, linked versus heading-only category rows, category index pages, sidebar_position discipline, frontmatter schema, no-h1 rule, relative .mdx links, and admonition syntax. Triggered by 'write docs', 'add a page', 'create a page', 'add category', 'structure navigation', 'nav design', 'zudo-doc-writing'.
zudo-doc-version-bump
Bump package version, update changelog and versioned docs snapshot (if those features are enabled), commit, tag, and create a GitHub release. Use when: (1) User says 'version bump', 'bump version', 'release', or 'zudo-doc-version-bump', (2) User wants to create a new release of this project.
zudo-doc-translate
Translate zudo-doc documentation between the locales configured in this project, with Japanese conventions applied only to the `ja` locale.
zudo-doc-design-system
Project-specific CSS and component rules for zudo-doc. Must be consulted before writing or editing CSS, zudo-wind utilities, color tokens, or component markup in this project. Covers: component-first strategy, design token system, three-tier color architecture, and palette index convention. Triggered by 'design system', 'zudo-doc-design-system', 'zudo-doc-css-wisdom' (old name).
localized-shell
Fixture skill for localized generated resource routes.
zudo-doc-writing-rules
Doc-writing rules for zudo-doc content (mdx files under src/content/docs/ and src/content/docs-ja/). Consult before writing or editing doc content. Covers: no h1 in content, sidebar_position is mandatory, kebab-case file names, bilingual rule, linking conventions, and admonition syntax. Triggered by 'writing rules', 'zudo-doc-writing-rules', 'doc rule', 'mdx rule', 'write a doc', 'create a page'.