zizi d97e194383 docs(治理): SoT注册表+docs-gate六检门,清缩历史档126→69
- 注册表:docs/architecture/README.md §2,37 份 canonical(frontmatter topic+canonical:true)与表双向机器对账
- 门:.agents/tools/docs-gate.py 六检(品牌根/canonical唯一/死链/入口卫生/留痕隔离/设计档申报),挂 .githooks/pre-commit(本仓已激活)+ .gitea/workflows/docs-gate.yml(待runner)+ wave-close 第8步;旧 check-deadlinks.sh 退役并入 G3
- 清缩:删 54 项历史档(plans 16/agent-specs 设计与spike 20/brainstorms 5/memorys 3/goals+作战清单完成史归档/王蓝莓design/SAA现状html/add-game-template);channel-spike 564K 代码资产迁仓级 spikes/;六件删前蒸馏已迁(代码评审16条open项→进度总账§5、prefix-cache字段表→cheap-model skill、意图基线29条→需求清单附录、九门降级rationale→验收门、A11 TODO→tech-decisions、3layer边界→littlejs-game-dev 指针)
- 修口径约90处:六处SAA『现行主线』旧标、Nacos/RocketMQ『未部署』旧述(07-01反转)、gameDefinition残留、全部死链改 git show 定位;AGENTS.md 249→136行(决策史归tech-decisions);_index 改纯在飞板;对外演示版 md→html
- 依据:docs/agent-specs/2026-07-02-文档治理-{全量普查与裁决-report,SoT注册表与治理门-设计}.md(四路普查191份md+Codex/Opus双评审必修项已折入);恢复基线 8ea97234(单档 git checkout 8ea97234 -- <路径>)
2026-07-02 14:24:12 +08:00

127 lines
6.5 KiB
Bash
Executable File
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.

#!/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}..HEADdocs/ + .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]
# Claude auto-memory 目录按用户/机器不同,不硬编码:从环境变量 CLAUDE_MEMORY_DIR 读,缺省则跳过该段(只修 .agents/docs 内引用)
mem=os.environ.get("CLAUDE_MEMORY_DIR","")
arch=[os.path.basename(p) for p in glob.glob(root+"/docs/agent-specs/_archive/*.md")]
tgt=set()
bases=[root+"/.agents",root+"/docs"]
if mem and os.path.isdir(mem): bases.append(mem)
for base in bases:
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