import { type KeybindingsConfig, type KeyId, KeybindingsManager as TuiKeybindingsManager } from "@kolisachint/hoocode-tui"; interface AppKeybindings { "app.interrupt": true; "app.clear": true; "app.exit": true; "app.suspend": true; "app.thinking.cycleForward": true; "app.thinking.cycleBackward": true; "app.model.cycleForward": true; "app.model.cycleBackward": true; "app.model.select": true; "app.tools.expand": true; "app.view.cycleForward": true; "app.view.cycleBackward": true; "app.scroll.pageUp": true; "app.scroll.pageDown": true; "app.scroll.top": true; "app.scroll.bottom": true; "app.scroll.lineUp": true; "app.scroll.lineDown": true; "app.scroll.exit": true; "app.scroll.search": true; "app.scroll.searchInView": true; "app.scroll.searchNext": true; "app.scroll.searchPrevious": true; "app.scroll.previousMessage": true; "app.scroll.nextMessage": true; "app.clipboard.copyMessage": true; "app.thinking.toggle": true; "app.chrome.cycleForward": true; "app.chrome.cycleBackward": true; "app.tasks.cycleForward": true; "app.tasks.cycleBackward": true; "app.team.focus": true; "app.team.nudge": true; "app.team.attach": true; "app.session.toggleNamedFilter": true; "app.editor.external": true; "app.message.followUp": true; "app.message.dequeue": true; "app.clipboard.pasteImage": true; "app.input.voiceTranscribe": true; "app.session.new": true; "app.session.tree": true; "app.session.fork": true; "app.session.resume": true; "app.session.changeDirectory": true; "app.session.color.cycleForward": true; "app.session.color.cycleBackward": true; "app.settings.open": true; "app.hotkeys.open": true; "app.mode.cycleForward": true; "app.mode.cycleBackward": true; "app.options.next": true; "app.options.back": true; "app.tree.foldOrUp": true; "app.tree.unfoldOrDown": true; "app.tree.editLabel": true; "app.tree.toggleLabelTimestamp": true; "app.session.togglePath": true; "app.session.toggleSort": true; "app.session.rename": true; "app.session.delete": true; "app.session.deleteNoninvasive": true; "app.models.save": true; "app.models.enableAll": true; "app.models.clearAll": true; "app.models.toggleProvider": true; "app.models.reorderUp": true; "app.models.reorderDown": true; "app.tree.filter.default": true; "app.tree.filter.noTools": true; "app.tree.filter.userOnly": true; "app.tree.filter.labeledOnly": true; "app.tree.filter.all": true; "app.tree.filter.cycleForward": true; "app.tree.filter.cycleBackward": true; } export type AppKeybinding = keyof AppKeybindings; declare module "@kolisachint/hoocode-tui" { interface Keybindings extends AppKeybindings { } } /** * The keyboard map. * * ## Why it is grouped the way it is * * There are around sixty bindings here. Nobody holds sixty of anything, and the * usual answer — sort them by mechanism, so everything that cycles sits together * — makes a list that is tidy on the page and useless at the keyboard. "It * cycles" is a fact about the widget. It is not what anyone is thinking when * they reach for the key. * * So the grouping is by **intention**: the five things a person is ever doing * here, in the order the loop runs. * * 1. **Flow** — get out, get back. esc, ctrl+c, ctrl+d, ctrl+z. * 2. **Compose** — the message in your hands. alt+e, alt+r, alt+enter, alt+↑. * 3. **Steer** — what the agent is before it runs. alt+a, alt+m, alt+t. * 4. **Read** — what you see of what it did. alt+o, alt+l, ctrl+o, ctrl+t. * 5. **Screen** — how much room there is to see it in. alt+z. * 6. **Scroll** — where in it you are looking. pageUp/pageDown, ctrl+home/end. * 7. **Go** — sessions and places. alt+h, alt+w, alt+s, alt+k, alt+c. * * Seven groups, none of the learned ones larger than five, which is the size a * person can actually hold. Three cost nothing: **Flow** and **Scroll** are the * sets every terminal program and every pager already taught you, and the * **overlays** (pickers, the tree, the options pane, the pinned scroll view) * print their own keys on their own hint lines — recognised, never recalled. * **Screen** is one key. That leaves three groups to genuinely know. * * Screen is its own group rather than part of Read on purpose: every other * family changes what the screen *says*, and that one changes how much screen * there is to say it in. Folding it into Read pushed that family to six * subjects, which is the one thing this grouping exists to prevent. * * The declaration order below *is* the grouping, and it is not cosmetic: * `orderKeybindingsConfig` writes `keybindings.json` in this order, so the file * a user opens to rebind something is grouped the same way this one is. * * ## What the chord tells you * * The modifier says what kind of thing will happen; the letter says to what. * * - **alt+ sets a value.** Nothing takes the screen, nothing loses * focus, you keep typing. Seven of these are dials — an ordered set of stops * with the current one painted where you can see it — and `shift+alt+` * always steps back: * * **a**gent mode · **m**odel · **t**hinking · tool **o**utput * task **l**ist · session **c**olour · chrome (**z**) * * Reversibility is the point. A control you can undo invites you to try it; a * one-way control makes you stop and think first, which is the wrong tax on a * key you press all day. * * - **ctrl+ acts on what is drawn right now**, and shares its letter * with the alt key for the same subject. `alt+o` sets how much tool output * there ever is, `ctrl+o` jumps to all of it and back. `alt+t` sets how much * thinking there ever is, `ctrl+t` shows or hides what you have. Two subjects, * two letters, four keys — half of what four unrelated chords would cost. * * - **A bare navigation key moves the view.** pageUp, pageDown, ctrl+home and * ctrl+end scroll the transcript and nothing else, which is what they do * everywhere else too. They are the one family that took a key off another * binding — the prompt editor's page keys, which had one to three lines to * page through and so did nothing on nearly every press. * * - **A slash command chooses a stop outright.** `/mode`, `/model`, `/color`, * `/chrome`, `/tree`. The key steps, the command picks; that is why * `app.model.select` and `app.session.tree` ship unbound, having given their * letters to dials. It is also the only way a dial stays reachable on a * terminal that composes characters instead of sending alt — macOS * Terminal.app — which is why any dial that can strand a setting has one. * * Two letters in the whole set name nothing, and both survive on the same * fallback — what they do is legible on screen, so the letter is read off rather * than remembered. `alt+n` focuses the team roster, and the task panel prints it * in its own header. `alt+z` steps the chrome dial, whose stop *is* the shape of * the screen you are looking at. Every letter that could have named the second * one is already taken by the thing it controls. * * ## The constraints that shaped it * * - No binding takes a key the editor or the terminal already owns * (ctrl+a/e/b/f/k/u/w/y/d/l/r/g, ctrl+s XOFF, ctrl+m == enter, ctrl+i == tab). * - Inside an overlay the query line is a text field, so every `ctrl+` * there belongs to the *text*. Overlay verbs are all on `alt+`. * - Only `alt+` and `alt+` survive a terminal without the Kitty * keyboard protocol; `alt+[` and `alt+]` arrive as the CSI and OSC introducers. * - `shift+` needs Kitty too, so a `shift+…` default is a * convenience on top of a key that works everywhere. `shift+` is * banned outright: without Kitty it *is* the uppercase letter, which no scope * with a query line can tell from typing. * - Legacy `alt+p` and `alt+n` are also read as `alt+up` and `alt+down`, so no * scope may bind both halves of either pair. * * `test/keybinding-layout.test.ts` holds all of it, including that every * binding belongs to exactly one family. */ export declare const KEYBINDINGS: { readonly "tui.editor.cursorUp": { readonly defaultKeys: "up"; readonly description: "Move cursor up"; }; readonly "tui.editor.cursorDown": { readonly defaultKeys: "down"; readonly description: "Move cursor down"; }; readonly "tui.editor.cursorLeft": { readonly defaultKeys: ["left", "ctrl+b"]; readonly description: "Move cursor left"; }; readonly "tui.editor.cursorRight": { readonly defaultKeys: ["right", "ctrl+f"]; readonly description: "Move cursor right"; }; readonly "tui.editor.cursorWordLeft": { readonly defaultKeys: ["alt+left", "ctrl+left", "alt+b"]; readonly description: "Move cursor word left"; }; readonly "tui.editor.cursorWordRight": { readonly defaultKeys: ["alt+right", "ctrl+right", "alt+f"]; readonly description: "Move cursor word right"; }; readonly "tui.editor.cursorLineStart": { readonly defaultKeys: ["home", "ctrl+a"]; readonly description: "Move to line start"; }; readonly "tui.editor.cursorLineEnd": { readonly defaultKeys: ["end", "ctrl+e"]; readonly description: "Move to line end"; }; readonly "tui.editor.jumpForward": { readonly defaultKeys: "ctrl+]"; readonly description: "Jump forward to character"; }; readonly "tui.editor.jumpBackward": { readonly defaultKeys: "ctrl+alt+]"; readonly description: "Jump backward to character"; }; readonly "tui.editor.pageUp": { readonly defaultKeys: []; readonly description: "Page up within the prompt"; }; readonly "tui.editor.pageDown": { readonly defaultKeys: []; readonly description: "Page down within the prompt"; }; readonly "tui.editor.deleteCharBackward": { readonly defaultKeys: "backspace"; readonly description: "Delete character backward"; }; readonly "tui.editor.deleteCharForward": { readonly defaultKeys: ["delete", "ctrl+d"]; readonly description: "Delete character forward"; }; readonly "tui.editor.deleteWordBackward": { readonly defaultKeys: ["ctrl+w", "alt+backspace"]; readonly description: "Delete word backward"; }; readonly "tui.editor.deleteWordForward": { readonly defaultKeys: ["alt+d", "alt+delete"]; readonly description: "Delete word forward"; }; readonly "tui.editor.deleteToLineStart": { readonly defaultKeys: "ctrl+u"; readonly description: "Delete to line start"; }; readonly "tui.editor.deleteToLineEnd": { readonly defaultKeys: "ctrl+k"; readonly description: "Delete to line end"; }; readonly "tui.editor.yank": { readonly defaultKeys: "ctrl+y"; readonly description: "Yank"; }; readonly "tui.editor.yankPop": { readonly defaultKeys: "alt+y"; readonly description: "Yank pop"; }; readonly "tui.editor.undo": { readonly defaultKeys: "ctrl+-"; readonly description: "Undo"; }; readonly "tui.editor.redo": { readonly defaultKeys: "alt+u"; readonly description: "Redo"; }; readonly "tui.input.newLine": { readonly defaultKeys: "shift+enter"; readonly description: "Insert newline"; }; readonly "tui.input.submit": { readonly defaultKeys: "enter"; readonly description: "Submit input"; }; readonly "tui.input.tab": { readonly defaultKeys: "tab"; readonly description: "Tab / autocomplete"; }; readonly "tui.input.copy": { readonly defaultKeys: "ctrl+c"; readonly description: "Copy selection"; }; readonly "tui.select.up": { readonly defaultKeys: "up"; readonly description: "Move selection up"; }; readonly "tui.select.down": { readonly defaultKeys: "down"; readonly description: "Move selection down"; }; readonly "tui.select.pageUp": { readonly defaultKeys: "pageUp"; readonly description: "Selection page up"; }; readonly "tui.select.pageDown": { readonly defaultKeys: "pageDown"; readonly description: "Selection page down"; }; readonly "tui.select.confirm": { readonly defaultKeys: "enter"; readonly description: "Confirm selection"; }; readonly "tui.select.cancel": { readonly defaultKeys: ["escape", "ctrl+c"]; readonly description: "Cancel selection"; }; readonly "app.interrupt": { readonly defaultKeys: "escape"; readonly description: "Cancel or abort"; }; readonly "app.clear": { readonly defaultKeys: "ctrl+c"; readonly description: "Clear editor"; }; readonly "app.exit": { readonly defaultKeys: "ctrl+d"; readonly description: "Exit when editor is empty"; }; readonly "app.suspend": { readonly defaultKeys: "ctrl+z" | never[]; readonly description: "Suspend to background"; }; readonly "app.editor.external": { readonly defaultKeys: "alt+e"; readonly description: "Open external editor"; }; readonly "app.input.voiceTranscribe": { readonly defaultKeys: "alt+r"; readonly description: "Record voice and transcribe into the editor"; }; readonly "app.clipboard.pasteImage": { readonly defaultKeys: "alt+v" | "ctrl+v"; readonly description: "Paste image from clipboard"; }; readonly "app.clipboard.copyMessage": { readonly defaultKeys: "alt+q"; readonly description: "Copy the agent's last message to the clipboard"; }; readonly "app.message.followUp": { readonly defaultKeys: "alt+enter"; readonly description: "Queue follow-up message"; }; readonly "app.message.dequeue": { readonly defaultKeys: "alt+up"; readonly description: "Restore queued messages"; }; readonly "app.mode.cycleForward": { readonly defaultKeys: "alt+a"; readonly description: "Cycle agent mode (ask → plan → build → debug)"; }; readonly "app.mode.cycleBackward": { readonly defaultKeys: "shift+alt+a"; readonly description: "Cycle agent mode backward"; }; readonly "app.model.cycleForward": { readonly defaultKeys: "alt+m"; readonly description: "Cycle to next model"; }; readonly "app.model.cycleBackward": { readonly defaultKeys: "shift+alt+m"; readonly description: "Cycle to previous model"; }; readonly "app.model.select": { readonly defaultKeys: []; readonly description: "Open model selector"; }; readonly "app.thinking.cycleForward": { readonly defaultKeys: ["alt+t", "shift+tab"]; readonly description: "Cycle thinking level (off → … → high)"; }; readonly "app.thinking.cycleBackward": { readonly defaultKeys: "shift+alt+t"; readonly description: "Cycle thinking level backward"; }; readonly "app.view.cycleForward": { readonly defaultKeys: "alt+o"; readonly description: "Cycle tool output view (radar → peek → full)"; }; readonly "app.view.cycleBackward": { readonly defaultKeys: "shift+alt+o"; readonly description: "Cycle tool output view backward"; }; readonly "app.tools.expand": { readonly defaultKeys: "ctrl+o"; readonly description: "Jump to the full view from wherever you are, and back again"; }; readonly "app.thinking.toggle": { readonly defaultKeys: "ctrl+t"; readonly description: "Toggle thinking blocks"; }; readonly "app.tasks.cycleForward": { readonly defaultKeys: "alt+l"; readonly description: "Cycle task panel view (tasks → subagents → teams, skips empty lenses)"; }; readonly "app.tasks.cycleBackward": { readonly defaultKeys: "shift+alt+l"; readonly description: "Cycle task panel view backward"; }; readonly "app.team.focus": { readonly defaultKeys: "alt+n"; readonly description: "Focus the team roster (navigate roles, n nudge, a attach)"; }; readonly "app.chrome.cycleForward": { readonly defaultKeys: "alt+z"; readonly description: "Cycle chrome density (full → compact → bare)"; }; readonly "app.chrome.cycleBackward": { readonly defaultKeys: "shift+alt+z"; readonly description: "Cycle chrome density backward"; }; readonly "app.scroll.pageUp": { readonly defaultKeys: "pageUp"; readonly description: "Scroll the transcript up a page (pins the view)"; }; readonly "app.scroll.pageDown": { readonly defaultKeys: "pageDown"; readonly description: "Scroll the transcript down a page"; }; readonly "app.scroll.top": { readonly defaultKeys: "ctrl+home"; readonly description: "Jump to the start of the transcript"; }; readonly "app.scroll.bottom": { readonly defaultKeys: "ctrl+end"; readonly description: "Jump back to live output"; }; readonly "app.scroll.search": { readonly defaultKeys: "ctrl+r"; readonly description: "Search the transcript"; }; readonly "app.scroll.previousMessage": { readonly defaultKeys: "ctrl+up"; readonly description: "Jump to your previous message"; }; readonly "app.scroll.nextMessage": { readonly defaultKeys: "ctrl+down"; readonly description: "Jump to your next message"; }; readonly "app.session.resume": { readonly defaultKeys: "alt+h"; readonly description: "Resume a session from history"; }; readonly "app.session.tree": { readonly defaultKeys: []; readonly description: "Open session tree"; }; readonly "app.session.new": { readonly defaultKeys: []; readonly description: "Start a new session"; }; readonly "app.session.fork": { readonly defaultKeys: []; readonly description: "Fork current session"; }; readonly "app.session.changeDirectory": { readonly defaultKeys: "alt+w"; readonly description: "Change working directory (move to another repo without quitting)"; }; readonly "app.session.color.cycleForward": { readonly defaultKeys: "alt+c"; readonly description: "Cycle the session chip's color"; }; readonly "app.session.color.cycleBackward": { readonly defaultKeys: "shift+alt+c"; readonly description: "Cycle the session chip's color backward"; }; readonly "app.settings.open": { readonly defaultKeys: "alt+s"; readonly description: "Open settings"; }; readonly "app.hotkeys.open": { readonly defaultKeys: "alt+k"; readonly description: "Show keyboard shortcuts"; }; readonly "app.team.nudge": { readonly defaultKeys: "n"; readonly description: "Nudge the selected team role (team focus mode)"; }; readonly "app.team.attach": { readonly defaultKeys: "a"; readonly description: "Attach to the selected team role (team focus mode)"; }; readonly "app.scroll.lineUp": { readonly defaultKeys: "up"; readonly description: "Scroll up a line (pinned view)"; }; readonly "app.scroll.lineDown": { readonly defaultKeys: "down"; readonly description: "Scroll down a line (pinned view)"; }; readonly "app.scroll.exit": { readonly defaultKeys: "escape"; readonly description: "Leave the pinned view and follow live output"; }; readonly "app.scroll.searchInView": { readonly defaultKeys: "/"; readonly description: "Search the transcript (pinned view)"; }; readonly "app.scroll.searchNext": { readonly defaultKeys: "n"; readonly description: "Next search match (pinned view)"; }; readonly "app.scroll.searchPrevious": { readonly defaultKeys: "p"; readonly description: "Previous search match (pinned view)"; }; readonly "app.options.next": { readonly defaultKeys: "right"; readonly description: "Confirm and advance to the next question"; }; readonly "app.options.back": { readonly defaultKeys: "left"; readonly description: "Go back to the previous question"; }; readonly "app.session.togglePath": { readonly defaultKeys: "alt+p"; readonly description: "Toggle session path display"; }; readonly "app.session.toggleSort": { readonly defaultKeys: "alt+o"; readonly description: "Toggle session sort order"; }; readonly "app.session.toggleNamedFilter": { readonly defaultKeys: "alt+n"; readonly description: "Toggle named session filter"; }; readonly "app.session.rename": { readonly defaultKeys: "alt+r"; readonly description: "Rename session"; }; readonly "app.session.delete": { readonly defaultKeys: "alt+x"; readonly description: "Delete session"; }; readonly "app.session.deleteNoninvasive": { readonly defaultKeys: "ctrl+backspace"; readonly description: "Delete session when query is empty"; }; readonly "app.models.save": { readonly defaultKeys: "alt+s"; readonly description: "Save model selection"; }; readonly "app.models.enableAll": { readonly defaultKeys: "alt+a"; readonly description: "Enable all models"; }; readonly "app.models.clearAll": { readonly defaultKeys: "alt+x"; readonly description: "Clear all models"; }; readonly "app.models.toggleProvider": { readonly defaultKeys: "alt+g"; readonly description: "Toggle all models for provider"; }; readonly "app.models.reorderUp": { readonly defaultKeys: "alt+up"; readonly description: "Move model up in order"; }; readonly "app.models.reorderDown": { readonly defaultKeys: "alt+down"; readonly description: "Move model down in order"; }; readonly "app.tree.foldOrUp": { readonly defaultKeys: ["ctrl+left", "alt+left"]; readonly description: "Fold tree branch or move up"; }; readonly "app.tree.unfoldOrDown": { readonly defaultKeys: ["ctrl+right", "alt+right"]; readonly description: "Unfold tree branch or move down"; }; readonly "app.tree.editLabel": { readonly defaultKeys: "alt+l"; readonly description: "Edit tree label"; }; readonly "app.tree.toggleLabelTimestamp": { readonly defaultKeys: "alt+t"; readonly description: "Toggle tree label timestamps"; }; readonly "app.tree.filter.default": { readonly defaultKeys: "alt+1"; readonly description: "Tree filter: default view"; }; readonly "app.tree.filter.noTools": { readonly defaultKeys: "alt+2"; readonly description: "Tree filter: hide tool results"; }; readonly "app.tree.filter.userOnly": { readonly defaultKeys: "alt+3"; readonly description: "Tree filter: user messages only"; }; readonly "app.tree.filter.labeledOnly": { readonly defaultKeys: "alt+4"; readonly description: "Tree filter: labeled entries only"; }; readonly "app.tree.filter.all": { readonly defaultKeys: "alt+5"; readonly description: "Tree filter: show all entries"; }; readonly "app.tree.filter.cycleForward": { readonly defaultKeys: "alt+c"; readonly description: "Tree filter: cycle forward"; }; readonly "app.tree.filter.cycleBackward": { readonly defaultKeys: "shift+alt+c"; readonly description: "Tree filter: cycle backward"; }; }; export declare function migrateKeybindingsConfig(rawConfig: Record): { config: Record; migrated: boolean; }; export declare class KeybindingsManager extends TuiKeybindingsManager { private configPath; constructor(userBindings?: KeybindingsConfig, configPath?: string); static create(agentDir?: string): KeybindingsManager; reload(): void; getEffectiveConfig(): KeybindingsConfig; private static loadFromFile; } export type { KeyId, KeybindingsConfig }; //# sourceMappingURL=keybindings.d.ts.map