[codex] Clear role-scoped sessions (#139)
* add gated codex goals support * sync README SDK versions * bump claude agent sdk * add codex goals settings toggle * reuse status dashboard message and simplify settings actions * refine settings page UX * fix settings nav hash routing * add dashboard UX verification * refine dashboard settings and inbox UX * remove inbox top-level navigation * remove dashboard health top-level navigation * fix: allow runtime image attachment paths * feat: configure attachment allowlist dirs * fix: clean duplicate dashboard status messages * fix: poll dashboard duplicate cleanup between status updates * fix: delete dashboard duplicates on create * Refine settings IA with tabbed sections * Add read-only runtime inventory settings * Fix runtime inventory MCP JSON parsing * Add room skill settings inventory * Add room skill setting mutations * Apply room skill overrides to runner spawn * Refine scheduled task dashboard UX * Remove reviewer final prompt reinjection * Stabilize pnpm verification fixture * Remove previous owner final prompt carryover * Clear role-scoped sessions
This commit is contained in:
28
src/db-sessions.test.ts
Normal file
28
src/db-sessions.test.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import {
|
||||||
|
_initTestDatabase,
|
||||||
|
deleteAllSessionsForGroup,
|
||||||
|
getSession,
|
||||||
|
setSession,
|
||||||
|
} from './db.js';
|
||||||
|
|
||||||
|
describe('session accessors', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
_initTestDatabase();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deletes owner, reviewer, and arbiter role-scoped sessions for a group', () => {
|
||||||
|
setSession('group-a', 'owner-session');
|
||||||
|
setSession('group-a:reviewer', 'reviewer-session');
|
||||||
|
setSession('group-a:arbiter', 'arbiter-session');
|
||||||
|
setSession('group-b', 'other-session');
|
||||||
|
|
||||||
|
deleteAllSessionsForGroup('group-a');
|
||||||
|
|
||||||
|
expect(getSession('group-a')).toBeUndefined();
|
||||||
|
expect(getSession('group-a:reviewer')).toBeUndefined();
|
||||||
|
expect(getSession('group-a:arbiter')).toBeUndefined();
|
||||||
|
expect(getSession('group-b')).toBe('other-session');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -141,8 +141,11 @@ export function deleteAllSessionsForGroupFromDatabase(
|
|||||||
groupFolder: string,
|
groupFolder: string,
|
||||||
): void {
|
): void {
|
||||||
database
|
database
|
||||||
.prepare('DELETE FROM sessions WHERE group_folder = ?')
|
.prepare(
|
||||||
.run(groupFolder);
|
`DELETE FROM sessions
|
||||||
|
WHERE group_folder IN (?, ?, ?)`,
|
||||||
|
)
|
||||||
|
.run(groupFolder, `${groupFolder}:reviewer`, `${groupFolder}:arbiter`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAllSessionsForAgentTypeFromDatabase(
|
export function getAllSessionsForAgentTypeFromDatabase(
|
||||||
|
|||||||
37
src/runtime-state.test.ts
Normal file
37
src/runtime-state.test.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
const db = vi.hoisted(() => ({
|
||||||
|
assignRoom: vi.fn(),
|
||||||
|
deleteAllSessionsForGroup: vi.fn(),
|
||||||
|
deleteSession: vi.fn(),
|
||||||
|
getAllRoomBindings: vi.fn(() => ({})),
|
||||||
|
getAllSessions: vi.fn(() => ({})),
|
||||||
|
getRouterState: vi.fn(() => ''),
|
||||||
|
setRouterState: vi.fn(),
|
||||||
|
setSession: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('./db.js', () => db);
|
||||||
|
|
||||||
|
import { createRuntimeState } from './runtime-state.js';
|
||||||
|
|
||||||
|
describe('createRuntimeState', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clears role-scoped sessions from memory when allRoles is requested', () => {
|
||||||
|
const state = createRuntimeState();
|
||||||
|
|
||||||
|
state.persistSession('group-a', 'owner-session');
|
||||||
|
state.persistSession('group-a:reviewer', 'reviewer-session');
|
||||||
|
state.persistSession('group-a:arbiter', 'arbiter-session');
|
||||||
|
state.persistSession('group-b', 'other-session');
|
||||||
|
|
||||||
|
state.clearSession('group-a', { allRoles: true });
|
||||||
|
|
||||||
|
expect(state.getSessions()).toEqual({ 'group-b': 'other-session' });
|
||||||
|
expect(db.deleteAllSessionsForGroup).toHaveBeenCalledWith('group-a');
|
||||||
|
expect(db.deleteSession).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -48,10 +48,17 @@ export function createRuntimeState(): RuntimeState {
|
|||||||
groupFolder: string,
|
groupFolder: string,
|
||||||
opts?: { allRoles?: boolean },
|
opts?: { allRoles?: boolean },
|
||||||
): void => {
|
): void => {
|
||||||
delete sessions[groupFolder];
|
|
||||||
if (opts?.allRoles) {
|
if (opts?.allRoles) {
|
||||||
|
for (const key of [
|
||||||
|
groupFolder,
|
||||||
|
`${groupFolder}:reviewer`,
|
||||||
|
`${groupFolder}:arbiter`,
|
||||||
|
]) {
|
||||||
|
delete sessions[key];
|
||||||
|
}
|
||||||
deleteAllSessionsForGroup(groupFolder);
|
deleteAllSessionsForGroup(groupFolder);
|
||||||
} else {
|
} else {
|
||||||
|
delete sessions[groupFolder];
|
||||||
deleteSession(groupFolder);
|
deleteSession(groupFolder);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user