doc-organizer 两阶段审批门·阶段二(创始人批:执行/全改17处/清PNG/动态日期)。 分析相=25 opus agent 三轴只读 fan-out;计划经 opus 对抗评审 GO-带必修。 轴①过期分类(20档): - COMPRESS 2桩: round2-staging-e2e-verdict→round3(703e462c)、生成引擎-并行编排→多session总账 - ARCHIVE 2: 技术决策版重写-review(对齐已落)/视觉增强repair-review(NO-GO) 入 _archive/ - KEEP 16: W-G1开闸验收门/studio设计体系HJ-FE-DS-001/生成线 在飞 SoT 不动 轴②核心档措辞: - 玩法模板术语17处跨4核心档+工具analyze.mjs TRUTH 对齐 HJ-DEMO-AUDIT-001 (废=游戏模板/填参线;玩法模板=品类框架·引导生成·未废=最高优先级待建) - Dify/OpenGame家族0真改(已标作废/future-state/决策史,证实06-16对齐可信) - W-T1b-Runner历史档顶部加术语指针(正文不改) 轴③总账: M2现在时漂移修(四模板→W-CLEAN清+generic桥接接棒,demo审计C6) + 06-17工作回填(SAA trace真库收口/generic开闸首件/crypto.subtle整款加载修/census) 工具: doc-organizer.sh 硬编码06-16→动态 latest_date(免一天即过期) 清: 7证据PNG(留report.md) | _index 活地图维护(supersede链/补漏登/修断链) 留痕: docs/agent-specs/2026-06-17-文档整理-plan.md(计划+评审) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
123 lines
6.3 KiB
Bash
Executable File
123 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 文档整理助手 · 机械底层(检测 + 归档 + 记时)
|
||
# 判断(KEEP/ARCHIVE/COMPRESS、措辞对齐、总账回填)一律留 agent —— 见 .agents/skills/doc-organizer.md
|
||
# 设计:脚本只做"可机械化的检测与可逆搬运",绝不自删/自改正文。全程 core.quotePath=false 防中文路径转义坑。
|
||
set -uo pipefail
|
||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # 仓根
|
||
SPECS="docs/agent-specs"
|
||
STATE="$ROOT/.agents/tools/doc-organizer-state.json"
|
||
G(){ git -C "$ROOT" -c core.quotePath=false "$@"; }
|
||
|
||
# 最新日期前缀(今日在飞保护锚点):动态取目录内最大 dated 档,免硬编码过期
|
||
# (2026-06-17 改:旧硬编码 2026-06-16 一天即过期——致 06-16 档被误当在飞拒归档、真在飞的 06-17 档反没保护)
|
||
latest_date(){ ls -1 "$ROOT/$SPECS"/2026-*.md 2>/dev/null | sed -E 's#.*/(2026-[0-9]{2}-[0-9]{2}).*#\1#' | sort -u | tail -1; }
|
||
|
||
# 从 state 读上次清理锚点(无 jq 也能跑:python 解析)
|
||
last_field(){ python3 -c "import json,sys;print(json.load(open('$STATE'))['last_cleanup'].get('$1',''))" 2>/dev/null; }
|
||
|
||
cmd="${1:-scan}"
|
||
case "$cmd" in
|
||
since)
|
||
echo "上次清理 commit = $(last_field commit)"
|
||
echo "上次清理 时间 = $(last_field at)"
|
||
echo "当前 UTC = $(date -u +%FT%TZ) | HEAD = $(G rev-parse --short HEAD)"
|
||
;;
|
||
|
||
delta) # 窗口内改动/新增的文档
|
||
lc="$(last_field commit)"; [ -z "$lc" ] && lc="$(G rev-list --max-parents=0 HEAD | tail -1)"
|
||
echo "## 窗口内改动的 .md(${lc}..HEAD,docs/ + .agents/)"
|
||
G diff --name-only "${lc}..HEAD" -- docs .agents 2>/dev/null | grep -E '\.md"?$' || echo " (无)"
|
||
echo "## 窗口内新增未跟踪 .md"
|
||
G ls-files --others --exclude-standard -- docs .agents 2>/dev/null | grep -E '\.md"?$' || echo " (无)"
|
||
;;
|
||
|
||
health) # 热目录健康度(阈值据 engineering-conventions §10)
|
||
cd "$ROOT/$SPECS"
|
||
LD="$(latest_date)"; n=$(ls -1 2026-*.md 2>/dev/null | grep -v "^$LD" | wc -l)
|
||
sz=$(du -sm "$ROOT/$SPECS" | cut -f1)
|
||
echo "## 热目录健康度"
|
||
echo " 顶层 dated .md(非最新日): $n $([ "$n" -gt 30 ] && echo '⚠>30 该归档' || echo 'OK')"
|
||
echo " agent-specs 体积: ${sz}M $([ "$sz" -gt 6 ] && echo '⚠>6M 该清证据' || echo 'OK')"
|
||
echo "## 带 SHIPPED/SUPERSEDED 横幅却仍在热目录(应 archive)"
|
||
grep -lE '状态: ?(SHIPPED|SUPERSEDED|SPIKE-DONE)' 2026-*.md 2>/dev/null | grep -v "^$LD" | sed 's/^/ /' || true
|
||
echo "## execution/edit-plan >150 行仍在热目录(应 compress 留桩)"
|
||
for f in 2026-*-execution.md 2026-*-edit-plan.md; do
|
||
[ -f "$f" ] || continue; case "$f" in "$LD"-*) continue;; esac
|
||
l=$(wc -l <"$f"); [ "$l" -gt 150 ] && echo " $l 行 $f"
|
||
done
|
||
echo "## doc 树混入的非 md(白名单 orchestrator/channel-spike/generation-spike/_archive 除外)"
|
||
G ls-files "$SPECS" | grep -vE '\.md"?$|orchestrator/|channel-spike/|generation-spike/|_archive/' | sed 's/^/ /' | head -20 || true
|
||
;;
|
||
|
||
stale) # 核心设计档残留废弃选型词(人工判:当现行=改 / 已标降级=放过)
|
||
echo "## 核心设计档残留废弃选型词(总数 / 疑似当现行=无降级标注的行)"
|
||
for d in "$ROOT"/docs/architecture/*.md "$ROOT"/.agents/knowledge/*.md; do
|
||
[ -f "$d" ] || continue
|
||
tot=$(grep -icE 'Dify|OpenGame|Canvas Runtime|ComfyUI|AgentScope' "$d")
|
||
[ "$tot" -eq 0 ] && continue
|
||
sus=$(grep -iE 'Dify|OpenGame|Canvas Runtime|ComfyUI|AgentScope' "$d" | grep -ivE '降级|废弃|废除|future-state|supersede|备选|moot|不部署|~~|已退役|历史' | wc -l)
|
||
echo " 共${tot} 疑似${sus} $(basename "$d")"
|
||
done
|
||
echo " 现行真相基准 = .agents/knowledge/tech-decisions.md + AGENTS.md §3(已对齐,权威源)"
|
||
;;
|
||
|
||
ledger) # 总账新鲜度
|
||
L="$ROOT/docs/mvp/MVP进度总账.md"
|
||
lc="$(last_field commit)"
|
||
echo "## 总账新鲜度"
|
||
grep -m1 '最近更新' "$L" 2>/dev/null | sed 's/^/ 总账: /' || echo " (未找到表头)"
|
||
echo " 窗口内收口报告/验收报告(可能需回填总账 §6):"
|
||
G diff --name-only "${lc}..HEAD" -- "$SPECS" 2>/dev/null | grep -E '收口报告|验收|report|报告' | sed 's/^/ /' || echo " (无)"
|
||
;;
|
||
|
||
scan) # 一次拿全部信号
|
||
"$0" since; echo; "$0" delta; echo; "$0" health; echo; "$0" stale; echo; "$0" ledger
|
||
;;
|
||
|
||
archive) # 可逆搬运: git mv 入 _archive + 同步修引用。用法: archive <basename...>
|
||
shift; [ $# -eq 0 ] && { echo "用法: archive <文件名...>"; exit 1; }
|
||
mkdir -p "$ROOT/$SPECS/_archive"
|
||
LD="$(latest_date)"
|
||
for f in "$@"; do
|
||
b="$(basename "$f")"
|
||
case "$b" in "$LD"-*) echo "拒绝: $b 是最新日($LD)在飞档"; continue;; esac
|
||
G mv "$SPECS/$b" "$SPECS/_archive/$b" && echo "归档: $b"
|
||
done
|
||
# 同步修引用: agent-specs/<已归档名> -> agent-specs/_archive/<名>(字面替换,幂等)
|
||
python3 - "$ROOT" <<'PY'
|
||
import os,sys,glob
|
||
root=sys.argv[1]; mem="/root/.claude/projects/-root-games-development-ai/memory"
|
||
arch=[os.path.basename(p) for p in glob.glob(root+"/docs/agent-specs/_archive/*.md")]
|
||
tgt=set()
|
||
for base in [root+"/.agents",root+"/docs",mem]:
|
||
for dp,_,fns in os.walk(base):
|
||
if "/_archive" in dp: continue
|
||
for fn in fns:
|
||
if fn.endswith(".md"): tgt.add(os.path.join(dp,fn))
|
||
fixed=0
|
||
for t in tgt:
|
||
try: s=open(t,encoding="utf-8").read()
|
||
except: continue
|
||
o=s
|
||
for b in arch: s=s.replace("agent-specs/"+b,"agent-specs/_archive/"+b)
|
||
if s!=o: open(t,"w",encoding="utf-8").write(s); fixed+=1
|
||
print(f"引用修复文件数: {fixed}")
|
||
PY
|
||
;;
|
||
|
||
record) # 记本次清理时间. 用法: record <commit> <一句话摘要...>
|
||
shift; commit="${1:-$(G rev-parse --short HEAD)}"; shift || true; summary="${*:-清理}"
|
||
python3 - "$STATE" "$(date -u +%FT%TZ)" "$commit" "$summary" <<'PY'
|
||
import json,sys
|
||
p,now,commit,summary=sys.argv[1:5]
|
||
d=json.load(open(p))
|
||
d["last_cleanup"]={"at":now,"commit":commit,"note":summary}
|
||
d.setdefault("history",[]).append({"at":now,"commit":commit,"summary":summary})
|
||
json.dump(d,open(p,"w"),ensure_ascii=False,indent=2)
|
||
print("已记本次清理:",now,commit)
|
||
PY
|
||
;;
|
||
|
||
*) echo "用法: doc-organizer.sh {scan|since|delta|health|stale|ledger|archive <文件名...>|record <commit> <摘要>}";;
|
||
esac
|