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' ? '' : mode === 'opencode' ? '' : mode === 'codex' ? '' : mode === 'gemini' ? '' : mode === 'antigravity' ? '' : mode === 'pi' ? '' : mode === 'grok' ? '' : mode === 'deepseek' ? '' : mode === 'omp' ? '' : ''} + ${mode === 'claude' ? '' : mode === 'shell' ? '' : mode === 'opencode' ? '' : mode === 'codex' ? '' : mode === 'gemini' ? '' : mode === 'antigravity' ? '' : mode === 'pi' ? '' : mode === 'grok' ? '' : mode === 'deepseek' ? '' : mode === 'omp' ? '' : ''} ${tabLabel} ${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'); - }); -});