create-zudo-doc 3.2.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +3 -2
  2. package/dist/api.d.ts +2 -0
  3. package/dist/api.js +9 -1
  4. package/dist/claude-md-gen.d.ts +8 -0
  5. package/dist/claude-md-gen.js +44 -26
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +11 -1
  8. package/dist/compose.d.ts +14 -20
  9. package/dist/compose.js +15 -25
  10. package/dist/constants.d.ts +6 -0
  11. package/dist/constants.js +123 -1
  12. package/dist/features/body-foot-util.d.ts +8 -4
  13. package/dist/features/body-foot-util.js +8 -4
  14. package/dist/features/claude-resources.d.ts +9 -0
  15. package/dist/features/claude-resources.js +10 -6
  16. package/dist/features/design-token-panel.d.ts +0 -12
  17. package/dist/features/design-token-panel.js +32 -93
  18. package/dist/features/doc-history.d.ts +19 -3
  19. package/dist/features/doc-history.js +49 -60
  20. package/dist/features/doc-tags.d.ts +9 -13
  21. package/dist/features/doc-tags.js +10 -26
  22. package/dist/features/dynamic-page-transition.d.ts +19 -30
  23. package/dist/features/dynamic-page-transition.js +21 -209
  24. package/dist/features/footer-taglist.d.ts +1 -1
  25. package/dist/features/footer-taglist.js +1 -1
  26. package/dist/features/footer.d.ts +3 -2
  27. package/dist/features/footer.js +3 -2
  28. package/dist/features/i18n.d.ts +13 -8
  29. package/dist/features/i18n.js +14 -9
  30. package/dist/features/image-enlarge.d.ts +7 -26
  31. package/dist/features/image-enlarge.js +7 -26
  32. package/dist/features/index.js +2 -0
  33. package/dist/features/llms-txt.d.ts +3 -5
  34. package/dist/features/llms-txt.js +3 -5
  35. package/dist/features/search.d.ts +7 -3
  36. package/dist/features/search.js +7 -3
  37. package/dist/features/sidebar-resizer.d.ts +4 -8
  38. package/dist/features/sidebar-resizer.js +4 -8
  39. package/dist/features/sidebar-toggle.d.ts +7 -7
  40. package/dist/features/sidebar-toggle.js +7 -7
  41. package/dist/features/tag-governance.d.ts +3 -8
  42. package/dist/features/tag-governance.js +37 -9
  43. package/dist/features/tauri.d.ts +13 -10
  44. package/dist/features/tauri.js +16 -52
  45. package/dist/features/theme-pack-switcher.d.ts +11 -0
  46. package/dist/features/theme-pack-switcher.js +13 -0
  47. package/dist/features/versioning.d.ts +12 -24
  48. package/dist/features/versioning.js +13 -39
  49. package/dist/index.js +5 -3
  50. package/dist/preset.d.ts +2 -0
  51. package/dist/preset.js +12 -1
  52. package/dist/prompts.d.ts +2 -0
  53. package/dist/prompts.js +22 -1
  54. package/dist/scaffold.d.ts +13 -6
  55. package/dist/scaffold.js +97 -78
  56. package/dist/utils.d.ts +10 -0
  57. package/dist/utils.js +14 -0
  58. package/dist/zfb-config-gen.d.ts +32 -20
  59. package/dist/zfb-config-gen.js +410 -53
  60. package/package.json +2 -2
  61. package/templates/base/pages/docs/[[...slug]].tsx +64 -0
  62. package/templates/base/pages/index.tsx +6 -41
  63. package/templates/base/src/styles/global.css +15 -340
  64. package/templates/base/tsconfig.json +3 -26
  65. package/templates/features/i18n/files/pages/[locale]/docs/[[...slug]].tsx +92 -0
  66. package/dist/settings-gen.d.ts +0 -2
  67. package/dist/settings-gen.js +0 -320
  68. package/templates/base/.htmlvalidate.json +0 -5
  69. package/templates/base/.zfb/doc-history-meta.json +0 -1
  70. package/templates/base/pages/_data.ts +0 -160
  71. package/templates/base/pages/lib/_body-end-islands.tsx +0 -165
  72. package/templates/base/pages/lib/_chrome.ts +0 -167
  73. package/templates/base/pages/lib/_details.tsx +0 -29
  74. package/templates/base/pages/lib/_doc-route-entries.ts +0 -10
  75. package/templates/base/pages/lib/_extract-headings.ts +0 -37
  76. package/templates/base/pages/lib/_frontmatter-preview-data.ts +0 -27
  77. package/templates/base/pages/lib/_nav-source-cache.ts +0 -100
  78. package/templates/base/pages/lib/_nav-source-docs.ts +0 -17
  79. package/templates/base/pages/lib/_preset-generator.tsx +0 -81
  80. package/templates/base/pages/lib/_route-context.ts +0 -32
  81. package/templates/base/pages/lib/_search-widget.tsx +0 -17
  82. package/templates/base/pages/lib/doc-page-props.ts +0 -30
  83. package/templates/base/pages/lib/locale-merge.ts +0 -59
  84. package/templates/base/scripts/run-b4push.sh +0 -102
  85. package/templates/base/src/components/ai-chat-modal.tsx +0 -18
  86. package/templates/base/src/components/content/code-group.tsx +0 -3
  87. package/templates/base/src/components/content/content-admonition.tsx +0 -4
  88. package/templates/base/src/components/desktop-sidebar-toggle.tsx +0 -15
  89. package/templates/base/src/components/doc-history.tsx +0 -21
  90. package/templates/base/src/components/image-enlarge.tsx +0 -24
  91. package/templates/base/src/components/preset-generator.tsx +0 -14
  92. package/templates/base/src/components/sidebar-toggle.tsx +0 -6
  93. package/templates/base/src/components/sidebar-tree.tsx +0 -6
  94. package/templates/base/src/config/color-scheme-utils.ts +0 -69
  95. package/templates/base/src/config/color-schemes.ts +0 -165
  96. package/templates/base/src/config/docs-schema.ts +0 -95
  97. package/templates/base/src/config/frontmatter-preview-defaults.ts +0 -27
  98. package/templates/base/src/config/frontmatter-preview-renderers.tsx +0 -46
  99. package/templates/base/src/config/i18n.ts +0 -239
  100. package/templates/base/src/config/settings-types.ts +0 -45
  101. package/templates/base/src/config/sidebars.ts +0 -66
  102. package/templates/base/src/config/tag-vocabulary-types.ts +0 -4
  103. package/templates/base/src/config/tag-vocabulary.ts +0 -20
  104. package/templates/base/src/config/z-index-tokens.ts +0 -128
  105. package/templates/base/src/types/docs-entry.ts +0 -28
  106. package/templates/base/src/types/heading.ts +0 -5
  107. package/templates/base/src/types/locale.ts +0 -10
  108. package/templates/base/src/utils/base.ts +0 -164
  109. package/templates/base/src/utils/docs.ts +0 -446
  110. package/templates/base/src/utils/git-info.ts +0 -70
  111. package/templates/base/src/utils/github.ts +0 -22
  112. package/templates/base/src/utils/nav-scope.ts +0 -34
  113. package/templates/base/src/utils/sidebar.ts +0 -36
  114. package/templates/base/src/utils/slug.ts +0 -10
  115. package/templates/base/src/utils/smart-break.tsx +0 -12
  116. package/templates/base/src/utils/tags.ts +0 -83
  117. package/templates/base/zfb-shim.d.ts +0 -183
  118. package/templates/features/bodyFootUtil/files/src/utils/github.ts +0 -22
  119. package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +0 -42
  120. package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +0 -752
  121. package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +0 -97
  122. package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +0 -735
  123. package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +0 -15
  124. package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +0 -435
  125. package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +0 -174
  126. package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +0 -30
  127. package/templates/features/docHistory/files/src/components/doc-history.tsx +0 -10
  128. package/templates/features/docHistory/files/src/types/doc-history.ts +0 -7
  129. package/templates/features/dynamicPageTransition/files/src/components/client-router-bootstrap.tsx +0 -72
  130. package/templates/features/i18n/files/pages/[locale]/index.tsx +0 -72
  131. package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +0 -11
  132. package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +0 -6
  133. package/templates/features/tagGovernance/files/scripts/tags-audit.ts +0 -131
  134. package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +0 -428
  135. package/templates/features/tauri/files/src/components/find-bar.tsx +0 -122
  136. package/templates/features/tauri/files/src/components/find-in-page-init.tsx +0 -59
  137. package/templates/features/tauri/files/src/utils/find-in-page.ts +0 -175
