From 2d33f7df225fbfb4d81c760413ea5ffa316d3372 Mon Sep 17 00:00:00 2001
From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
Date: Fri, 23 Oct 2026 22:00:12 -0700
Subject: [PATCH 1/4] fix(native-chat): name workspaces by folder in the resume
dialog while workspaces load
On restart the resume dialog opens before the full workspace list loads, so
every row it could not look up showed its raw repo-qualified id. Fall back to
the folder name the id carries, as the status bar and Automations already do.
---
.../components/NativeChatResumeOnRestartGroups.test.tsx | 8 ++++++++
.../src/components/NativeChatResumeOnRestartGroups.tsx | 9 +++++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
index 70c7dfdbf24e..b6fd5e0b6953 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
@@ -207,6 +207,14 @@ it('names a workspace the store does not know by its id, with the kind the host
expect(chatBox('lost').getAttribute('aria-label')).toContain('in folder:missing-folder')
})
+it('names a git worktree the store does not know by its folder, not its repo-qualified id', () => {
+ render({ candidates: [candidate('lost', worktree('blobfish-2'))] })
+
+ expect(nodeBox('blobfish-2')).not.toBeNull()
+ expect(chatBox('lost').getAttribute('aria-label')).toContain('in blobfish-2')
+ expect(container.textContent).not.toContain('repo-1::')
+})
+
// Its project is unknown too: a nameless "Select all chats in " checkbox would help no one.
it('gives workspaces the store cannot place no project node', () => {
const unknown: ResumeCandidate = {
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
index 42d5cc23301c..969a36063371 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
@@ -9,6 +9,7 @@ import {
resolveWorktreeDisplayName
} from '@/lib/worktree-default-display-name'
import { getHostContextLabel } from '../../../shared/worktree/host-context-labels'
+import { getWorktreePathBasenameFromId } from '../../../shared/worktree/id'
import {
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
@@ -57,7 +58,8 @@ export type { ResumeCandidate } from './native-chat-resume-on-restart-grouping'
* level shows only when the machine is not obvious (a remote host, or chats on more than one), and
* then it is what names the host, so no workspace repeats it.
*
- * A workspace the store does not know yet (host connecting, or deleted) is named by its id.
+ * A workspace the store does not know yet (host connecting, or deleted) is named by its folder, the
+ * name its id carries.
*/
/** A group node: its row, then (while open) what is under it. */
@@ -124,7 +126,10 @@ function WorkspaceNode({
const kind = first ? resumeWorkspaceKind(first) : 'git-worktree'
// Kind comes from the host's record, never from a name.
const KindGlyph = kind === 'folder' ? Folder : GitBranch
- const name = (worktree && resolveWorktreeDisplayName(worktree)) || group.workspaceId
+ const name =
+ (worktree && resolveWorktreeDisplayName(worktree)) ||
+ getWorktreePathBasenameFromId(group.workspaceId) ||
+ group.workspaceId
const branch = worktree && kind === 'git-worktree' ? resolveWorktreeBranchLabel(worktree) : ''
return (
Date: Fri, 23 Oct 2026 22:29:39 -0700
Subject: [PATCH 2/4] fix: distinguish unknown resume workspaces with matching
folder names
---
.../NativeChatResumeOnRestartGroups.test.tsx | 71 ++++++++++++++++++-
.../NativeChatResumeOnRestartGroups.tsx | 36 +++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
index b6fd5e0b6953..c98dea9e97ab 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
@@ -4,7 +4,8 @@
import { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
-import { afterEach, beforeEach, expect, it } from 'vitest'
+import { afterEach, beforeEach, expect, it, vi } from 'vitest'
+import * as worktreeIds from '../../../shared/worktree/id'
import { useAppStore } from '../store'
import { getDefaultSettings } from '../../../shared/constants'
import { getHostContextLabel } from '../../../shared/worktree/host-context-labels'
@@ -41,6 +42,7 @@ beforeEach(() => {
afterEach(() => {
act(() => root.unmount())
+ vi.restoreAllMocks()
container.remove()
useAppStore.setState(useAppStore.getInitialState(), true)
})
@@ -215,6 +217,73 @@ it('names a git worktree the store does not know by its folder, not its repo-qua
expect(container.textContent).not.toContain('repo-1::')
})
+it('disambiguates only colliding unknown folders with linear display work on render', () => {
+ const known = worktree('main', { displayName: 'Configured', hostId: 'local' })
+ useAppStore.setState({ worktreesByRepo: { 'repo-1': [known] } })
+ const controls = [
+ candidate('known', known),
+ candidate('unique', worktree('blobfish-2')),
+ candidate('opaque', worktree('opaque', { id: 'folder:missing-folder' }))
+ ]
+ const basename = vi.spyOn(worktreeIds, 'getWorktreePathBasenameFromId')
+ let nameReads = 0
+ const mapSet = Map.prototype.set
+ vi.spyOn(Map.prototype, 'set').mockImplementation(
+ function (this: Map, key, value) {
+ if (typeof value?.parentPath === 'string' && value.name === 'main') {
+ const name = value.name
+ Object.defineProperty(value, 'name', {
+ get: () => {
+ nameReads++
+ return name
+ }
+ })
+ }
+ return mapSet.call(this, key, value)
+ }
+ )
+ const operations: number[] = []
+ let unknown: ResumeCandidate[] = []
+ for (const size of [10, 100]) {
+ unknown = Array.from({ length: size }, (_, index) =>
+ candidate(
+ `lost-${index}`,
+ worktree('main', {
+ id: `repo-1::/Users/test/projects/organization/orca/workspaces/client-${index}/main`
+ })
+ )
+ )
+ basename.mockClear()
+ nameReads = 0
+ render({ candidates: [...controls, ...unknown] })
+ const parses = basename.mock.calls.filter(([id]) => id.startsWith('repo-1::/Users/')).length
+ const work = parses + nameReads
+ expect(Math.min(parses, nameReads)).toBeGreaterThanOrEqual(size)
+ expect(work).toBeLessThanOrEqual(6 * size)
+ operations.push(work)
+ for (const index of [0, 1]) {
+ const parent = `/Users/test/projects/organization/orca/workspaces/client-${index}`
+ const detail = container.querySelector(`[title="${parent}"]`)
+ expect(detail?.textContent).toBe(parent)
+ expect(detail?.lastElementChild?.textContent).toBe(`/workspaces/client-${index}`)
+ }
+ expect(itemOf(nodeBox('Configured')).textContent).toContain('main-branch')
+ expect(itemOf(nodeBox('blobfish-2')).querySelector('[title]')).toBeNull()
+ expect(nodeBox('folder:missing-folder')).not.toBeNull()
+ }
+ expect(operations[1]).toBeLessThanOrEqual(12 * operations[0]!)
+ const collisionBoxes = container.querySelectorAll(
+ '[aria-label="Select all chats in main"]'
+ )
+ act(() => collisionBoxes[1]!.click())
+ expect(onToggleSpy).toHaveBeenCalledExactlyOnceWith('lost-1', false)
+ render({ candidates: unknown.slice(0, 2) })
+ const hydrated = { ...known, id: unknown[0]!.workspaceId, displayName: 'Resolved' }
+ act(() => useAppStore.setState({ worktreesByRepo: { 'repo-1': [known, hydrated] } }))
+ expect(nodeBox('Resolved')).not.toBeNull()
+ expect(itemOf(nodeBox('main')).querySelector('[title]')).toBeNull()
+})
+
// Its project is unknown too: a nameless "Select all chats in " checkbox would help no one.
it('gives workspaces the store cannot place no project node', () => {
const unknown: ResumeCandidate = {
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
index 969a36063371..db0a336ae18b 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
@@ -1,15 +1,20 @@
import { useContext, useMemo } from 'react'
import { Folder, FolderTree, GitBranch, Monitor } from 'lucide-react'
import { RepoIconGlyph } from '@/components/repo/repo-icon'
+import { ProjectOptionDetail } from '@/components/new-workspace/ProjectComboboxRow'
import { WorktreeHostContextBadge } from '@/components/sidebar/WorktreeHostContextBadge'
import { useSidebarHostScopeOptions } from '@/components/sidebar/use-sidebar-host-scope-options'
import { translate } from '@/i18n/i18n'
+import { dirname } from '@/lib/path'
import {
resolveWorktreeBranchLabel,
resolveWorktreeDisplayName
} from '@/lib/worktree-default-display-name'
import { getHostContextLabel } from '../../../shared/worktree/host-context-labels'
-import { getWorktreePathBasenameFromId } from '../../../shared/worktree/id'
+import {
+ getWorktreePathBasenameFromId,
+ splitWorktreeIdForFilesystem
+} from '../../../shared/worktree/id'
import {
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
@@ -49,6 +54,8 @@ import {
export type { ResumeCandidate } from './native-chat-resume-on-restart-grouping'
+type WorkspaceFallback = { name: string; parentPath: string }
+
/**
* The offered chats as a tree: machine, then project, then workspace (a child workspace is a node
* inside its parent, after the parent's chats), then the chats.
@@ -113,12 +120,14 @@ function WorkspaceNode({
node,
hostId,
depth,
- tree
+ tree,
+ fallbackDisplays
}: {
node: ResumeWorkspaceNode
hostId: ExecutionHostId
depth: number
tree: TreeProps
+ fallbackDisplays?: ReadonlyMap
}): React.JSX.Element {
const { group } = node
const first = group.candidates[0]
@@ -126,8 +135,10 @@ function WorkspaceNode({
const kind = first ? resumeWorkspaceKind(first) : 'git-worktree'
// Kind comes from the host's record, never from a name.
const KindGlyph = kind === 'folder' ? Folder : GitBranch
+ const fallback = fallbackDisplays?.get(group)
const name =
(worktree && resolveWorktreeDisplayName(worktree)) ||
+ fallback?.name ||
getWorktreePathBasenameFromId(group.workspaceId) ||
group.workspaceId
const branch = worktree && kind === 'git-worktree' ? resolveWorktreeBranchLabel(worktree) : ''
@@ -152,6 +163,12 @@ function WorkspaceNode({
{branch}
)}
+ {!worktree && fallback?.parentPath && (
+
+ )}
>
}
>
@@ -181,6 +198,7 @@ function WorkspaceNode({
hostId={hostId}
depth={depth + 1}
tree={tree}
+ fallbackDisplays={fallbackDisplays}
/>
))}
@@ -277,6 +295,19 @@ function MachineContents({
<>
{groupResumeWorkspacesByRepo(workspaces, lookup(tree.repoIdOf, null)).map((repoGroup) => {
const nodes = nestResumeWorkspaces(repoGroup.workspaces, ancestorsOf)
+ const fallbackDisplays = new Map()
+ if (repoGroup.repoId === null) {
+ const countByName = new Map()
+ for (const group of repoGroup.workspaces) {
+ const name = getWorktreePathBasenameFromId(group.workspaceId) || group.workspaceId
+ const path = splitWorktreeIdForFilesystem(group.workspaceId)?.worktreePath
+ fallbackDisplays.set(group, { name, parentPath: path ? dirname(path) : '' })
+ countByName.set(name, (countByName.get(name) ?? 0) + 1)
+ }
+ for (const display of fallbackDisplays.values()) {
+ if (countByName.get(display.name) === 1) display.parentPath = ''
+ }
+ }
// A group the store cannot place has no project to name or select; Select all covers it.
return repoGroup.repoId === null ? (
nodes.map((node) => (
@@ -286,6 +317,7 @@ function MachineContents({
hostId={hostId}
depth={depth}
tree={tree}
+ fallbackDisplays={fallbackDisplays}
/>
))
) : (
From 11102e38d381ce7046c6d22502a8ad5fee449b7f Mon Sep 17 00:00:00 2001
From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
Date: Fri, 23 Oct 2026 22:44:56 -0700
Subject: [PATCH 3/4] refactor: extract resume workspace display derivation
---
.../NativeChatResumeOnRestartGroups.test.tsx | 28 ++++++------
.../NativeChatResumeOnRestartGroups.tsx | 35 +++------------
.../native-chat-resume-workspace-display.ts | 45 +++++++++++++++++++
3 files changed, 65 insertions(+), 43 deletions(-)
create mode 100644 src/renderer/src/components/native-chat-resume-workspace-display.ts
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
index c98dea9e97ab..b33c365d22ce 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
@@ -228,20 +228,22 @@ it('disambiguates only colliding unknown folders with linear display work on ren
const basename = vi.spyOn(worktreeIds, 'getWorktreePathBasenameFromId')
let nameReads = 0
const mapSet = Map.prototype.set
- vi.spyOn(Map.prototype, 'set').mockImplementation(
- function (this: Map, key, value) {
- if (typeof value?.parentPath === 'string' && value.name === 'main') {
- const name = value.name
- Object.defineProperty(value, 'name', {
- get: () => {
- nameReads++
- return name
- }
- })
- }
- return mapSet.call(this, key, value)
+ vi.spyOn(Map.prototype, 'set').mockImplementation(function (
+ this: Map,
+ key,
+ value
+ ) {
+ if (typeof value?.parentPath === 'string' && value.name === 'main') {
+ const name = value.name
+ Object.defineProperty(value, 'name', {
+ get: () => {
+ nameReads++
+ return name
+ }
+ })
}
- )
+ return mapSet.call(this, key, value)
+ })
const operations: number[] = []
let unknown: ResumeCandidate[] = []
for (const size of [10, 100]) {
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
index db0a336ae18b..09f3d903e8eb 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
@@ -5,22 +5,15 @@ import { ProjectOptionDetail } from '@/components/new-workspace/ProjectComboboxR
import { WorktreeHostContextBadge } from '@/components/sidebar/WorktreeHostContextBadge'
import { useSidebarHostScopeOptions } from '@/components/sidebar/use-sidebar-host-scope-options'
import { translate } from '@/i18n/i18n'
-import { dirname } from '@/lib/path'
-import {
- resolveWorktreeBranchLabel,
- resolveWorktreeDisplayName
-} from '@/lib/worktree-default-display-name'
+import { resolveWorktreeBranchLabel } from '@/lib/worktree-default-display-name'
import { getHostContextLabel } from '../../../shared/worktree/host-context-labels'
-import {
- getWorktreePathBasenameFromId,
- splitWorktreeIdForFilesystem
-} from '../../../shared/worktree/id'
import {
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
type ExecutionHostId
} from '../../../shared/execution-host'
import { useAppStore } from '../store'
+import * as workspaceDisplay from './native-chat-resume-workspace-display'
import {
useLineageAncestors,
useRepoIdByWorkspace,
@@ -54,8 +47,6 @@ import {
export type { ResumeCandidate } from './native-chat-resume-on-restart-grouping'
-type WorkspaceFallback = { name: string; parentPath: string }
-
/**
* The offered chats as a tree: machine, then project, then workspace (a child workspace is a node
* inside its parent, after the parent's chats), then the chats.
@@ -127,7 +118,7 @@ function WorkspaceNode({
hostId: ExecutionHostId
depth: number
tree: TreeProps
- fallbackDisplays?: ReadonlyMap
+ fallbackDisplays?: workspaceDisplay.WorkspaceFallbacks
}): React.JSX.Element {
const { group } = node
const first = group.candidates[0]
@@ -136,11 +127,7 @@ function WorkspaceNode({
// Kind comes from the host's record, never from a name.
const KindGlyph = kind === 'folder' ? Folder : GitBranch
const fallback = fallbackDisplays?.get(group)
- const name =
- (worktree && resolveWorktreeDisplayName(worktree)) ||
- fallback?.name ||
- getWorktreePathBasenameFromId(group.workspaceId) ||
- group.workspaceId
+ const name = workspaceDisplay.resolveName(worktree, fallback, group.workspaceId)
const branch = worktree && kind === 'git-worktree' ? resolveWorktreeBranchLabel(worktree) : ''
return (
{groupResumeWorkspacesByRepo(workspaces, lookup(tree.repoIdOf, null)).map((repoGroup) => {
const nodes = nestResumeWorkspaces(repoGroup.workspaces, ancestorsOf)
- const fallbackDisplays = new Map()
- if (repoGroup.repoId === null) {
- const countByName = new Map()
- for (const group of repoGroup.workspaces) {
- const name = getWorktreePathBasenameFromId(group.workspaceId) || group.workspaceId
- const path = splitWorktreeIdForFilesystem(group.workspaceId)?.worktreePath
- fallbackDisplays.set(group, { name, parentPath: path ? dirname(path) : '' })
- countByName.set(name, (countByName.get(name) ?? 0) + 1)
- }
- for (const display of fallbackDisplays.values()) {
- if (countByName.get(display.name) === 1) display.parentPath = ''
- }
- }
+ const fallbackDisplays = workspaceDisplay.deriveFallbacks(repoGroup)
// A group the store cannot place has no project to name or select; Select all covers it.
return repoGroup.repoId === null ? (
nodes.map((node) => (
diff --git a/src/renderer/src/components/native-chat-resume-workspace-display.ts b/src/renderer/src/components/native-chat-resume-workspace-display.ts
new file mode 100644
index 000000000000..bda32987a9c5
--- /dev/null
+++ b/src/renderer/src/components/native-chat-resume-workspace-display.ts
@@ -0,0 +1,45 @@
+import { dirname } from '@/lib/path'
+import { resolveWorktreeDisplayName } from '@/lib/worktree-default-display-name'
+import {
+ getWorktreePathBasenameFromId,
+ splitWorktreeIdForFilesystem
+} from '../../../shared/worktree/id'
+import type {
+ ResumeRepoGroup,
+ ResumeWorkspaceGroup
+} from './native-chat-resume-on-restart-grouping'
+
+type WorkspaceFallback = { name: string; parentPath: string }
+export type WorkspaceFallbacks = ReadonlyMap
+
+export function deriveFallbacks(repoGroup: ResumeRepoGroup): WorkspaceFallbacks {
+ const fallbackDisplays = new Map()
+ if (repoGroup.repoId === null) {
+ const countByName = new Map()
+ for (const group of repoGroup.workspaces) {
+ const name = getWorktreePathBasenameFromId(group.workspaceId) || group.workspaceId
+ const path = splitWorktreeIdForFilesystem(group.workspaceId)?.worktreePath
+ fallbackDisplays.set(group, { name, parentPath: path ? dirname(path) : '' })
+ countByName.set(name, (countByName.get(name) ?? 0) + 1)
+ }
+ for (const display of fallbackDisplays.values()) {
+ if (countByName.get(display.name) === 1) {
+ display.parentPath = ''
+ }
+ }
+ }
+ return fallbackDisplays
+}
+
+export function resolveName(
+ worktree: Parameters[0] | undefined,
+ fallback: WorkspaceFallback | undefined,
+ workspaceId: string
+): string {
+ return (
+ (worktree && resolveWorktreeDisplayName(worktree)) ||
+ fallback?.name ||
+ getWorktreePathBasenameFromId(workspaceId) ||
+ workspaceId
+ )
+}
From 10c44502844943067b04ca26e6bea1ea2b3cb6ef Mon Sep 17 00:00:00 2001
From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
Date: Sat, 24 Oct 2026 00:48:43 -0700
Subject: [PATCH 4/4] fix: distinguish resume workspace control names
---
.../NativeChatResumeOnRestartGroups.test.tsx | 16 +++++++++++++++-
.../NativeChatResumeOnRestartGroups.tsx | 8 ++++----
.../native-chat-resume-workspace-display.ts | 11 +++++++----
3 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
index b33c365d22ce..e47603e8f81c 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.test.tsx
@@ -268,6 +268,13 @@ it('disambiguates only colliding unknown folders with linear display work on ren
const detail = container.querySelector(`[title="${parent}"]`)
expect(detail?.textContent).toBe(parent)
expect(detail?.lastElementChild?.textContent).toBe(`/workspaces/client-${index}`)
+ const label = `main (${parent})`
+ const row = itemOf(nodeBox(label))
+ expect(row.querySelector('.font-medium')?.textContent).toBe('main')
+ expect(row.querySelector('button[aria-expanded]')?.getAttribute('aria-label')).toBe(
+ `Collapse ${label}`
+ )
+ expect(chatBox(`lost-${index}`).getAttribute('aria-label')).toContain(`in ${label}`)
}
expect(itemOf(nodeBox('Configured')).textContent).toContain('main-branch')
expect(itemOf(nodeBox('blobfish-2')).querySelector('[title]')).toBeNull()
@@ -275,7 +282,7 @@ it('disambiguates only colliding unknown folders with linear display work on ren
}
expect(operations[1]).toBeLessThanOrEqual(12 * operations[0]!)
const collisionBoxes = container.querySelectorAll(
- '[aria-label="Select all chats in main"]'
+ '[role="checkbox"][aria-label^="Select all chats in main ("]'
)
act(() => collisionBoxes[1]!.click())
expect(onToggleSpy).toHaveBeenCalledExactlyOnceWith('lost-1', false)
@@ -284,6 +291,13 @@ it('disambiguates only colliding unknown folders with linear display work on ren
act(() => useAppStore.setState({ worktreesByRepo: { 'repo-1': [known, hydrated] } }))
expect(nodeBox('Resolved')).not.toBeNull()
expect(itemOf(nodeBox('main')).querySelector('[title]')).toBeNull()
+ expect(container.querySelector('[aria-label^="Select all chats in main ("]')).toBeNull()
+ expect(
+ itemOf(nodeBox('main')).querySelector('button[aria-expanded]')?.getAttribute('aria-label')
+ ).toBe('Collapse main')
+ expect(chatBox('lost-1').getAttribute('aria-label')).toBe(
+ 'Resume Codex chat "Prompt lost-1" in main'
+ )
})
// Its project is unknown too: a nameless "Select all chats in " checkbox would help no one.
diff --git a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
index 09f3d903e8eb..d412245c332f 100644
--- a/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
+++ b/src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
@@ -127,17 +127,17 @@ function WorkspaceNode({
// Kind comes from the host's record, never from a name.
const KindGlyph = kind === 'folder' ? Folder : GitBranch
const fallback = fallbackDisplays?.get(group)
- const name = workspaceDisplay.resolveName(worktree, fallback, group.workspaceId)
+ const { name, controlName } = workspaceDisplay.resolveNames(worktree, fallback, group.workspaceId)
const branch = worktree && kind === 'git-worktree' ? resolveWorktreeBranchLabel(worktree) : ''
return (
[0] | undefined,
fallback: WorkspaceFallback | undefined,
workspaceId: string
-): string {
- return (
+): { name: string; controlName: string } {
+ const name =
(worktree && resolveWorktreeDisplayName(worktree)) ||
fallback?.name ||
getWorktreePathBasenameFromId(workspaceId) ||
workspaceId
- )
+ return {
+ name,
+ controlName: !worktree && fallback?.parentPath ? `${name} (${fallback.parentPath})` : name
+ }
}