From 34b49739a3c22710003dbd1a4d54a3a1ac3ec610 Mon Sep 17 00:00:00 2001
From: Devvyn <22340871+opticon454@users.noreply.github.com>
Date: Sat, 26 Sep 2026 08:36:26 +0800
Subject: [PATCH 1/2] fix(tabs): show Claude Code prefix
---
.changeset/claude-code-tab-prefix.md | 5 +++
src/web/public/app.js | 2 +-
src/web/public/home-sessions.js | 1 +
test/claude-tab-prefix.browser.test.ts | 48 ++++++++++++++++++++++++++
test/claude-tab-prefix.test.ts | 17 +++++++++
test/home-sessions.test.ts | 13 ++++---
6 files changed, 80 insertions(+), 6 deletions(-)
create mode 100644 .changeset/claude-code-tab-prefix.md
create mode 100644 test/claude-tab-prefix.browser.test.ts
create mode 100644 test/claude-tab-prefix.test.ts
diff --git a/.changeset/claude-code-tab-prefix.md b/.changeset/claude-code-tab-prefix.md
new file mode 100644
index 000000000..c7626d5dd
--- /dev/null
+++ b/.changeset/claude-code-tab-prefix.md
@@ -0,0 +1,5 @@
+---
+"aicodeman": patch
+---
+
+Show the CC prefix on Claude Code terminal tabs.
diff --git a/src/web/public/app.js b/src/web/public/app.js
index 05577c343..97605e069 100644
--- a/src/web/public/app.js
+++ b/src/web/public/app.js
@@ -5660,7 +5660,7 @@ class CodemanApp {
- ${mode === 'shell' ? 'sh' : mode === 'opencode' ? 'oc' : mode === 'codex' ? 'cx' : mode === 'gemini' ? 'gm' : mode === 'antigravity' ? 'ag' : mode === 'pi' ? 'pi' : mode === 'grok' ? 'gk' : mode === 'deepseek' ? 'ds' : mode === 'omp' ? 'om' : ''}
+ ${mode === 'claude' ? 'cc' : mode === 'shell' ? 'sh' : mode === 'opencode' ? 'oc' : mode === 'codex' ? 'cx' : mode === 'gemini' ? 'gm' : mode === 'antigravity' ? 'ag' : mode === 'pi' ? 'pi' : mode === 'grok' ? 'gk' : mode === 'deepseek' ? 'ds' : mode === 'omp' ? 'om' : ''}
${tabLabel}
${paneExitBadge ? `${escapeHtml(paneExitBadge)}` : ''}
${inlineSessionActions ? tabActionsHtml : ''}
diff --git a/src/web/public/home-sessions.js b/src/web/public/home-sessions.js
index eeb12c536..beff4de23 100644
--- a/src/web/public/home-sessions.js
+++ b/src/web/public/home-sessions.js
@@ -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',
diff --git a/test/claude-tab-prefix.browser.test.ts b/test/claude-tab-prefix.browser.test.ts
new file mode 100644
index 000000000..f4d844813
--- /dev/null
+++ b/test/claude-tab-prefix.browser.test.ts
@@ -0,0 +1,48 @@
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
+import { chromium, type Browser, type Page } from 'playwright';
+import { WebServer } from '../src/web/server.js';
+
+const PORT = 3165;
+const BASE_URL = `http://localhost:${PORT}`;
+
+describe('Claude Code tab prefix', () => {
+ let server: WebServer;
+ let browser: Browser;
+ let page: Page;
+
+ beforeAll(async () => {
+ server = new WebServer(PORT, false, true);
+ await server.start();
+ browser = await chromium.launch({ headless: true });
+ page = await browser.newPage();
+ await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });
+ await page.waitForFunction(() => typeof window.app !== 'undefined');
+ }, 60000);
+
+ afterAll(async () => {
+ await browser?.close();
+ await server?.stop();
+ }, 60000);
+
+ it('renders CC on a Claude Code terminal tab', async () => {
+ const badge = await page.evaluate(() => {
+ const app = window.app as {
+ sessions: Map;
+ sessionOrder: string[];
+ _renderSessionTabsImmediate: () => void;
+ };
+ app.sessions.clear();
+ app.sessions.set('claude-prefix', {
+ id: 'claude-prefix',
+ name: 'w1-prefix-test',
+ mode: 'claude',
+ status: 'idle',
+ });
+ app.sessionOrder = ['claude-prefix'];
+ app._renderSessionTabsImmediate();
+ return document.querySelector('[data-id="claude-prefix"] .tab-mode')?.textContent;
+ });
+
+ expect(badge).toBe('cc');
+ });
+});
diff --git a/test/claude-tab-prefix.test.ts b/test/claude-tab-prefix.test.ts
new file mode 100644
index 000000000..0952fcd1b
--- /dev/null
+++ b/test/claude-tab-prefix.test.ts
@@ -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' ? 'cc'"
+ );
+ });
+});
diff --git a/test/home-sessions.test.ts b/test/home-sessions.test.ts
index 67da3e55b..87520396a 100644
--- a/test/home-sessions.test.ts
+++ b/test/home-sessions.test.ts
@@ -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 }]),
From 20319f8fc8ebedc15aab5393aa30c75afc7f93d3 Mon Sep 17 00:00:00 2001
From: Devvyn <22340871+opticon454@users.noreply.github.com>
Date: Sat, 26 Sep 2026 08:57:06 +0800
Subject: [PATCH 2/2] test(tabs): keep browser checks out of unit CI
---
test/claude-tab-prefix.browser.test.ts | 48 --------------------------
1 file changed, 48 deletions(-)
delete mode 100644 test/claude-tab-prefix.browser.test.ts
diff --git a/test/claude-tab-prefix.browser.test.ts b/test/claude-tab-prefix.browser.test.ts
deleted file mode 100644
index f4d844813..000000000
--- a/test/claude-tab-prefix.browser.test.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { afterAll, beforeAll, describe, expect, it } from 'vitest';
-import { chromium, type Browser, type Page } from 'playwright';
-import { WebServer } from '../src/web/server.js';
-
-const PORT = 3165;
-const BASE_URL = `http://localhost:${PORT}`;
-
-describe('Claude Code tab prefix', () => {
- let server: WebServer;
- let browser: Browser;
- let page: Page;
-
- beforeAll(async () => {
- server = new WebServer(PORT, false, true);
- await server.start();
- browser = await chromium.launch({ headless: true });
- page = await browser.newPage();
- await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });
- await page.waitForFunction(() => typeof window.app !== 'undefined');
- }, 60000);
-
- afterAll(async () => {
- await browser?.close();
- await server?.stop();
- }, 60000);
-
- it('renders CC on a Claude Code terminal tab', async () => {
- const badge = await page.evaluate(() => {
- const app = window.app as {
- sessions: Map;
- sessionOrder: string[];
- _renderSessionTabsImmediate: () => void;
- };
- app.sessions.clear();
- app.sessions.set('claude-prefix', {
- id: 'claude-prefix',
- name: 'w1-prefix-test',
- mode: 'claude',
- status: 'idle',
- });
- app.sessionOrder = ['claude-prefix'];
- app._renderSessionTabsImmediate();
- return document.querySelector('[data-id="claude-prefix"] .tab-mode')?.textContent;
- });
-
- expect(badge).toBe('cc');
- });
-});