From f6adba29317407a633d40539977ec611b5232329 Mon Sep 17 00:00:00 2001 From: roboomp Date: Wed, 1 Jul 2026 22:10:38 +0000 Subject: [PATCH 1/2] fix(tui): bound macos command-v image paste Fixes #4178 --- packages/coding-agent/CHANGELOG.md | 1 + .../coding-agent/src/config/keybindings.ts | 4 +++- .../modes/components/custom-editor.test.ts | 21 +++++++++++++++++++ .../test/keybindings-display.test.ts | 4 ++-- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 7ad9ee50e..6231c6d92 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -54,6 +54,7 @@ - Added retry-path diagnostics for assistant-tail removal and scheduled continuations after transient provider errors. - Fixed CJK history rendering issues across repeated compactions. - Fixed user-invoked skills failing to identify themselves or resolve relative paths across various execution paths. +- Fixed macOS `Command+V` image pastes in Ghostty by binding the Kitty `super+v` key event to the image-paste action alongside `Ctrl+V`. ([#4178](https://github.com/can1357/oh-my-pi/issues/4178)) ## [16.2.13] - 2026-07-01 diff --git a/packages/coding-agent/src/config/keybindings.ts b/packages/coding-agent/src/config/keybindings.ts index 5ad80c670..385fa2258 100644 --- a/packages/coding-agent/src/config/keybindings.ts +++ b/packages/coding-agent/src/config/keybindings.ts @@ -65,7 +65,9 @@ declare module "@oh-my-pi/pi-tui" { * 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"]; + if (platform === "win32") return ["ctrl+v", "alt+v"]; + if (platform === "darwin") return ["ctrl+v", "super+v"]; + return ["ctrl+v"]; } /** diff --git a/packages/coding-agent/src/modes/components/custom-editor.test.ts b/packages/coding-agent/src/modes/components/custom-editor.test.ts index 49ae52a4f..c05eb45ef 100644 --- a/packages/coding-agent/src/modes/components/custom-editor.test.ts +++ b/packages/coding-agent/src/modes/components/custom-editor.test.ts @@ -1,6 +1,8 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "bun:test"; import { $ } from "bun"; +import { setKittyProtocolActive } from "@oh-my-pi/pi-tui/keys"; import { getEditorTheme, initTheme } from "../theme/theme"; +import { getDefaultPasteImageKeys } from "../../config/keybindings"; import { CustomEditor, extractBracketedImagePastePaths, @@ -124,6 +126,25 @@ describe("CustomEditor bracketed path paste", () => { expect(imagePathCalls).toBe(0); }); }); +describe("CustomEditor configured paste image keys", () => { + it("routes Ghostty Cmd+V kitty key events through the macOS image-paste default", () => { + const { editor } = makeEditor(); + const onPasteImage = vi.fn(); + editor.onPasteImage = onPasteImage; + editor.setActionKeys("app.clipboard.pasteImage", getDefaultPasteImageKeys("darwin")); + setKittyProtocolActive(true); + + try { + editor.handleInput("\x1b[118;9u"); + } finally { + setKittyProtocolActive(false); + } + + expect(onPasteImage).toHaveBeenCalledTimes(1); + expect(editor.getText()).toBe(""); + }); +}); + describe("extractImagePathFromText (issue #3506)", () => { it("returns the path when the text is a single image file path", () => { diff --git a/packages/coding-agent/test/keybindings-display.test.ts b/packages/coding-agent/test/keybindings-display.test.ts index 65b0eefde..3fafef3ff 100644 --- a/packages/coding-agent/test/keybindings-display.test.ts +++ b/packages/coding-agent/test/keybindings-display.test.ts @@ -38,8 +38,8 @@ describe("getDefaultPasteImageKeys", () => { expect(getDefaultPasteImageKeys("win32")).toEqual(["ctrl+v", "alt+v"]); }); - it("uses Ctrl+V as the image-paste shortcut on non-Windows platforms", () => { + it("adds the macOS Command key event to Ctrl+V for image paste", () => { expect(getDefaultPasteImageKeys("linux")).toEqual(["ctrl+v"]); - expect(getDefaultPasteImageKeys("darwin")).toEqual(["ctrl+v"]); + expect(getDefaultPasteImageKeys("darwin")).toEqual(["ctrl+v", "super+v"]); }); }); From 5d07fe5041fc1b7b36b4dc4a04ed149b16c649e2 Mon Sep 17 00:00:00 2001 From: roboomp Date: Wed, 1 Jul 2026 22:10:59 +0000 Subject: [PATCH 2/2] style: bun run fix --- .../coding-agent/src/modes/components/custom-editor.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/coding-agent/src/modes/components/custom-editor.test.ts b/packages/coding-agent/src/modes/components/custom-editor.test.ts index c05eb45ef..18a5fd681 100644 --- a/packages/coding-agent/src/modes/components/custom-editor.test.ts +++ b/packages/coding-agent/src/modes/components/custom-editor.test.ts @@ -1,8 +1,8 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "bun:test"; -import { $ } from "bun"; import { setKittyProtocolActive } from "@oh-my-pi/pi-tui/keys"; -import { getEditorTheme, initTheme } from "../theme/theme"; +import { $ } from "bun"; import { getDefaultPasteImageKeys } from "../../config/keybindings"; +import { getEditorTheme, initTheme } from "../theme/theme"; import { CustomEditor, extractBracketedImagePastePaths, @@ -145,7 +145,6 @@ describe("CustomEditor configured paste image keys", () => { }); }); - describe("extractImagePathFromText (issue #3506)", () => { it("returns the path when the text is a single image file path", () => { expect(extractImagePathFromText("/tmp/screenshot.png")).toBe("/tmp/screenshot.png");