From 5174ba015575a6174d62f19af140f28286c483a4 Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 2 Jun 2026 11:15:09 +0000 Subject: [PATCH 1/2] fix(tui): registered ctrl-v image paste on windows Kept Ctrl+V as a default clipboard-image paste shortcut on Windows while preserving Alt+V as the Windows Terminal-safe fallback. Updated keybinding docs and regression coverage for the platform-specific default. Fixes #1708 --- docs/keybindings.md | 38 ++++++++++--------- packages/coding-agent/CHANGELOG.md | 2 + .../coding-agent/src/config/keybindings.ts | 9 ++++- .../test/keybindings-display.test.ts | 13 ++++++- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/docs/keybindings.md b/docs/keybindings.md index 511aa65d1..8e8158bbf 100644 --- a/docs/keybindings.md +++ b/docs/keybindings.md @@ -22,23 +22,25 @@ app.stt.toggle: [] ## Common action IDs -| Action ID | Default | Meaning | -| --------------------------- | ----------------------------- | --------------------------------------------- | -| `app.model.cycleForward` | `Ctrl+P` | Cycle role models forward | -| `app.model.cycleBackward` | `Shift+Ctrl+P` | Cycle role models in temporary mode | -| `app.model.selectTemporary` | `Alt+P` | Pick a model temporarily for this session | -| `app.model.select` | `Ctrl+L` | Open the model selector and set roles | -| `app.plan.toggle` | `Alt+Shift+P` | Toggle plan mode | -| `app.history.search` | `Ctrl+R` | Search prompt history | -| `app.tools.expand` | `Ctrl+O` | Toggle tool-output expansion | -| `app.thinking.toggle` | `Ctrl+T` | Toggle thinking-block visibility | -| `app.thinking.cycle` | `Shift+Tab` | Cycle thinking level | -| `app.editor.external` | `Ctrl+G` | Edit the draft in `$VISUAL` / `$EDITOR` | -| `app.message.followUp` | `Ctrl+Enter` | Queue a follow-up message | -| `app.message.dequeue` | `Alt+Up` | Dequeue a queued message back into the editor | -| `app.clipboard.copyLine` | `Alt+Shift+L` | Copy the current line | -| `app.clipboard.copyPrompt` | `Alt+Shift+C` | Copy the whole prompt | -| `app.clipboard.pasteImage` | `Ctrl+V` (`Alt+V` on Windows) | Paste an image from the clipboard | -| `app.stt.toggle` | `Alt+H` | Toggle speech-to-text recording | +| Action ID | Default | Meaning | +| --------------------------- | -------------------------------------- | --------------------------------------------- | +| `app.model.cycleForward` | `Ctrl+P` | Cycle role models forward | +| `app.model.cycleBackward` | `Shift+Ctrl+P` | Cycle role models in temporary mode | +| `app.model.selectTemporary` | `Alt+P` | Pick a model temporarily for this session | +| `app.model.select` | `Ctrl+L` | Open the model selector and set roles | +| `app.plan.toggle` | `Alt+Shift+P` | Toggle plan mode | +| `app.history.search` | `Ctrl+R` | Search prompt history | +| `app.tools.expand` | `Ctrl+O` | Toggle tool-output expansion | +| `app.thinking.toggle` | `Ctrl+T` | Toggle thinking-block visibility | +| `app.thinking.cycle` | `Shift+Tab` | Cycle thinking level | +| `app.editor.external` | `Ctrl+G` | Edit the draft in `$VISUAL` / `$EDITOR` | +| `app.message.followUp` | `Ctrl+Enter` | Queue a follow-up message | +| `app.message.dequeue` | `Alt+Up` | Dequeue a queued message back into the editor | +| `app.clipboard.copyLine` | `Alt+Shift+L` | Copy the current line | +| `app.clipboard.copyPrompt` | `Alt+Shift+C` | Copy the whole prompt | +| `app.clipboard.pasteImage` | `Ctrl+V` (`Alt+V` fallback on Windows) | Paste an image from the clipboard | +| `app.stt.toggle` | `Alt+H` | Toggle speech-to-text recording | + +On Windows Terminal, `Ctrl+V` may be handled by the terminal paste command before `omp` sees it; use the `Alt+V` fallback when clipboard image paste appears to do nothing. Older unqualified action names are migrated when `keybindings.yml` is loaded, but new docs and new configs should use the namespaced action IDs above. Existing `keybindings.json` files are still accepted and migrated to `keybindings.yml`; `keybindings.yaml` is also accepted. diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 7041710cd..3d5058722 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -21,6 +21,8 @@ ### Fixed +- Fixed Windows clipboard-image paste keeping `Ctrl+V` unregistered by default. The TUI now registers `Ctrl+V` plus the Windows Terminal-safe `Alt+V` fallback, and the keybinding docs call out when to use the fallback ([#1708](https://github.com/can1357/oh-my-pi/issues/1708)). + - Fixed `read`, `search`, `find`, `ast_grep`, and `ast_edit` recovering when a model flattens multiple existing paths into one comma-, semicolon-, or space-delimited string while preserving real paths that contain delimiters. - Fixed Exa web search reporting available without Exa credentials, which could route searches into the unauthenticated public MCP fallback and stall before trying the next provider. Availability and `searchExa()` now resolve through the standard `AuthStorage` cascade (`EXA_API_KEY` env or stored credential) ([#1695](https://github.com/can1357/oh-my-pi/issues/1695)). - Fixed Anthropic web search ignoring `ANTHROPIC_SEARCH_BASE_URL` when credentials came from stored Anthropic auth or generic Anthropic env fallback rather than `ANTHROPIC_SEARCH_API_KEY` ([#1694](https://github.com/can1357/oh-my-pi/issues/1694)). diff --git a/packages/coding-agent/src/config/keybindings.ts b/packages/coding-agent/src/config/keybindings.ts index 1c379b972..ace7f7860 100644 --- a/packages/coding-agent/src/config/keybindings.ts +++ b/packages/coding-agent/src/config/keybindings.ts @@ -58,6 +58,13 @@ declare module "@oh-my-pi/pi-tui" { interface Keybindings extends AppKeybindings {} } +/** + * Resolve default image-paste shortcuts for the current terminal platform. + */ +export function getDefaultPasteImageKeys(platform: NodeJS.Platform = process.platform): KeyId[] { + return platform === "win32" ? ["ctrl+v", "alt+v"] : ["ctrl+v"]; +} + /** * All keybindings definitions: TUI + app-specific. */ @@ -120,7 +127,7 @@ export const KEYBINDINGS = { description: "Dequeue message", }, "app.clipboard.pasteImage": { - defaultKeys: process.platform === "win32" ? "alt+v" : "ctrl+v", + defaultKeys: getDefaultPasteImageKeys(), description: "Paste image from clipboard", }, "app.clipboard.pasteTextRaw": { diff --git a/packages/coding-agent/test/keybindings-display.test.ts b/packages/coding-agent/test/keybindings-display.test.ts index 1a0e37bd4..e0b93a327 100644 --- a/packages/coding-agent/test/keybindings-display.test.ts +++ b/packages/coding-agent/test/keybindings-display.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "bun:test"; -import { KeybindingsManager } from "../src/config/keybindings"; +import { KeybindingsManager, getDefaultPasteImageKeys } from "../src/config/keybindings"; describe("KeybindingsManager.getDisplayString", () => { it("formats a single binding as a human-readable key hint", () => { @@ -26,3 +26,14 @@ describe("KeybindingsManager.getDisplayString", () => { expect(keybindings.getDisplayString("app.clipboard.copyPrompt")).toBe(""); }); }); + +describe("getDefaultPasteImageKeys", () => { + it("keeps Ctrl+V registered for image paste on Windows alongside the terminal-safe fallback", () => { + expect(getDefaultPasteImageKeys("win32")).toEqual(["ctrl+v", "alt+v"]); + }); + + it("uses Ctrl+V as the image-paste shortcut on non-Windows platforms", () => { + expect(getDefaultPasteImageKeys("linux")).toEqual(["ctrl+v"]); + expect(getDefaultPasteImageKeys("darwin")).toEqual(["ctrl+v"]); + }); +}); From 56c47e8447244a21c898e60d41bbe9d78cb92ed6 Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 2 Jun 2026 11:15:22 +0000 Subject: [PATCH 2/2] style: bun run fix --- packages/coding-agent/test/keybindings-display.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/coding-agent/test/keybindings-display.test.ts b/packages/coding-agent/test/keybindings-display.test.ts index e0b93a327..ae98e83d8 100644 --- a/packages/coding-agent/test/keybindings-display.test.ts +++ b/packages/coding-agent/test/keybindings-display.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "bun:test"; -import { KeybindingsManager, getDefaultPasteImageKeys } from "../src/config/keybindings"; +import { getDefaultPasteImageKeys, KeybindingsManager } from "../src/config/keybindings"; describe("KeybindingsManager.getDisplayString", () => { it("formats a single binding as a human-readable key hint", () => {