feat(tui): add Esc key to cancel active prompt without exiting

This commit is contained in:
William Valentin
2026-02-16 11:31:17 -08:00
parent 598a77947d
commit c34ae9b75b
2 changed files with 106 additions and 8 deletions
+60
View File
@@ -29,10 +29,26 @@ function asAgent(value: unknown): NativeAgent {
function minimalTuiPrivates(value: MinimalTui): {
handleBackendCommand: (provider: string) => Promise<void>;
handleModelCommand: (tier: string, providerModel?: string) => void;
prompt: (text: string) => Promise<string>;
rl: {
once: (event: string, cb: () => void) => void;
removeListener: (event: string, cb: () => void) => void;
question: (text: string, cb: (answer: string) => void) => void;
write: (data: string | null, key?: { ctrl?: boolean; name?: string }) => void;
};
activePromptCancel: (() => void) | null;
} {
return value as unknown as {
handleBackendCommand: (provider: string) => Promise<void>;
handleModelCommand: (tier: string, providerModel?: string) => void;
prompt: (text: string) => Promise<string>;
rl: {
once: (event: string, cb: () => void) => void;
removeListener: (event: string, cb: () => void) => void;
question: (text: string, cb: (answer: string) => void) => void;
write: (data: string | null, key?: { ctrl?: boolean; name?: string }) => void;
};
activePromptCancel: (() => void) | null;
};
}
@@ -270,3 +286,47 @@ describe('MinimalTui backend command', () => {
}
});
});
describe('MinimalTui prompt cancellation', () => {
it('cancels an active prompt without closing the TUI', async () => {
const mockSession = {
id: 'test',
getHistory: () => [],
addMessage: vi.fn(),
clear: vi.fn(),
replaceHistory: vi.fn(),
};
const tui = new MinimalTui({
session: asSession(mockSession),
modelClient: asRouter({}),
systemPrompt: 'test',
});
let onAnswer: ((answer: string) => void) | undefined;
const write = vi.fn((_: string | null, key?: { ctrl?: boolean; name?: string }) => {
if (key?.name === 'return') {
onAnswer?.('');
}
});
minimalTuiPrivates(tui).rl = {
once: vi.fn(),
removeListener: vi.fn(),
question: vi.fn((_text: string, cb: (answer: string) => void) => {
onAnswer = cb;
}),
write,
};
const promptPromise = minimalTuiPrivates(tui).prompt('Confirm? ');
expect(minimalTuiPrivates(tui).activePromptCancel).toBeTypeOf('function');
minimalTuiPrivates(tui).activePromptCancel?.();
await expect(promptPromise).resolves.toBe('');
expect(write).toHaveBeenCalledWith(null, { ctrl: true, name: 'u' });
expect(write).toHaveBeenCalledWith(null, { name: 'return' });
expect(minimalTuiPrivates(tui).activePromptCancel).toBeNull();
});
});