From ebc656f71f6304f5310c629ddc087b7370ff5df4 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Thu, 13 Aug 2026 22:31:59 -0700 Subject: [PATCH] fix(mobile): preserve explicit repository ownership --- .../src/components/NewWorktreeModal.test.tsx | 7 +++-- .../new-workspace-repo-detail.test.ts | 30 ++++++++++++++++++ .../components/new-workspace-repo-detail.ts | 31 +++++++++++++------ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/mobile/src/components/NewWorktreeModal.test.tsx b/mobile/src/components/NewWorktreeModal.test.tsx index e3a4a329b80..997d8710b26 100644 --- a/mobile/src/components/NewWorktreeModal.test.tsx +++ b/mobile/src/components/NewWorktreeModal.test.tsx @@ -1,5 +1,5 @@ import { createElement } from 'react' -import { act, create, type ReactTestRenderer } from 'react-test-renderer' +import { act, create } from 'react-test-renderer' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { RpcClient } from '../transport/rpc-client' @@ -47,15 +47,16 @@ import { setCachedRepos } from '../cache/repo-cache' import { NewWorktreeModal } from './NewWorktreeModal' const repos = [{ id: 'repo-1', displayName: 'orca', path: '/src/orca', kind: 'git' }] +type TestRenderer = ReturnType -function repoPickerItems(renderer: ReactTestRenderer | null): { label: string; detail: string }[] { +function repoPickerItems(renderer: TestRenderer | null): { label: string; detail: string }[] { const pickers = renderer?.root.findAll((node) => node.type === 'PickerListDrawer') ?? [] const repoPicker = pickers.find((node) => node.props.title === 'Repository') return repoPicker?.props.items ?? [] } describe('NewWorktreeModal repo list', () => { - let renderer: ReactTestRenderer | null = null + let renderer: TestRenderer | null = null beforeEach(() => { setCachedRepos('host-1', repos) diff --git a/mobile/src/components/new-workspace-repo-detail.test.ts b/mobile/src/components/new-workspace-repo-detail.test.ts index aeb0de81b63..7033454c0bb 100644 --- a/mobile/src/components/new-workspace-repo-detail.test.ts +++ b/mobile/src/components/new-workspace-repo-detail.test.ts @@ -23,4 +23,34 @@ describe('new workspace repository detail', () => { getNewWorkspaceRepoDetail({ path: '/src/orca', executionHostId: 'runtime:devbox' }) ).toBe('Remote · devbox · /src/orca') }) + + it('prefers the explicit execution host over stale SSH metadata', () => { + expect( + getNewWorkspaceRepoDetail({ + path: '/src/orca', + connectionId: 'old-ssh-target', + executionHostId: 'runtime:devbox' + }) + ).toBe('Remote · devbox · /src/orca') + expect( + getNewWorkspaceRepoDetail({ + path: '/src/orca', + connectionId: 'old-ssh-target', + executionHostId: 'local' + }) + ).toBe('Local · /src/orca') + }) + + it('falls back when an execution host label is malformed', () => { + expect( + getNewWorkspaceRepoDetail({ + path: '/src/orca', + connectionId: 'build-server', + executionHostId: 'ssh:%E0%A4%A' + }) + ).toBe('SSH · build-server · /src/orca') + expect(getNewWorkspaceRepoDetail({ path: '/src/orca', executionHostId: 'runtime:' })).toBe( + 'Local · /src/orca' + ) + }) }) diff --git a/mobile/src/components/new-workspace-repo-detail.ts b/mobile/src/components/new-workspace-repo-detail.ts index 8e719d0d4b8..9e9ae9a3752 100644 --- a/mobile/src/components/new-workspace-repo-detail.ts +++ b/mobile/src/components/new-workspace-repo-detail.ts @@ -4,25 +4,38 @@ type RepoLocation = { executionHostId?: 'local' | `ssh:${string}` | `runtime:${string}` | null } -function executionHostName(executionHostId: string): string { +function executionHostName(executionHostId: string): string | null { const encodedName = executionHostId.slice(executionHostId.indexOf(':') + 1) + if (!encodedName) { + return null + } try { - return decodeURIComponent(encodedName) + return decodeURIComponent(encodedName) || null } catch { - return encodedName + return null } } export function getNewWorkspaceRepoDetail(repo: RepoLocation): string { + const executionHostId = repo.executionHostId?.trim() + if (executionHostId === 'local') { + return `Local · ${repo.path}` + } + if (executionHostId?.startsWith('ssh:')) { + const hostName = executionHostName(executionHostId) + if (hostName) { + return `SSH · ${hostName} · ${repo.path}` + } + } + if (executionHostId?.startsWith('runtime:')) { + const hostName = executionHostName(executionHostId) + if (hostName) { + return `Remote · ${hostName} · ${repo.path}` + } + } const connectionId = repo.connectionId?.trim() if (connectionId) { return `SSH · ${connectionId} · ${repo.path}` } - if (repo.executionHostId?.startsWith('ssh:')) { - return `SSH · ${executionHostName(repo.executionHostId)} · ${repo.path}` - } - if (repo.executionHostId?.startsWith('runtime:')) { - return `Remote · ${executionHostName(repo.executionHostId)} · ${repo.path}` - } return `Local · ${repo.path}` }