create-zudo-doc 3.0.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/constants.js +1 -1
- package/dist/preset.d.ts +1 -0
- package/dist/preset.js +5 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +1 -0
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +29 -18
- package/dist/settings-gen.js +2 -0
- package/dist/zfb-config-gen.d.ts +2 -2
- package/dist/zfb-config-gen.js +2 -2
- package/package.json +1 -1
- package/templates/base/scripts/setup-doc-skill.sh +261 -0
- package/templates/base/src/config/docs-schema.ts +1 -0
- package/templates/base/src/config/frontmatter-preview-defaults.ts +1 -0
- package/templates/base/src/config/settings-types.ts +1 -0
- package/templates/base/zfb-shim.d.ts +5 -0
package/dist/constants.js
CHANGED
|
@@ -106,7 +106,7 @@ export const FEATURES = [
|
|
|
106
106
|
{
|
|
107
107
|
value: "skillSymlinker",
|
|
108
108
|
label: "Skill symlinker",
|
|
109
|
-
hint: "Symlink documentation skills",
|
|
109
|
+
hint: "Symlink documentation skills into Claude Code or Codex",
|
|
110
110
|
default: false,
|
|
111
111
|
cliFlag: "skill-symlinker",
|
|
112
112
|
},
|
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,
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
21
|
+
export const ZUDO_DOC_PIN = "^3.2.0";
|
|
22
22
|
/**
|
|
23
|
-
* Files in `templates/base/**` that must
|
|
24
|
-
*
|
|
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.0.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
|
-
//
|
|
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(
|
|
218
|
+
const scriptSrc = path.join(baseDir, "scripts/setup-doc-skill.sh");
|
|
218
219
|
const scriptDest = path.join(targetDir, "scripts/setup-doc-skill.sh");
|
|
219
|
-
|
|
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)
|
|
@@ -333,12 +332,14 @@ export async function scaffold(choices) {
|
|
|
333
332
|
// skill a user later installs under a matching name. The skill name is
|
|
334
333
|
// deterministic (always `<projectName>-wisdom`, matching DEFAULT_SKILL_NAME
|
|
335
334
|
// in scripts/setup-doc-skill.sh and the package name), so these entries match
|
|
336
|
-
// the directory the script creates. The
|
|
337
|
-
//
|
|
335
|
+
// the directory the script creates. The setup script can target either
|
|
336
|
+
// .claude or .codex, so ignore both possible generated directories. The
|
|
337
|
+
// docs-ja symlink only exists for i18n projects (the script creates it
|
|
338
|
+
// conditionally), so gate those lines on i18n.
|
|
338
339
|
if (choices.features.includes("skillSymlinker")) {
|
|
339
|
-
gitignoreLines.push("# Generated doc-lookup skill", `.claude/skills/${choices.projectName}-wisdom/SKILL.md`, `.claude/skills/${choices.projectName}-wisdom/docs`);
|
|
340
|
+
gitignoreLines.push("# Generated doc-lookup skill", `.claude/skills/${choices.projectName}-wisdom/SKILL.md`, `.claude/skills/${choices.projectName}-wisdom/docs`, `.codex/skills/${choices.projectName}-wisdom/SKILL.md`, `.codex/skills/${choices.projectName}-wisdom/docs`);
|
|
340
341
|
if (choices.features.includes("i18n")) {
|
|
341
|
-
gitignoreLines.push(`.claude/skills/${choices.projectName}-wisdom/docs-ja`);
|
|
342
|
+
gitignoreLines.push(`.claude/skills/${choices.projectName}-wisdom/docs-ja`, `.codex/skills/${choices.projectName}-wisdom/docs-ja`);
|
|
342
343
|
}
|
|
343
344
|
gitignoreLines.push("");
|
|
344
345
|
}
|
|
@@ -493,13 +494,17 @@ function generatePackageJson(choices) {
|
|
|
493
494
|
// class-candidate scanning through symlinked project trees
|
|
494
495
|
// (zudolab/zudo-doc#2511), adopted in lockstep with the root package.json
|
|
495
496
|
// pins. No consumer-facing / CLI change.
|
|
496
|
-
// next.76
|
|
497
|
+
// next.76: routine toolchain bump from next.75, adopted in
|
|
497
498
|
// lockstep with the root package.json pins. No consumer-facing / CLI change.
|
|
498
|
-
|
|
499
|
-
|
|
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",
|
|
500
505
|
// zfb-adapter-cloudflare — required for any route with `prerender = false`.
|
|
501
506
|
// Pinned in lockstep with @takazudo/zfb.
|
|
502
|
-
"@takazudo/zfb-adapter-cloudflare": "0.1.0-next.
|
|
507
|
+
"@takazudo/zfb-adapter-cloudflare": "0.1.0-next.78",
|
|
503
508
|
// @takazudo/zudo-doc — published from this monorepo via
|
|
504
509
|
// .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
|
|
505
510
|
// lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
|
|
@@ -582,7 +587,7 @@ function generatePackageJson(choices) {
|
|
|
582
587
|
// @takazudo/zudo-doc/integrations/doc-history which in turn imports
|
|
583
588
|
// @takazudo/zudo-doc-history-server/git-history. Without this dep the
|
|
584
589
|
// plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
|
|
585
|
-
deps["@takazudo/zudo-doc-history-server"] = "^3.
|
|
590
|
+
deps["@takazudo/zudo-doc-history-server"] = "^3.2.0";
|
|
586
591
|
// tsx is no longer needed here: the relocated package plugin imports the
|
|
587
592
|
// runner directly (no `tsx -e` spawn) since the package ships compiled
|
|
588
593
|
// dist/ — package-first migration #2321 (#2337).
|
|
@@ -635,6 +640,12 @@ function generatePackageJson(choices) {
|
|
|
635
640
|
scripts["setup:doc-skill"] = "bash scripts/setup-doc-skill.sh";
|
|
636
641
|
scripts["setup:doc-skill-silent"] =
|
|
637
642
|
"bash scripts/setup-doc-skill.sh --silent";
|
|
643
|
+
scripts["setup:doc-skill:claude"] =
|
|
644
|
+
"bash scripts/setup-doc-skill.sh --target claude";
|
|
645
|
+
scripts["setup:doc-skill:codex"] =
|
|
646
|
+
"bash scripts/setup-doc-skill.sh --target codex";
|
|
647
|
+
scripts["setup:doc-skill:both"] =
|
|
648
|
+
"bash scripts/setup-doc-skill.sh --target both";
|
|
638
649
|
}
|
|
639
650
|
const runCmd = choices.packageManager === "npm" || choices.packageManager === "bun" ? `${choices.packageManager} run` : choices.packageManager;
|
|
640
651
|
// claudeSkills ships the zudo-doc-version-bump skill, whose release workflow
|
package/dist/settings-gen.js
CHANGED
|
@@ -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();
|
|
@@ -130,6 +131,7 @@ export function generateSettingsFile(choices) {
|
|
|
130
131
|
else {
|
|
131
132
|
lines.push(` llmsTxt: false,`);
|
|
132
133
|
}
|
|
134
|
+
lines.push(` changelogs: false,`);
|
|
133
135
|
lines.push(` math: false,`);
|
|
134
136
|
lines.push(` cjkFriendly: ${choices.cjkFriendly ?? false} as boolean,`);
|
|
135
137
|
lines.push(` onBrokenMarkdownLinks: "warn" as "warn" | "error" | "ignore",`);
|
package/dist/zfb-config-gen.d.ts
CHANGED
|
@@ -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,
|
|
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`).
|
package/dist/zfb-config-gen.js
CHANGED
|
@@ -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,
|
|
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
|
@@ -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 ""
|
|
@@ -62,6 +62,7 @@ export function buildDocsSchema() {
|
|
|
62
62
|
unlisted: z.boolean().optional(),
|
|
63
63
|
hide_sidebar: z.boolean().optional(),
|
|
64
64
|
hide_toc: z.boolean().optional(),
|
|
65
|
+
wide: z.boolean().optional(),
|
|
65
66
|
doc_history: z.boolean().optional(),
|
|
66
67
|
standalone: z.boolean().optional(),
|
|
67
68
|
slug: z.string().optional(),
|
|
@@ -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
|