diff --git a/mobile/src/components/HostKindIcon.tsx b/mobile/src/components/HostKindIcon.tsx
new file mode 100644
index 00000000000..11fb9bb0b55
--- /dev/null
+++ b/mobile/src/components/HostKindIcon.tsx
@@ -0,0 +1,10 @@
+import { Monitor, Server } from 'lucide-react-native'
+import { parseExecutionHostId } from '../../../src/shared/execution-host'
+import { colors } from '../theme/mobile-theme'
+
+/** The desktop's own machine is a monitor, any other host a server, as on the desktop's run targets. */
+export function HostKindIcon({ hostId, size }: { hostId: string | undefined; size: number }) {
+ // Rows from hosts that predate hostId stamping are local: a remote row always carries one.
+ const Icon = (parseExecutionHostId(hostId)?.kind ?? 'local') === 'local' ? Monitor : Server
+ return
+}
diff --git a/mobile/src/components/NewWorktreeFormSheet.tsx b/mobile/src/components/NewWorktreeFormSheet.tsx
index 895b601b84b..3f4f8a725e2 100644
--- a/mobile/src/components/NewWorktreeFormSheet.tsx
+++ b/mobile/src/components/NewWorktreeFormSheet.tsx
@@ -24,7 +24,7 @@ export function NewWorktreeFormSheet(props: {
loading: boolean
hasRepos: boolean
project: Selection | null
- runTarget: Selection | null
+ runTarget: (Selection & { hostId: string }) | null
projectBadgeColor: string | null
selectedRepoIsGit: boolean
selectedRepoConnectionId: string | null
diff --git a/mobile/src/components/NewWorktreeModal.test.tsx b/mobile/src/components/NewWorktreeModal.test.tsx
index 459fdf4a4f2..5d1bbf450ff 100644
--- a/mobile/src/components/NewWorktreeModal.test.tsx
+++ b/mobile/src/components/NewWorktreeModal.test.tsx
@@ -184,7 +184,7 @@ describe('NewWorktreeModal project targets', () => {
expect(pickerItems(renderer, 'Run on')).toEqual([
expect.objectContaining({ label: LOCAL_HOST_LABEL, detail: '/src/orca' }),
expect.objectContaining({
- label: 'SSH · build-server',
+ label: 'build-server',
detail: '/home/dev/orca'
})
])
@@ -349,6 +349,7 @@ describe('NewWorktreeModal project targets', () => {
client: requestsOnly(desktop),
serverClients: new Map([['runtime:env-1', requestsOnly(server)]]),
hostId: 'host-1',
+ hostLabelById: new Map([['runtime:env-1', 'scratch-server']]),
onCreated,
onClose: () => {}
})
@@ -357,10 +358,26 @@ describe('NewWorktreeModal project targets', () => {
await flushUpdates()
const runTargets = pickerItems(renderer, 'Run on')
- expect(runTargets.map((item) => item.detail)).toEqual(['/src/orca', '/srv/orca'])
+ expect(runTargets.map((item) => [item.label, item.detail])).toEqual([
+ [LOCAL_HOST_LABEL, '/src/orca'],
+ ['scratch-server', '/srv/orca']
+ ])
const serverTarget = runTargetPicker(renderer)
+ const iconOf = (item: unknown) => {
+ let icon: ReactTestRenderer | undefined
+ act(() => {
+ icon = create(serverTarget.props.renderIcon(item))
+ })
+ return icon?.toJSON()
+ }
+ expect(serverTarget.props.items.map(iconOf)).toMatchObject([
+ { type: 'Monitor' },
+ { type: 'Server' }
+ ])
await act(async () => serverTarget.props.onSelect(serverTarget.props.items[1]))
await flushUpdates()
+ // The Run on field shows the picked server's glyph, as its row does.
+ expect(renderer.root.findAll((node) => node.type === 'Server')).toHaveLength(1)
expect(pickerItems(renderer, 'Run on')[0]?.label).toBe(LOCAL_HOST_LABEL)
act(() => sourceInputs(renderer)[0]!.props.onChangeText('srv-wt'))
const form = renderer.root.find((node) => typeof node.props.onCreate === 'function')
diff --git a/mobile/src/components/NewWorktreeModal.tsx b/mobile/src/components/NewWorktreeModal.tsx
index 1c3a310a674..222083fd70b 100644
--- a/mobile/src/components/NewWorktreeModal.tsx
+++ b/mobile/src/components/NewWorktreeModal.tsx
@@ -69,6 +69,7 @@ function NewWorktreeModalContent(props: NewWorktreeModalProps) {
client: desktopClient,
serverClients,
hostId,
+ hostLabelById,
existingWorktreePaths,
existingWorktrees,
openExternalUrl,
@@ -182,11 +183,11 @@ function NewWorktreeModalContent(props: NewWorktreeModalProps) {
const selectedProject =
projectPickerItems.find((project) => project.id === selectedProjectId) ?? null
const runTargetPickerItems = useMemo(
- () => buildNewWorkspaceRunTargetOptions(repos, selectedProjectId, hostPlatform),
- [hostPlatform, repos, selectedProjectId]
+ () => buildNewWorkspaceRunTargetOptions(repos, selectedProjectId, hostPlatform, hostLabelById),
+ [hostLabelById, hostPlatform, repos, selectedProjectId]
)
const selectedRunTarget = selectedRepo
- ? getNewWorkspaceRunTarget(selectedRepo, hostPlatform)
+ ? getNewWorkspaceRunTarget(selectedRepo, hostPlatform, hostLabelById)
: null
const needsSetupChoice = Boolean(setupScript.setupCommand) && setupScript.setupRunPolicy === 'ask'
const canCreate =
diff --git a/mobile/src/components/NewWorktreeModalController.tsx b/mobile/src/components/NewWorktreeModalController.tsx
index f73556bdc48..c00dfc03e9e 100644
--- a/mobile/src/components/NewWorktreeModalController.tsx
+++ b/mobile/src/components/NewWorktreeModalController.tsx
@@ -20,6 +20,7 @@ export const NewWorktreeModalController = forwardRef props.onRepoChange(item.repo)}
onClose={props.onTransitionToForm}
- renderIcon={() => }
+ renderIcon={(item) => }
/>
void
onOpenRunTarget: () => void
@@ -33,7 +34,7 @@ export function NewWorktreeProjectTargetFields({
Run on
-
+
diff --git a/mobile/src/components/WorktreeListRow.tsx b/mobile/src/components/WorktreeListRow.tsx
index 6a01c8f8766..3faaf00635a 100644
--- a/mobile/src/components/WorktreeListRow.tsx
+++ b/mobile/src/components/WorktreeListRow.tsx
@@ -1,21 +1,14 @@
import { memo } from 'react'
-import {
- Bell,
- ChevronDown,
- ChevronRight,
- GitBranch,
- GitPullRequest,
- Monitor,
- Server
-} from 'lucide-react-native'
+import { Bell, ChevronDown, ChevronRight, GitBranch, GitPullRequest } from 'lucide-react-native'
import { Pressable, StyleSheet, Text, View } from 'react-native'
-import { parseExecutionHostId, type ExecutionHostId } from '../../../src/shared/execution-host'
+import type { ExecutionHostId } from '../../../src/shared/execution-host'
import type { AgentWorkingMode } from '../../../src/shared/agent-status-types'
import type { RuntimeWorktreeAgentRow } from '../../../src/shared/runtime-types'
import type { MobileRenderableRepoIcon } from '../host-screen/host-screen-reply-schema'
import { triggerMediumImpact } from '../platform/haptics'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
import { AgentSpinner } from './AgentSpinner'
+import { HostKindIcon } from './HostKindIcon'
import { MobileRepoIcon } from './MobileRepoIcon'
import { WorktreeAgentList } from './WorktreeAgentList'
import { WorktreeMetaGlyphs, prStateColor } from './WorktreeMetaGlyphs'
@@ -173,13 +166,7 @@ function WorktreeListRowComponent({
.filter(Boolean)
.join(', ')}
>
- {/* Rows from hosts that predate hostId stamping are local: a remote row always carries one. */}
- {(parseExecutionHostId(item.hostContextHostId ?? item.hostId)?.kind ?? 'local') ===
- 'local' ? (
-
- ) : (
-
- )}
+
{item.hostContextLabel}
diff --git a/mobile/src/components/new-workspace-project-targets.test.ts b/mobile/src/components/new-workspace-project-targets.test.ts
index 18c379f2d14..d1e83550e9c 100644
--- a/mobile/src/components/new-workspace-project-targets.test.ts
+++ b/mobile/src/components/new-workspace-project-targets.test.ts
@@ -43,16 +43,16 @@ describe('new workspace project targets', () => {
expect(options[0]).toMatchObject({ label: 'orca', detail: 'stablyai/orca' })
})
- it('labels local, SSH, and paired runtime targets', () => {
+ it('labels local, SSH, and paired runtime targets as the host list names them', () => {
expect(
getNewWorkspaceRunTarget({ id: 'local', displayName: 'orca', path: '/src/orca' }, 'darwin')
- ).toEqual({ label: LOCAL_HOST_LABEL, detail: '/src/orca' })
+ ).toEqual({ hostId: 'local', label: LOCAL_HOST_LABEL, detail: '/src/orca' })
expect(
getNewWorkspaceRunTarget({ id: 'local', displayName: 'orca', path: 'C:\\src\\orca' })
- ).toEqual({ label: 'This computer', detail: 'C:\\src\\orca' })
+ ).toMatchObject({ label: 'This computer' })
expect(
getNewWorkspaceRunTarget({ id: 'local', displayName: 'orca', path: 'C:\\src\\orca' }, 'win32')
- ).toEqual({ label: 'Local Windows', detail: 'C:\\src\\orca' })
+ ).toMatchObject({ label: 'Local Windows' })
expect(
getNewWorkspaceRunTarget({
id: 'ssh',
@@ -60,15 +60,19 @@ describe('new workspace project targets', () => {
path: 'C:\\src\\orca',
executionHostId: 'ssh:Windows%20VM'
})
- ).toEqual({ label: 'SSH · Windows VM', detail: 'C:\\src\\orca' })
- expect(
- getNewWorkspaceRunTarget({
- id: 'runtime',
- displayName: 'orca',
- path: '/src/orca',
- executionHostId: 'runtime:devbox'
- })
- ).toEqual({ label: 'Remote · devbox', detail: '/src/orca' })
+ ).toEqual({ hostId: 'ssh:Windows%20VM', label: 'Windows VM', detail: 'C:\\src\\orca' })
+ const server = {
+ id: 'runtime',
+ displayName: 'orca',
+ path: '/src/orca',
+ executionHostId: 'runtime:20269ff3-60aa-4e79-a581-513a3f8e394b'
+ }
+ const labels = new Map([[server.executionHostId, 'scratch-server']] as const)
+ expect(getNewWorkspaceRunTarget(server, 'darwin', labels)).toEqual({
+ hostId: server.executionHostId,
+ label: 'scratch-server',
+ detail: '/src/orca'
+ })
})
it('shows one target per host when the project has multiple local worktrees', () => {
@@ -90,7 +94,7 @@ describe('new workspace project targets', () => {
expect.objectContaining({ id: 'local', label: LOCAL_HOST_LABEL, detail: '/src/orca-a' }),
expect.objectContaining({
id: 'ssh:build-server',
- label: 'SSH · build-server',
+ label: 'build-server',
detail: '/home/dev/orca'
})
])
diff --git a/mobile/src/components/new-workspace-project-targets.ts b/mobile/src/components/new-workspace-project-targets.ts
index 20c46aafd3b..c3f5d436a40 100644
--- a/mobile/src/components/new-workspace-project-targets.ts
+++ b/mobile/src/components/new-workspace-project-targets.ts
@@ -1,14 +1,10 @@
import type { Repo } from '../../../src/shared/repo-types'
-import {
- getExecutionHostLabel,
- getLocalExecutionHostLabel,
- getRepoExecutionHostId,
- parseExecutionHostId
-} from '../../../src/shared/execution-host'
+import { getRepoExecutionHostId, type ExecutionHostId } from '../../../src/shared/execution-host'
import {
getProjectIdentityKey,
getProjectProviderIdentity
} from '../../../src/shared/project-host-setup-projection'
+import { getHostContextLabel } from '../../../src/shared/worktree/host-context-labels'
type WorkspaceRepo = Pick &
Partial<
@@ -24,6 +20,7 @@ export type NewWorkspaceProjectOption = {
export type NewWorkspaceRunTargetOption = {
id: string
+ hostId: ExecutionHostId
label: string
detail: string
repo: TRepo
@@ -58,24 +55,23 @@ export function buildNewWorkspaceProjectOptions(
})
}
+/** Named like the host list's badge; the desktop's picker shows the bare host label too. */
export function getNewWorkspaceRunTarget(
repo: WorkspaceRepo,
- localPlatform: NodeJS.Platform | null = null
+ localPlatform: NodeJS.Platform | null = null,
+ hostLabelById?: ReadonlyMap
): {
+ hostId: ExecutionHostId
label: string
detail: string
} {
const hostId = getRepoExecutionHostId(repo)
- const host = parseExecutionHostId(hostId)
- const hostLabel = getExecutionHostLabel(hostId)
- if (host?.kind === 'ssh') {
- return { label: `SSH · ${hostLabel}`, detail: repo.path }
- }
- if (host?.kind === 'runtime') {
- return { label: `Remote · ${hostLabel}`, detail: repo.path }
- }
return {
- label: localPlatform ? getLocalExecutionHostLabel(localPlatform) : 'This computer',
+ hostId,
+ label: getHostContextLabel(hostId, {
+ hostLabelById,
+ hostPlatform: localPlatform
+ }),
detail: repo.path
}
}
@@ -83,7 +79,8 @@ export function getNewWorkspaceRunTarget(
export function buildNewWorkspaceRunTargetOptions(
repos: readonly TRepo[],
projectId: string | null,
- localPlatform: NodeJS.Platform | null = null
+ localPlatform: NodeJS.Platform | null = null,
+ hostLabelById?: ReadonlyMap
): NewWorkspaceRunTargetOption[] {
if (!projectId) {
return []
@@ -98,7 +95,7 @@ export function buildNewWorkspaceRunTargetOptions(
// Keyed by host: a repo id names one repo per host, so two hosts can share one.
options.set(hostId, {
id: hostId,
- ...getNewWorkspaceRunTarget(repo, localPlatform),
+ ...getNewWorkspaceRunTarget(repo, localPlatform, hostLabelById),
repo
})
}
diff --git a/mobile/src/components/new-worktree-modal-types.ts b/mobile/src/components/new-worktree-modal-types.ts
index 13cfd38b101..b943d06b608 100644
--- a/mobile/src/components/new-worktree-modal-types.ts
+++ b/mobile/src/components/new-worktree-modal-types.ts
@@ -24,6 +24,8 @@ export type NewWorktreeModalProps = {
/** The desktop's servers this phone can reach now; their repos are offered and created there. */
serverClients?: ReadonlyMap
hostId?: string
+ /** The host list's badge labels, so a run target reads as its row does. */
+ hostLabelById?: ReadonlyMap
existingWorktreePaths?: readonly string[]
existingWorktrees?: readonly { repoId: string; branch: string }[]
openExternalUrl: (url: string) => void
diff --git a/mobile/src/host-screen/host-screen-overlays.tsx b/mobile/src/host-screen/host-screen-overlays.tsx
index 153c90cc3ce..2eda461fa43 100644
--- a/mobile/src/host-screen/host-screen-overlays.tsx
+++ b/mobile/src/host-screen/host-screen-overlays.tsx
@@ -31,6 +31,7 @@ export function HostScreenOverlays({ controller }: { controller: HostScreenContr
existingWorktreePaths,
hostCapabilities,
hostId,
+ hostLabels,
settings,
showNewWorktree,
state
@@ -229,6 +230,7 @@ export function HostScreenOverlays({ controller }: { controller: HostScreenContr
client={client}
serverClients={serverClients}
hostId={hostId}
+ hostLabelById={hostLabels.hostLabelById}
existingWorktreePaths={existingWorktreePaths}
existingWorktrees={state.worktrees}
// The seam, not react-native's `Linking`: this screen is in the tasks page closure, and
diff --git a/mobile/src/host-screen/host-server-workspaces-wiring.test.ts b/mobile/src/host-screen/host-server-workspaces-wiring.test.ts
index 39dfea137dc..9813d2a6a5e 100644
--- a/mobile/src/host-screen/host-server-workspaces-wiring.test.ts
+++ b/mobile/src/host-screen/host-server-workspaces-wiring.test.ts
@@ -18,11 +18,15 @@ vi.mock('../transport/use-worktree-resync', () => ({
}))
import { MOBILE_DESKTOP_RELAY_RUNTIME_CAPABILITY } from '../../../src/shared/mobile-desktop-relay-contract'
+import {
+ recordHostDescriptor,
+ resetHostDescriptorStoreForTests
+} from '../transport/host-descriptor-store'
import { FakeSession } from '../transport/mobile-endpoint-supervisor-test-fakes'
import type { RpcResponse } from '../transport/types'
import { readVisibleHostIds } from '../worktree/visible-host-rows'
import type { Worktree } from '../worktree/workspace-list-types'
-import { useHostDisplayWorktrees } from './use-host-display-worktrees'
+import { useHostDisplayWorktrees, useHostLabelSources } from './use-host-display-worktrees'
import { useHostScreenState } from './use-host-screen-state'
import { useHostWorktreeActions } from './use-host-worktree-actions'
import { useHostWorktreeCatalog } from './use-host-worktree-catalog'
@@ -145,7 +149,7 @@ async function mountScreen(first: FakeSession, hostCapabilities: string[]): Prom
})
held.state = state
held.fetch = catalog.fetchWorktrees
- held.rows = useHostDisplayWorktrees('connected', state)
+ held.rows = useHostDisplayWorktrees('connected', state, useHostLabelSources('host-1', state))
return null
}
await act(async () => {
@@ -213,6 +217,19 @@ describe("a desktop's server workspaces on the phone", () => {
])
})
+ it("names the desktop's own row for the desktop's platform once servers mix the list", async () => {
+ recordHostDescriptor('host-1', { machineName: null, platform: 'darwin' })
+ try {
+ const screen = await mountScreen(desktop(), RELAYS)
+ expect(screen.rows()[0]).toMatchObject({
+ worktreeId: 'mac-wt',
+ hostContextLabel: 'Local Mac'
+ })
+ } finally {
+ resetHostDescriptorStoreForTests()
+ }
+ })
+
it('keeps showing today’s view under an older desktop or an older shell', async () => {
const oldDesktop = desktop()
const oldShell = desktop({ carriesExecutionHost: false })
diff --git a/mobile/src/host-screen/host-ssh-health-badge-wiring.test.ts b/mobile/src/host-screen/host-ssh-health-badge-wiring.test.ts
index ffd7e73f63a..90ff4e31cd8 100644
--- a/mobile/src/host-screen/host-ssh-health-badge-wiring.test.ts
+++ b/mobile/src/host-screen/host-ssh-health-badge-wiring.test.ts
@@ -11,7 +11,7 @@ vi.mock('../cache/repo-cache', () => ({ setCachedRepos: () => {} }))
import { FakeSession } from '../transport/mobile-endpoint-supervisor-test-fakes'
import type { RpcResponse } from '../transport/types'
import type { Worktree } from '../worktree/workspace-list-types'
-import { useHostDisplayWorktrees } from './use-host-display-worktrees'
+import { useHostDisplayWorktrees, useHostLabelSources } from './use-host-display-worktrees'
import { useHostRepoMetadata } from './use-host-repo-metadata'
import { useHostScreenState } from './use-host-screen-state'
@@ -68,7 +68,7 @@ async function displayedRows(args: {
state.clientRef.current = client
setWorktrees = state.setWorktrees
seen.refresh = useHostRepoMetadata({ client, connState: 'connected', hostId: 'host-1', state })
- seen.rows = useHostDisplayWorktrees('connected', state)
+ seen.rows = useHostDisplayWorktrees('connected', state, useHostLabelSources('host-1', state))
return null
}
await act(async () => {
diff --git a/mobile/src/host-screen/use-host-display-worktrees.ts b/mobile/src/host-screen/use-host-display-worktrees.ts
index 3631d1f4cc3..86f85c9c94d 100644
--- a/mobile/src/host-screen/use-host-display-worktrees.ts
+++ b/mobile/src/host-screen/use-host-display-worktrees.ts
@@ -1,14 +1,21 @@
import { useMemo } from 'react'
import type { ExecutionHostId } from '../../../src/shared/execution-host'
+import { useHostDescriptor } from '../transport/host-descriptor-store'
import type { ConnectionState } from '../transport/types'
import { serverHostHealth } from '../worktree/server-workspaces'
import { filterVisibleHostRows } from '../worktree/visible-host-rows'
-import { applyWorktreeHostContextLabels } from '../worktree/worktree-host-context-labels'
+import {
+ applyWorktreeHostContextLabels,
+ type HostLabelSources
+} from '../worktree/worktree-host-context-labels'
import { applyWorktreeRowDisplayState } from '../worktree/worktree-host-row-identity'
import type { HostScreenState } from './use-host-screen-state'
-/** The rows the host list renders: the live or last-known catalog with display state and host badges. */
-export function useHostDisplayWorktrees(connState: ConnectionState, state: HostScreenState) {
+/** What names each host on this screen: the row badges and the new-workspace run targets. */
+export function useHostLabelSources(
+ hostId: string | undefined,
+ state: HostScreenState
+): HostLabelSources {
const { serverWorkspaces } = state
// Why: a server's label and health come with its rows, alongside the desktop's SSH ones.
const hostLabelById = useMemo(
@@ -19,36 +26,49 @@ export function useHostDisplayWorktrees(connState: ConnectionState, state: HostS
() => withServerHosts(state.hostHealthById, serverWorkspaces.hosts, serverHostHealth),
[state.hostHealthById, serverWorkspaces.hosts]
)
+ const descriptorPlatform = useHostDescriptor(hostId)?.platform ?? null
+ // Why: metadata reads the platform only for a mixed desktop catalog; server rows mix it too.
+ const hostPlatform = state.hostPlatform ?? descriptorPlatform
+ return useMemo(
+ () => ({
+ repoHostIdByRepoId: state.repoHostIdByRepoId,
+ hostLabelById,
+ hostPlatform,
+ hostHealthById
+ }),
+ [state.repoHostIdByRepoId, hostLabelById, hostPlatform, hostHealthById]
+ )
+}
+
+/** The rows the host list renders: the live or last-known catalog with display state and host badges. */
+export function useHostDisplayWorktrees(
+ connState: ConnectionState,
+ state: HostScreenState,
+ labels: HostLabelSources
+) {
return useMemo(() => {
// Why: live `worktrees` is authoritative only while connected; under the amber
// mount default, connecting/handshaking must keep the pre-reconnect list too.
const base = connState === 'connected' ? state.worktrees : state.lastKnownWorktrees
const rows = filterVisibleHostRows(
- [...base, ...serverWorkspaces.worktrees],
+ [...base, ...state.serverWorkspaces.worktrees],
state.visibleHostIds,
state.repoHostIdByRepoId
)
return applyWorktreeHostContextLabels(
applyWorktreeRowDisplayState(rows, state.sleptIds, state.optimisticActiveWorktreeIdentity),
- {
- repoHostIdByRepoId: state.repoHostIdByRepoId,
- hostLabelById,
- hostPlatform: state.hostPlatform,
- hostHealthById
- }
+ labels
)
}, [
connState,
state.worktrees,
state.lastKnownWorktrees,
- serverWorkspaces.worktrees,
+ state.serverWorkspaces.worktrees,
state.visibleHostIds,
state.sleptIds,
state.optimisticActiveWorktreeIdentity,
state.repoHostIdByRepoId,
- hostLabelById,
- state.hostPlatform,
- hostHealthById
+ labels
])
}
diff --git a/mobile/src/host-screen/use-host-screen-controller.ts b/mobile/src/host-screen/use-host-screen-controller.ts
index b3e8620b54f..cbb91f89b3f 100644
--- a/mobile/src/host-screen/use-host-screen-controller.ts
+++ b/mobile/src/host-screen/use-host-screen-controller.ts
@@ -15,7 +15,7 @@ import {
useRelayRecoveryStatus
} from '../transport/client-context-connection-metrics'
import { useWorkspaceSections } from '../worktree/use-workspace-sections'
-import { useHostDisplayWorktrees } from './use-host-display-worktrees'
+import { useHostDisplayWorktrees, useHostLabelSources } from './use-host-display-worktrees'
import { useHostRepoMetadata } from './use-host-repo-metadata'
import { useHostScreenIdentity } from './use-host-screen-identity'
import { useHostScreenState } from './use-host-screen-state'
@@ -103,7 +103,8 @@ export function useHostScreenController({
}
const showNewWorktree = resolvedRouteActionState.showNewWorktree
- const displayWorktrees = useHostDisplayWorktrees(connState, state)
+ const hostLabels = useHostLabelSources(hostId, state)
+ const displayWorktrees = useHostDisplayWorktrees(connState, state, hostLabels)
const sectionsResult = useWorkspaceSections({
displayWorktrees,
sortMode: state.sortMode,
@@ -135,6 +136,7 @@ export function useHostScreenController({
hostCapabilities,
hostDisplay,
hostId,
+ hostLabels,
insets,
isReadOnly: connState === 'auth-failed',
isWideLayout,