Skip to content

Commit dfbf26b

Browse files
committed
feat(frontend): clarify context list labels
Prefer provenance-derived username@hostname badges in the context list and render titles as provider, worktree name, and timestamp when that metadata is available. This keeps the sidebar easier to scan during local multi-worktree runs while preserving the existing stored title fallback when provenance is missing.
1 parent 12bf860 commit dfbf26b

1 file changed

Lines changed: 54 additions & 9 deletions

File tree

frontend/components/ContextList.tsx

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { memo, useMemo, useState, useEffect, useCallback, useRef } from 'react';
44
import type { ContextEntry, StoreEvent } from '@/types';
5-
import { cn } from '@/lib/utils';
5+
import { cn, formatTimestamp } from '@/lib/utils';
66
import { Database, GitBranch, GitFork, ChevronRight, Folder, User, Tag } from './icons';
77
import { PresenceIndicator, LiveTimestamp } from './live';
88
import type { PresenceState } from './live';
@@ -22,6 +22,47 @@ function getTagColor(tag: string) {
2222
return TAG_COLORS[tag.toLowerCase()] || DEFAULT_TAG_COLOR;
2323
}
2424

25+
function getContextBadgeLabel(context: ContextEntry): string | null {
26+
const provenance = context.provenance;
27+
const username =
28+
provenance?.on_behalf_of ||
29+
provenance?.process_owner ||
30+
provenance?.on_behalf_of_email ||
31+
null;
32+
const hostname = provenance?.host_name || null;
33+
34+
if (username && hostname) {
35+
return `${username}@${hostname}`;
36+
}
37+
if (username) {
38+
return username;
39+
}
40+
if (hostname) {
41+
return hostname;
42+
}
43+
return context.client_tag || null;
44+
}
45+
46+
function basename(path?: string): string | null {
47+
if (!path) return null;
48+
const trimmed = path.replace(/\/+$/, '');
49+
const segments = trimmed.split('/').filter(Boolean);
50+
return segments.length > 0 ? segments[segments.length - 1] : null;
51+
}
52+
53+
function getContextTitleLabel(context: ContextEntry): string | null {
54+
const provider = context.client_tag?.split('/').pop() || null;
55+
const worktreeName = basename(context.provenance?.env?.PWD);
56+
const timestampSource = context.provenance?.captured_at ?? context.created_at_unix_ms;
57+
const timestamp = timestampSource ? formatTimestamp(timestampSource) : null;
58+
59+
if (provider && worktreeName && timestamp) {
60+
return `${provider}: ${worktreeName} ${timestamp}`;
61+
}
62+
63+
return context.title || null;
64+
}
65+
2566
interface ContextListProps {
2667
contexts: ContextEntry[];
2768
selectedId?: string;
@@ -73,6 +114,8 @@ const ContextListItem = memo(function ContextListItem({
73114
const hasParent = !!(provenance?.parent_context_id);
74115
const onBehalfOf = provenance?.on_behalf_of || provenance?.on_behalf_of_email;
75116
const sourceStyle = provenance?.on_behalf_of_source ? getSourceStyle(provenance.on_behalf_of_source) : null;
117+
const badgeLabel = getContextBadgeLabel(context);
118+
const titleLabel = getContextTitleLabel(context);
76119

77120
return (
78121
<button
@@ -92,13 +135,13 @@ const ContextListItem = memo(function ContextListItem({
92135
)}
93136
>
94137
{/* Title row (if available) */}
95-
{context.title && (
138+
{titleLabel && (
96139
<div className="flex items-center gap-1.5 mb-1">
97140
<span className={cn(
98141
'text-sm font-medium truncate',
99142
isSelected ? 'text-theme-text' : 'text-theme-text-secondary'
100143
)}>
101-
{context.title}
144+
{titleLabel}
102145
</span>
103146
</div>
104147
)}
@@ -123,14 +166,16 @@ const ContextListItem = memo(function ContextListItem({
123166
)}>
124167
{context.context_id}
125168
</span>
126-
{/* Client tag badge */}
127-
{context.client_tag && (
169+
{/* Context provenance badge */}
170+
{badgeLabel && (
128171
<span className={cn(
129172
'px-1.5 py-0.5 rounded text-[10px] font-medium truncate',
130-
getTagColor(context.client_tag).bg,
131-
getTagColor(context.client_tag).text
132-
)}>
133-
{context.client_tag}
173+
getTagColor(context.client_tag || 'default').bg,
174+
getTagColor(context.client_tag || 'default').text
175+
)}
176+
title={badgeLabel}
177+
>
178+
{badgeLabel}
134179
</span>
135180
)}
136181
{/* Filesystem snapshot indicator */}

0 commit comments

Comments
 (0)