重置项目上下文与规范文档

This commit is contained in:
2026-08-07 16:18:07 +08:00
parent 6611ca5226
commit 79e2d9ff92
1900 changed files with 1552 additions and 348365 deletions

88
scripts/context-health.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/zsh
set -euo pipefail
ROOT=${0:A:h:h}
cd "$ROOT"
openspec doctor --json | grep -q '"healthy": true'
openspec validate --all >/dev/null
for forbidden in .planning .scratch .sisyphus CONTEXT.md specs; do
[[ ! -e "$forbidden" ]] || { print -u2 "禁止目录或文件仍存在:$forbidden"; exit 1; }
done
[[ -z "$(find "$HOME/.codex/skills" -maxdepth 1 -name 'gsd-*' -print 2>/dev/null)" ]]
[[ -z "$(find "$HOME/.codex/agents" -maxdepth 1 -name 'gsd-*' -print 2>/dev/null)" ]]
[[ -z "$(command -v omx 2>/dev/null || true)" ]]
! grep -RIlE 'oh-my-codex|OMX:' AGENTS.md CLAUDE.md .agents .claude >/dev/null 2>&1
[[ -z "$(git ls-files .lh-harness)" ]]
[[ -z "$(find . -type f -name '*_test.go' -not -path './.git/*' -print)" ]]
[[ ! -e tests ]]
[[ ! -e internal/testutil ]]
[[ ! -e scripts/benchmark ]]
[[ -z "$(find scripts -type f -name 'test_*' -print 2>/dev/null)" ]]
python3 - <<'PY'
from pathlib import Path
import json, re, sys
files=[Path('AGENTS.md'),Path('CLAUDE.md'),Path('README.md'),Path('ARCHITECTURE.md'),*Path('docs').rglob('*.md'),*Path('openspec').rglob('*.md')]
bad=[]
for p in files:
for link in re.findall(r'\[[^]]*\]\(([^)]+)\)', p.read_text(errors='ignore')):
target=link.split('#')[0]
if not target or '://' in target or target.startswith('mailto:'):
continue
if not (p.parent/target).resolve().exists():
bad.append(f'{p}: {link}')
if bad:
print('失效链接:\n'+'\n'.join(bad), file=sys.stderr)
raise SystemExit(1)
spec_requirements=set()
indexed_routes=set()
for spec in Path('openspec/specs').glob('*/spec.md'):
text=spec.read_text()
if re.search(r'^### Requirement: .*接口集合$', text, re.M):
raise SystemExit(f'接口集合仍被用作行为 Requirement{spec}')
names=re.findall(r'^### Requirement: (.+)$', text, re.M)
if not names:
raise SystemExit(f'Capability 缺少行为 Requirement{spec}')
spec_requirements.update(f'{spec.parent.name}::{name}' for name in names)
indexed_routes.update(f'{method} {path}' for method,path in re.findall(r'`(GET|POST|PUT|PATCH|DELETE) ([^`]+)`', text))
evidence_dir=Path('.lh-harness/context-reset')
evidence=json.loads((evidence_dir/'requirement-evidence.json').read_text())
matrix=json.loads((evidence_dir/'entry-capability-requirement-matrix.json').read_text())
evidence_requirements={f"{row['capability']}::{row['requirement']}" for row in evidence}
if evidence_requirements != spec_requirements:
raise SystemExit('Requirement 证据链与 Specs 不一致')
matrix_http={row['entry'] for row in matrix if row['entry_type']=='http'}
if matrix_http != indexed_routes:
raise SystemExit('HTTP Route 与可达操作索引双向覆盖不一致')
linked={name for row in matrix for name in row['requirements']}
if linked != spec_requirements:
raise SystemExit('入口矩阵未双向覆盖全部行为 Requirement')
worker_source=Path('pkg/queue/handler.go').read_text()+Path('cmd/worker/main.go').read_text()
registered={'constants.'+name for name in re.findall(r'(?:HandleFunc|Register)\(constants\.(TaskType\w+|OutboxEventType\w+)', worker_source)}
matrix_async={row['entry'] for row in matrix if row['entry_type']=='async'}
if matrix_async != registered:
raise SystemExit('异步注册入口与证据矩阵双向覆盖不一致')
PY
tmpdir=$(mktemp -d)
generated=docs/admin-openapi.yaml
had_generated=0
if [[ -f "$generated" ]]; then
had_generated=1
cp "$generated" "$tmpdir/original.yaml"
fi
cleanup_generated() {
if (( had_generated )); then cp "$tmpdir/original.yaml" "$generated"; else rm -f "$generated"; fi
rm -rf "$tmpdir"
}
trap cleanup_generated EXIT
go run cmd/gendocs/main.go >/dev/null 2>&1
cp "$generated" "$tmpdir/first.yaml"
go run cmd/gendocs/main.go >/dev/null 2>&1
cmp -s "$tmpdir/first.yaml" "$generated" || { print -u2 'OpenAPI 连续生成结果不一致'; exit 1; }
print 'Context 健康检查通过'