diff --git a/site/build.mjs b/site/build.mjs index 74bd908..5555b32 100644 --- a/site/build.mjs +++ b/site/build.mjs @@ -24,6 +24,24 @@ const PKG = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')); const cssVer = createHash('sha256').update(readFileSync(join(TEMPLATE, 'styles.css'))).digest('hex').slice(0, 10); const jsVer = createHash('sha256').update(readFileSync(join(TEMPLATE, 'app.js'))).digest('hex').slice(0, 10); +// 从 RELEASE-NOTES.zh.md 读最新版本条目。 +// 动机:v1.7.11 的全部意义是「六款工具此前装了不生效,请重装」,而官网此前 +// 一个字都没提 —— 上周装过的用户来站上看不到任何提示。版本号不手写,从 +// release notes 解析,再与 package.json 交叉校验,两边漂了就构建失败。 +function latestRelease() { + const md = readFileSync(join(ROOT, 'RELEASE-NOTES.zh.md'), 'utf8'); + const m = md.match(/^## v(\d+\.\d+\.\d+)\s*\(([\d-]+)\)/m); + if (!m) throw new Error('RELEASE-NOTES.zh.md 里找不到形如「## v1.2.3 (2026-01-01)」的最新条目'); + return { version: m[1], date: m[2] }; +} +const LATEST = latestRelease(); +if (LATEST.version !== PKG.version) { + throw new Error(`版本漂移:package.json 是 ${PKG.version},RELEASE-NOTES.zh.md 最新条目是 v${LATEST.version} —— 发版时漏改了一边`); +} + +// 本版需要重装的工具(三语共用;产品名不翻译)。改这里时同步改 release notes 正文。 +const REINSTALL_TOOLS = ['Codex CLI', 'VS Code', 'Windsurf', 'Qwen Code', 'DeerFlow', 'Claw Code']; + // 页脚二维码的真实像素尺寸,构建时从文件读取(见 imageSize 的注释) const QR = { wechat: imageSize(join(TEMPLATE, 'assets', 'qr-wechat.jpg')), @@ -123,35 +141,35 @@ const GROUPS = [ const TOOLS = [ { name: 'Claude Code', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, { name: 'Cursor', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Windsurf', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Codex CLI', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Gemini CLI', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Kiro', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Trae', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Qoder', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'Aider', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'OpenCode', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, + { name: 'Windsurf', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'windsurf' }, + { name: 'Codex CLI', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'codex' }, + { name: 'Gemini CLI', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'gemini-cli' }, + { name: 'Kiro', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'kiro' }, + { name: 'Trae', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'trae' }, + { name: 'Qoder', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'qoder' }, + { name: 'Aider', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'aider' }, + { name: 'OpenCode', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'opencode' }, // Qwen Code = QwenLM/qwen-code 这个命令行工具(Gemini CLI 的 fork),不是通义灵码。 - { name: 'Qwen Code', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, + { name: 'Qwen Code', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'qwen' }, // Antigravity 是 Google 的 AI IDE(antigravity.google),见 docs/README.antigravity.md。 - { name: 'Antigravity', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'DeerFlow 2.0', type: 'Agent', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'VS Code · Copilot', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, + { name: 'Antigravity', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'antigravity' }, + { name: 'DeerFlow 2.0', type: 'Agent', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'deerflow' }, + { name: 'VS Code · Copilot', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'vscode' }, // Copilot CLI 与 Claude Code 共用 .claude/skills,别名 copilot -> Claude Code, // 它自己没有检测标记,所以必须 --tool 指定。 { name: 'Copilot CLI', type: 'CLI', cmd: 'npx superpowers-zh --tool copilot', mode: 'manual' }, // Hermes 官方只自动加载 ~/.hermes/skills/,项目级目录要手写 config.yaml 才被发现, // 所以这里给的是 --global 的装法(与 README 的一键安装列一致)。 - { name: 'Hermes Agent', type: 'CLI', cmd: 'npx superpowers-zh --global --tool hermes', mode: 'global' }, - { name: 'Claw Code', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'OpenClaw', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'CodeBuddy', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, - { name: 'CodeArts', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto' }, + { name: 'Hermes Agent', type: 'CLI', cmd: 'npx superpowers-zh --global --tool hermes', mode: 'global', doc: 'hermes' }, + { name: 'Claw Code', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'claw' }, + { name: 'OpenClaw', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'openclaw' }, + { name: 'CodeBuddy', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'codebuddy' }, + { name: 'CodeArts', type: 'IDE', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'codearts' }, // Cline / Kilo Code 的检测标记是 rules 目录(.clinerules / .kilocode),没建过规则的 // 项目检测不到,与 README 一致给显式 --tool。 - { name: 'Cline', type: 'IDE', cmd: 'npx superpowers-zh --tool cline', mode: 'manual' }, - { name: 'Kilo Code', type: 'IDE', cmd: 'npx superpowers-zh --tool kilocode', mode: 'manual' }, - { name: 'Crush', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto' }, + { name: 'Cline', type: 'IDE', cmd: 'npx superpowers-zh --tool cline', mode: 'manual', doc: 'cline' }, + { name: 'Kilo Code', type: 'IDE', cmd: 'npx superpowers-zh --tool kilocode', mode: 'manual', doc: 'kilocode' }, + { name: 'Crush', type: 'CLI', cmd: 'npx superpowers-zh', mode: 'auto', doc: 'crush' }, ]; // ---- 双语文案 ---- @@ -266,6 +284,17 @@ const SPONSORS = [ // 赞助位是付费展示位,图挂了就是事故。旗舰卡读 img、常规卡读 logo,两条路径 // 各自需要的字段不同 —— 把 tier 从 flagship 改成 standard 而忘了配 logo, // 页面上就是一个静默的碎图。构建时直接拦下来,不让它上线。 +// 工具墙上挂的每个文档链接都必须真的存在 —— 官网链到 GitHub 上一个不存在的 +// docs/README.*.md,就是又一条「编造出处」,而这正是本仓已经栽过的坑。 +function assertToolDocs() { + for (const x of TOOLS) { + if (!x.doc) continue; + const f = join(ROOT, 'docs', `README.${x.doc}.md`); + if (!existsSync(f)) throw new Error(`工具 ${x.name} 的文档不存在:docs/README.${x.doc}.md`); + } +} +assertToolDocs(); + function assertSponsors() { for (const s of SPONSORS) { const need = s.tier === 'flagship' ? ['img', 'w', 'h', 'points'] : ['logo', 'desc']; @@ -320,6 +349,8 @@ const T = { heroLead: '{n} 个经过实战验证的工作方法论 skill —— 从头脑风暴到 TDD,从系统化调试到代码审查。
一条命令,自动识别项目里的工具并安装。', heroBtn1: '查看安装命令', heroBtn2: 'GitHub 源码', stats: ['Skills', '中国原创', '支持工具', '当前版本'], + releaseNote: '{tools} 用户请重新安装 —— 此前版本装了不生效。查看完整更新说明', + toolDocHint: '{name} 的专属安装指南', whyTitle: '为什么选择 superpowers-zh?', whySub: '不是又一套提示词模板 —— 是让 AI 真正按工程方法干活的系统化能力。', plTitle: '一条龙工作流,每一步都有 skill 把关', @@ -452,6 +483,8 @@ const T = { heroLead: '{n} battle-tested workflow skills — from brainstorming to TDD, systematic debugging to code review.
One command auto-detects your tool and installs.', heroBtn1: 'Get the command', heroBtn2: 'GitHub', stats: ['Skills', 'China-native', 'Tools', 'Version'], + releaseNote: '{tools} users should reinstall — earlier versions installed to the wrong place. Read the full release notes', + toolDocHint: 'Install guide for {name}', whyTitle: 'Why superpowers-zh?', whySub: 'Not another prompt-template pack — real engineering methodology that makes AI work properly.', plTitle: 'An end-to-end workflow, every step guarded by a skill', @@ -584,6 +617,8 @@ const T = { heroLead: '{n} 個經過實戰驗證的工作方法論 skill —— 從頭腦風暴到 TDD,從系統化除錯到程式碼審查。
一條命令,自動識別專案裡的工具並安裝。', heroBtn1: '查看安裝命令', heroBtn2: 'GitHub 原始碼', stats: ['Skills', '中國原創', '支援工具', '目前版本'], + releaseNote: '{tools} 使用者請重新安裝 —— 此前版本裝了不生效。檢視完整更新說明', + toolDocHint: '{name} 的專屬安裝指南', whyTitle: '為什麼選擇 superpowers-zh?', whySub: '不是又一套提示詞範本 —— 是讓 AI 真正按工程方法幹活的系統化能力。', plTitle: '一條龍工作流,每一步都有 skill 把關', @@ -858,7 +893,14 @@ function renderLanding(skills, lang) { ``).join(''); const modeTag = { auto: '', manual: '(--tool)', global: '(--global)' }; const toolOpts = TOOLS.map((x, i) => ``).join(''); - const toolWall = TOOLS.map(x => `
${esc(x.name)}${esc(x.type)}
`).join(''); + // 有专属安装文档的工具,pill 直接链过去 —— docs/ 里 22 份指南此前在官网零暴露, + // 而「为什么要重装 / 旧布局怎么清 / 该不该用 --global」的答案全在那里。 + const toolWall = TOOLS.map(x => { + const inner = `${esc(x.name)}${esc(x.type)}`; + return x.doc + ? `${inner}` + : `
${inner}
`; + }).join(''); const feats = t.features.map(f => `
${f.icon}

