From 8af67c6b997b96f099e0900a31445fa1f2f9392f Mon Sep 17 00:00:00 2001 From: Merge Sim Date: Fri, 4 Sep 2026 01:50:59 -0700 Subject: [PATCH] fix(mobile): separate the terminal-mode image attach path too (STA-4847) The dock attach button wrote a bare bracketed paste, so the user's next keystroke glued onto the path -- the ticket's exact `...pngadd`, reproduced on device. Attach-then-type is the whole interaction here, so unlike native chat there is no following text to test: always separate. Desktop's twin of this button is terminal-drop-path-writer, which #15820 already routed through the shared helper. Terminal clipboard paste stays bare on both platforms, tracked separately (desktop: STA-5258). --- mobile/src/session/mobile-image-attachment.test.ts | 4 +++- mobile/src/session/mobile-image-attachment.ts | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mobile/src/session/mobile-image-attachment.test.ts b/mobile/src/session/mobile-image-attachment.test.ts index 9d725d5fe60..eead9691303 100644 --- a/mobile/src/session/mobile-image-attachment.test.ts +++ b/mobile/src/session/mobile-image-attachment.test.ts @@ -50,7 +50,9 @@ describe('attachMobileImageToTerminal', () => { const sendCall = client.calls.find((c) => c.method === 'terminal.send') expect(sendCall?.params).toEqual({ terminal: 'term-1', - text: '\x1b[200~/tmp/orca-attach.png\x1b[201~', + // Trailing space: the user types on this same line next, so a bare + // `…\x1b[201~` would arrive as `…pngadd` (STA-4847). + text: '\x1b[200~/tmp/orca-attach.png\x1b[201~ ', enter: false, client: { id: 'device-9', type: 'mobile' } }) diff --git a/mobile/src/session/mobile-image-attachment.ts b/mobile/src/session/mobile-image-attachment.ts index 567be99a9a1..9cb7d60aa8e 100644 --- a/mobile/src/session/mobile-image-attachment.ts +++ b/mobile/src/session/mobile-image-attachment.ts @@ -1,4 +1,5 @@ import type { RpcClient } from '../transport/rpc-client' +import { separateImagePasteFromFollowingText } from '../../../src/shared/image-paste-following-text' import { buildMobileImagePastePayload, saveMobileClipboardImageAsTempFile @@ -47,7 +48,10 @@ export async function attachMobileImageToTerminal( }) // Why: a generated image path is terminal image injection, so it's always // bracketed (matching desktop paste) regardless of terminal mode. - const payload = buildMobileImagePastePayload(imagePath) + // Always separated: attach-then-type is the whole interaction here, so the user's + // next keystroke would otherwise glue onto the path (`…pngadd`). Unlike native + // chat there is no batch to look ahead in, and a trailing space is inert. + const payload = separateImagePasteFromFollowingText(buildMobileImagePastePayload(imagePath), true) if (beforeTerminalSend && !(await beforeTerminalSend(terminal))) { return false }