mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 22:49:41 +02:00
feat(sessions): show the git worktree on session rows
Closes #266. Sessions from different worktrees of the same repo were indistinguishable in the Resume list, Cmd+K and search — the row showed a session name and a case label, nothing about which worktree it ran in. Claude Code already stamps "cwd" and "gitBranch" on every user/assistant record, and writes a worktree-state record naming the worktree when the session was started through its own worktree feature. scanProjectDir() already buffers the head of every transcript for prompt extraction, so extractTranscriptGitInfo() parses buffers that are already in memory: no extra file reads, no git subprocess. (Measured on this machine: a git rev-parse per directory costs 482ms for 35 rows; parsing the existing buffers costs nothing.) cwd is taken from the first record that carries it, since a session's cwd does not move. gitBranch is taken from the last, since a branch genuinely changes mid-session. The badge requires a worktree NAME. An earlier revision rendered whenever a branch was known, which put a badge on all 35 rows of a real history -- "master" on every ordinary session, burying the ten rows the badge exists to distinguish. A hand-made `git worktree add` therefore gets no badge rather than a guessed name; Claude's own <repo>/.claude/worktrees/<name> layout is recognised from the path when no worktree-state record is present. worktreeName and gitBranch join the filterAndPaginate haystack so the session manager can search by them. panels-ui re-projects the unified item into a 5-field record before rendering, so the new fields are carried there explicitly -- omitting that silently drops them from Cmd+K only. Also prefers the transcript cwd over decodeProjectKey()'s stat-walked guess, which falls back to $HOME when nothing resolves (#265). Note that path is currently LATENT, not active: on the install this was developed against, every project key whose directory is gone has zero transcripts and so produces no row at all. The transcript value is used because it is authoritative and non-lossy, not because a live bug was reproduced. Verified against a real 35-session history on an isolated CODEMAN_INSTANCE: 10 of 36 rows badged, history row count unchanged at 35 (nothing dropped), no page errors. 129 tests pass across the new suite plus the unified service, unified route and session route suites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uTqt8ttmsBLXbm5JFHis3
This commit is contained in:
co-authored by
Claude Opus 5
parent
c942bb5dfb
commit
aa35c1a0c4
@@ -649,6 +649,11 @@ Object.assign(CodemanApp.prototype, {
|
||||
sizeBytes: s.sizeBytes ?? 0,
|
||||
lastModified: new Date(s.lastActivityAt ?? s.createdAt ?? Date.now()).toISOString(),
|
||||
firstPrompt: s.firstPrompt || s.name || '',
|
||||
// Must be carried explicitly: this record is a re-projection, so any
|
||||
// field omitted here silently vanishes from the Cmd+K list (#266).
|
||||
gitBranch: s.gitBranch,
|
||||
worktreeName: s.worktreeName,
|
||||
worktreeRepo: s.worktreeRepo,
|
||||
};
|
||||
const isLive = !!this.sessions?.has?.(s.sessionId);
|
||||
const item = this._buildHistoryItem(record, this.cases, {
|
||||
|
||||
@@ -3840,6 +3840,17 @@ body.touch-device .terminal-container .xterm .xterm-helper-textarea {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
/* Worktree pill (#266). Tinted off the accent so it reads as metadata rather
|
||||
than status — LIVE is the only badge that should look like state. */
|
||||
.history-item-badge-worktree {
|
||||
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
||||
color: var(--accent);
|
||||
max-width: 22ch;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.history-item-meta {
|
||||
font-size: 0.7rem;
|
||||
color: var(--text-muted);
|
||||
|
||||
@@ -1517,6 +1517,24 @@ Object.assign(CodemanApp.prototype, {
|
||||
* - workingDir under a case dir → "#caseName/subdir"
|
||||
* - Otherwise → basename (e.g. "Claudeman")
|
||||
*/
|
||||
/**
|
||||
* Badge text for a session's git worktree, or '' when it isn't on one.
|
||||
* `⑂ <name> · <branch>`, either half alone if that's all we know.
|
||||
* Branch is truncated: the badge row is a single nowrap line.
|
||||
*/
|
||||
_worktreeLabel(s) {
|
||||
// Worktree name is REQUIRED. gitBranch alone is not worktree information —
|
||||
// every ordinary repo session has one, and badging all of them with `⑂ master`
|
||||
// is noise that buries the rows this badge exists to distinguish.
|
||||
const name = s && s.worktreeName;
|
||||
if (!name) return '';
|
||||
let branch = s.gitBranch || '';
|
||||
// A worktree's branch often just restates its name; don't print it twice.
|
||||
if (branch === name || branch === `worktree-${name}`) branch = '';
|
||||
if (branch.length > 24) branch = branch.slice(0, 23) + '\u2026';
|
||||
return '⑂ ' + [name, branch].filter(Boolean).join(' · ');
|
||||
},
|
||||
|
||||
_resolveCaseLabel(workingDir, cases) {
|
||||
if (!workingDir) return '';
|
||||
let best = null;
|
||||
@@ -1639,6 +1657,18 @@ Object.assign(CodemanApp.prototype, {
|
||||
modeBadge.textContent = s.mode;
|
||||
badgeRow.appendChild(modeBadge);
|
||||
}
|
||||
// Worktree pill (#266): distinguishes sessions from different worktrees of the
|
||||
// same repo, which are otherwise identical in this list. Name AND branch when
|
||||
// both are known; a hand-made `git worktree add` yields no recoverable name,
|
||||
// so it degrades to branch-only rather than guessing one.
|
||||
const wtLabel = this._worktreeLabel(s);
|
||||
if (wtLabel) {
|
||||
const wtBadge = document.createElement('span');
|
||||
wtBadge.className = 'history-item-badge history-item-badge-worktree';
|
||||
wtBadge.textContent = wtLabel;
|
||||
wtBadge.title = s.worktreeRepo ? `worktree of ${s.worktreeRepo}` : wtLabel;
|
||||
badgeRow.appendChild(wtBadge);
|
||||
}
|
||||
if (isLive) {
|
||||
const liveBadge = document.createElement('span');
|
||||
liveBadge.className = 'history-item-badge history-item-badge-live';
|
||||
|
||||
Reference in New Issue
Block a user