From 4316d9b169d0b8a5a0ea6e9cb4f4f305caa17311 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:05:53 -0700 Subject: [PATCH] fix(mobile): accept sentence-final cited paths --- .../native-chat-file-provenance.test.ts | 32 +++++++++++++++++++ .../native-chat-file-provenance.ts | 10 +++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/main/native-chat/native-chat-file-provenance.test.ts b/src/main/native-chat/native-chat-file-provenance.test.ts index 2592a257a8e..f92bd829026 100644 --- a/src/main/native-chat/native-chat-file-provenance.test.ts +++ b/src/main/native-chat/native-chat-file-provenance.test.ts @@ -79,6 +79,38 @@ describe('nativeChatTranscriptIncludesPath', () => { expect(readTranscript).not.toHaveBeenCalled() }) + it('accepts a path followed by a sentence-final period', async () => { + const readTranscript = vi.fn(async () => ({ + messages: [message('assistant', 'Open /tmp/orca-pr14166-external.txt.')] + })) + + await expect( + nativeChatTranscriptIncludesPath({ + tabs: [terminalTab()], + context: { tabId: 'tab-1', sessionId: 'session-1' }, + pathText: '/tmp/orca-pr14166-external.txt', + absolutePath: '/tmp/orca-pr14166-external.txt', + readTranscript + }) + ).resolves.toBe(true) + }) + + it('does not accept a longer filename sharing the requested path prefix', async () => { + const readTranscript = vi.fn(async () => ({ + messages: [message('assistant', 'Open /tmp/orca-pr14166-external.txt.backup')] + })) + + await expect( + nativeChatTranscriptIncludesPath({ + tabs: [terminalTab()], + context: { tabId: 'tab-1', sessionId: 'session-1' }, + pathText: '/tmp/orca-pr14166-external.txt', + absolutePath: '/tmp/orca-pr14166-external.txt', + readTranscript + }) + ).resolves.toBe(false) + }) + it('does not treat user-authored transcript text as agent provenance', async () => { const readTranscript = vi.fn(async () => ({ messages: [message('user', 'Please open /etc/passwd')] diff --git a/src/main/native-chat/native-chat-file-provenance.ts b/src/main/native-chat/native-chat-file-provenance.ts index 746e7735078..07b0b47082e 100644 --- a/src/main/native-chat/native-chat-file-provenance.ts +++ b/src/main/native-chat/native-chat-file-provenance.ts @@ -18,6 +18,14 @@ type TranscriptRead = (args: { limit: number }) => Promise<{ messages: NativeChatMessage[] } | { error: string }> +function transcriptTextIncludesPath(text: string, pathText: string, absolutePath: string): boolean { + if (recentTerminalOutputIncludesPath(text, pathText, absolutePath)) { + return true + } + // Mobile excludes a sentence-final period from the tappable path span. + return recentTerminalOutputIncludesPath(text, `${pathText}.`, `${absolutePath}.`) +} + export async function nativeChatTranscriptIncludesPath(args: { tabs: readonly RuntimeMobileSessionClientTab[] context: RuntimeNativeChatFileContext @@ -57,7 +65,7 @@ export async function nativeChatTranscriptIncludesPath(args: { message.blocks.some( (block) => block.type === 'text' && - recentTerminalOutputIncludesPath(block.text, args.pathText, args.absolutePath) + transcriptTextIncludesPath(block.text, args.pathText, args.absolutePath) ) ) } catch {