1import type { ProviderDriverKind } from "@t3tools/contracts";
2import { FolderGit2Icon, FolderIcon, GitBranchIcon } from "lucide-react";
3import { ProjectFavicon, type ProjectFaviconProject } from "./ProjectFavicon";
4import { ProviderInstanceIcon } from "./chat/ProviderInstanceIcon";
5import { cn } from "~/lib/utils";
6
7import { MiddleTruncate } from "./ui/middle-truncate";
8
9/**
10 * Flip this while reviewing command-palette thread subtitles.
11 * - favicon-workspace-harness: favicon + Folder/FolderGit2 + branch + harness (default)
12 * - favicon-workspace: same without harness
13 * - favicon-branch-harness: GitBranch for local, FolderGit2 for worktrees, + harness
14 */
15export type ThreadCommandSubtitleVariant =
16 | "favicon-workspace-harness"
17 | "favicon-workspace"
18 | "favicon-branch-harness";
19
20const THREAD_COMMAND_SUBTITLE_VARIANT: ThreadCommandSubtitleVariant = "favicon-workspace-harness";
21
22export const COMMAND_PALETTE_META_ICON_CLASS = "size-3 shrink-0 text-muted-foreground/70";
23
24export function CommandPaletteMetaDot() {
25 return <span className="shrink-0 text-muted-foreground/50">·</span>;
26}
27
28function WorkspaceIcon(props: { variant: ThreadCommandSubtitleVariant; isWorktree: boolean }) {
29 if (props.isWorktree) {
30 return <FolderGit2Icon className={COMMAND_PALETTE_META_ICON_CLASS} aria-hidden />;
31 }
32 if (props.variant === "favicon-branch-harness") {
33 return <GitBranchIcon className={COMMAND_PALETTE_META_ICON_CLASS} aria-hidden />;
34 }
35 return <FolderIcon className={COMMAND_PALETTE_META_ICON_CLASS} aria-hidden />;
36}
37
38export function ThreadCommandSubtitle(props: {
39 project: ProjectFaviconProject | null;
40 projectTitle: string | null;
41 environmentLabel?: string | null;
42 branch: string | null;
43 worktreePath: string | null;
44 isCurrent: boolean;
45 driverKind?: ProviderDriverKind | null;
46 providerDisplayName?: string | null;
47 acpRegistryAgentId?: string | undefined;
48 acpRegistryIconUrl?: string | undefined;
49 variant?: ThreadCommandSubtitleVariant;
50 className?: string;
51}) {
52 const variant = props.variant ?? THREAD_COMMAND_SUBTITLE_VARIANT;
53 const isWorktree = props.worktreePath != null && props.worktreePath.trim().length > 0;
54 const showHarness =
55 variant !== "favicon-workspace" && props.driverKind != null && props.providerDisplayName;
56
57 const projectLabel = props.projectTitle?.trim() || null;
58 const branchLabel = props.branch?.trim() || null;
59
60 if (!projectLabel && !branchLabel && !props.isCurrent && !showHarness) {
61 return null;
62 }
63
64 return (
65 <span
66 className={cn(
67 "inline-flex min-w-0 max-w-full items-center gap-1 text-xs text-muted-foreground/70",
68 props.className,
69 )}
70 >
71 {projectLabel ? (
72 <span className="inline-flex min-w-0 items-center gap-1">
73 {props.project ? (
74 <ProjectFavicon project={props.project} className="size-3 shrink-0" />
75 ) : null}
76 <span className="min-w-0 truncate">{projectLabel}</span>
77 {props.environmentLabel ? (
78 <>
79 <CommandPaletteMetaDot />
80 <span className="shrink-0">{props.environmentLabel}</span>
81 </>
82 ) : null}
83 </span>
84 ) : null}
85
86 {branchLabel ? (
87 <>
88 {projectLabel ? <CommandPaletteMetaDot /> : null}
89 <span className="inline-flex min-w-0 items-center gap-1">
90 <WorkspaceIcon variant={variant} isWorktree={isWorktree} />
91 <MiddleTruncate value={branchLabel} />
92 </span>
93 </>
94 ) : null}
95
96 {showHarness && props.driverKind ? (
97 <>
98 {projectLabel || branchLabel ? <CommandPaletteMetaDot /> : null}
99 <ProviderInstanceIcon
100 driverKind={props.driverKind}
101 displayName={props.providerDisplayName ?? props.driverKind}
102 acpRegistryAgentId={props.acpRegistryAgentId}
103 acpRegistryIconUrl={props.acpRegistryIconUrl}
104 iconClassName="size-3 shrink-0 opacity-70"
105 />
106 </>
107 ) : null}
108
109 {props.isCurrent ? (
110 <>
111 {projectLabel || branchLabel || showHarness ? <CommandPaletteMetaDot /> : null}
112 <span className="shrink-0">Current thread</span>
113 </>
114 ) : null}
115 </span>
116 );
117}