@@ -1,16 +1,44 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import { getSecondaryLang } from "../utils.js";
1
4
  /**
2
5
  * Tag governance feature.
3
6
  *
4
- * Ships the tag audit and suggest scripts. Settings (`tagVocabulary`,
5
- * `tagGovernance`) are emitted by `settings-gen.ts`; devDeps and
6
- * `tags:audit` / `tags:suggest` package scripts are added in
7
- * `scaffold.ts#generatePackageJson`.
8
- *
9
- * `src/config/tag-vocabulary.ts` and `tag-vocabulary-types.ts` stay in the
10
- * base template because `src/utils/tags.ts` and `settings-types.ts` import
11
- * from them regardless of whether governance is on.
7
+ * Writes one project-owned tag vocabulary module. Its named vocabulary export
8
+ * feeds zfb while its default TagCliConfig export feeds both package-owned
9
+ * bins through an explicit `--config` package-script argument.
12
10
  */
13
- export const tagGovernanceFeature = () => ({
11
+ export const tagGovernanceFeature = (choices) => ({
14
12
  name: "tagGovernance",
15
13
  injections: [],
14
+ postProcess: async (targetDir) => {
15
+ const vocabPath = path.join(targetDir, "src/config/tag-vocabulary.ts");
16
+ if (!(await fs.pathExists(vocabPath))) {
17
+ const contentDirs = choices.features.includes("i18n")
18
+ ? `[
19
+ "src/content/docs",
20
+ "src/content/docs-${getSecondaryLang(choices.defaultLang)}",
21
+ ]`
22
+ : `["src/content/docs"]`;
23
+ await fs.outputFile(vocabPath, `import type { TagCliConfig } from "@takazudo/zudo-doc/tags-audit";
24
+ import type { TagVocabularyEntry } from "@takazudo/zudo-doc/settings";
25
+
26
+ // Starter (empty) tag vocabulary — add an entry per tag you use in doc
27
+ // frontmatter so \`pnpm tags:audit\` can validate it. This named export is
28
+ // also consumed by zfb.config.ts as tagVocabularyEntries.
29
+ export const tagVocabulary: TagVocabularyEntry[] = [];
30
+
31
+ // Package scripts pass this module to the package-owned audit/suggest bins.
32
+ // Paths are resolved from the project root.
33
+ const tagCliConfig = {
34
+ contentDirs: ${contentDirs},
35
+ vocabulary: tagVocabulary,
36
+ governance: "warn",
37
+ vocabularyActive: true,
38
+ } satisfies TagCliConfig;
39
+
40
+ export default tagCliConfig;
41
+ `);
42
+ }
43
+ },
16
44
  });
@@ -2,15 +2,18 @@ import type { FeatureModule } from "../compose.js";
2
2
  /**
3
3
  * Tauri feature.
4
4
  *
5
- * #2052: the FindInPageInit island (Cmd/Ctrl+F find bar for the Tauri
6
- * WebView, where the browser-native find UI is unavailable) is wired into
7
- * `pages/lib/_body-end-islands.tsx` via the three injections below — import,
8
- * displayName, and Island mount. zfb's island scanner only registers
9
- * components reachable through static import chains (page → wrapper →
10
- * component), so without this injection the feature-copied component files
11
- * are orphaned dead code that never hydrates. The find-match highlight CSS
12
- * is unconditional in `templates/base/src/styles/global.css` (matches host);
13
- * the component runtime-gates itself (renders null unless
14
- * `window.__TAURI_INTERNALS__` exists), so no settings field is needed.
5
+ * Minimal-scaffold cutover (epic zudolab/zudo-doc#2651, Wave 6 #2660): the
6
+ * `src-tauri/**` Rust shell is a genuine, unconditional file copy (no
7
+ * package equivalent — kept exactly as before).
8
+ *
9
+ * The FindInPageInit island (Cmd/Ctrl+F find bar, #2052) is now
10
+ * package-owned (`@takazudo/zudo-doc`, #2689) instead of a template file
11
+ * copy — `zfb-config-gen.ts`'s `buildDesiredConfig()` sets
12
+ * `findInPage: true` whenever this feature is selected (#2690), which mounts
13
+ * the package's `FindInPageInit` island via `zudoDocPreset()`. There is no
14
+ * separate `findInPage` feature module or CLI flag; it rides this one. The
15
+ * island self-gates on `window.__TAURI_INTERNALS__`, so it's a safe no-op in
16
+ * a plain browser build even though `findInPage: true` is unconditionally
17
+ * emitted for every tauri-feature scaffold.
15
18
  */
16
19
  export declare const tauriFeature: FeatureModule;
@@ -1,60 +1,26 @@
1
1
  import fs from "fs-extra";
2
2
  import path from "path";
3
+ import { pmRunCommand } from "../utils.js";
3
4
  /**
4
5
  * Tauri feature.
5
6
  *
6
- * #2052: the FindInPageInit island (Cmd/Ctrl+F find bar for the Tauri
7
- * WebView, where the browser-native find UI is unavailable) is wired into
8
- * `pages/lib/_body-end-islands.tsx` via the three injections below — import,
9
- * displayName, and Island mount. zfb's island scanner only registers
10
- * components reachable through static import chains (page → wrapper →
11
- * component), so without this injection the feature-copied component files
12
- * are orphaned dead code that never hydrates. The find-match highlight CSS
13
- * is unconditional in `templates/base/src/styles/global.css` (matches host);
14
- * the component runtime-gates itself (renders null unless
15
- * `window.__TAURI_INTERNALS__` exists), so no settings field is needed.
7
+ * Minimal-scaffold cutover (epic zudolab/zudo-doc#2651, Wave 6 #2660): the
8
+ * `src-tauri/**` Rust shell is a genuine, unconditional file copy (no
9
+ * package equivalent — kept exactly as before).
10
+ *
11
+ * The FindInPageInit island (Cmd/Ctrl+F find bar, #2052) is now
12
+ * package-owned (`@takazudo/zudo-doc`, #2689) instead of a template file
13
+ * copy — `zfb-config-gen.ts`'s `buildDesiredConfig()` sets
14
+ * `findInPage: true` whenever this feature is selected (#2690), which mounts
15
+ * the package's `FindInPageInit` island via `zudoDocPreset()`. There is no
16
+ * separate `findInPage` feature module or CLI flag; it rides this one. The
17
+ * island self-gates on `window.__TAURI_INTERNALS__`, so it's a safe no-op in
18
+ * a plain browser build even though `findInPage: true` is unconditionally
19
+ * emitted for every tauri-feature scaffold.
16
20
  */
17
21
  export const tauriFeature = (choices) => ({
18
22
  name: "tauri",
19
- injections: [
20
- // 1. Import the island entry. Inserted AFTER the
21
- // `// @slot:body-end-islands:imports` anchor.
22
- {
23
- file: "pages/lib/_body-end-islands.tsx",
24
- anchor: "// @slot:body-end-islands:imports",
25
- position: "after",
26
- content: `import FindInPageInit from "@/components/find-in-page-init";`,
27
- },
28
- // 2. Stable island marker name (same belt-and-braces guard as the
29
- // sibling islands in the file). Inserted AFTER the
30
- // `// @slot:body-end-islands:display-names` anchor.
31
- {
32
- file: "pages/lib/_body-end-islands.tsx",
33
- anchor: "// @slot:body-end-islands:display-names",
34
- position: "after",
35
- content: `(FindInPageInit as { displayName?: string }).displayName = "FindInPageInit";`,
36
- },
37
- // 3. Island mount. Inserted AFTER the
38
- // `{/* @slot:body-end-islands:extra-islands */}` anchor.
39
- // when="load" (not "idle"): the island's job is to intercept
40
- // Cmd/Ctrl+F via a keydown listener, so it must hydrate as soon as
41
- // the islands runtime mounts — same rationale as the
42
- // clientRouterBootstrap click intercept above it. Deferring to idle
43
- // would leave a post-load window where Cmd+F does nothing, which is
44
- // the very bug this injection fixes.
45
- {
46
- file: "pages/lib/_body-end-islands.tsx",
47
- anchor: "{/* @slot:body-end-islands:extra-islands */}",
48
- position: "after",
49
- content: ` {/* Tauri-only find-in-page (Cmd/Ctrl+F) bar. Renders null outside
50
- a Tauri WebView, so the island is inert in plain browser builds
51
- of the same scaffold. */}
52
- {Island({
53
- when: "load",
54
- children: <FindInPageInit />,
55
- }) as unknown as VNode}`,
56
- },
57
- ],
23
+ injections: [],
58
24
  postProcess: async (targetDir) => {
59
25
  // Patch Cargo.toml package name
60
26
  const cargoPath = path.join(targetDir, "src-tauri/Cargo.toml");
@@ -76,9 +42,7 @@ export const tauriFeature = (choices) => ({
76
42
  content = content.replace(/"productName": "ZudoDoc"/, `"productName": "${productName}"`);
77
43
  content = content.replace(/"identifier": "com.zudolab.zudo-doc"/, `"identifier": "${identifier}"`);
78
44
  // Patch beforeDevCommand for the chosen package manager
79
- const devCmd = choices.packageManager === "npm" || choices.packageManager === "bun"
80
- ? `${choices.packageManager} run dev`
81
- : `${choices.packageManager} dev`;
45
+ const devCmd = pmRunCommand(choices.packageManager, "dev");
82
46
  content = content.replace(/"beforeDevCommand": "pnpm dev"/, `"beforeDevCommand": "${devCmd}"`);
83
47
  await fs.writeFile(confPath, content);
84
48
  }
@@ -0,0 +1,11 @@
1
+ import type { FeatureModule } from "../compose.js";
2
+ /**
3
+ * themePackSwitcher feature (theme pack ADR #2818).
4
+ *
5
+ * Purely a `zudoDoc({ themePackSwitcher: true })` field (see
6
+ * `zfb-config-gen.ts`) — the bottom-right switcher flyout and its browse-all
7
+ * dialog are PACKAGE-INJECTED (`@takazudo/zudo-doc`'s theme-pack-provider /
8
+ * theme-pack-sync + the flyout/dialog islands), gated on
9
+ * `settings.themePackSwitcher`. There is nothing to copy or postProcess.
10
+ */
11
+ export declare const themePackSwitcherFeature: FeatureModule;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * themePackSwitcher feature (theme pack ADR #2818).
3
+ *
4
+ * Purely a `zudoDoc({ themePackSwitcher: true })` field (see
5
+ * `zfb-config-gen.ts`) — the bottom-right switcher flyout and its browse-all
6
+ * dialog are PACKAGE-INJECTED (`@takazudo/zudo-doc`'s theme-pack-provider /
7
+ * theme-pack-sync + the flyout/dialog islands), gated on
8
+ * `settings.themePackSwitcher`. There is nothing to copy or postProcess.
9
+ */
10
+ export const themePackSwitcherFeature = () => ({
11
+ name: "themePackSwitcher",
12
+ injections: [],
13
+ });
@@ -2,30 +2,18 @@ import type { FeatureModule } from "../compose.js";
2
2
  /**
3
3
  * Versioning feature.
4
4
  *
5
- * The pages/lib wrappers gate `VersionSwitcher` and `VersionBanner` on
6
- * `settings.versions`. Doc-layout flow is handled by route enumerators +
7
- * `_inline-version-switcher.tsx`. This feature copies versioning page
8
- * templates from `templates/features/versioning/files/` via
9
- * `copyFeatureFiles` (compose.ts), and injects nothing into `global.css`.
5
+ * Purely a `zudoDoc({ versions: [] })` field (see `zfb-config-gen.ts`) — the
6
+ * versioned doc routes (`/docs/versions`, `/v/[version]/docs/[[...slug]]`,
7
+ * and their i18n counterparts) are PACKAGE-INJECTED
8
+ * (`settings.packageOwnedRoutes`, default on) and render through the shared
9
+ * `renderDocPage` chrome. `templates/features/versioning/files/` has been
10
+ * empty since #2390 — there is no host stub left to copy or postProcess.
10
11
  *
11
- * W7C (#1738): the versioning feature ships pages under
12
- * `templates/features/versioning/files/pages/`:
13
- *
14
- * lib/_versions-page.tsx (always — versions-listing renderer)
15
- *
16
- * The versioned DOC routes — `/docs/versions`, `/v/[version]/docs/[[...slug]]`,
17
- * and `/v/[version]/[locale]/docs/[[...slug]]` — are now PACKAGE-INJECTED
18
- * (packageOwnedRoutes); their host catch-all stubs were deleted from the
19
- * template in #2390 (supersedes #2377) so generated projects render them via
20
- * injection through `@takazudo/zudo-doc`'s `_chrome` chrome (which wires the
21
- * MDX content components). The package route is the functional equivalent of
22
- * the old stub (it enumerates `settings.versions` and renders via the shared
23
- * `renderDocPage`).
24
- *
25
- * `copyFeatureFiles` (compose.ts) auto-copies everything under `files/`.
26
- * postProcess is now a defensive no-op: the i18n-gated stubs it strips
27
- * (`[locale]/docs/versions.tsx`, `v/[version]/[locale]/**`) no longer ship in
28
- * the template, but the cleanup is kept so a re-added stub can never leak an
29
- * orphan locale route into a single-locale project.
12
+ * Known limitation (pre-existing, not introduced by the minimal-scaffold
13
+ * cutover — inherited from the same injected-DYNAMIC-route dev-mode gap the
14
+ * locked manifest's `pages/docs/[[...slug]].tsx` stub exists to fix for the
15
+ * primary doc route, tracked as a #2667 follow-up): the versioned doc
16
+ * routes may still 404 in `zfb dev` since versioning has no stub of its own
17
+ * in the locked manifest. `zfb build` is unaffected.
30
18
  */
31
19
  export declare const versioningFeature: FeatureModule;
@@ -1,47 +1,21 @@
1
- import fs from "fs-extra";
2
- import path from "path";
3
1
  /**
4
2
  * Versioning feature.
5
3
  *
6
- * The pages/lib wrappers gate `VersionSwitcher` and `VersionBanner` on
7
- * `settings.versions`. Doc-layout flow is handled by route enumerators +
8
- * `_inline-version-switcher.tsx`. This feature copies versioning page
9
- * templates from `templates/features/versioning/files/` via
10
- * `copyFeatureFiles` (compose.ts), and injects nothing into `global.css`.
4
+ * Purely a `zudoDoc({ versions: [] })` field (see `zfb-config-gen.ts`) — the
5
+ * versioned doc routes (`/docs/versions`, `/v/[version]/docs/[[...slug]]`,
6
+ * and their i18n counterparts) are PACKAGE-INJECTED
7
+ * (`settings.packageOwnedRoutes`, default on) and render through the shared
8
+ * `renderDocPage` chrome. `templates/features/versioning/files/` has been
9
+ * empty since #2390 — there is no host stub left to copy or postProcess.
11
10
  *
12
- * W7C (#1738): the versioning feature ships pages under
13
- * `templates/features/versioning/files/pages/`:
14
- *
15
- * lib/_versions-page.tsx (always — versions-listing renderer)
16
- *
17
- * The versioned DOC routes — `/docs/versions`, `/v/[version]/docs/[[...slug]]`,
18
- * and `/v/[version]/[locale]/docs/[[...slug]]` — are now PACKAGE-INJECTED
19
- * (packageOwnedRoutes); their host catch-all stubs were deleted from the
20
- * template in #2390 (supersedes #2377) so generated projects render them via
21
- * injection through `@takazudo/zudo-doc`'s `_chrome` chrome (which wires the
22
- * MDX content components). The package route is the functional equivalent of
23
- * the old stub (it enumerates `settings.versions` and renders via the shared
24
- * `renderDocPage`).
25
- *
26
- * `copyFeatureFiles` (compose.ts) auto-copies everything under `files/`.
27
- * postProcess is now a defensive no-op: the i18n-gated stubs it strips
28
- * (`[locale]/docs/versions.tsx`, `v/[version]/[locale]/**`) no longer ship in
29
- * the template, but the cleanup is kept so a re-added stub can never leak an
30
- * orphan locale route into a single-locale project.
11
+ * Known limitation (pre-existing, not introduced by the minimal-scaffold
12
+ * cutover — inherited from the same injected-DYNAMIC-route dev-mode gap the
13
+ * locked manifest's `pages/docs/[[...slug]].tsx` stub exists to fix for the
14
+ * primary doc route, tracked as a #2667 follow-up): the versioned doc
15
+ * routes may still 404 in `zfb dev` since versioning has no stub of its own
16
+ * in the locked manifest. `zfb build` is unaffected.
31
17
  */
32
- export const versioningFeature = (choices) => ({
18
+ export const versioningFeature = () => ({
33
19
  name: "versioning",
34
- postProcess: async (targetDir) => {
35
- if (!choices.features.includes("i18n")) {
36
- const localeVersions = path.join(targetDir, "pages", "[locale]", "docs", "versions.tsx");
37
- if (await fs.pathExists(localeVersions)) {
38
- await fs.remove(localeVersions);
39
- }
40
- const localeVersionedDocs = path.join(targetDir, "pages", "v", "[version]", "[locale]");
41
- if (await fs.pathExists(localeVersionedDocs)) {
42
- await fs.remove(localeVersionedDocs);
43
- }
44
- }
45
- },
46
20
  injections: [],
47
21
  });
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { FEATURES } from "./constants.js";
6
6
  import { loadPreset } from "./preset.js";
7
7
  import { runPrompts } from "./prompts.js";
8
8
  import { scaffold } from "./scaffold.js";
9
- import { installDependencies, initGitRepo } from "./utils.js";
9
+ import { installDependencies, initGitRepo, pmRunCommand } from "./utils.js";
10
10
  async function main() {
11
11
  const args = parseArgs();
12
12
  // Handle --help
@@ -55,6 +55,8 @@ async function main() {
55
55
  if (args.respectSystemPreference !== undefined) {
56
56
  prefilled.respectPrefersColorScheme = args.respectSystemPreference;
57
57
  }
58
+ if (args.themePack)
59
+ prefilled.themePack = args.themePack;
58
60
  if (args.pm)
59
61
  prefilled.packageManager = args.pm;
60
62
  if (args.githubUrl !== undefined)
@@ -91,6 +93,7 @@ async function main() {
91
93
  else {
92
94
  prefilled.singleScheme ??= "Default Dark";
93
95
  }
96
+ prefilled.themePack ??= "default";
94
97
  prefilled.packageManager ??= "pnpm";
95
98
  prefilled.githubUrl ??= "";
96
99
  // For features: set defaults for any not explicitly specified
@@ -173,8 +176,7 @@ async function main() {
173
176
  console.log();
174
177
  console.log(` ${pc.bold("Next steps:")}`);
175
178
  console.log(` cd ${choices.projectName}`);
176
- const runCmd = choices.packageManager === "npm" ? "npm run" : choices.packageManager;
177
- console.log(` ${runCmd} dev`);
179
+ console.log(` ${pmRunCommand(choices.packageManager, "dev")}`);
178
180
  console.log();
179
181
  }
180
182
  main().catch((err) => {
package/dist/preset.d.ts CHANGED
@@ -35,6 +35,8 @@ export interface PresetJson {
35
35
  darkScheme?: string;
36
36
  defaultMode?: "light" | "dark";
37
37
  respectPrefersColorScheme?: boolean;
38
+ /** Theme pack slug (ADR #2818 Decision 7), validated against THEME_PACKS. */
39
+ themePack?: string;
38
40
  features?: string[];
39
41
  githubUrl?: string;
40
42
  cjkFriendly?: boolean;
package/dist/preset.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import fs from "fs";
2
- import { FEATURES, SINGLE_SCHEMES, SUPPORTED_LANGS } from "./constants.js";
2
+ import { FEATURES, SINGLE_SCHEMES, SUPPORTED_LANGS, THEME_PACKS } from "./constants.js";
3
3
  import { validateProjectName } from "./utils.js";
4
4
  const VALID_HEADER_RIGHT_COMPONENTS = new Set([
5
5
  "theme-toggle",
@@ -30,6 +30,7 @@ export function loadPreset(pathOrStdin) {
30
30
  const VALID_LANGS = new Set(SUPPORTED_LANGS.map((l) => l.value));
31
31
  const VALID_SCHEMES = new Set(SINGLE_SCHEMES);
32
32
  const VALID_PMS = new Set(["pnpm", "npm", "yarn", "bun"]);
33
+ const VALID_THEME_PACKS = new Set(THEME_PACKS.map((t) => t.slug));
33
34
  export function validatePreset(json) {
34
35
  if (json === null || typeof json !== "object" || Array.isArray(json)) {
35
36
  return "Preset must be a JSON object";
@@ -66,6 +67,14 @@ export function validatePreset(json) {
66
67
  if (p.defaultMode && !["light", "dark"].includes(p.defaultMode)) {
67
68
  return `Invalid defaultMode "${p.defaultMode}" in preset`;
68
69
  }
70
+ if (p.themePack !== undefined) {
71
+ if (typeof p.themePack !== "string") {
72
+ return `"themePack" must be a string in preset`;
73
+ }
74
+ if (!VALID_THEME_PACKS.has(p.themePack)) {
75
+ return `Unknown theme pack "${p.themePack}" in preset. Available: ${[...VALID_THEME_PACKS].join(", ")}`;
76
+ }
77
+ }
69
78
  if (p.packageManager && !VALID_PMS.has(p.packageManager)) {
70
79
  return `Invalid packageManager "${p.packageManager}" in preset`;
71
80
  }
@@ -174,6 +183,8 @@ export function presetToChoices(json) {
174
183
  if (json.respectPrefersColorScheme !== undefined) {
175
184
  choices.respectPrefersColorScheme = json.respectPrefersColorScheme;
176
185
  }
186
+ if (json.themePack)
187
+ choices.themePack = json.themePack;
177
188
  if (json.packageManager)
178
189
  choices.packageManager = json.packageManager;
179
190
  if (json.githubUrl !== undefined)
package/dist/prompts.d.ts CHANGED
@@ -8,6 +8,7 @@ export interface UserChoices {
8
8
  darkScheme?: string;
9
9
  respectPrefersColorScheme?: boolean;
10
10
  defaultMode?: "light" | "dark";
11
+ themePack?: string;
11
12
  features: string[];
12
13
  explicitlyDisabledFeatures?: string[];
13
14
  githubUrl?: string;
@@ -26,6 +27,7 @@ export interface PartialChoices {
26
27
  darkScheme?: string;
27
28
  respectPrefersColorScheme?: boolean;
28
29
  defaultMode?: "light" | "dark";
30
+ themePack?: string;
29
31
  features?: Partial<Record<string, boolean>>;
30
32
  explicitlyDisabledFeatures?: string[];
31
33
  githubUrl?: string;
package/dist/prompts.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as p from "@clack/prompts";
2
- import { SINGLE_SCHEMES, FEATURES, SUPPORTED_LANGS } from "./constants.js";
2
+ import { SINGLE_SCHEMES, FEATURES, SUPPORTED_LANGS, THEME_PACKS } from "./constants.js";
3
3
  import { validateProjectName } from "./utils.js";
4
4
  export async function runPrompts(prefilled = {}) {
5
5
  // 1. Project name
@@ -124,6 +124,26 @@ export async function runPrompts(prefilled = {}) {
124
124
  respectPrefersColorScheme = respect;
125
125
  }
126
126
  }
127
+ // 3.5 Theme pack (ADR #2818 Decision 7) — placed between the color-scheme
128
+ // block above and the features multiselect below (locked spec, #2823).
129
+ let themePack;
130
+ if (prefilled.themePack) {
131
+ themePack = prefilled.themePack;
132
+ }
133
+ else {
134
+ const result = await p.select({
135
+ message: "Theme pack:",
136
+ options: THEME_PACKS.map((t) => ({
137
+ value: t.slug,
138
+ label: t.label,
139
+ hint: t.hint,
140
+ })),
141
+ initialValue: "default",
142
+ });
143
+ if (p.isCancel(result))
144
+ process.exit(0);
145
+ themePack = result;
146
+ }
127
147
  // 4. Features
128
148
  let features;
129
149
  if (prefilled.features) {
@@ -196,6 +216,7 @@ export async function runPrompts(prefilled = {}) {
196
216
  darkScheme,
197
217
  respectPrefersColorScheme,
198
218
  defaultMode,
219
+ themePack,
199
220
  features,
200
221
  explicitlyDisabledFeatures: prefilled.explicitlyDisabledFeatures,
201
222
  githubUrl,
@@ -2,14 +2,21 @@ import type { UserChoices } from "./prompts.js";
2
2
  import { getSecondaryLang } from "./utils.js";
3
3
  export { getSecondaryLang };
4
4
  /**
5
- * Pinned `@takazudo/zudo-doc` version used in both `generatePackageJson()`
6
- * and the `.zudo-doc.json` seed written by `scaffold()`. Hoisted as a shared
7
- * constant so the dep pin and the provenance seed can never drift.
5
+ * Pinned `@takazudo/zudo-doc` version used by `generatePackageJson()`.
6
+ * Hoisted as a shared constant (kept even though it now has a single
7
+ * call site) because `scripts/check-pin-parity.mjs` resolves this exact
8
+ * declaration below via its constant-reference regex form (see that
9
+ * script's `readScaffoldPin()`) — keep the declaration line's shape
10
+ * parseable (const name, `=`, a quoted literal) and do NOT repeat that
11
+ * exact pattern anywhere earlier in this file (a comment containing the
12
+ * literal text would false-match the same regex, since it isn't anchored
13
+ * to a real `export const` statement).
8
14
  *
9
- * Strip the caret from this string to get the bare version for provenance:
10
- * ZUDO_DOC_PIN.replace(/^\^/, "") → "1.0.0"
15
+ * `.zudo-doc.json` is NO LONGER seeded here (locked decision #2653 #6 —
16
+ * lazy-create on first `zudo-doc eject`; `packages/zudo-doc/src/eject/index.ts`
17
+ * already tolerates its absence and writes the file on first successful eject).
11
18
  *
12
19
  * Bumped in lockstep by scripts/release-create-zudo-doc.sh.
13
20
  */
14
- export declare const ZUDO_DOC_PIN = "^3.2.0";
21
+ export declare const ZUDO_DOC_PIN = "^4.0.0";
15
22
  export declare function scaffold(choices: UserChoices): Promise<void>;