fix(coding-agent): submit /agents create form and hook editor on Ctrl+Q

Windows Terminal does not deliver a distinct Ctrl+Enter event, so the agent
dashboard's new-agent description form (`AgentDashboard#handleInput` in
the `createInput` branch) and the hook editor's hook-style mode
(`HookEditorComponent#handleHookStyleInput`) could not be submitted: both
branches only matched Ctrl+Enter encodings, and the user-reported Ctrl+Enter
press registers as plain \r — same as Enter — so it fell straight through to
the newline branch. Fix #1903 already added Ctrl+Q as the Windows-friendly
default for `app.message.followUp`, but the create form and hook editor
hardcoded their own Ctrl+Enter check that bypassed that keybinding.

Routes both submit checks through a new `matchesAppFollowUp` helper that
delegates to `app.message.followUp`, falling back to a Ctrl+Q/Ctrl+Enter
literal match for component tests that don't install the app keybindings
manager. Updated hint text in both components to surface Ctrl+Q alongside
Ctrl+Enter. Added regression tests asserting Ctrl+Q submits after typing a
multi-line description (the exact Windows Terminal scenario).

Fixes #2118
This commit is contained in:
roboomp
2026-06-08 20:33:34 +00:00
parent 7d2eb3c550
commit b91b6aa0da
8 changed files with 127 additions and 21 deletions
@@ -141,6 +141,41 @@ describe("HookEditorComponent default (hook) mode", () => {
expect(onSubmit).toHaveBeenCalledWith("draft");
expect(onCancel).not.toHaveBeenCalled();
});
it("submits the current text on Ctrl+Q (Windows Terminal fallback for #2118)", () => {
const onSubmit = vi.fn();
const onCancel = vi.fn();
const component = new HookEditorComponent(createTui(), "Prompt", "line 1\nline 2", onSubmit, onCancel);
// Ctrl+Q raw byte (0x11). Windows Terminal cannot deliver a distinct
// Ctrl+Enter, so app.message.followUp also binds Ctrl+Q (#1903), and the
// hook editor must honor it for the same reason.
component.handleInput("\x11");
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith("line 1\nline 2");
expect(onCancel).not.toHaveBeenCalled();
});
it("keeps Ctrl+Q working after Enter inserts a newline (Windows Terminal)", () => {
const onSubmit = vi.fn();
const onCancel = vi.fn();
const component = new HookEditorComponent(createTui(), "Prompt", undefined, onSubmit, onCancel);
component.handleInput("a");
component.handleInput("b");
// Windows Terminal sends bare `\r` for both Enter and Ctrl+Enter; the
// hook editor must treat `\r` as a newline and reserve Ctrl+Q for submit.
component.handleInput("\r");
component.handleInput("c");
component.handleInput("d");
expect(onSubmit).not.toHaveBeenCalled();
component.handleInput("\x11");
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith("ab\ncd");
expect(onCancel).not.toHaveBeenCalled();
});
it("expands large paste markers when submitting on Ctrl+Enter", () => {
const onSubmit = vi.fn();