${esc(f.t)}

${esc(f.d)}

`).join(''); const pipe = t.pipeline.map((p, i) => `
${i + 1}
${esc(p.n)}${esc(p.d)}
${i < t.pipeline.length - 1 ? '
' : ''}`).join(''); const ucs = t.usecases.map(u => `
${esc(u.tag)}${esc(u.skills)}

${esc(u.desc)}

`).join(''); @@ -875,6 +917,11 @@ function renderLanding(skills, lang) { ${t.heroBtn1} ${t.heroBtn2} + + v${LATEST.version} + ${fill(t.releaseNote, { tools: REINSTALL_TOOLS.join(' / ') })} + +
${total}${t.stats[0]}
${cnCount}${t.stats[1]}
diff --git a/site/template/styles.css b/site/template/styles.css index f4d6284..906cb1b 100644 --- a/site/template/styles.css +++ b/site/template/styles.css @@ -357,6 +357,25 @@ footer { border-top: 1px solid var(--border-soft); margin-top: 40px; padding: 40 .flag-body h3 { font-size: 19px; font-weight: 700; } .flag-tag { font-size: 13.5px; color: var(--accent-2); font-weight: 600; margin: 6px 0 12px; } .flag-desc { font-size: 14px; color: var(--text-dim); line-height: 1.75; } +/* hero 下方的版本提示条:本版最重要的一句话(谁该重装)此前官网完全没有 */ +.release-note { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; + max-width: 720px; margin: 20px auto 0; padding: 9px 16px; border-radius: 999px; + background: var(--card); border: 1px solid var(--border-soft); + color: var(--text-dim); font-size: 13.5px; line-height: 1.6; text-decoration: none; + transition: border-color .18s, color .18s; } +.release-note:hover { border-color: var(--accent-2); color: var(--text); } +.rn-ver { flex: 0 0 auto; padding: 2px 9px; border-radius: 999px; font-weight: 700; font-size: 12.5px; + background: var(--accent-2); color: #0b0d14; } +.rn-text { flex: 1 1 auto; min-width: 0; text-align: left; } +.rn-go { flex: 0 0 auto; } +@media (max-width: 620px) { .release-note { border-radius: 14px; text-align: left; } } + +/* 工具墙:有专属安装文档的 pill 可点,右上角一个 ↗ */ +.tool-pill.has-doc { text-decoration: none; cursor: pointer; transition: border-color .18s, transform .18s; } +.tool-pill.has-doc:hover { border-color: var(--accent-2); transform: translateY(-1px); } +.tool-doc { margin-left: 6px; font-size: 11px; color: var(--text-faint); } +.tool-pill.has-doc:hover .tool-doc { color: var(--accent-2); } + /* 旗舰卡的要点分段:图标定宽一列,标题与说明同一行起排 */ .flag-points { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; } .flag-points li { display: flex; gap: 10px; align-items: flex-start; }