feat: add project-review workflow (whole-project / single-feature review)

Adds the project-review workflow for code review independent of the git
diff. The scope is parsed from the user instruction: 全面/整个项目 ->
whole-project (score every source file), otherwise feature + target
keyword (locate the code with semantic search + graph queries).

- scoring_tools.py: score_review_func gains all_files=True to score every
  source file in the graph via store.get_all_files()
- main.py: score_review_tool gains all_files param; registers the
  project_review MCP prompt (prompts 6->7)
- prompts.py: project_review_prompt(scope, target) with whole-project and
  feature branches (fixed a precedence bug that truncated the feature text)
- skills.py + skills/project-review/: new read-only project-review skill
  with shared checklists
- .opencode/command/code-review-graph-project-review.md: slash command
- tests: test_project_review.py (prompt rendering), TestProjectReviewPrompt,
  skill count assertions 5->6, all_files wiring checks
- docs: prompts (6->7) + project-review entries across COMMANDS, CLAUDE,
  README (+localized), INDEX, architecture, LLM-OPTIMIZED-REFERENCE,
  CHANGELOG
This commit is contained in:
dev
2026-08-06 13:56:54 +08:00
parent 6f0e6f0775
commit 307d2fd471
45 changed files with 1339 additions and 131 deletions
+7 -3
View File
@@ -118,12 +118,13 @@ class TestGenerateSkills:
assert result.is_dir()
assert result == tmp_path / ".claude" / "skills"
def test_creates_five_skill_subdirs(self, tmp_path):
def test_creates_six_skill_subdirs(self, tmp_path):
skills_dir = generate_skills(tmp_path)
subdirs = sorted(f.name for f in skills_dir.iterdir() if f.is_dir())
assert subdirs == [
"debug-issue",
"explore-codebase",
"project-review",
"refactor-safely",
"review-changes",
"unified-review",
@@ -153,6 +154,7 @@ class TestGenerateSkills:
for skill_name in (
"debug-issue",
"explore-codebase",
"project-review",
"refactor-safely",
"review-changes",
"unified-review",
@@ -169,7 +171,7 @@ class TestGenerateSkills:
result = generate_skills(tmp_path, skills_dir=custom)
assert result == custom
assert result.is_dir()
assert len(list(result.iterdir())) == 5
assert len(list(result.iterdir())) == 6
def test_skill_content_includes_get_minimal_context(self, tmp_path):
"""Every skill template must reference get_minimal_context."""
@@ -194,7 +196,7 @@ class TestGenerateSkills:
generate_skills(tmp_path)
generate_skills(tmp_path)
skills_dir = tmp_path / ".claude" / "skills"
assert len(list(skills_dir.iterdir())) == 5
assert len(list(skills_dir.iterdir())) == 6
class TestGenerateHooksConfig:
@@ -859,8 +861,10 @@ class TestCodeBuddyPlatform:
assert {path.name for path in skills_root.iterdir()} == {
"debug-issue",
"explore-codebase",
"project-review",
"refactor-safely",
"review-changes",
"unified-review",
}
for skill_dir in skills_root.iterdir():
content = (skill_dir / "SKILL.md").read_text(encoding="utf-8")