diff --git a/packages/coding-agent/src/experimental/client-tui.ts b/packages/coding-agent/src/experimental/client-tui.ts index 1a1fef1a0..cee2ff9ca 100644 --- a/packages/coding-agent/src/experimental/client-tui.ts +++ b/packages/coding-agent/src/experimental/client-tui.ts @@ -95,6 +95,7 @@ export class ExperimentalClientTui implements Component { readonly #modelSelections = new Map(); readonly #agents = new Map(); readonly #modelActions = new Map(); + readonly #keybindings = KeybindingsManager.create(); readonly #chatInput: CustomEditor; #selectList: SelectList | undefined; #screen: "models" | "chat" = "chat"; @@ -114,9 +115,8 @@ export class ExperimentalClientTui implements Component { this.#requestRender = requestRender; this.#finish = finish; this.#loadedFacets = loadedFacets; - const keybindings = KeybindingsManager.create(); - setKeybindings(keybindings); - this.#chatInput = new CustomEditor(ui, getEditorTheme(), keybindings, { paddingX: 1 }); + setKeybindings(this.#keybindings); + this.#chatInput = new CustomEditor(ui, getEditorTheme(), this.#keybindings, { paddingX: 1 }); this.#chatInput.onSubmit = (message) => void this.#runPrompt(message); this.#chatInput.onEscape = () => this.#interrupt(); this.#chatInput.onCtrlD = finish; @@ -181,7 +181,15 @@ export class ExperimentalClientTui implements Component { } handleInput(data: string): void { - if (this.#busy) return; + if (this.#busy) { + if ( + this.#keybindings.matches(data, "app.clear") || + (this.#chatInput.getText().length === 0 && this.#keybindings.matches(data, "app.exit")) + ) { + this.#finish(); + } + return; + } if (this.#screen === "chat") { this.#chatInput.handleInput(data); this.#requestRender(); diff --git a/packages/coding-agent/test/experimental-client-tui.test.ts b/packages/coding-agent/test/experimental-client-tui.test.ts index 6fa0b8f0d..005cb8dca 100644 --- a/packages/coding-agent/test/experimental-client-tui.test.ts +++ b/packages/coding-agent/test/experimental-client-tui.test.ts @@ -288,6 +288,12 @@ describe("experimental client TUI", () => { BACKGROUND_CONTEXT, ); await vi.waitFor(() => expect(component.render(80).join("\n")).toContain("retrying")); + component.handleInput("\u0003"); + expect(finished).toBe(true); + finished = false; + component.handleInput("\u0004"); + expect(finished).toBe(true); + finished = false; connectionState.set({ status: "connecting", attempt: 1 }, BACKGROUND_CONTEXT); connectionState.set({ status: "connected", since: "reconnected" }, BACKGROUND_CONTEXT); attachment.set({ status: "attached", sessionId }, BACKGROUND_CONTEXT);