研发协作
已有 GitHub Issue 树需要定期盘点更新时…
对既存 GitHub Issue 树做盘点:把 closed 父下的残留 open issue 改挂到合适的 open Phase 父、重排孤儿、同步 phase 标签、按粒度基准拆分过大 issue,并重生成根 issue 正文。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
已有 GitHub Issue 树需要定特定
解决思路
- 从根 tracking issue 号出发,用 sub_issues API 递归获取整棵树,per_page=100 并处理分页,记录每个 issue 的 state、标签、标题形成树图。
- 确定粒度基准 GRANULARITY,优先级为 --granularity 参数 > 根 issue 正文中的 <!-- granularity: Nh --> 标记 > 默认 2h;参数值先用正则 ^[1-9][0-9]*h$ 校验,不合法则不执行并让用户重新指定;根 issue 正文获取失败时不要回退到默认值,直接中止;确定后输出粒度值与来源。
- 盘点并分类:closed 父下残留的 open issue(改挂到合适的 open Phase 父)、无父的孤儿 issue(挂到对应 Phase 父,Phase 不明时问用户)、phase 标签与父不一致(同步标签)、现有 Phase 装不下的新任务(考虑新建 Phase 父)、实现时间超过 GRANULARITY 的 issue(拆成 sub-issue)、父在别的仓库的 cross-repository sub-issue(本技能范围外,排除并记入待确认)。
- 把盘点结果先给用户确认,再把已批准的对象落到两个计划数组:REASSIGN_PLAN(元素为 "<issue> <old-parent> <new-parent>")和 ORPHAN_PLAN(元素为 "<orphan-issue> <phase-parent>");即使 0 件也必须显式声明为空数组,未声明就进入后续步骤要 fail-closed 停止。
- 执行改挂时调用 scripts/reassign-sub-issue.sh(旧父 DELETE → 新父 POST 两段操作、幂等判定、事后确认都封装在里面),不要在本技能正文里直接写裸 gh api DELETE/POST。
- 每个代码块按独立 shell 处理:Step 3 和 Step 4 各自用相同的前置代码从 3 种布局(skills/、.agents/skills/、.claude/skills/)中查找并 source reassign-lib.sh,用 -f 判断存在(不要用 -x,避免 vendoring 掉执行位时误判),source 失败则退出;这些代码块内不要用 set -euo pipefail。
- 调用前用 require_plan_array 校验计划数组存在且类型正确;循环中用 IFS=' ' read -r 拆分条目,用 `status=0; reassign_one ... || status=$?` 显式保存退出码(不要用 if ...; then ... fi,否则 fi 后的 $? 会变成 0 而吞掉失败)。
- 按退出码分流:0 计入对应件数(reassigned / posted-only 计入,already-attached 不计);9(cross-repository 父)记入待确认并继续下一件;10(补偿恢复成功、已回到旧父)和 11(DELETE 后第三方已设别的父、放弃补偿)记入待确认但不 fatal、继续下一件;其余 1〜8 视为可解决的前提不备,中止并让用户先解决原因。
- 孤儿的再配置用同一个脚本、省略 --old-parent 只做 POST;Phase 判断不了就读标题和正文,仍判断不了就问用户。
- 需要新建 Phase 父时,先用 gh label create "phase:N" --color "0075ca" 建标签(已存在则忽略失败),再用 gh issue create 创建(它不支持 --json,输出 URL,用 grep -oE '[0-9]+$' 取号),然后用 gh api 取 database id,POST 到 repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues 并传 sub_issue_id=${NEW_PHASE_ID}。
- 同步 phase 标签:用 gh issue edit <号> --add-label "phase:N" 加新标签、--remove-label "phase:0" 删旧标签。
- 把超过 GRANULARITY 的 issue 拆成 sub-issue:同样先建标签,gh issue create 后用 grep -oE '[0-9]+$' 取号,取 database id 后 POST 到父 issue 的 sub_issues。
- 用 gh issue edit 重生成根 issue 正文:用 printf 输出 <!-- granularity: <GRANULARITY> --> 标记行(不能丢),再附上概要、本次盘点整理(改挂 N 件、孤儿重排 N 件、标签同步 N 件、新建 Phase N 件)、Phase 别计划表、各 Phase 的 issue 表、运用规则(新 issue 起票时挂到 Phase 父、执行顺序按 sub-issues 列表、closed 父下不留 open issue、保持 implement-issue-tree 能按 post-order DFS 消化的结构)。
- 输出完成报告:根 issue、各项操作件数、当前 Phase 别汇总、待确认事项;件数只统计 result= 行为 reassigned / posted-only 的调用,所有非零退出(1〜8、10、11)一律不计入件数并带理由写入待确认,尤其 exit 8 会留下部分变更不能漏报。
- 验证:确认根 issue 正文的 Phase 表已更新、closed Phase 父下没有残留 open issue(exit 10 有意回到旧父的除外,需与待确认记录对照)、各次调用的 exit 码与 result= 行已反映到待确认、fatal 系(1〜8)代码块确实以非零状态返回、9/10/11 则正常结束并处理完计划数组剩余全部条目。
- 注意事项:shell 变量一律用 "${var}" 引号;不要用 --no-verify;sub_issues API 的 sub_issue_id 是 database id 而非 issue 号;DELETE 的路径是单数 sub_issue(复数会 404);--repo 指的是目标 issue 所在仓库,不是父所在仓库,不要填成父仓库以免误操作同号 issue。
适用边界 · 注意事项
- 目标树跨多个仓库时(cross-repository sub-issue 不在本技能范围内,需先在父仓库侧解除父链接)。
- 没有 gh CLI 或未认证、对目标仓库没有 Issue 写权限时。
- 只想新建 Issue 树(用 create-issue-tree)或只想消化实现(用 implement-issue-tree)时。