diff --git a/src/renderer/src/components/WorktreeJumpPalette.test.tsx b/src/renderer/src/components/WorktreeJumpPalette.test.tsx
index e9c560dfc4b..63dbfdcd62a 100644
--- a/src/renderer/src/components/WorktreeJumpPalette.test.tsx
+++ b/src/renderer/src/components/WorktreeJumpPalette.test.tsx
@@ -8,7 +8,7 @@ import type * as ReactI18Next from 'react-i18next'
import { useAppStore } from '@/store'
import type { AppState } from '@/store/types'
import WorktreeJumpPalette from './WorktreeJumpPalette'
-import { makeRepo, makeWorktree } from './worktree-jump-palette-test-fixtures'
+import { makeRecentTabState, makeRepo, makeWorktree } from './worktree-jump-palette-test-fixtures'
const { activateAndRevealWorktree } = vi.hoisted(() => ({
activateAndRevealWorktree: vi.fn(() => false)
@@ -48,9 +48,10 @@ vi.mock('@/components/repo/RepoBadgeLabel', () => ({
RepoBadgeMark: () =>
}))
-vi.mock('@/components/cmd-j/palette-host-badge', () => ({
- getPaletteHostBadge: () => null
+const { getPaletteHostBadge } = vi.hoisted(() => ({
+ getPaletteHostBadge: vi.fn(() => null as { hostId: 'local'; label: string } | null)
}))
+vi.mock('@/components/cmd-j/palette-host-badge', () => ({ getPaletteHostBadge }))
// Why: activation reaches into window.api and the whole worktree-reveal path; the palette's own
// contract is which result it hands over, so stub the boundary and assert on that.
@@ -191,6 +192,7 @@ describe('WorktreeJumpPalette', () => {
globalThis.IS_REACT_ACT_ENVIRONMENT = true
setCommandQuery = null
activateAndRevealWorktree.mockClear()
+ getPaletteHostBadge.mockReturnValue(null)
useAppStore.setState(initialAppState, true)
testContainer = document.createElement('div')
document.body.appendChild(testContainer)
@@ -230,6 +232,17 @@ describe('WorktreeJumpPalette', () => {
expect(testContainer.textContent).toContain('Folder workspace')
})
+ it('renders the owning host badge on worktree and tab rows', async () => {
+ getPaletteHostBadge.mockReturnValue({ hostId: 'local', label: 'Local Mac' })
+ await renderPalette(makeRecentTabState())
+
+ const badge = '[aria-label="Host: Local Mac"]'
+ expect(testContainer.querySelector(`[data-command-item*="worktree:"] ${badge}`)).not.toBeNull()
+ expect(
+ testContainer.querySelector(`[data-command-item*="workspace-tab:"] ${badge}`)
+ ).not.toBeNull()
+ })
+
it('keeps the explicit default-branch filter authoritative', async () => {
const defaultBranch = makeWorktree('default-branch', 'Default branch workspace', {
isMainWorktree: true,
diff --git a/src/renderer/src/components/WorktreeJumpPalette.tsx b/src/renderer/src/components/WorktreeJumpPalette.tsx
index 9a54ed398c7..4f0b4a6bff4 100644
--- a/src/renderer/src/components/WorktreeJumpPalette.tsx
+++ b/src/renderer/src/components/WorktreeJumpPalette.tsx
@@ -141,6 +141,7 @@ import {
import { RepoBadgeMark } from '@/components/repo/RepoBadgeLabel'
import { buildSidebarHostOptions } from '@/components/sidebar/sidebar-host-options'
import { getPaletteHostBadge } from '@/components/cmd-j/palette-host-badge'
+import PaletteHostBadgeChip from '@/components/cmd-j/PaletteHostBadgeChip'
import { getWorktreeHostIdentity } from '../../../shared/worktree/host-qualified-identity'
import { getRepoHostIdentity } from '@/store/slices/repo-host-identity'
import type { Repo } from '../../../shared/repo-types'
@@ -3221,6 +3222,7 @@ function WorktreeJumpPaletteContent({
: null
const isSshDisconnected = sshStatus != null && sshStatus !== 'connected'
const sessionAge = formatPaletteSessionAge(worktree.lastActivityAt, paletteNowMs)
+ const hostBadge = getPaletteHostBadge(repo, hostOptions, hostFilterActive)
return (
+
{repoName && (
@@ -3350,6 +3353,9 @@ function WorktreeJumpPaletteContent({
if (entry.type === 'project-target') {
const result = entry.result
const isProject = result.kind === 'project'
+ const hostBadge = isProject
+ ? getPaletteHostBadge(result.repo, hostOptions, hostFilterActive)
+ : null
const badgeLabel = isProject
? translate('auto.components.WorktreeJumpPalette.projectBadge', 'Project')
: translate('auto.components.WorktreeJumpPalette.repoGroupBadge', 'Repo group')
@@ -3377,6 +3383,7 @@ function WorktreeJumpPaletteContent({
{isProject ? (
+
{result.repo.displayName}
@@ -3434,6 +3441,11 @@ function WorktreeJumpPaletteContent({
? resolveRepoForWorktree(workspaceTabWorktree)
: undefined
const workspaceTabRepoName = workspaceTabRepo?.displayName ?? result.repoName
+ const workspaceTabHostBadge = getPaletteHostBadge(
+ workspaceTabRepo,
+ hostOptions,
+ hostFilterActive
+ )
const workspaceTabFallback =
result.contentType === 'terminal' && result.occupantAgent ? (
+
{workspaceTabRepoName && (
@@ -3529,6 +3542,11 @@ function WorktreeJumpPaletteContent({
? resolveRepoForWorktree(simulatorWorktree)
: undefined
const simulatorRepoName = simulatorRepo?.displayName ?? result.repoName
+ const simulatorHostBadge = getPaletteHostBadge(
+ simulatorRepo,
+ hostOptions,
+ hostFilterActive
+ )
const sessionAge = formatPaletteSessionAge(
result.lastActiveAt ?? null,
paletteNowMs
@@ -3582,6 +3600,7 @@ function WorktreeJumpPaletteContent({
worktree={simulatorWorktree}
className="max-w-[280px] truncate text-[12px] font-medium text-muted-foreground"
/>
+
{simulatorRepoName && (
@@ -3610,6 +3629,11 @@ function WorktreeJumpPaletteContent({
? resolveRepoForWorktree(browserWorktree)
: undefined
const browserRepoName = browserRepo?.displayName ?? result.repoName
+ const browserHostBadge = getPaletteHostBadge(
+ browserRepo,
+ hostOptions,
+ hostFilterActive
+ )
const sessionAge = formatPaletteSessionAge(result.lastActiveAt ?? null, paletteNowMs)
return (
@@ -3660,6 +3684,7 @@ function WorktreeJumpPaletteContent({
worktree={browserWorktree}
className="max-w-[280px] truncate text-[12px] font-medium text-muted-foreground"
/>
+
{browserRepoName && (
diff --git a/src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx b/src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx
new file mode 100644
index 00000000000..35d60addb36
--- /dev/null
+++ b/src/renderer/src/components/cmd-j/PaletteHostBadgeChip.tsx
@@ -0,0 +1,25 @@
+import { translate } from '@/i18n/i18n'
+import type { PaletteHostBadge } from './palette-host-badge'
+
+export default function PaletteHostBadgeChip({
+ badge
+}: {
+ badge: PaletteHostBadge | null
+}): React.JSX.Element | null {
+ if (!badge) {
+ return null
+ }
+
+ return (
+
+ {badge.label}
+
+ )
+}