fix one-shot review for rooms without workDir

This commit is contained in:
Codex
2026-05-27 11:20:30 +09:00
parent 51512c9aeb
commit 7ed0af98a2
3 changed files with 53 additions and 17 deletions

View File

@@ -655,15 +655,16 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
return gateResult.success;
}
maybeActivateOneShotReviewLease({
chatJid,
group,
messages: missedMessages,
});
const oneShotReviewGroup =
maybeActivateOneShotReviewLease({
chatJid,
group,
messages: missedMessages,
}) ?? group;
return runQueuedGroupTurn({
chatJid,
group,
group: oneShotReviewGroup,
runId,
log,
timezone: deps.timezone,

View File

@@ -58,13 +58,16 @@ describe('one-shot review', () => {
expect(getEffectiveRuntimeRoomMode('dc:single-room')).toBe('single');
expect(hasReviewerLease('dc:single-room')).toBe(false);
const activated = maybeActivateOneShotReviewLease({
const reviewGroup = maybeActivateOneShotReviewLease({
chatJid: 'dc:single-room',
group: group!,
messages: [humanMessage('이번 요청만 리뷰어 사용해서 검증해줘')],
});
expect(activated).toBe(true);
expect(reviewGroup).toMatchObject({
folder: 'single_room',
workDir: '/tmp/ejclaw-single-room',
});
expect(getEffectiveRuntimeRoomMode('dc:single-room')).toBe('single');
expect(getChannelOwnerLease('dc:single-room')).toMatchObject({
reason: ONE_SHOT_REVIEW_LEASE_REASON,
@@ -88,10 +91,32 @@ describe('one-shot review', () => {
group: group!,
messages: [humanMessage('그냥 구현해줘')],
}),
).toBe(false);
).toBeNull();
expect(getChannelOwnerLease('dc:single-room')).toBeUndefined();
});
it('uses the group folder as the workDir for one-shot review in rooms without workDir', () => {
const group = assignRoom('dc:single-room', {
name: 'single room',
folder: 'single_room',
roomMode: 'single',
ownerAgentType: 'claude-code',
});
const reviewGroup = maybeActivateOneShotReviewLease({
chatJid: 'dc:single-room',
group: group!,
messages: [humanMessage('리뷰어로 검증해줘')],
});
expect(reviewGroup?.folder).toBe('single_room');
expect(reviewGroup?.workDir).toMatch(/\/groups\/single_room$/);
expect(getChannelOwnerLease('dc:single-room')).toMatchObject({
reason: ONE_SHOT_REVIEW_LEASE_REASON,
});
expect(hasReviewerLease('dc:single-room')).toBe(true);
});
it('clears an idle one-shot reviewer lease', () => {
const group = assignRoom('dc:single-room', {
name: 'single room',

View File

@@ -12,6 +12,7 @@ import {
setChannelOwnerLease,
} from './db.js';
import { logger } from './logger.js';
import { resolveGroupFolderPath } from './group-folder.js';
import { resolveRoleAgentPlan } from './role-agent-plan.js';
import { resolveRoleServiceShadow } from './role-service-shadow.js';
import {
@@ -50,11 +51,18 @@ export function maybeActivateOneShotReviewLease(args: {
chatJid: string;
group: RegisteredGroup;
messages: NewMessage[];
}): boolean {
if (!args.group.workDir) return false;
if (getEffectiveRuntimeRoomMode(args.chatJid) !== 'single') return false;
if (hasReviewerLease(args.chatJid)) return false;
if (!hasHumanOneShotReviewRequest(args.messages)) return false;
}): RegisteredGroup | null {
if (getEffectiveRuntimeRoomMode(args.chatJid) !== 'single') return null;
if (hasReviewerLease(args.chatJid)) return null;
if (!hasHumanOneShotReviewRequest(args.messages)) return null;
let effectiveGroup = args.group;
if (!effectiveGroup.workDir) {
effectiveGroup = {
...effectiveGroup,
workDir: resolveGroupFolderPath(effectiveGroup.folder),
};
}
const lease = getEffectiveChannelLease(args.chatJid);
const storedPlan = getStoredRoomRoleAgentPlan(args.chatJid);
@@ -76,7 +84,7 @@ export function maybeActivateOneShotReviewLease(args: {
rolePlan.reviewerAgentType,
);
if (!reviewerServiceId || !rolePlan.reviewerAgentType) {
return false;
return null;
}
setChannelOwnerLease({
@@ -96,13 +104,15 @@ export function maybeActivateOneShotReviewLease(args: {
logger.info(
{
chatJid: args.chatJid,
groupFolder: args.group.folder,
groupFolder: effectiveGroup.folder,
workDir: effectiveGroup.workDir,
usedDefaultWorkDir: !args.group.workDir,
ownerAgentType: rolePlan.ownerAgentType,
reviewerAgentType: rolePlan.reviewerAgentType,
},
'Activated one-shot reviewer lease for a single-mode room',
);
return true;
return effectiveGroup;
}
export function clearOneShotReviewLeaseIfIdle(chatJid: string): boolean {