Skip to content

Commit 38fe3ee

Browse files
feat(session): block resume and error when session directory mismatches cwd
1 parent 6a8f57e commit 38fe3ee

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

src/cli.test.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ type RunAction = (model: string, prompt: string) => Promise<void>;
22
type ResumeAction = (sessionId: string) => Promise<void>;
33

44
const {
5+
color,
56
createSystemMessage,
67
executeTool,
78
loadSession,
@@ -12,6 +13,7 @@ const {
1213
write,
1314
writeError,
1415
} = vi.hoisted(() => ({
16+
color: vi.fn((text: string) => text),
1517
createSystemMessage: vi.fn(() => ({
1618
role: 'system',
1719
content: 'system prompt',
@@ -38,7 +40,7 @@ vi.mock('./utils', () => ({
3840
ollama: { streamChat },
3941
screen: { reset: mockReset },
4042
session: { loadSession },
41-
terminal: { write, writeError },
43+
terminal: { color, write, writeError },
4244
tools: { TOOLS: ['mock-tool'], executeTool },
4345
}));
4446
vi.mock('./tui', () => ({ renderApp }));
@@ -260,6 +262,25 @@ describe('cli', () => {
260262
expect(renderApp).toHaveBeenCalledWith('session-1');
261263
});
262264

265+
it('blocks TUI and errors when resuming a session from a different directory', async () => {
266+
loadSession.mockReturnValueOnce({
267+
metadata: { id: 'session-1', directory: '/other/project' },
268+
messages: [],
269+
});
270+
271+
await commandState.resumeAction?.('session-1');
272+
273+
expect(color).toHaveBeenCalledWith(
274+
expect.stringContaining(
275+
'Cannot resume: session belongs to /other/project',
276+
),
277+
'yellow',
278+
);
279+
expect(writeError).toHaveBeenCalledOnce();
280+
expect(process.exitCode).toBe(1);
281+
expect(renderApp).not.toHaveBeenCalled();
282+
});
283+
263284
it('reports resume errors and sets exit code', async () => {
264285
loadSession.mockImplementationOnce(() => {
265286
throw new Error('Session not found: missing');

src/cli.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { realpathSync } from 'node:fs';
44

55
import cac from 'cac';
66

7-
import { PACKAGE, ROLE } from './constants';
7+
import { PACKAGE, ROLE, UI } from './constants';
88
import type { ToolName } from './types';
99
import { agents, ollama, screen, session, terminal, tools } from './utils';
1010

@@ -30,7 +30,17 @@ cli
3030
.command('resume <sessionId>', 'Resume a saved session')
3131
.action(async (sessionId: string) => {
3232
try {
33-
session.loadSession(sessionId);
33+
const loaded = session.loadSession(sessionId);
34+
if (loaded.metadata.directory !== process.cwd()) {
35+
terminal.writeError(
36+
terminal.color(
37+
`${UI.WARNING} Cannot resume: session belongs to ${loaded.metadata.directory}\n`,
38+
'yellow',
39+
),
40+
);
41+
process.exitCode = 1;
42+
return;
43+
}
3444
await launchTui(sessionId);
3545
} catch (error) {
3646
const message = error instanceof Error ? error.message : 'Unknown error';

0 commit comments

Comments
 (0)