From 778a382d3ecbfe35288bb56d161910ccb6527500 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:28:38 -0700 Subject: [PATCH] test(agent-status): harden Antigravity title collision --- .../agent-title-agy-gemini-collision.test.ts | 51 ++++++++++--------- src/shared/agent-title-core.ts | 10 ++-- src/shared/terminal-title-agent-type.ts | 10 ++-- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/shared/agent-title-agy-gemini-collision.test.ts b/src/shared/agent-title-agy-gemini-collision.test.ts index cd8c1e8714f..08d004882bb 100644 --- a/src/shared/agent-title-agy-gemini-collision.test.ts +++ b/src/shared/agent-title-agy-gemini-collision.test.ts @@ -1,12 +1,13 @@ import { describe, expect, it } from 'vitest' import { getAgentLabel } from './agent-title-identity' import { resolveExplicitTerminalTitleAgentType } from './terminal-title-agent-type' -import { GEMINI_IDLE, GEMINI_WORKING } from './agent-title-core' +import { + GEMINI_IDLE, + GEMINI_PERMISSION, + GEMINI_SILENT_WORKING, + GEMINI_WORKING +} from './agent-title-core' -// Why: Antigravity's models are named "Gemini " (see the real `agy models` -// output parsed in commit-message-agent-spec.test.ts), so an agy pane's own title carries a -// whole `gemini` token. Gemini CLI is checked before Antigravity in getAgentLabel, so the -// model name used to win and an agy pane read as Gemini CLI. describe('agy titles carrying a Gemini model name', () => { const AGY_TITLES = [ '⠋ agy · Gemini 3.7 Flash · high', @@ -14,34 +15,38 @@ describe('agy titles carrying a Gemini model name', () => { 'agy · Gemini 3.5 Flash (High)' ] - it.each(AGY_TITLES)('labels %s as Antigravity', (title) => { + it.each(AGY_TITLES)('labels %s as Antigravity on both title paths', (title) => { expect(getAgentLabel(title)).toBe('Antigravity') - }) - - // Why: the two chain copies are reached by different surfaces — the sidebar goes through - // getAgentLabel, the tab through resolveExplicitTerminalTitleAgentType. A fix in one only - // moves the disagreement rather than removing it. - it.each(AGY_TITLES)('resolves %s as antigravity on the tab path too', (title) => { expect(resolveExplicitTerminalTitleAgentType(title)).toBe('antigravity') }) }) describe('titles that must keep their existing label', () => { - // Why: a real recorded pane title from terminal history. A Grok pane whose TASK TEXT - // contains the token "Antigravity" — it resolves correctly only because grok is checked - // before antigravity, which is why this fix narrows a token instead of reordering. - it('keeps a grok pane whose task text names Antigravity', () => { - expect(getAgentLabel('STA-4011 Linux Antigravity Commit Messages - grok')).toBe('Grok') + it('keeps the recorded Grok pane whose task text names Antigravity', () => { + const title = 'STA-4011 Linux Antigravity Commit Messages - grok' + expect(getAgentLabel(title)).toBe('Grok') + expect(resolveExplicitTerminalTitleAgentType(title)).toBe('grok') }) - // Why: the four Gemini OSC glyphs are decisive and stay so; agy emits none of them. - it('still labels a glyph-bearing Gemini CLI title', () => { - expect(getAgentLabel(`${GEMINI_WORKING} Gemini CLI`)).toBe('Gemini CLI') - expect(getAgentLabel(`${GEMINI_IDLE} Gemini CLI`)).toBe('Gemini CLI') - }) + it.each([GEMINI_PERMISSION, GEMINI_WORKING, GEMINI_SILENT_WORKING, GEMINI_IDLE])( + 'keeps Gemini glyph %s decisive over an agy token', + (glyph) => { + const title = `${glyph} agy · Gemini 3.7 Flash` + expect(getAgentLabel(title)).toBe('Gemini CLI') + expect(resolveExplicitTerminalTitleAgentType(title)).toBe('gemini') + } + ) - // Why: a Gemini CLI title with no agy token must be unaffected by the narrowing. it('still labels a bare gemini token title', () => { expect(getAgentLabel('gemini ready')).toBe('Gemini CLI') + expect(resolveExplicitTerminalTitleAgentType('gemini ready')).toBe('gemini') }) + + it.each(['agy-workspace · Gemini ready', '/tmp/agy/models · Gemini ready'])( + 'does not treat an agy path fragment as Antigravity in %s', + (title) => { + expect(getAgentLabel(title)).toBe('Gemini CLI') + expect(resolveExplicitTerminalTitleAgentType(title)).toBe('gemini') + } + ) }) diff --git a/src/shared/agent-title-core.ts b/src/shared/agent-title-core.ts index cc773ce164e..a05a6d8dff6 100644 --- a/src/shared/agent-title-core.ts +++ b/src/shared/agent-title-core.ts @@ -67,15 +67,11 @@ export function isGeminiTerminalTitle(title: string): boolean { if (isPiAgentTitle(title)) { return false } - // Why: Antigravity's models are named "Gemini ", so an agy pane's own - // title carries a whole `gemini` token. Gemini CLI is checked before Antigravity in - // getAgentLabel, so without this the model name wins and an agy pane reads as Gemini - // CLI. Only the token path defers — the four Gemini OSC glyphs stay decisive, and agy - // emits none of them. - if (titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title)) { + if (!titleHasAgentName(title, 'gemini')) { return false } - return titleHasAgentName(title, 'gemini') + // Why: agy titles include Gemini model names; the glyph path above stays authoritative. + return !(titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title)) } export function isPiTerminalTitle(title: string): boolean { diff --git a/src/shared/terminal-title-agent-type.ts b/src/shared/terminal-title-agent-type.ts index 03a979132b9..e6615c4e85f 100644 --- a/src/shared/terminal-title-agent-type.ts +++ b/src/shared/terminal-title-agent-type.ts @@ -48,15 +48,11 @@ export function isGeminiTerminalTitle(title: string): boolean { if (isPiAgentTitle(title)) { return false } - // Why: Antigravity's models are named "Gemini ", so an agy pane's own - // title carries a whole `gemini` token. Gemini CLI is checked before Antigravity in - // getAgentLabel, so without this the model name wins and an agy pane reads as Gemini - // CLI. Only the token path defers — the four Gemini OSC glyphs stay decisive, and agy - // emits none of them. - if (titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title)) { + if (!titleHasAgentName(title, 'gemini')) { return false } - return titleHasAgentName(title, 'gemini') + // Why: agy titles include Gemini model names; the glyph path above stays authoritative. + return !(titleHasAgentName(title, 'antigravity') || AGY_AGENT_NAME_RE.test(title)) } // Why: Grok Build's working OSC titles use a fixed frame shape —