From 1081cefc425a361fefc822b3c74b97cee6ea5855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI=E4=B8=8D=E6=AD=A2=E8=AF=AD?= <12096460+jnMetaCode@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:19:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(docs,site):=20README=20=E6=8A=8A=202=20?= =?UTF-8?q?=E4=B8=AA=E4=B8=8A=E6=B8=B8=20skill=20=E7=AE=97=E6=88=90?= =?UTF-8?q?=E3=80=8C=E4=B8=AD=E5=9B=BD=E7=89=B9=E8=89=B2=E3=80=8D=EF=BC=9B?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=BC=BA=20height=EF=BC=9B=E5=AE=98?= =?UTF-8?q?=E7=BD=91=E5=A4=96=E9=93=BE=E6=B2=A1=E4=BA=BA=E9=AA=8C=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按主站逐项核对时查出的三处,都不是新引入的,是一直没人发现。 ## ① README 的「中国特色 Skills(6 个)」与官网自相矛盾 三处口径本来就不一致: | 位置 | 原来的说法 | |---|---| | 官网统计块 | 4 中国原创 | | `.claude-plugin/plugin.json` | 20 个 skills(14 翻译 + 4 中国原创 + 2 上游历史保留)| | 两版 README | **6 个中国特色 Skills** ← 只有它是 6 | README 把 `mcp-builder` 和 `workflow-runner` 也算进了「中国特色」。用 GitHub API 核过: **上游 obra/superpowers 现有 14 个 skill,本仓 20 个,多出的正是 4 个 `chinese-*` 加这两个。** 它们来自上游、上游后来移除、本 fork 保留继续维护 —— 跟中国特色没有任何关系,把它们 算成中国原创等于虚报了 50% 的原创量。 改:规模表列名改「中国原创 Skills」值改 4(附注另有 2 个上游历史保留);小节标题拆成 「中国原创(4 个)· 上游历史保留(2 个)」;表格里这两行的「上游有吗?」由「无」改为 「曾有,上游已移除」——原来写「无」会被读成「我们原创的」,正是错误的来源。简繁同步。 (`using-superpowers` 正文里的「中国特色技能路由」是真实存在的小节名,不动。) ## ② 页脚三个二维码缺 height,加载时把页脚顶下去 `` 没有 height,浏览器算不出宽高比,图一到位就发生布局偏移(CLS)。 赞助商 banner 和 logo 都是齐的,只有二维码漏了。 没有写死数字,而是新增零依赖的 `imageSize()`(PNG 读 IHDR、JPEG 逐段找 SOFn), 构建时从文件读真实尺寸:258×258 / 1125×1680 / 316×316,与 `sips` 实测逐一吻合。 换二维码时属性自动跟随,不会悄悄退回错的比例。 顺带用同一个函数补了一条门禁:**赞助商声明的 `w`/`h` 必须与素材真实尺寸一致** —— 换了 banner 忘了改数字,页面就会按错的宽高比预留位置。 ## ③ 外链验活门禁扫不到官网,三条付费展位链接一直无人看守 `verify-release` H 段只扫 `docs/*.md` 与两版 README,`site/build.mjs` 不在列。也就是 旗舰赞助商与两个常规位的推广链接挂掉了不会有任何人知道 —— 而这是要赔的。 扫描范围加上 `site/build.mjs`,并把 `compshare|cubence` 移出排除名单(原来被当噪音跳过), 正则补 `?=&` 让带 aff/referral 参数的推广链接被完整验证而不是截断到路径。 覆盖链接 45 → 52 条。 排除名单新增 `googletagmanager|google-analytics`:它们在 build.mjs 里是 **CSP 白名单条目 不是链接**,裸域 `googletagmanager.com` 实测返回 404,纳入等于凭空造一条误报 —— 这条门禁最忌讳的就是误报。 ## 反向验证(三条逐一造错,必须拦下) - 把官网的 book.aibuzhiyu.com 改成不存在的路径 -> `死链(404)`,FAIL 1 - 把 infistar banner 的 w/h 改成 800×368 -> 构建退出码 1, `banner 尺寸对不上:声明 800×368,实际 1269×337` - 二维码尺寸不再有写死数字(`width="158"` 已从源码消失) ## 全量测试 官网 66 页构建 / 站内死链 0 / 无效 href="#" 0 / **缺 height 的 img 0**(原为 3); audit 170 pass 0 fail;verify-release 115 pass 0 fail;CI 等价 20 skills 0 错误 v1.7.11; tests/kimi · pi · opencode · brainstorm-server 全 PASS。 --- README.md | 12 ++++++----- README.zh-Hant.md | 12 ++++++----- scripts/verify-release.sh | 12 +++++++++-- site/build.mjs | 44 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 716c050..5d05ae3 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ Chinese community edition of [superpowers](https://github.com/obra/superpowers) ### 📊 项目规模 -| 📦 翻译 Skills | 🇨🇳 中国特色 Skills | 🤖 支持工具 | +| 📦 翻译 Skills | 🇨🇳 中国原创 Skills | 🤖 支持工具 | |:---:|:---:|:---:| -| **14** | **6** | **Claude Code / Copilot CLI / Hermes Agent / Cursor / Windsurf / Kiro / Gemini CLI / Codex / Aider / Trae / VS Code (Copilot) / DeerFlow / OpenCode / OpenClaw / Qwen Code / Antigravity / Claw Code / Qoder / CodeBuddy(腾讯)/ CodeArts(华为云码道)/ Cline / Kilo Code / Crush** | +| **14** | **4**
另有 2 个上游历史保留 | **Claude Code / Copilot CLI / Hermes Agent / Cursor / Windsurf / Kiro / Gemini CLI / Codex / Aider / Trae / VS Code (Copilot) / DeerFlow / OpenCode / OpenClaw / Qwen Code / Antigravity / Claw Code / Qoder / CodeBuddy(腾讯)/ CodeArts(华为云码道)/ Cline / Kilo Code / Crush** | --- @@ -191,10 +191,12 @@ AI:在开始实现之前,我需要了解几个关键问题: | **编写 Skills** (writing-skills) | 创建新 skill 的方法论 | | **使用 Superpowers** (using-superpowers) | 元技能:如何调用和优先使用 skills | -### 🇨🇳 中国特色 Skills(6 个) +### 🇨🇳 中国原创 Skills(4 个)· 上游历史保留(2 个) > ⚠️ **下表前 4 个 chinese-\* 为「手动调用」skill**——不会自动触发,需在对话中显式输入 `/chinese-xxx` 才会加载。 > 设计为参考资料而非工作流,避免污染上游 skill 的自动调度(如 `requesting-code-review`、`brainstorming` 等)。 +> +> ⚠️ **表格最后两个(mcp-builder / workflow-runner)不是中国原创** —— 它们来自上游,上游后来移除了,本 fork 保留下来继续维护。全仓 20 个 skill = 14 翻译 + 4 中国原创 + 2 上游历史保留。 | Skill | 用途 | 调用方式 | 上游有吗? | |-------|------|---------|:---:| @@ -202,8 +204,8 @@ AI:在开始实现之前,我需要了解几个关键问题: | **中文 Git 工作流** (chinese-git-workflow) | 适配 Gitee/Coding/极狐 GitLab/CNB | `/chinese-git-workflow`(手动) | 无 | | **中文技术文档** (chinese-documentation) | 中文排版规范、中英混排、告别机翻味 | `/chinese-documentation`(手动) | 无 | | **中文提交规范** (chinese-commit-conventions) | 适配国内团队的 commit message 规范 | `/chinese-commit-conventions`(手动) | 无 | -| **MCP 服务器构建** (mcp-builder) | 构建生产级 MCP 工具,扩展 AI 能力边界 | 自动 | 无 | -| **工作流执行器** (workflow-runner) | 在 AI 工具内运行多角色 YAML 工作流 | 自动 | 无 | +| **MCP 服务器构建** (mcp-builder) | 构建生产级 MCP 工具,扩展 AI 能力边界 | 自动 | 曾有,上游已移除 | +| **工作流执行器** (workflow-runner) | 在 AI 工具内运行多角色 YAML 工作流 | 自动 | 曾有,上游已移除 | --- diff --git a/README.zh-Hant.md b/README.zh-Hant.md index cf7cae4..fd11f86 100644 --- a/README.zh-Hant.md +++ b/README.zh-Hant.md @@ -27,9 +27,9 @@ Chinese community edition of [superpowers](https://github.com/obra/superpowers) ### 📊 專案規模 -| 📦 翻譯 Skills | 🇨🇳 中國特色 Skills | 🤖 支援工具 | +| 📦 翻譯 Skills | 🇨🇳 中國原創 Skills | 🤖 支援工具 | |:---:|:---:|:---:| -| **14** | **6** | **Claude Code / Copilot CLI / Hermes Agent / Cursor / Windsurf / Kiro / Gemini CLI / Codex / Aider / Trae / VS Code (Copilot) / DeerFlow / OpenCode / OpenClaw / Qwen Code / Antigravity / Claw Code / Qoder / CodeBuddy(騰訊)/ CodeArts(華為雲碼道)/ Cline / Kilo Code / Crush** | +| **14** | **4**
另有 2 個上游歷史保留 | **Claude Code / Copilot CLI / Hermes Agent / Cursor / Windsurf / Kiro / Gemini CLI / Codex / Aider / Trae / VS Code (Copilot) / DeerFlow / OpenCode / OpenClaw / Qwen Code / Antigravity / Claw Code / Qoder / CodeBuddy(騰訊)/ CodeArts(華為雲碼道)/ Cline / Kilo Code / Crush** | --- @@ -191,10 +191,12 @@ AI:在開始實作之前,我需要了解幾個關鍵問題: | **編寫 Skills** (writing-skills) | 建立新 skill 的方法論 | | **使用 Superpowers** (using-superpowers) | 元技能:如何呼叫和優先使用 skills | -### 🇨🇳 中國特色 Skills(6 個) +### 🇨🇳 中國原創 Skills(4 個)· 上游歷史保留(2 個) > ⚠️ **下表前 4 個 chinese-\* 為「手動呼叫」skill**——不會自動觸發,需在對話中顯式輸入 `/chinese-xxx` 才會載入。 > 設計為參考資料而非工作流,避免污染上游 skill 的自動排程(如 `requesting-code-review`、`brainstorming` 等)。 +> +> ⚠️ **表格最後兩個(mcp-builder / workflow-runner)不是中國原創** —— 它們來自上游,上游後來移除了,本 fork 保留下來繼續維護。全倉 20 個 skill = 14 翻譯 + 4 中國原創 + 2 上游歷史保留。 | Skill | 用途 | 呼叫方式 | 上游有嗎? | |-------|------|---------|:---:| @@ -202,8 +204,8 @@ AI:在開始實作之前,我需要了解幾個關鍵問題: | **中文 Git 工作流** (chinese-git-workflow) | 適配 Gitee/Coding/極狐 GitLab/CNB | `/chinese-git-workflow`(手動) | 無 | | **中文技術文件** (chinese-documentation) | 中文排版規範、中英混排、告別機翻味 | `/chinese-documentation`(手動) | 無 | | **中文提交規範** (chinese-commit-conventions) | 適配國內團隊的 commit message 規範 | `/chinese-commit-conventions`(手動) | 無 | -| **MCP 伺服器建置** (mcp-builder) | 建置生產級 MCP 工具,擴展 AI 能力邊界 | 自動 | 無 | -| **工作流執行器** (workflow-runner) | 在 AI 工具內執行多角色 YAML 工作流 | 自動 | 無 | +| **MCP 伺服器建置** (mcp-builder) | 建置生產級 MCP 工具,擴展 AI 能力邊界 | 自動 | 曾有,上游已移除 | +| **工作流執行器** (workflow-runner) | 在 AI 工具內執行多角色 YAML 工作流 | 自動 | 曾有,上游已移除 | --- diff --git a/scripts/verify-release.sh b/scripts/verify-release.sh index 047cad5..5fb1567 100755 --- a/scripts/verify-release.sh +++ b/scripts/verify-release.sh @@ -259,8 +259,16 @@ if curl -sS -o /dev/null --max-time 5 https://github.com 2>/dev/null; then # 第一遍并行快扫。注意这一遍**会误报** —— 实测 docs.codeium.com 在 8s 上限下 # 偶发超时,而它其实活着。一个会误报的门禁比没有门禁更糟:人会学会忽略它。 # 所以第一遍只产出「嫌疑名单」,不下结论。 - grep -rhoE "https://[a-zA-Z0-9./_-]+" "$REPO"/docs/*.md "$REPO"/README.md "$REPO"/README.zh-Hant.md 2>/dev/null \ - | grep -viE "jnmetacode|aiolaola|user-images|shields\.io|opensource\.org|makeapullrequest|npmjs\.com|compshare|cubence|claude\.ai/code" \ + # 扫描范围含 site/build.mjs:官网的外链此前完全没人验活,而其中三条是**付费展位**的 + # 推广链接(旗舰 + 两个常规位)—— 赞助链接挂掉是要赔的,比文档死链更该守。 + # 正则含 ?=& :推广链接的 aff / referral 参数在 query 里,截断了就等于没验真正那条。 + # 排除项说明: + # jnmetacode / aiolaola —— 自家域名(含站点自引用),挂了自己会先知道 + # npmjs / shields / user-images / opensource / makeapullrequest —— 已知对爬虫不友好或纯徽章 + # googletagmanager / google-analytics —— 它们在 build.mjs 里是 **CSP 白名单条目**不是链接; + # 裸域 googletagmanager.com 本身返回 404,纳入就是凭空造一条误报 + grep -rhoE "https://[a-zA-Z0-9./_?=&-]+" "$REPO"/docs/*.md "$REPO"/README.md "$REPO"/README.zh-Hant.md "$REPO"/site/build.mjs 2>/dev/null \ + | grep -viE "jnmetacode|aiolaola|user-images|shields\.io|opensource\.org|makeapullrequest|npmjs\.com|claude\.ai/code|googletagmanager|google-analytics" \ | sed 's/[.,)]*$//' | sort -u \ | xargs -P 10 -I{} sh -c 'c=$(curl -sS -o /dev/null -w "%{http_code}" -L --max-time 8 "$1" 2>/dev/null); case "$c" in 2*|3*|401|403|405|429) ;; *) echo "$1" ;; esac' _ {} \ > "$LINKTMP" 2>/dev/null diff --git a/site/build.mjs b/site/build.mjs index 5043e48..74bd908 100644 --- a/site/build.mjs +++ b/site/build.mjs @@ -24,11 +24,42 @@ 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); +// 页脚二维码的真实像素尺寸,构建时从文件读取(见 imageSize 的注释) +const QR = { + wechat: imageSize(join(TEMPLATE, 'assets', 'qr-wechat.jpg')), + douyin: imageSize(join(TEMPLATE, 'assets', 'qr-douyin.jpg')), + x: imageSize(join(TEMPLATE, 'assets', 'qr-x.png')), +}; + // SEO:站点根 URL(用于 canonical / hreflang / og:url / sitemap) const SITE_URL = 'https://sp.aiolaola.com'; // 仓库源码基址(skill 详情页的相对链接解析到这里) const GH_BLOB = 'https://github.com/jnMetaCode/superpowers-zh/blob/main'; +// 读 PNG / JPEG 的真实像素尺寸(零依赖)。 +// 用途: 必须带 width+height,浏览器才能在图加载前按宽高比预留位置, +// 否则图一到位就把下面的内容顶下去(CLS)。页脚三个二维码此前只有 width。 +// 不写死数字而是读文件:换二维码时属性自动跟着变,不会悄悄变回错的比例。 +function imageSize(file) { + const b = readFileSync(file); + if (b.length > 24 && b[0] === 0x89 && b[1] === 0x50) { // PNG: IHDR 定长在头部 + return { w: b.readUInt32BE(16), h: b.readUInt32BE(20) }; + } + if (b[0] === 0xff && b[1] === 0xd8) { // JPEG: 逐段找 SOFn + let i = 2; + while (i < b.length - 9) { + if (b[i] !== 0xff) { i++; continue; } + const m = b[i + 1]; + // SOF0-SOF3 / SOF5-SOF7 / SOF9-SOF11 / SOF13-SOF15 都带尺寸;DHT(c4)/JPG(c8)/DAC(cc) 不是 + if (m >= 0xc0 && m <= 0xcf && m !== 0xc4 && m !== 0xc8 && m !== 0xcc) { + return { h: b.readUInt16BE(i + 5), w: b.readUInt16BE(i + 7) }; + } + i += 2 + b.readUInt16BE(i + 2); + } + } + throw new Error(`无法解析图片尺寸:${file}`); +} + const esc = s => String(s).replace(/&/g, '&').replace(//g, '>'); // ---- frontmatter 解析 ---- @@ -246,6 +277,13 @@ function assertSponsors() { if (!existsSync(join(ROOT, 'assets', 'sponsors', f))) { throw new Error(`赞助商 ${s.name?.zh || '?'} 的素材不存在:assets/sponsors/${f}`); } + // 声明的 w/h 必须与素材真实尺寸一致 —— 换了图忘了改数字,页面就按错的宽高比预留位置 + if (f === s.img) { + const real = imageSize(join(ROOT, 'assets', 'sponsors', f)); + if (real.w !== s.w || real.h !== s.h) { + throw new Error(`赞助商 ${s.name?.zh || '?'} 的 banner 尺寸对不上:声明 ${s.w}×${s.h},实际 ${real.w}×${real.h}`); + } + } } const textKeys = s.tier === 'flagship' ? ['name', 'tagline', 'alt', 'perk', 'perkShort'] @@ -772,9 +810,9 @@ ${body}

${t.followUs}

-
${esc(t.qrWechat)}
${t.qrWechat}
-
${esc(t.qrDouyin)}
${t.qrDouyin}
-
${esc(t.qrX)}
${t.qrX}
+
${esc(t.qrWechat)}
${t.qrWechat}
+
${esc(t.qrDouyin)}
${t.qrDouyin}
+
${esc(t.qrX)}
${t.qrX}