Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/claude-code-tab-prefix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"aicodeman": patch
---

Show the CC prefix on Claude Code terminal tabs.
2 changes: 1 addition & 1 deletion src/web/public/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5660,7 +5660,7 @@ class CodemanApp {
<span class="tab-status ${status}" aria-hidden="true"></span>
<span class="tab-info">
<span class="tab-name-row">
${mode === 'shell' ? '<span class="tab-mode shell" aria-hidden="true">sh</span>' : mode === 'opencode' ? '<span class="tab-mode opencode" aria-hidden="true">oc</span>' : mode === 'codex' ? '<span class="tab-mode codex" aria-hidden="true">cx</span>' : mode === 'gemini' ? '<span class="tab-mode gemini" aria-hidden="true">gm</span>' : mode === 'antigravity' ? '<span class="tab-mode antigravity" aria-hidden="true">ag</span>' : mode === 'pi' ? '<span class="tab-mode pi" aria-hidden="true">pi</span>' : mode === 'grok' ? '<span class="tab-mode grok" aria-hidden="true">gk</span>' : mode === 'deepseek' ? '<span class="tab-mode deepseek" aria-hidden="true">ds</span>' : mode === 'omp' ? '<span class="tab-mode omp" aria-hidden="true">om</span>' : ''}
${mode === 'claude' ? '<span class="tab-mode claude" aria-hidden="true">cc</span>' : mode === 'shell' ? '<span class="tab-mode shell" aria-hidden="true">sh</span>' : mode === 'opencode' ? '<span class="tab-mode opencode" aria-hidden="true">oc</span>' : mode === 'codex' ? '<span class="tab-mode codex" aria-hidden="true">cx</span>' : mode === 'gemini' ? '<span class="tab-mode gemini" aria-hidden="true">gm</span>' : mode === 'antigravity' ? '<span class="tab-mode antigravity" aria-hidden="true">ag</span>' : mode === 'pi' ? '<span class="tab-mode pi" aria-hidden="true">pi</span>' : mode === 'grok' ? '<span class="tab-mode grok" aria-hidden="true">gk</span>' : mode === 'deepseek' ? '<span class="tab-mode deepseek" aria-hidden="true">ds</span>' : mode === 'omp' ? '<span class="tab-mode omp" aria-hidden="true">om</span>' : ''}
<span class="tab-name" data-session-id="${id}" data-full-name="${escapeHtml(name)}">${tabLabel}</span>
${paneExitBadge ? `<span class="tab-exited-badge" data-i18n-skip aria-hidden="true">${escapeHtml(paneExitBadge)}</span>` : ''}
${inlineSessionActions ? tabActionsHtml : ''}
Expand Down
1 change: 1 addition & 0 deletions src/web/public/home-sessions.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const HOME_SESSIONS_PILL_LABEL = {

/** Short backend badge, mirroring `.tab-mode` in the tab strip. */
const HOME_SESSIONS_MODE_BADGE = {
claude: 'cc',
shell: 'sh',
opencode: 'oc',
codex: 'cx',
Expand Down
17 changes: 17 additions & 0 deletions test/claude-tab-prefix.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @vitest-environment node

import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { describe, expect, it } from 'vitest';

const APP = resolve(import.meta.dirname, '../src/web/public/app.js');

describe('Claude Code tab prefix', () => {
it('includes CC in the main tab-strip markup', () => {
const app = readFileSync(APP, 'utf8');

expect(app).toContain(
"mode === 'claude' ? '<span class=\"tab-mode claude\" aria-hidden=\"true\">cc</span>'"
);
});
});
13 changes: 8 additions & 5 deletions test/home-sessions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,25 +165,28 @@ describe('home sessions column: model', () => {
const [row] = app.buildHomeSessionRows();
expect(row.caseName).toBe('claudeman');
expect(row.modeBadge).toBe('cx');
// claude is the default backend and gets no badge — the strip does the same.
const plain = loadHomeSessionsApp({
const claude = loadHomeSessionsApp({
sessions: sessionMap([{ id: 'a', mode: 'claude' }]),
sessionOrder: ['a'],
cases: CASES,
});
expect(plain.buildHomeSessionRows()[0].modeBadge).toBe('');
expect(claude.buildHomeSessionRows()[0].modeBadge).toBe('cc');
});

it('badges every non-claude backend, so a new run mode cannot read as claude here', () => {
it('badges every supported backend', () => {
// The badge map is a per-mode lookup with a '' fallback, so a mode missing from it
// is indistinguishable from claude in this rail while the tab strip badges it fine.
// is visually indistinguishable from an unrecognised session in this rail.
for (const [mode, badge] of [
['claude', 'cc'],
['shell', 'sh'],
['opencode', 'oc'],
['codex', 'cx'],
['gemini', 'gm'],
['antigravity', 'ag'],
['pi', 'pi'],
['grok', 'gk'],
['deepseek', 'ds'],
['omp', 'om'],
] as const) {
const app = loadHomeSessionsApp({
sessions: sessionMap([{ id: 'a', mode }]),
Expand Down
Loading