feat: re-review on post-approval changes, container improvements
- Compare git HEAD at reviewer approval vs owner finalize to detect new code changes after DONE verdict. Re-trigger reviewer if changed, complete if unchanged (commit-only is fine). - Record approved HEAD in source_ref when reviewer says DONE - Add pnpm store mount, pre-flight checks, idle timeout for containers - Clean up orphaned containers on shutdown
This commit is contained in:
@@ -87,7 +87,13 @@ function detectPnpmStorePath(workspaceDir: string): string | null {
|
|||||||
/* pnpm not available */
|
/* pnpm not available */
|
||||||
}
|
}
|
||||||
// Fallback to default location
|
// Fallback to default location
|
||||||
const defaultStore = path.join(os.homedir(), '.local', 'share', 'pnpm', 'store');
|
const defaultStore = path.join(
|
||||||
|
os.homedir(),
|
||||||
|
'.local',
|
||||||
|
'share',
|
||||||
|
'pnpm',
|
||||||
|
'store',
|
||||||
|
);
|
||||||
if (fs.existsSync(defaultStore)) return defaultStore;
|
if (fs.existsSync(defaultStore)) return defaultStore;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,14 +302,30 @@ export function completePairedExecutionContext(args: {
|
|||||||
if (role === 'owner') {
|
if (role === 'owner') {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
// merge_ready → owner finalized after reviewer approval → completed
|
// merge_ready → reviewer already approved. Check if owner made
|
||||||
|
// additional changes that need re-review.
|
||||||
if (task.status === 'merge_ready') {
|
if (task.status === 'merge_ready') {
|
||||||
updatePairedTask(taskId, { status: 'completed', updated_at: now });
|
const workspace = getPairedWorkspace(task.id, 'owner');
|
||||||
|
const currentHead = workspace?.workspace_dir
|
||||||
|
? resolveCanonicalHead(workspace.workspace_dir)
|
||||||
|
: null;
|
||||||
|
const snapshotRef = task.source_ref;
|
||||||
|
const hasNewChanges = currentHead && currentHead !== snapshotRef;
|
||||||
|
|
||||||
|
if (!hasNewChanges) {
|
||||||
|
// No code changes since reviewer approved → finalize complete
|
||||||
|
updatePairedTask(taskId, { status: 'completed', updated_at: now });
|
||||||
|
logger.info(
|
||||||
|
{ taskId, summary: args.summary?.slice(0, 100) },
|
||||||
|
'Owner finalized after reviewer approval — task completed',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Owner made changes after approval → needs re-review
|
||||||
logger.info(
|
logger.info(
|
||||||
{ taskId, summary: args.summary?.slice(0, 100) },
|
{ taskId, previousHead: snapshotRef, currentHead },
|
||||||
'Owner finalized after reviewer approval — task completed',
|
'Owner made changes after reviewer approval — re-triggering review',
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal turn → auto-trigger reviewer (if within round trip limit)
|
// Normal turn → auto-trigger reviewer (if within round trip limit)
|
||||||
@@ -345,14 +361,25 @@ export function completePairedExecutionContext(args: {
|
|||||||
const verdict = classifyReviewerVerdict(args.summary);
|
const verdict = classifyReviewerVerdict(args.summary);
|
||||||
|
|
||||||
switch (verdict) {
|
switch (verdict) {
|
||||||
case 'done':
|
case 'done': {
|
||||||
// Approved → owner gets final turn to commit/push
|
// Approved → owner gets final turn to commit/push.
|
||||||
updatePairedTask(taskId, { status: 'merge_ready', updated_at: now });
|
// Record the current HEAD as source_ref so the finalize turn
|
||||||
|
// can detect if the owner made additional code changes.
|
||||||
|
const ownerWs = getPairedWorkspace(taskId, 'owner');
|
||||||
|
const approvedHead = ownerWs?.workspace_dir
|
||||||
|
? resolveCanonicalHead(ownerWs.workspace_dir)
|
||||||
|
: null;
|
||||||
|
updatePairedTask(taskId, {
|
||||||
|
status: 'merge_ready',
|
||||||
|
source_ref: approvedHead ?? task.source_ref,
|
||||||
|
updated_at: now,
|
||||||
|
});
|
||||||
logger.info(
|
logger.info(
|
||||||
{ taskId, verdict, summary: args.summary?.slice(0, 100) },
|
{ taskId, verdict, approvedHead, summary: args.summary?.slice(0, 100) },
|
||||||
'Reviewer approved — owner gets final turn to finalize',
|
'Reviewer approved — owner gets final turn to finalize',
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'blocked':
|
case 'blocked':
|
||||||
case 'needs_context':
|
case 'needs_context':
|
||||||
|
|||||||
Reference in New Issue
Block a user