forked from Gitlink/gitlink-cli
13 KiB
13 KiB
gitlink-stale — 动作执行手册
本文档说明如何把分析报告中的推荐动作安全地应用到 GitLink Issue/PR。 所有命令默认 dry-run,确认后再去掉
--dry-run实际执行。
1. 应用前置检查
1.1 备份当前状态
# 导出当前所有目标 Issue/PR 的原始字段(用于回滚)
gitlink-cli issue +list --owner <owner> --repo <repo> --state open --format json \
> /tmp/before-stale-$(date +%s).json
1.2 确认权限
# 检查当前用户对该仓库的写权限
gitlink-cli user +me --format json
gitlink-cli api GET /:owner/:repo --format json | jq '.data.permissions'
若 permissions.push !== true,所有写操作会失败,应停止并提示用户。
1.3 确认仓库有 stale 标签
# 检查仓库标签是否存在 stale
gitlink-cli api GET /v1/<owner>/<repo>/issue_tags.json --format json \
| jq '.data.issue_tags[] | select(.name == "stale")'
# 如果不存在,提示用户手动创建(或通过 Raw API 创建)
# 强烈建议由人工创建,避免 Skill 越权
2. 三种推荐动作
2.1 动作 A:mark_stale(标记 stale)
触发条件:
days_inactive >= 60(stale 阈值)ai_analysis.truly_stale == trueconfidence >= 0.6
执行命令:
# 1. 打 stale 标签
gitlink-cli issue +label-add \
--owner <owner> --repo <repo> \
--number <N> \
--labels "stale"
# 2. 评论催办(友好版,非警告)
gitlink-cli issue +comment \
--owner <owner> --repo <repo> \
--number <N> \
--body "⏰ **长期未活动提醒**
本 Issue 已 60 天未收到新回复,暂时标记为 \`stale\`。
- 如果**仍然相关**,请回复任意内容,会自动移除 stale 标签
- 如果**已经过时**,欢迎手动关闭
- 如果在 **14 天内**没有新活动,将自动关闭以保持 Issue 列表清爽
> 🤖 由 gitlink-stale skill 自动生成。"
2.2 动作 B:auto_close(自动关闭)
触发条件:
days_inactive >= 74(close 阈值)ai_analysis.truly_stale == trueconfidence >= 0.8
执行命令:
# 1. 确保 stale 标签存在(如果之前没打,先打)
gitlink-cli issue +label-add \
--owner <owner> --repo <repo> \
--number <N> \
--labels "stale"
# 2. 评论关闭说明
gitlink-cli issue +comment \
--owner <owner> --repo <repo> \
--number <N> \
--body "🔒 **自动关闭(长期未活动)**
本 Issue 已 74 天无活动,自动关闭。
- 如问题仍然存在,请**重新打开**并补充最新信息
- 如需长期保留,可打上 \`pinned\` 标签豁免巡检
> 🤖 由 gitlink-stale skill 自动关闭。原始讨论保留在历史中。"
# 3. 关闭 Issue
gitlink-cli issue +close \
--owner <owner> --repo <repo> \
--number <N>
2.3 动作 C:PR 催办(PR stale)
⚠️ PR 端点暂不支持 label 操作,仅评论催办。
执行命令:
gitlink-cli pr +comment \
--owner <owner> --repo <repo> \
--id <N> \
--body "⏰ **PR 长期未活动**
本 PR 已 60 天未更新,可能存在以下情况:
- 合并遇到冲突?请 rebase 后重新推送
- 等待 review?可 @mention 相关维护者
- 不再需要?欢迎手动关闭
如果 **14 天内**没有新活动,将默认关闭。
> 🤖 由 gitlink-stale skill 自动生成。"
如果 PR 也超过 close 阈值(74 天):
gitlink-cli pr +comment \
--owner <owner> --repo <repo> \
--id <N> \
--body "🔒 **PR 自动关闭(长期未活动)**
本 PR 已 74 天无活动,自动关闭。
- 如仍需合并,请 rebase 后重新打开
- 如有冲突,可重新发起 PR
> 🤖 由 gitlink-stale skill 自动关闭。"
gitlink-cli pr +close \
--owner <owner> --repo <repo> \
--id <N>
3. 用户回复后移除 stale 标签
默认情况下,本 Skill 是按需触发(如每周巡检),不会自动监听回复事件。
但如果用户希望"用户回复后立刻移除 stale 标签",可以单独触发:
# 检查某 Issue 是否有新回复
CURRENT=$(gitlink-cli issue +view --owner <owner> --repo <repo> \
--number <N> --format json)
HAS_STALE=$(echo "$CURRENT" | jq '[.data.issue_tags[] | select(.name == "stale")] | length > 0')
LAST_JOURNAL_USER=$(echo "$CURRENT" | jq -r '.data.journals[-1].user.login')
AUTHOR=$(echo "$CURRENT" | jq -r '.data.author.login')
if [ "$HAS_STALE" = "true" ] && [ "$LAST_JOURNAL_USER" = "$AUTHOR" ]; then
# 作者回复了 → 移除 stale
gitlink-cli issue +label-remove \
--owner <owner> --repo <repo> \
--number <N> \
--label "stale"
gitlink-cli issue +comment \
--owner <owner> --repo <repo> \
--number <N> \
--body "✅ 检测到作者回复,已移除 stale 标签。"
fi
💡 推荐做法:用 webhook 监听 Issue 评论事件,触发本段脚本,实现"自动响应回复"。详见
../gitlink-webhook/SKILL.md。
4. 批量应用模板
4.1 Shell 脚本(推荐)
#!/usr/bin/env bash
# apply-stale.sh — 从 report.json 应用 stale 动作
set -euo pipefail
OWNER="${1:?usage: apply-stale.sh <owner> <repo> <report.json>}"
REPO="${2:?missing repo}"
REPORT="${3:?missing report.json}"
# 读取报告
TOTAL=$(jq '.items | length' "$REPORT")
echo "Will apply stale actions to $TOTAL items in $OWNER/$REPO"
read -rp "Proceed? (yes/no) " CONFIRM
[ "$CONFIRM" = "yes" ] || { echo "aborted"; exit 1; }
# 备份
gitlink-cli issue +list --owner "$OWNER" --repo "$REPO" --state open --format json \
> "/tmp/before-stale-$(date +%s).json"
# 逐条应用
jq -c '.items[]' "$REPORT" | while read -r item; do
TYPE=$(echo "$item" | jq -r '.type')
NUM=$(echo "$item" | jq '.number')
ACTION=$(echo "$item" | jq -r '.recommended_action')
CONF=$(echo "$item" | jq '.ai_analysis.confidence')
echo "→ #$NUM ($TYPE): $ACTION (conf=$CONF)"
# 跳过低置信度
if (( $(echo "$CONF < 0.6" | bc -l) )); then
echo " skipped (low confidence)"
continue
fi
# 按动作执行
case "$ACTION" in
mark_stale)
apply_mark_stale "$OWNER" "$REPO" "$TYPE" "$NUM"
;;
auto_close)
apply_auto_close "$OWNER" "$REPO" "$TYPE" "$NUM"
;;
*)
echo " skipped (action=$ACTION)"
;;
esac
sleep 0.5 # 避免限流
done
echo "✓ Batch applied"
4.2 AI Agent 执行模板
向 Claude Code 发送:
请按以下步骤应用 /tmp/stale-report.json 中的动作:
1. 读取报告,过滤 confidence < 0.6 的项
2. 对每个剩余项:
a. 若 action == mark_stale:
- issue +label-add --labels stale
- issue +comment --body <模板>
b. 若 action == auto_close:
- 上述步骤 + issue +close
c. 若 type == pr:
- 仅 pr +comment(不打标签)
3. 每应用 10 个后暂停,问我是否继续
4. 完成后输出统计:成功数、失败数、跳过数
任何步骤失败都不要继续,停下来问我。
5. 评论模板库
5.1 友好催办(mark_stale)
通用版(推荐):
⏰ **长期未活动提醒**
本 Issue 已 60 天未收到新回复,暂时标记为 `stale`。
- 如果**仍然相关**,请回复任意内容,会自动移除 stale 标签
- 如果**已经过时**,欢迎手动关闭
- 如果在 **14 天内**没有新活动,将自动关闭以保持 Issue 列表清爽
> 🤖 由 gitlink-stale skill 自动生成。
bug 类专用:
⏰ **这个 bug 还能复现吗?**
本 Issue 已 60 天未活动,可能:
- 问题已经在最新版本中修复?欢迎确认
- 问题不再复现?欢迎手动关闭
- 仍然存在?请回复最新版本号和复现步骤
如果 **14 天内**没有新活动,将默认视为已解决,自动关闭。
feature 类专用:
⏰ **这个需求还在期待吗?**
本 feature 请求已 60 天未活动。可能:
- 不再需要?欢迎手动关闭
- 仍然想要?欢迎回复说明用例
- 想自己实现?欢迎提交 PR
如果 **14 天内**没有新活动,将默认视为不再需要,自动关闭。
5.2 自动关闭(auto_close)
🔒 **自动关闭(长期未活动)**
本 Issue 已 74 天无活动,自动关闭。
- 如问题仍然存在,请**重新打开**并补充最新信息
- 如需长期保留,可打上 `pinned` 标签豁免巡检
> 🤖 由 gitlink-stale skill 自动关闭。原始讨论保留在历史中。
5.3 PR 催办
⏰ **PR 长期未活动**
本 PR 已 60 天未更新,可能存在以下情况:
- 合并遇到冲突?请 rebase 后重新推送
- 等待 review?可 @mention 相关维护者
- 不再需要?欢迎手动关闭
如果 **14 天内**没有新活动,将默认关闭。
5.4 误标道歉(回滚用)
🙏 **抱歉,刚刚的 stale 标记是误判**
经过人工复核,本 Issue 不应被标记为 stale,已移除标签。
如带来困扰,敬请谅解。
> 🤖 由 gitlink-stale skill 回滚。
6. 回滚策略
6.1 误标的 Issue(仅打了 stale 标签)
# 移除 stale 标签
gitlink-cli issue +label-remove \
--owner <owner> --repo <repo> \
--number <N> \
--label "stale"
# 道歉评论
gitlink-cli issue +comment \
--owner <owner> --repo <repo> \
--number <N> \
--body "🙏 **抱歉,刚刚的 stale 标记是误判**..."
6.2 误关闭的 Issue(被自动关闭)
# 重新打开(用 Raw API,因 +update 需要状态参数)
CURRENT=$(gitlink-cli issue +view \
--owner <owner> --repo <repo> \
--number <N> --format json)
SUBJECT=$(echo "$CURRENT" | jq -r '.data.subject')
DESC=$(echo "$CURRENT" | jq -r '.data.description // ""')
PAYLOAD=$(jq -n \
--arg s "$SUBJECT" \
--arg d "$DESC" \
'{subject:$s, description:$d, status_id:1}')
gitlink-cli api PATCH "/v1/<owner>/<repo>/issues/<N>" --body "$PAYLOAD"
# 移除 stale 标签
gitlink-cli issue +label-remove \
--owner <owner> --repo <repo> \
--number <N> \
--label "stale"
# 道歉评论
gitlink-cli issue +comment \
--owner <owner> --repo <repo> \
--number <N> \
--body "🙏 **已重新打开**,刚才的自动关闭是误判,抱歉。原始讨论继续。"
6.3 批量回滚
#!/usr/bin/env bash
# rollback-stale.sh — 从备份文件批量恢复
BACKUP="${1:?usage: rollback-stale.sh <backup.json>}"
jq -c '.data.issues[]' "$BACKUP" | while read -r issue; do
NUM=$(echo "$issue" | jq '.number')
SUBJECT=$(echo "$issue" | jq -r '.subject')
DESC=$(echo "$issue" | jq -r '.description // ""')
# 重新打开
PAYLOAD=$(jq -n --arg s "$SUBJECT" --arg d "$DESC" \
'{subject:$s, description:$d, status_id:1}')
gitlink-cli api PATCH "/v1/<owner>/<repo>/issues/$NUM" --body "$PAYLOAD" > /dev/null
# 移除 stale 标签
gitlink-cli issue +label-remove --number "$NUM" --label "stale" 2>/dev/null || true
sleep 0.3
done
echo "✓ Rollback complete"
7. 错误处理
| 错误 | 原因 | 处理 |
|---|---|---|
HTTP 401 |
Token 失效 | gitlink-cli auth login |
HTTP 403 |
无写权限 | 联系仓库 owner |
HTTP 404 |
Issue 已被删除 | 跳过,记录到 errors |
HTTP 422 |
subject/description 被清空 | 必须先 GET 再 PATCH |
label not found |
仓库无 stale 标签 |
提示用户先创建标签 |
state: -1 |
参数错 | 检查 issue +close 的 number |
应用失败时不要重试,记录到错误日志,整体应用结束后人工排查。
8. 审计日志
每次应用后记录:
{
"applied_at": "2026-06-23T10:30:00Z",
"operator": "ai-agent + human-confirm",
"batch_id": "stale-20260623-1",
"repository": "owner/repo",
"thresholds": {
"stale_days": 60,
"close_days": 74
},
"summary": {
"total_scanned": 85,
"total_applied": 18,
"skipped_low_confidence": 4,
"exempt": 15,
"actions": {
"mark_stale": 12,
"auto_close": 6
}
},
"items_applied": [
{
"type": "issue",
"number": 142,
"action": "mark_stale",
"confidence": 0.85,
"success": true,
"changes": {
"labels_added": ["stale"],
"comment_added": true
}
}
],
"backup_file": "/tmp/before-stale-1719139200.json"
}
保存到 /tmp/stale-audit-<timestamp>.json,便于追溯。
9. 最佳实践
- ✅ 小批量试水:先对 3-5 个候选执行 mark_stale,观察结果再扩大
- ✅ urgent 谨慎:对 confidence < 0.85 的 urgent/feature 类 Issue 额外人工复核
- ✅ 避开高峰:大批量执行安排在用户活跃低谷时段
- ✅ 通知 owner:执行前在仓库管理员沟通渠道同步"本次将清理 N 个 Issue"
- ✅ 保留备份:所有备份文件至少保留 30 天
- ❌ 禁止:跳过 dry-run 直接批量执行
- ❌ 禁止:对 archived 或 read-only 仓库执行
- ❌ 禁止:批量关闭超过 50 个 Issue 而不分批