diff --git a/apps/desktop/src/app/command-palette/index.tsx b/apps/desktop/src/app/command-palette/index.tsx
index 026f8f2f8aa..cf7abbd7f05 100644
--- a/apps/desktop/src/app/command-palette/index.tsx
+++ b/apps/desktop/src/app/command-palette/index.tsx
@@ -260,7 +260,9 @@ const PaletteRow = memo(function PaletteRow({
shows exactly which words earned the row its rank. */}
- {item.detail && {item.detail}}
+ {/* Reads as a suffix of the label, so it sits closer than the row's
+ icon-to-label gap-2 — negative margin trims that back to ~4px. */}
+ {item.detail && {item.detail}}
{combo && }
{item.to && }
{item.active && }
@@ -494,19 +496,16 @@ export function CommandPalette() {
const contributedItems = usePaletteContributions()
- const baseGroups = useMemo(() => {
- const settingsTab = (tab: string) => `${SETTINGS_ROUTE}?tab=${tab}`
- const cc = t.commandCenter
-
- // The active repo's worktrees → "new conversation in ". This is the
- // ⌘K-typed "I want to work on " reflex: each entry seeds a fresh
- // session anchored to that worktree's checkout (requestStartWorkSession),
- // so git is the source of truth and edits land in the right tree.
- const branchGroup: PaletteGroup[] =
+ // The active repo's worktrees → "new conversation in ". This is the
+ // ⌘K-typed "I want to work on " reflex: each entry seeds a fresh
+ // session anchored to that worktree's checkout (requestStartWorkSession),
+ // so git is the source of truth and edits land in the right tree.
+ const branchGroup = useMemo(
+ () =>
worktrees.length > 0
? [
{
- heading: cc.branches,
+ heading: t.commandCenter.branches,
items: worktrees.map(wt => {
const name = wt.branch?.trim() || wt.path.split('/').pop() || wt.path
@@ -514,14 +513,46 @@ export function CommandPalette() {
icon: GitBranch,
id: `worktree-${wt.path}`,
keywords: ['branch', 'worktree', 'switch', name, wt.path],
- label: cc.startInBranch(name),
+ label: t.commandCenter.startInBranch(name),
run: () => requestStartWorkSession(wt.path)
}
})
}
]
+ : [],
+ [t, worktrees]
+ )
+
+ const baseGroups = useMemo(() => {
+ const settingsTab = (tab: string) => `${SETTINGS_ROUTE}?tab=${tab}`
+ const cc = t.commandCenter
+
+ // Registry-contributed rows (core features + plugins) — one group, omitted
+ // while nothing contributes.
+ const commandGroup: PaletteGroup[] =
+ contributedItems.length > 0
+ ? [
+ {
+ heading: cc.commands,
+ items: contributedItems.map(item => ({
+ action: item.action,
+ // Resolved per palette open (see the `open` dep below) so a
+ // state-describing row can't show a state it left.
+ detail: item.detail?.(),
+ icon: item.icon ?? Zap,
+ id: item.key,
+ keywords: item.keywords,
+ label: item.label,
+ run: item.run
+ }))
+ }
+ ]
: []
+ // Group order is the tiebreaker rankGroups falls back on (stable sort), and
+ // exact ties are the common case — "yolo" hits both "Toggle YOLO" and a
+ // worktree named bb/yolo-* as a whole word. So this order IS the priority:
+ // where you're going, then what you can do, then what you can configure.
return [
{
heading: cc.goTo,
@@ -602,7 +633,7 @@ export function CommandPalette() {
}
]
},
- ...branchGroup,
+ ...commandGroup,
{
heading: cc.commandCenter,
items: [
@@ -698,29 +729,9 @@ export function CommandPalette() {
run: go(settingsTab(entry.tab))
}))
]
- },
- // Registry-contributed rows (core features + plugins) — one group,
- // omitted while nothing contributes.
- ...(contributedItems.length > 0
- ? [
- {
- heading: cc.commands,
- items: contributedItems.map(item => ({
- action: item.action,
- // Resolved per palette open (see the `open` dep below) so a
- // state-describing row can't show a state it left.
- detail: item.detail?.(),
- icon: item.icon ?? Zap,
- id: item.key,
- keywords: item.keywords,
- label: item.label,
- run: item.run
- }))
- }
- ]
- : [])
+ }
]
- }, [contributedItems, go, open, settingsSectionLabel, t, updateVersionLabel, worktrees, yoloActive])
+ }, [contributedItems, go, open, settingsSectionLabel, t, updateVersionLabel, yoloActive])
// The long, granular lists (settings fields, API keys, MCP servers, archived
// chats) only surface once the user types — otherwise they'd bury the
@@ -900,7 +911,14 @@ export function CommandPalette() {
themeName
])
- const groups = useMemo(() => [...baseGroups, ...searchGroups], [baseGroups, searchGroups])
+ // Branch rows rank below BOTH the fixed groups and the typed-only lists: they
+ // scale with whatever worktrees happen to exist, so on a tie they're the least
+ // likely thing meant. Everything above is either always-present chrome or a
+ // list the search itself asked for.
+ const groups = useMemo(
+ () => [...baseGroups, ...searchGroups, ...branchGroup],
+ [baseGroups, branchGroup, searchGroups]
+ )
// Nested palette pages (VS Code-style submenus). Reusable: add an entry here
// and point a root item at it via `to`.