Skip to content

Commit 4bb648e

Browse files
recuu-pfegclaude
andcommitted
fix: reviewer matches task from commit messages, falls back to pure code quality review
When --diff is used without --task, extract task IDs from commit messages. If no match found, use pure code quality review (skip requirement checks). Fixes reviewer judging diffs against unrelated tasks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3f7fbbb commit 4bb648e

File tree

1 file changed

+57
-10
lines changed

1 file changed

+57
-10
lines changed

src/commands/review.ts

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export async function handleReview(
2929
): Promise<void> {
3030
const api = createApiClient(apiUrl, apiKey);
3131
const { execSync: revExec } = await import("node:child_process");
32+
const cwd = process.cwd();
3233

3334
ui.intro();
3435
const s = ui.createSpinner();
@@ -42,6 +43,31 @@ export async function handleReview(
4243
if (!found) { s.stop("Not found"); ui.error(`Task ${taskId} not found`); process.exit(1); }
4344
task = found;
4445
s.stop(`Reviewing: ${task.title}`);
46+
} else if (diffRange) {
47+
// When --diff is provided without --task, try to match task from commit messages
48+
s.start("Matching task from commit messages...");
49+
try {
50+
const commitLog = revExec(`git log --format=%s ${diffRange}`, { cwd, stdio: "pipe" }).toString().trim();
51+
const tasks = await api.fetchTasks();
52+
// Look for task ID patterns in commit messages (8-char hex prefix or full UUID)
53+
const idPattern = /\b([0-9a-f]{8})(?:-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?\b/gi;
54+
const matches = commitLog.match(idPattern) || [];
55+
for (const candidate of matches) {
56+
const prefix = candidate.slice(0, 8).toLowerCase();
57+
const found = tasks.find((t: Task) => t.id.toLowerCase().startsWith(prefix));
58+
if (found) {
59+
task = found;
60+
break;
61+
}
62+
}
63+
if (task) {
64+
s.stop(`Matched task from commits: ${task.title}`);
65+
} else {
66+
s.stop("No task matched — will do pure code quality review");
67+
}
68+
} catch {
69+
s.stop("Could not parse commits — will do pure code quality review");
70+
}
4571
} else {
4672
s.start("Finding latest review task...");
4773
const tasks = await api.fetchTasks();
@@ -55,7 +81,6 @@ export async function handleReview(
5581
}
5682

5783
// Determine diff range
58-
const cwd = process.cwd();
5984
let diffRef = diffRange || "HEAD~1..HEAD";
6085
if (!diffRange) {
6186
try {
@@ -80,15 +105,37 @@ export async function handleReview(
80105
ui.info(`[review] Tags for skill matching: ${reviewTags.join(", ")}`);
81106
}
82107

83-
const reviewSystem = interpolate(PROMPT_TEMPLATES["reviewer-system"] || "", {
84-
projectName: cwd.split("/").pop() || "unknown",
85-
language: "English",
86-
taskTitle: task?.title || "Manual review request",
87-
taskType,
88-
taskDescription: task?.description || "(manual review — no task description)",
89-
taskTypeHint: typeHints[taskType] || typeHints.implementation || "",
90-
customReviewRules: customRules ? `\n${customRules}` : "",
91-
});
108+
let reviewSystem: string;
109+
if (task) {
110+
// Task matched — use the full reviewer-system template with task context
111+
reviewSystem = interpolate(PROMPT_TEMPLATES["reviewer-system"] || "", {
112+
projectName: cwd.split("/").pop() || "unknown",
113+
language: "English",
114+
taskTitle: task.title,
115+
taskType,
116+
taskDescription: task.description || "(no description)",
117+
taskTypeHint: typeHints[taskType] || typeHints.implementation || "",
118+
customReviewRules: customRules ? `\n${customRules}` : "",
119+
});
120+
} else {
121+
// No task matched — pure code quality review (no requirement matching)
122+
reviewSystem = [
123+
`You are a strict code reviewer for project "${cwd.split("/").pop() || "unknown"}".`,
124+
`Reply in English. Output JSON only, no markdown.`,
125+
``,
126+
`## Review Mode: Pure Code Quality (no task context)`,
127+
`No specific task was matched to this diff. Do NOT judge requirement fulfillment.`,
128+
`Instead, focus exclusively on:`,
129+
`1. CODE QUALITY: Readability, naming, structure, error handling`,
130+
`2. SECURITY: Injection risks, credential leaks, unsafe operations`,
131+
`3. CORRECTNESS: Logic errors, edge cases, null/undefined handling`,
132+
`4. TEST COVERAGE: Are changes tested? Do existing tests still pass?`,
133+
`5. STYLE: Consistency with surrounding code, no dead code or debug leftovers`,
134+
``,
135+
`For requirement_match in your output, write "N/A — no task context, pure code quality review".`,
136+
customRules ? `\n${customRules}` : "",
137+
].join("\n");
138+
}
92139
const outputFormat = PROMPT_TEMPLATES["reviewer-output-format"] || '{"verdict":"APPROVE or NEEDS_CHANGES"}';
93140

94141
const prompt = [

0 commit comments

Comments
 (0)