mirror of
https://github.com/tradecatlabs/vibe-coding-cn.git
synced 2026-11-02 12:56:17 +00:00
迁移443条说明到v2二十项结构,保留来源、书目与历史意见;经验迁移功法暂拟天阶初级。442条概念及443条条目注释仍待核,不主张独立语义审查、运行、效果或正式评级已经完成。
136 lines
5.2 KiB
Python
136 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Check repository-owned directories have README.md and AGENTS.md."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from source_boundaries import SOURCE_PREFIXES, VENDOR_SUBTREES, is_research_repository_snapshot
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
REQUIRED_DIRS = list(map(Path, (
|
|
'.github', '.github/ISSUE_TEMPLATE',
|
|
'.github/context', '.github/context/gongfa', '.github/context/faqi',
|
|
'.github/extensions',
|
|
'.github/skills', '.github/skills/skill', '.github/skills/skill/assets',
|
|
'.github/skills/skill/references',
|
|
)))
|
|
COLLECTION_DIRS = {Path('.github/context/gongfa'), Path('.github/context/faqi')}
|
|
COLLECTION_FILES = {'data.json', 'README.md', 'tian.md', 'di.md', 'xuan.md', 'huang.md'}
|
|
RETIRED_DIRS = (
|
|
Path('.github/workflows'), Path('.github/lib'),
|
|
Path('.github/extensions/prompts-library'),
|
|
Path('.github/context/ai-citation'), Path('.github/context/getting-started'),
|
|
Path('.github/context/metadata'), Path('.github/context/prompts'),
|
|
Path('.github/context/assets'), Path('.github/context/external-resources'),
|
|
Path('.github/skills/auto-tmux'),
|
|
)
|
|
RETIRED_FILES = (
|
|
Path('.github/context/tool-explanation-template-v0.md'),
|
|
Path('.github/context/tool-explanation-template-v1.md'),
|
|
Path('.github/context/tool-explanation-template-v2.md'),
|
|
)
|
|
LEGACY_PROMPT_TOOL = Path('.github/extensions/prompts-library')
|
|
LEGACY_PROMPT_EXPORTS = LEGACY_PROMPT_TOOL / 'prompt_jsonl'
|
|
README_OPTIONAL_DIRS = {
|
|
# GitHub repository pages can surface `.github/README.md` as an overview file.
|
|
# Keep the root project README authoritative and use `.github/AGENTS.md` only.
|
|
Path(".github"),
|
|
}
|
|
GENERATED_OR_VENDOR_DIRS = [
|
|
Path("build"),
|
|
Path("node_modules"),
|
|
LEGACY_PROMPT_EXPORTS,
|
|
]
|
|
SKIP_PARTS = {".git", ".history", "build", "node_modules", "__pycache__"}
|
|
SKIP_PREFIXES = SOURCE_PREFIXES
|
|
|
|
|
|
def only_legacy_prompt_exports(directory: Path) -> bool:
|
|
if directory.is_symlink() or not directory.is_dir():
|
|
return False
|
|
entries = list(directory.iterdir())
|
|
return (len(entries) == 1 and entries[0].name == LEGACY_PROMPT_EXPORTS.name
|
|
and entries[0].is_dir() and not entries[0].is_symlink())
|
|
|
|
|
|
def should_skip(directory: Path) -> bool:
|
|
rel = directory.relative_to(ROOT)
|
|
if rel == LEGACY_PROMPT_TOOL and only_legacy_prompt_exports(directory):
|
|
return True
|
|
if rel == LEGACY_PROMPT_EXPORTS or LEGACY_PROMPT_EXPORTS in rel.parents:
|
|
return True
|
|
if any(part in SKIP_PARTS for part in rel.parts):
|
|
return True
|
|
if is_research_repository_snapshot(rel):
|
|
return True
|
|
if directory.is_symlink():
|
|
return True
|
|
if any(rel == prefix or prefix in rel.parents for prefix in SKIP_PREFIXES):
|
|
return True
|
|
return any(vendor in rel.parents for vendor in VENDOR_SUBTREES)
|
|
|
|
|
|
def repository_owned_dirs() -> list[Path]:
|
|
dirs = set(REQUIRED_DIRS)
|
|
for directory in ROOT.rglob("*"):
|
|
if not directory.is_dir():
|
|
continue
|
|
if should_skip(directory):
|
|
continue
|
|
dirs.add(directory.relative_to(ROOT))
|
|
return sorted(dirs)
|
|
|
|
|
|
def main() -> int:
|
|
errors: list[str] = []
|
|
|
|
for rel_dir in RETIRED_DIRS:
|
|
directory = ROOT / rel_dir
|
|
if directory.exists() or directory.is_symlink():
|
|
if rel_dir == LEGACY_PROMPT_TOOL and only_legacy_prompt_exports(directory):
|
|
continue
|
|
errors.append(f'{rel_dir}: 已退役目录不得重新创建')
|
|
|
|
for rel_file in RETIRED_FILES:
|
|
path = ROOT / rel_file
|
|
if path.exists() or path.is_symlink():
|
|
errors.append(f'{rel_file}: 已迁移文件不得在旧路径重建')
|
|
|
|
for rel_dir in repository_owned_dirs():
|
|
directory = ROOT / rel_dir
|
|
if not directory.is_dir():
|
|
errors.append(f"{rel_dir}: required directory is missing")
|
|
continue
|
|
if rel_dir in COLLECTION_DIRS:
|
|
entries = list(directory.iterdir())
|
|
if ({entry.name for entry in entries} != COLLECTION_FILES or any(entry.is_symlink() for entry in entries)):
|
|
errors.append(f'{rel_dir}: 文集只能包含data.json、导航README.md和四阶生成文档')
|
|
if not (ROOT / '.github/context/AGENTS.md').is_file():
|
|
errors.append(f'{rel_dir}: missing inherited context rules')
|
|
continue
|
|
required_files = ['AGENTS.md'] if rel_dir in README_OPTIONAL_DIRS else ['README.md', 'AGENTS.md']
|
|
for filename in required_files:
|
|
if not (directory / filename).is_file():
|
|
errors.append(f"{rel_dir}/{filename}: missing required directory document")
|
|
|
|
for rel_dir in GENERATED_OR_VENDOR_DIRS:
|
|
directory = ROOT / rel_dir
|
|
if directory.exists() and not (ROOT / ".gitignore").read_text(encoding="utf-8").count(str(rel_dir)):
|
|
errors.append(f"{rel_dir}: generated directory exists but is not ignored")
|
|
|
|
if errors:
|
|
print("DIRECTORY_DOC_ERRORS")
|
|
for error in errors:
|
|
print(error)
|
|
print(f"TOTAL={len(errors)}")
|
|
return 1
|
|
|
|
print(f"OK directory README/AGENTS pairs checked: {len(repository_owned_dirs())} directories")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|