fix(docs,site): README 把 2 个上游 skill 算成「中国特色」;二维码缺 height;官网外链没人验活

按主站逐项核对时查出的三处,都不是新引入的,是一直没人发现。

## ① 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,加载时把页脚顶下去

`<img width="158">` 没有 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。
This commit is contained in:
AI不止语
2026-09-02 21:19:58 +08:00
parent 293b300365
commit 1081cefc42
4 changed files with 65 additions and 15 deletions

View File

@@ -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**<br><sub>另有 2 个上游历史保留</sub> | **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 |
### 🇨🇳 中国特色 Skills6 个)
### 🇨🇳 中国原创 Skills4 个)· 上游历史保留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 工作流 | 自动 | 曾有,上游已移除 |
---

View File

@@ -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**<br><sub>另有 2 個上游歷史保留</sub> | **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 |
### 🇨🇳 中國特色 Skills6 個)
### 🇨🇳 中國原創 Skills4 個)· 上游歷史保留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 工作流 | 自動 | 曾有,上游已移除 |
---

View File

@@ -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

View File

@@ -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 的真实像素尺寸(零依赖)。
// 用途:<img> 必须带 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
// ---- 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}
<div class="foot-qr">
<h4 class="qr-title">${t.followUs}</h4>
<div class="qr-row">
<figure class="qr-card"><img src="/assets/qr-wechat.jpg" alt="${esc(t.qrWechat)}" width="158" loading="lazy"><figcaption>${t.qrWechat}</figcaption></figure>
<figure class="qr-card"><img src="/assets/qr-douyin.jpg" alt="${esc(t.qrDouyin)}" width="158" loading="lazy"><figcaption>${t.qrDouyin}</figcaption></figure>
<figure class="qr-card"><a href="https://x.com/jnMetaCode" target="_blank" rel="noopener"><img src="/assets/qr-x.png" alt="${esc(t.qrX)}" width="158" loading="lazy"></a><figcaption><a href="https://x.com/jnMetaCode" target="_blank" rel="noopener">${t.qrX}</a></figcaption></figure>
<figure class="qr-card"><img src="/assets/qr-wechat.jpg" alt="${esc(t.qrWechat)}" width="${QR.wechat.w}" height="${QR.wechat.h}" loading="lazy"><figcaption>${t.qrWechat}</figcaption></figure>
<figure class="qr-card"><img src="/assets/qr-douyin.jpg" alt="${esc(t.qrDouyin)}" width="${QR.douyin.w}" height="${QR.douyin.h}" loading="lazy"><figcaption>${t.qrDouyin}</figcaption></figure>
<figure class="qr-card"><a href="https://x.com/jnMetaCode" target="_blank" rel="noopener"><img src="/assets/qr-x.png" alt="${esc(t.qrX)}" width="${QR.x.w}" height="${QR.x.h}" loading="lazy"></a><figcaption><a href="https://x.com/jnMetaCode" target="_blank" rel="noopener">${t.qrX}</a></figcaption></figure>
</div>
</div>
<div class="foot-inner foot-cols">