Files
chinese-independent-developer/.claude/skills/chinese-indie-dev/SKILL.md
郑诚 (Cheng Zheng) 2f9ec9a536 修复 chinese-indie-dev skill:PR 批量误关闭、issue 关闭步骤缺失
- 检查三多个 PR 同时冲突时禁止批量誊抄进 master 再关闭,必须逐个走真正合并
- 修复检查二流程编号缺失导致 #1225 关闭 issue 步骤被漏掉的 bug
- 签名去除规则改为如实描述(真正兜底靠收尾扫描,不再虚报逐条重试验证)
- 文末注意事项明确"不建分支直接推 master"仅适用于检查一/二,不适用于 PR
2026-07-31 09:54:45 +08:00

397 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: chinese-indie-dev
description: >
处理 1c7/chinese-independent-developer 仓库的项目提交。
检查 issue #160 新评论、新开的 Issue、新开的 PR
将有效项目添加到对应 README关闭垃圾内容。
当用户说"处理提交"、"处理 issue"、"跑一下列表"时使用。
metadata:
author: 1c7
version: "2.2"
lang: zh-CN
allowed-tools:
- Bash
- Read
- Edit
- Write
---
# 中国独立开发者列表:处理项目提交
你的任务是处理 GitHub 仓库 `1c7/chinese-independent-developer` 的项目提交。
检查最近的新评论、新 Issue、新 PR将有效项目添加到对应 README关闭垃圾内容。
⚠️ 严格禁止:不得调用添加 reaction 的 API。
⚠️ 严格禁止:不得以任何理由删除或修改 README 中已有的条目。本 skill 的唯一允许操作是**新增**。如果发现疑似重复,只需跳过,绝对不能删除。
⚠️ 关于评论签名("Generated by Claude Code"GitHub 会在通过 API 创建的评论正文末尾自动追加这段签名,本 skill 里每处发评论都要求 POST 后立即 PATCH 覆写去掉它。**这一步不是可选的**,但实践证明单次 PATCH 不可靠(网络抖动、静默失败都发生过,例如 issue #160 的 4886068668 号评论),所以不要求也不要指望在发每一条评论时就用重试循环验证到底——那样会让每处发评论的代码都变得很重,而且历史证明重试计数本身也会撒谎(见文末「收尾扫描」的说明)。**真正的保证机制是文末的「收尾扫描」**:它在每次运行结束前无条件重扫全仓库最近的评论、发现残留签名就修,这一步不可省略,也不能因为「前面 PATCH 时看起来成功了」就跳过。
⚠️ 关于用户名旁边的 "with Claude" 标记:这是 GitHub 基于「哪个 GitHub App 完成了这次 API 调用」自动显示的归属标记(`performed_via_github_app`),和评论正文内容无关,无法通过修改 PATCH 后的 body 去掉。这套自动化现在已经通过 1c7 账号自己的 Personal Access Token 认证(在 Routine 的初始化步骤里 `gh auth login --with-token`),不再挂靠 claude.ai 的 GitHub Connector/官方 "Claude" GitHub App。
⚠️ 严格禁止:本 skill 涉及的所有 GitHub 操作(发评论、开关 issue、合并/关闭 PR、改 reaction 等)**只能通过 Bash 里的 `gh` / `git` 命令行执行**,绝对不能使用任何 GitHub 连接器Connector或平台自带的原生 GitHub 工具(例如各种 `add_issue_comment``merge_pull_request``create_pull_request` 之类的内置工具)去完成,哪怕当前环境里这些工具可用。原因:这些内置工具走的是 claude.ai 官方 "Claude" GitHub App 的身份认证,会导致评论重新出现无法去除的 "with Claude" 标记,且不受本 skill 里 PATCH 去签名逻辑的控制。如果发现当前环境里除 Bash/Read/Edit/Write 之外还暴露了 GitHub 相关工具,直接忽略它们,改用 `gh api` / `gh pr` / `gh issue` 等命令行等价操作。
⚠️ 本仓库**只收录中国独立开发者**的项目(仓库标题即「中国独立开发者项目列表」)。检查一、二、三的每一位提交者,在进入「通用处理流程」或合并 PR 之前都必须先按下方「身份判断」章节确认是中国人确认是老外的一律礼貌拒绝、不收录绝不能因为产品本身质量好、URL 有效就直接收录。
⚠️ 三个版面的**固定名称**是「主版面」「程序员版面」「游戏版面」——都以"版面"两个字结尾,不是"主版"/"程序员版"/"游戏版"。所有感谢评论、PR/issue 评论中提到版面名称的地方,写完之后要逐字核对有没有漏掉"面"字(历史运行中出现过在感谢评论里把"程序员版面"错写成"程序员版"的情况,且没有被自动校验发现)。
⚠️ **格式问题绝不能作为关闭 PR / Issue / 拒绝收录的理由。** 提交格式再乱(一行纯文本、没有 `####` 作者行、没有 `:white_check_mark:`、中英文没空格、描述像广告词),都只是我们收尾时要清理的事,不是拒绝提交者的理由。允许关闭的理由只有两类:**垃圾广告/无关内容**,以及**非中国开发者**。正确做法是先合并/先收录,再按下面的格式规范单独发一条整理 commit。历史上出现过 bot 以"格式和本仓库的收录要求不符"为由关掉了一个本可以合并的 PR#1205),这是错误的。发拒绝评论前,逐字检查理由里有没有出现"格式"两个字——如果有,说明这次拒绝就是错的,退回去改成合并。
⚠️ **版面判断必须点开产品链接实际看一眼,不能只凭提交者的标题和描述猜。** 判断标准见「步骤2分类」的表格这里不重复。要强调的是动作每个待收录项目都要真的打开一次是 GitHub 项目就再看一眼 `gh api repos/<owner>/<repo> | jq '{homepage}'`、release 有没有可下载的 assets、README 快速开始第一步是不是 `git clone` / docker / 包管理器命令。
⚠️ **多个 PR 同时打开、且会插入同一个日期区块时,必须逐个串行处理,禁止图省事改成"手动誊抄内容 + 批量关闭 PR"。** 历史事故2026-07-30 12:53 前后 #1220#1221#1226#1227 四个格式完全合规、非垃圾、提交者也是中国开发者的 PR因为都要插入同一天的日期区块、彼此会冲突处理时没有按下面「检查三」定义的单 PR 合并流程逐个走完,而是直接用 Edit 工具把内容誊抄进 master 合成一条 commit再把四个 PR 全部 `gh pr close`——内容确实进了 README但四个 PR 全都错误地显示为红色 Closed 而不是紫色 Merged贡献者观感很差。正确做法每次只处理一个 PR处理完无论是 `gh pr merge --squash` 还是下面步骤3 的本地合并+push**立即** `git fetch origin master` 拿到最新 master再开始下一个 PR——这样后处理的 PR 在合并时天然就能感知到前一个 PR 已经插入的行,走正常的冲突合并路径(保留双方条目),而不会退化成"批量手动誊抄"。**只有当某个 PR 的 `maintainer_can_modify` 确实是 `false` 且推送环节确实失败时**才允许落到步骤3 最终的"本地合并+关闭"兜底;不允许仅仅因为"同时有好几个 PR 要处理"就跳过前面的真实合并尝试直接走兜底。
⚠️ **PR 贡献者选的文件经常是错的,版面由我们判断,不由他改了哪个文件决定。** 检查三的 PR 走直接合并、不经过步骤2但版面判断这一步对 PR 同样必须做。发现放错版面时,**照常先合并**(绝不因此关闭或退回 PR再把条目挪到正确的版面并单独发一条修正 commit如果该 PR 的 `maintainer_can_modify``true`,也可以直接改他的分支、让 PR 一次就落到正确的文件再合并——两种方式都行,重点是必须 merge 且最终落在正确版面。挪完后如果感谢评论已经发出去了,记得 PATCH 修正评论里的版面名称。历史错误Site Guard 是自托管 Docker 部署却被合并进主版面(#1206)、摸鱼解压玩具是游戏却提交到主版面(#1208)。
⚠️ 感谢评论必须简短,只说结果,不说过程:固定句式是「@用户名 感谢提交,你的产品 X 已添加到 Y 版面!」(或已收录多个产品时按本文档后面给的变体)。**禁止**在评论里额外加"谢谢!"这类结尾客套话(前面已经有"感谢提交"了,不需要再谢一次);**禁止**提及处理过程中的内部细节,例如"PR 有冲突"「已由我们手动合并」「已手动处理」之类——不管背后是直接合并、手动解决冲突、还是走 issue 流程,提交者只需要知道结果(收录到了哪个版面),不需要知道我们是怎么做到的。发送前对照这条逐字检查。
---
## 预检:快速判断是否有任何新内容
**在做任何实质处理之前**,先并行运行以下三条命令,统计各自的结果数量:
```bash
SINCE=$(date -u -d '7 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-7H +%Y-%m-%dT%H:%M:%SZ)
# 检查一:#160 新评论数
COUNT_COMMENTS=$(gh api "repos/1c7/chinese-independent-developer/issues/160/comments?since=$SINCE&per_page=100" | jq 'length')
# 检查二:新 Issue 数
COUNT_ISSUES=$(gh api "repos/1c7/chinese-independent-developer/issues?state=open&per_page=50" \
| jq --arg since "$SINCE" '[.[] | select(.number != 160 and .pull_request == null and .created_at >= $since)] | length')
# 检查三:待处理 PR 数(排除 auto-add- 分支)
COUNT_PRS=$(gh api "repos/1c7/chinese-independent-developer/pulls?state=open&per_page=50" \
| jq '[.[] | select(.head.ref | startswith("auto-add-") | not)] | length')
echo "新评论: $COUNT_COMMENTS 新Issue: $COUNT_ISSUES 待处理PR: $COUNT_PRS"
```
如果三个数字**全部为 0**,输出「无新内容」,跳过检查一、二、三和通用处理流程,**但仍然必须执行文末的「收尾扫描」**(那一步与本次有没有新提交无关),扫完再结束。
只要有任意一个数字 > 0才继续向下执行。
---
## 检查一issue #160 的新评论
获取最近 7 小时内的评论(每 6 小时运行一次,留 1 小时余量):
```bash
SINCE=$(date -u -d '7 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-7H +%Y-%m-%dT%H:%M:%SZ)
gh api "repos/1c7/chinese-independent-developer/issues/160/comments?since=$SINCE&per_page=100"
```
对每条评论,从内容中提取产品 URL检查是否已在任意 README 中:
```bash
grep -rF "<产品完整URL>" README.md pages/README-Programmer-Edition.md pages/README-Game.md
```
⚠️ 去重规则(必须严格遵守):
- 必须用产品的**完整 URL**(如 `https://example.com`)做精确字符串匹配,使用 `grep -F`(固定字符串,非正则)
- 禁止用产品名称、描述文字或部分关键词判断重复——描述里提到某个工具名不等于该工具已在列表中
- URL 已存在 → 跳过,对 README 不做任何操作
- URL 不存在 → 进入「通用处理流程」
- 当前运行中已通过 PR 合并的条目,视为已存在,不再重复处理
处理完所有检查一的评论后,记录每位成功处理的评论作者用户名、收录的产品名和目标版面(用于最后一步在 #160 逐人发感谢评论)。
---
## 检查二:最近 7 小时内开启的新 Issue非 #160
```bash
SINCE=$(date -u -d '7 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-7H +%Y-%m-%dT%H:%M:%SZ)
gh api "repos/1c7/chinese-independent-developer/issues?state=open&per_page=50" \
| jq --arg since "$SINCE" \
'[.[] | select(.number != 160 and .pull_request == null and .created_at >= $since)]'
```
判断每个 Issue
- **有效项目提交**(含产品名 + 可访问 URL→ 进入「通用处理流程」,完成后:
1. 在**该 issue 本身**(不是 #160!)发感谢评论,需说清楚收录到了哪个版面(主版面/程序员版面/游戏版面对应「通用处理流程」步骤2的分类结果立即捕获 ID 并 PATCH 去掉自动追加的署名:
```bash
CLEAN_BODY="@<提交者用户名> 感谢提交,已将你的产品 <产品名> 添加到 <主版面/程序员版面/游戏版面>"
COMMENT_RESPONSE=$(gh api repos/1c7/chinese-independent-developer/issues/<number>/comments \
-X POST -f body="$CLEAN_BODY")
COMMENT_ID=$(echo "$COMMENT_RESPONSE" | jq -r '.id')
gh api --method PATCH \
repos/1c7/chinese-independent-developer/issues/comments/$COMMENT_ID \
-f body="$CLEAN_BODY"
```
2. 关闭 issue**不能漏,历史事故:#1225 发完感谢评论后就漏了这一步issue 一直挂着 open**
```bash
gh issue close <number>
```
- **垃圾广告、无关内容、内容不清晰** → 直接关闭:`gh issue close <number>`
检查二的提交者不需要在最后一步中 @ 到 #160他们已在各自的 issue 里收到了感谢。
---
## 检查三:所有未关闭的 PR排除 auto-add- 分支)
直接获取所有 open 状态的 PR不限时间确保不遗漏
```bash
gh api "repos/1c7/chinese-independent-developer/pulls?state=open&per_page=50" \
| jq '[.[] | select(.head.ref | startswith("auto-add-") | not)]'
```
判断每个 PR
- **有效项目提交**(对 README 的修改,含产品名 + URL→ 直接合并:
```bash
gh pr merge <number> --squash --yes
```
- 如果合并成功:在该 PR 发感谢评论,需说清楚收录到了哪个版面(根据 PR 修改的是 README.md / pages/README-Programmer-Edition.md / pages/README-Game.md 中的哪个文件,对应主版面/程序员版面/游戏版面),立即捕获 ID 并 PATCH 去掉署名:
```bash
CLEAN_BODY="@<提交者用户名> 感谢提交,已将你的产品 <产品名> 合并到 <主版面/程序员版面/游戏版面>"
PR_COMMENT_RESPONSE=$(gh api repos/1c7/chinese-independent-developer/issues/<number>/comments \
-X POST -f body="$CLEAN_BODY")
PR_COMMENT_ID=$(echo "$PR_COMMENT_RESPONSE" | jq -r '.id')
gh api --method PATCH \
repos/1c7/chinese-independent-developer/issues/comments/$PR_COMMENT_ID \
-f body="$CLEAN_BODY"
```
- 如果合并失败(如 merge conflict**由我们自己解决冲突并合并,绝不要求提交者 rebase**。优先尝试真正合并(让 PR 显示为 Merged只有技术上不可行时才降级为「手动合并进 master + 关闭 PR」。步骤
1. 先查该 PR 是否允许维护者编辑分支:
```bash
MAINTAINER_CAN_MODIFY=$(gh api repos/1c7/chinese-independent-developer/pulls/<number> | jq -r '.maintainer_can_modify')
```
2. **如果 `MAINTAINER_CAN_MODIFY` 为 `true`**(优先路径,能让 PR 真正显示为 Merged
```bash
HEAD_REF=$(gh api repos/1c7/chinese-independent-developer/pulls/<number> | jq -r '.head.ref')
HEAD_REPO_URL=$(gh api repos/1c7/chinese-independent-developer/pulls/<number> | jq -r '.head.repo.clone_url')
git fetch origin master
git fetch origin pull/<number>/head:pr-<number>
git checkout pr-<number>
git merge origin/master --no-edit
```
如果出现冲突:**手动编辑冲突文件**,保留双方新增的条目(不要删除任何一方已有的行),冲突标记全部清理干净,然后:
```bash
git add <冲突文件>
git commit --no-edit
git push "$HEAD_REPO_URL" "pr-<number>:$HEAD_REF"
gh pr merge <number> --merge
```
(用 `--merge` 而非 `--squash`,保留贡献者原始 commit 的作者信息)推送后如果因为权限或分支保护等原因失败,视为该路径不可行,降级到步骤 3。合并成功则按下面「合并成功」的致谢评论流程处理PR 会正常显示为 Merged。
3. **如果 `MAINTAINER_CAN_MODIFY` 为 `false`**(贡献者未勾选"允许维护者编辑",没有权限推送到其分支,只能走这条兜底路径),或步骤 2 推送失败:
```bash
git fetch origin master
git fetch origin pull/<number>/head:pr-<number>
git checkout master && git reset --hard origin/master
git merge pr-<number> --no-ff -m "合并 PR #<number><项目名>"
```
如果出现冲突:冲突几乎必然是 README 里同一个日期区块被多个 PR 同时插入条目导致的。**手动编辑冲突文件**,保留双方新增的条目(不要删除任何一方已有的行),冲突标记全部清理干净,然后:
```bash
git add <冲突文件>
git commit --no-edit
```
校验 README 格式无误后推送:
```bash
git push origin master
```
因为贡献者的分支落后于 master、GitHub 无法用按钮直接标记该 PR 为 merged所以改为关闭 PR 并致谢。**评论正文不要提冲突、不要提手动合并这类处理过程细节**,提交者不需要知道内部是怎么处理的,只需要知道结果:
```bash
CLEAN_BODY="@<提交者用户名> 感谢提交,你的产品 <产品名> 已添加到 <主版面/程序员版面/游戏版面>"
gh pr close <number> --comment "$CLEAN_BODY"
```
4. 如果冲突内容复杂到无法安全判断该保留什么(例如冲突不只是新增条目,而是修改了已有内容的结构),**不要瞎猜、不要删除任何已有内容**,改为在 PR 里说明具体冲突原因并保持 PR 打开,等待人工介入;但这应是极少数情况,绝大多数「新增条目」型冲突都应该自动解决。
- **不允许**的做法:连续多次发送「请 rebase / 请解决冲突后重新提交」这类要求人类提交者自己解决冲突的评论。冲突处理是我们的责任,不是提交者的。
- **垃圾广告、无关内容** → 直接关闭:`gh pr close <number>`
- **非中国开发者(老外)** → 不合并,按下方「身份判断」章节的拒绝流程处理:礼貌评论说明后 `gh pr close <number>`,不使用 `gh pr merge`
- **格式乱、不符合模板** → 这不是关闭理由照常合并合并后按下面「PR 合并后要检查描述格式」的要求单独发一条格式整理 commit见文档开头的格式禁令
⚠️ 严格禁止:检查三的 PR **无冲突时**必须走上面的 `gh pr merge --squash`,不能走通用处理流程(那样会丢失贡献者的 git 归属)。**有冲突时**才使用上面的本地合并步骤,因为 `git merge --no-ff` 会保留贡献者原始 commit 的作者信息,不会丢失归属。
⚠️ PR 合并后要检查描述格式(`gh pr merge` 是原样合并贡献者写的文字,不会自动清理):如果存在「中英文/数字之间没有空格」「一个、一款、高效、简洁、强大等填充词」「产品类型被埋在长修饰语最后面(如"是一个基于 X、Y、Z 构建的 W"这种结构,应改成"W基于 X、Y、Z 构建"把 W 提前)」这几类问题,合并完之后**单独用 Edit 工具再发一条格式整理的 commit**(只改标点空格和语序,不改事实信息,也不算作「修改已有条目」——因为这是本次新增内容的同一批次收尾,不是改动历史上已收录的条目)。不要把这类清理和「新增」提交混在一条 commit 里,保持 commit 语义清晰。
---
## 身份判断:仅收录中国独立开发者(检查一、二、三共用)
仓库标题是「中国独立开发者项目列表」,收录范围严格限定为**中国独立开发者**的项目产品本身质量再好、URL 再有效只要提交者不是中国人一律不收录。检查一、二、三的每一位提交者在进入「通用处理流程」步骤1之前或检查三判断是否合并 PR 之前),都要先做这一步判断。
**判断标准(满足以下任一条即可判定为中国人):**
1. 提交者用中文留言,且内容通顺自然、符合中文母语者的表达习惯(不是生硬的机器翻译腔)
2. 提交者的名字是拼音,或明显是中国人姓名(含港澳台常见姓名)
3. 提交者的 GitHub 主页能看出中国元素:例如 bio 是中文、有仓库的标题/描述是中文、location 写着中国城市/省份等
查证方式:
```bash
gh api users/<username> | jq '{name, bio, location}'
# 如上面三个字段都看不出结论,抽查几个仓库名称/描述辅助判断:
gh api "users/<username>/repos?sort=updated&per_page=10" | jq '[.[] | {name, description}]'
```
⚠️ 不能只看单一信号就下结论:
- 不能仅凭"提交内容是中文"就判定——要综合看,尤其留意机翻痕迹(用词生硬、语序不自然)
- 不能仅凭 GitHub 用户名/主页语言是英文就判定为老外——很多中国开发者也用纯英文用户名和英文 bio需结合上面三条综合判断
- `location` 字段是强信号但非绝对:结合 name/bio/repos 一起看
**默认原则:老外不收录,只有确认是中国人才收录。** 三条证据都拿不到、无法判断时,不要为了收录而"往好处想",倾向于按拒绝处理,评论里客气说明"暂时无法确认是否符合本仓库收录范围(仅限中国独立开发者)"。
**判定为非中国开发者后的处理:**
- 检查一issue #160 评论):不进入「通用处理流程」,不修改任何 README在 #160 该条评论下用提交者所用的语言礼貌回复说明原因即可(不需要额外关闭操作)
- 检查二(独立 issue不进入「通用处理流程」在该 issue 下礼貌回复后 `gh issue close <number>`
- 检查三PR不合并在 PR 下礼貌评论后 `gh pr close <number>`(不使用 `gh pr merge`
**拒绝评论模板**(用提交者使用的语言回复,语气礼貌简短,不解释具体判断依据,不含 Claude 署名——POST 后同样要 PATCH 去署名并 GET 验证):
```
感谢分享 <产品名>不过本仓库只收录中国独立开发者的项目README 开头写明"聚合所有中国独立开发者的项目"),所以暂时不在收录范围内,抱歉。祝 <产品名> 发展顺利!
```
英文示例:
```
Thanks for sharing <product>! This repo specifically curates projects made by Chinese independent developers, so it's outside the scope of this list. Good luck with <product>!
```
---
## 通用处理流程(适用于检查一和检查二,且已通过上方「身份判断」)
### 步骤1提取信息并格式化
从原始内容智能提取,整理为标准格式。提交格式千奇百怪,需灵活判断:
**必须有(缺则归入拒绝类):**
- 制作者名字:用户没写则用其 GitHub 用户名代替
- 产品名称 + 可访问的产品 URLhttp/https 开头)+ 一句话描述
**可选(有则填,无则略去):**
- 城市、GitHub 链接、博客链接、更多介绍链接
**标准输出格式:**
```
#### 制作者名字(城市) - [Github](url)
* :white_check_mark: [产品名](url):一句话描述 - [更多介绍](url)
```
**格式规范:**
- ⚠️ 优先级最高:如果提交者在评论/Issue/PR 正文中明确表示不希望改动其项目简介(例如"请不要改动我的项目简介""请尽量不要改动我的项目简介"等),必须原文一字不动地采用其提供的描述文字,跳过下面所有格式清理规则(去营销词、语序调整、标点空格等),只做产品名/URL 是否合规的必要核对。尊重提交者意愿优先于统一格式。
- 日期区块标题用北京时间:`TZ=Asia/Shanghai date +"%Y 年 %-m 月 %-d 号添加"`
- 描述末尾不加句号
- 去掉「高效、简洁、强大、快速、好用、一款、一个」等营销废话;「免费」若是核心特征则保留
- 产品名称提升到最前面
- 描述开头不要重复"「产品名」是一款/是一个……"这种句式(产品名已经是链接标题,不需要在描述里再说一遍),第一句直接说这个产品解决什么问题/能做什么;产品形态、平台(微信小程序/免费/Chrome 插件等)这类次要信息放到描述最后,用「 — 」或分号带出,不要放在开头占据最显眼的位置
- 严禁使用加粗格式(不要用 **
### 步骤2分类
| 类别 | 判断标准 | 目标文件 |
|------|---------|----------|
| 主版面 | 打开即用的网站或 App非游戏 | README.md |
| 程序员版面 | 需要命令行/写代码/安装依赖 | pages/README-Programmer-Edition.md |
| 游戏版面 | 任何游戏类产品 | pages/README-Game.md |
| 拒绝 | 论坛、无 URL、垃圾广告、无法判断、或提交者非中国开发者见上方「身份判断」 | 不处理 |
⚠️ 个人博客不算独立"产品",不作为单独的 `* :white_check_mark: [产品名](url)...` 条目收录(无论是在评论/Issue 里单独提交,还是和其他产品一起夹带提交)。如果提交内容里包含个人博客链接,按 CONTRIBUTING.md 的模板把它放进作者信息行,写成 `#### 制作者名字(城市) - [Github](url), [博客](博客url)`,不要单独起一行当产品处理。这条同样适用于检查三的 PRPR 里如果夹带了博客条目,即使 PR 整体因为改了 README 且含产品名+URL 被判定为"有效提交"要合并,合并后仍要单独检查其中每一行是否真的是产品,博客类条目要按上面方式改成作者信息里的链接,不能因为"PR 已经通过整体有效性检查"就跳过逐行审查。
⚠️ 不要盲信提交者对自己产品/链接的自我描述,尤其是"博客"这类字眼。历史上出现过提交者把链接写成"个人技术博客",实际打开后是网址导航站(且含疑似盗版影视资源链接),完全不符合收录标准。处理任何"博客"链接前,用 `curl -sL <url> | grep -o '<title>[^<]*</title>'` 和 meta description 快速核对一下页面实际内容是否真的是博客(文章列表/写作内容),而不是导航站、工具集合站等被包装成"博客"的东西。如果标题/描述显示是"导航""聚合""网址""hao123 类站点"等关键词,即使提交者自称是博客,也不要收录,按拒绝处理并说明原因。
### 步骤3插入文件并批量提交到 master
先用 Read 工具读取目标 README 了解格式,用 Edit 工具插入条目。**新条目插入当天日期区块的最顶部**(紧接日期标题行之后的空行后面)。
如果当天日期区块尚不存在,则在最新日期区块之前新建。
**所有项目的文件修改全部做完后**,统一一次性提交推送到 master
```bash
git checkout master && git pull origin master
# (用 Edit 工具对各 README 文件做完所有修改)
git add README.md pages/README-Programmer-Edition.md pages/README-Game.md
git commit -m "新增:<项目1名>、<项目2名>、..."
git push origin master
```
- 不建分支,不开 PR直接推 master
- 所有项目合为一条 commitcommit message 列出所有项目名
- 如果本次没有任何有效项目,跳过 git 操作
---
## 最后一步:逐人发感谢评论并删除 Claude 署名(仅针对检查一的提交者)
所有三个检查都处理完之后,如果检查一中成功收录了项目,在 issue #160 为**每位来自检查一的成功提交者单独发一条评论**
```
@<用户名> 感谢提交,已将你的产品 <产品名> 添加到 <主版面/程序员版面/游戏版面>
```
- 一条评论只 @ 一位用户,严禁把多位提交者合并到同一条评论
- 同一用户提交多个产品时,仍只发一条,在评论中列出所有成功收录的产品
- 同一用户的产品被收录到不同版面时,按版面分组说明,例如:`@user 感谢提交,已将你的产品 A、B 添加到主版面,并将 C 添加到程序员版面!`
- 检查二的提交者不要 @ 到这里(他们已在各自的 issue 里收到了感谢)
- 如果检查一没有成功处理任何项目,不发评论
Claude Code 会自动在正文末尾追加署名。每位用户的评论都必须分别执行 POST、立即 PATCH再 GET 验证署名已删除:
```bash
CLEAN_BODY="@user 感谢提交,已将你的产品 Product 添加到主版面!"
COMMENT_RESPONSE=$(gh api repos/1c7/chinese-independent-developer/issues/160/comments \
-X POST -f body="$CLEAN_BODY")
COMMENT_ID=$(echo "$COMMENT_RESPONSE" | jq -r '.id')
gh api --method PATCH \
repos/1c7/chinese-independent-developer/issues/comments/$COMMENT_ID \
-f body="$CLEAN_BODY"
gh api repos/1c7/chinese-independent-developer/issues/comments/$COMMENT_ID \
| jq -r .body
```
---
## 收尾扫描:无条件复查签名残留(每次运行都要做,包括「无新内容」的空跑)
前面每处发评论都要求 POST → PATCH → GET 验证但实践证明这一步会静默失效2026-06-23 至 07-28 期间累计有 **155 条**致谢评论带着签名一直没被清掉(#160 里 70 条,各 issue/PR 上另有 85 条),横跨 `1c7` 和 `claude[bot]` 两种身份,而每次运行都自认为验证通过了。所以不能只依赖发评论时的那次自检,**每次运行结束前必须再无条件重扫一遍**。
⚠️ 扫描范围必须是**整个仓库**,不能只扫 #160——检查二、检查三的致谢评论发在各自的 issue / PR 上,只扫 #160 会漏掉一大半。用仓库级评论接口,它支持 `sort`/`direction`,一次就能拿到全仓库最近的评论:
```bash
# 必须先把结果落盘再解析gh api 直接管道给 jq 时,网络 EOF 会让 jq 收到空输入、
# 静默输出 0 条,看起来像「已经干净」——这是假阴性,务必用重试 + 落盘。
for i in 1 2 3 4 5; do
gh api "repos/1c7/chinese-independent-developer/issues/comments?sort=created&direction=desc&per_page=100" \
> /tmp/sig_scan.json 2>/dev/null && break
sleep 3
done
jq -e 'type == "array" and length > 0' /tmp/sig_scan.json >/dev/null \
|| { echo "扫描接口没拿到数据,本次扫描无效,必须重试后再判断"; exit 1; }
jq -r '.[] | select(.body | test("Generated by")) | select(.user.login as $u | ["1c7","claude[bot]"] | index($u)) | .id' \
/tmp/sig_scan.json > /tmp/sig_dirty.txt
echo "检出待修: $(wc -l < /tmp/sig_dirty.txt) 条"
```
⚠️ 上面的 `select(.user.login ...)` 过滤不能省:**只修我们自己(`1c7` / `claude[bot]`)发的评论**。贡献者回复时经常用 `>` 引用我们带签名的原文,那是他本人的评论,一个字都不许改(例:#1155 的 5009781050 号评论)。
扫到任何 ID 就当场修掉,逐条 PATCH 后 GET 复核:
```bash
while read -r ID; do
gh api "repos/1c7/chinese-independent-developer/issues/comments/$ID" \
| jq '{body: (.body | sub("\\n*---\\n*_Generated by \\[Claude Code\\]\\(https://claude\\.ai/code\\)_\\s*$"; "") | rtrimstr("\n"))}' \
> /tmp/sig_payload.json
# 空正文保护:绝不把评论清空
[ "$(jq -r '.body | length' /tmp/sig_payload.json)" -eq 0 ] && { echo "跳过 $ID正文会被清空"; continue; }
gh api --method PATCH "repos/1c7/chinese-independent-developer/issues/comments/$ID" --input /tmp/sig_payload.json > /dev/null
gh api "repos/1c7/chinese-independent-developer/issues/comments/$ID" | jq -r '.body'
done < /tmp/sig_dirty.txt
```
⚠️ 写这类批量脚本时**不要用 `echo "$json" | jq` 传递 JSON**——`echo` 会把字符串里的 `\n` 当转义符展开,导致 jq 全线解析失败。一律用文件(`> file` 再 `jq ... file` / `--input file`)传递。
⚠️ **不允许凭脚本自己打印的「成功 N 条」就认为修完了。** 历史上出现过循环里 jq 静默失败、计数逻辑却报「成功 70 失败 0」、实际一条都没改的情况。必须重新拉一次评论列表、再次 `grep "Generated by"` 确认残留计数为 0贡献者引用产生的那几条除外才算这一步完成。
⚠️ 偶发的 `Post/Get "https://api.github.com/...": EOF` 是网络抖动,不是真失败。上面的循环已经带 3 次重试;如果收尾复查时仍有少量残留,单独把这几个 ID 再跑一遍即可,不要因此判定整批失败。
---
## 注意事项
- 幂等性靠 URL grep 检查保证,不依赖 reaction 标记
- **仅检查一、检查二**issue #160 评论 / 独立 issue来源的内容所有文件修改完成后统一一次 commit 推 master不建分支、不开 PR。**这条不适用于检查三的 PR**——PR 来源的内容必须走上文「检查三」定义的真正合并流程(`gh pr merge` 或本地 `git merge --no-ff` 保留贡献者归属),禁止把 PR 里的内容当成检查一/二那样直接誊抄进 master 再关闭 PR历史事故见上文 #1220/#1221/#1226/#1227
- 三个检查都没有新内容时,跳过处理流程,但仍要跑「收尾扫描」再结束