AGENT SKILL

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:

  1. 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 four public/ favicon files (the last is excluded from the unconditional mirror and copied only when skillSymlinker is selected — see scaffold.ts's EXCLUDE_FROM_MIRROR).
  2. Generate the ONE zfb.config.ts programmatically (zfb-config-gen.ts) — diff-from-defaults: only fields whose value differs from the matching ZudoDocConfig @default are emitted (siteName is always emitted). There is no more settings-gen.ts and no more src/config/settings.ts in a fresh scaffold.
  3. Compose selected features (compose.ts + src/features/*.ts) — most feature modules are now pure settings-field emission (injections: [], no postProcess) 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 explicit src/config/tag-vocabulary.ts CLI/config module), skillSymlinker (scripts/setup-doc-skill.sh, copied in scaffold.ts directly, not a templates/features/ dir), claudeSkills (copies curated zudo-doc-* Claude Code skills from the monorepo, also in scaffold.ts directly), claudeSkillsWriting (copies the zudo-doc-writing writing/navigation-guide skill, also in scaffold.ts directly).
    • postProcess patches (small, targeted string patches to an already-generated file — never new files): docHistory (patches the doc-route stub(s) to statically import the real DocHistory and thread it through createChrome), designTokenPanel (inserts the one conditional @import "@takazudo/zdtp/styles.css"; line into global.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 explicit tag-vocabulary.ts module).
    • Retired features: tauri / tauriDev were 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=false stay accepted as unadvertised no-ops.

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 @default JSDoc) and browser-safe settings-defaults.ts (the actual DEFAULT_SETTINGS, re-exported by config.ts).
  • Generator: packages/create-zudo-doc/src/zfb-config-gen.ts — DEFAULT_MIRROR (a hand-kept local copy of DEFAULT_SETTINGS, only for fields the generator can ever set — it can't import the 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.ts generatePackageJson() — 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 — spreads settings from src/config/settings.ts into zudoDoc({...})
  • Generator: packages/create-zudo-doc/src/zfb-config-gen.ts — programmatic diff-from-defaults generation, same zudoDoc() 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 ZudoDocConfig field 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 (only i18n has one; claudeSkills/claudeSkillsWriting directories are copied from scaffold.ts)

For each feature-gated behavior in the main project, verify:

  1. A feature module exists in src/features/ and is registered in src/features/index.ts
  2. If the feature ships genuine files, they exist in templates/features/<name>/files/
  3. If the feature introduces a new plugin/collection, packages/zudo-doc/src/preset.ts's zudoDocPreset() wires it from the matching settings field — NOT the generator (the generator only ever emits the field value)
  4. If the feature has a postProcess hook, verify the string patch it applies still matches the current shape of the file it patches (e.g. docHistory's patch targets the exact createChrome(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-export
  • templates/base/pages/docs/[[...slug]].tsx — self-contained doc-route stub (compare against the showcase's pages/docs/[[...slug]].tsx, which the .template-drift-allowlist allows to diverge — the showcase adds chromeBindingsModule wiring the minimal stub doesn't need)
  • templates/base/src/styles/global.css — fixed ~20-line @import chain (compare against the showcase's src/styles/global.css, also allowlisted — the showcase's is a superset)
  • templates/base/tsconfig.json — 5-line extends form (compare against the showcase's tsconfig.json, allowlisted — the showcase adds noUncheckedIndexedAccess, types, and extra include paths, while both stay baseUrl-free with relative alias targets — see "Owned JSX and project-local aliases" in packages/zudo-doc/CLAUDE.md)
  • templates/base/scripts/setup-doc-skill.sh — should be byte-identical to the root scripts/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 from zfb.config.ts instead of the showcase's src/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:

  1. Config-field drift → Update zfb-config-gen.ts's DEFAULT_MIRROR + buildDesiredConfig() + FIELD_ORDER. If the field doesn't exist yet on ZudoDocConfig, add it there first (with a @default JSDoc — enforced by config-jsdoc.test.ts) and to settings-defaults.ts's DEFAULT_SETTINGS.
  2. Dependency drift → Update scaffold.ts generatePackageJson() to add/remove deps
  3. Preset drift → Update packages/zudo-doc/src/preset.ts's zudoDocPreset() to wire the plugin/collection from the settings field
  4. Feature composition drift → Create/update feature module in src/features/, register it in src/features/index.ts, add template files only if there's a genuine gap (check whether @takazudo/zudo-doc already ships the behavior first)
  5. Base template drift → Update the stale file in templates/base/

After fixes:

  1. Run cd packages/create-zudo-doc && pnpm build to verify TypeScript compiles
  2. Run cd packages/create-zudo-doc && pnpm test to verify tests pass (including the settings-drift guard, which asserts ZudoDocConfig is a subset of FIELD_ORDER ∪ a reasoned allowlist)
  3. 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

zudolab
zudolab/zudo-doc

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'.

内容创作者写作与文案
★ 1
zudolab
zudolab/zudo-doc

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.

★ 1
zudolab
zudolab/zudo-doc

zudo-doc-translate

Translate zudo-doc documentation between the locales configured in this project, with Japanese conventions applied only to the `ja` locale.

★ 1
zudolab
zudolab/zudo-doc

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).

设计师前端开发视觉设计
★ 1
zudolab
zudolab/zudo-doc

localized-shell

Fixture skill for localized generated resource routes.

★ 1
zudolab
zudolab/zudo-doc

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'.

内容创作者写作与文案
★ 1