fix: /clear now resets both owner and reviewer sessions in paired rooms
This commit is contained in:
@@ -556,7 +556,8 @@ describe('paired task state', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: 'wire up workspaces',
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -594,7 +595,8 @@ describe('paired task state', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: null,
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
|
||||
@@ -1550,6 +1550,13 @@ export function deleteSession(groupFolder: string): void {
|
||||
).run(groupFolder, SERVICE_AGENT_TYPE);
|
||||
}
|
||||
|
||||
export function deleteAllSessionsForGroup(groupFolder: string): void {
|
||||
db.prepare('DELETE FROM service_sessions WHERE group_folder = ?').run(
|
||||
groupFolder,
|
||||
);
|
||||
db.prepare('DELETE FROM sessions WHERE group_folder = ?').run(groupFolder);
|
||||
}
|
||||
|
||||
export function getAllSessions(): Record<string, string> {
|
||||
const serviceRows = db
|
||||
.prepare(
|
||||
|
||||
12
src/index.ts
12
src/index.ts
@@ -37,6 +37,7 @@ import {
|
||||
initDatabase,
|
||||
setRegisteredGroup,
|
||||
setRouterState,
|
||||
deleteAllSessionsForGroup,
|
||||
deleteSession,
|
||||
setSession,
|
||||
storeChatMetadata,
|
||||
@@ -208,9 +209,16 @@ function saveState(): void {
|
||||
setRouterState('last_agent_seq', JSON.stringify(lastAgentTimestamp));
|
||||
}
|
||||
|
||||
function clearSession(groupFolder: string): void {
|
||||
function clearSession(
|
||||
groupFolder: string,
|
||||
opts?: { allRoles?: boolean },
|
||||
): void {
|
||||
delete sessions[groupFolder];
|
||||
deleteSession(groupFolder);
|
||||
if (opts?.allRoles) {
|
||||
deleteAllSessionsForGroup(groupFolder);
|
||||
} else {
|
||||
deleteSession(groupFolder);
|
||||
}
|
||||
}
|
||||
|
||||
function registerGroup(jid: string, group: RegisteredGroup): void {
|
||||
|
||||
@@ -326,7 +326,8 @@ describe('runAgentForGroup room memory', () => {
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
review_requested_at: null,
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
status: 'active',
|
||||
created_at: '2026-03-29T00:00:00.000Z',
|
||||
updated_at: '2026-03-29T00:00:00.000Z',
|
||||
@@ -386,7 +387,8 @@ describe('runAgentForGroup room memory', () => {
|
||||
reviewer_service_id: 'codex-main',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -467,7 +469,8 @@ describe('runAgentForGroup room memory', () => {
|
||||
reviewer_service_id: 'claude',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
|
||||
@@ -262,7 +262,8 @@ describe('createMessageRuntime', () => {
|
||||
reviewer_service_id: 'codex-main',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-29T00:00:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: '2026-03-29T00:00:00.000Z',
|
||||
@@ -354,7 +355,8 @@ describe('createMessageRuntime', () => {
|
||||
reviewer_service_id: 'codex-main',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-29T00:00:00.000Z',
|
||||
|
||||
@@ -101,7 +101,7 @@ export interface MessageRuntimeDeps {
|
||||
getLastAgentTimestamps: () => Record<string, string>;
|
||||
saveState: () => void;
|
||||
persistSession: (groupFolder: string, sessionId: string) => void;
|
||||
clearSession: (groupFolder: string) => void;
|
||||
clearSession: (groupFolder: string, opts?: { allRoles?: boolean }) => void;
|
||||
}
|
||||
|
||||
export function createMessageRuntime(deps: MessageRuntimeDeps): {
|
||||
@@ -542,7 +542,7 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
|
||||
deps.queue.closeStdin(chatJid, {
|
||||
reason: 'session-command',
|
||||
}),
|
||||
clearSession: () => deps.clearSession(group.folder),
|
||||
clearSession: (opts) => deps.clearSession(group.folder, opts),
|
||||
advanceCursor: (cursorOrTimestamp) => {
|
||||
advanceLastAgentCursor(
|
||||
deps.getLastAgentTimestamps(),
|
||||
|
||||
@@ -215,7 +215,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-28T00:00:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -246,7 +247,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-28T00:00:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -280,7 +282,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -320,7 +323,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-28T00:00:00.000Z',
|
||||
status: 'in_review',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -374,7 +378,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -388,7 +393,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-28T00:00:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -455,7 +461,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -469,7 +476,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-28T00:00:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -511,7 +519,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
@@ -525,7 +534,8 @@ describe('paired execution context', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-29T00:00:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: '2026-03-28T00:00:00.000Z',
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { execFileSync } from 'child_process';
|
||||
import crypto from 'crypto';
|
||||
|
||||
import { SERVICE_ID, normalizeServiceId, PAIRED_MAX_ROUND_TRIPS } from './config.js';
|
||||
import {
|
||||
SERVICE_ID,
|
||||
normalizeServiceId,
|
||||
PAIRED_MAX_ROUND_TRIPS,
|
||||
} from './config.js';
|
||||
import {
|
||||
createPairedTask,
|
||||
getLatestPairedTaskForChat,
|
||||
@@ -228,7 +232,11 @@ export function completePairedExecutionContext(args: {
|
||||
if (role === 'owner') {
|
||||
if (task.round_trip_count >= PAIRED_MAX_ROUND_TRIPS) {
|
||||
logger.info(
|
||||
{ taskId, roundTrips: task.round_trip_count, max: PAIRED_MAX_ROUND_TRIPS },
|
||||
{
|
||||
taskId,
|
||||
roundTrips: task.round_trip_count,
|
||||
max: PAIRED_MAX_ROUND_TRIPS,
|
||||
},
|
||||
'Round trip limit reached, skipping auto-review',
|
||||
);
|
||||
return;
|
||||
|
||||
@@ -74,7 +74,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: 'review the owner changes',
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -162,7 +163,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -214,7 +216,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: 'cross service review',
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -289,7 +292,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -363,7 +367,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -503,7 +508,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -564,7 +570,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -619,7 +626,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: '2026-03-28T00:01:00.000Z',
|
||||
status: 'review_ready',
|
||||
created_at: now,
|
||||
@@ -680,7 +688,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -743,7 +752,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
@@ -831,7 +841,8 @@ describe('paired workspace manager', () => {
|
||||
reviewer_service_id: 'codex-review',
|
||||
title: null,
|
||||
source_ref: 'HEAD',
|
||||
plan_notes: null, round_trip_count: 0,
|
||||
plan_notes: null,
|
||||
round_trip_count: 0,
|
||||
review_requested_at: null,
|
||||
status: 'active',
|
||||
created_at: now,
|
||||
|
||||
@@ -73,7 +73,7 @@ export interface SessionCommandDeps {
|
||||
onOutput: (result: AgentResult) => Promise<void>,
|
||||
) => Promise<'success' | 'error'>;
|
||||
closeStdin: () => void;
|
||||
clearSession: () => void;
|
||||
clearSession: (opts?: { allRoles?: boolean }) => void;
|
||||
advanceCursor: (timestamp: string) => void;
|
||||
formatMessages: (msgs: NewMessage[], timezone: string) => string;
|
||||
isAdminSender: (msg: NewMessage) => boolean;
|
||||
@@ -158,7 +158,7 @@ export async function handleSessionCommand(opts: {
|
||||
|
||||
if (command === '/clear') {
|
||||
deps.closeStdin();
|
||||
deps.clearSession();
|
||||
deps.clearSession({ allRoles: true });
|
||||
deps.advanceCursor(cmdMsg.timestamp);
|
||||
await deps.sendMessage(
|
||||
'Current session cleared. The next message will start a new conversation.',
|
||||
|
||||
Reference in New Issue
Block a user