fix: Set both tab and window title instead of just window title (#16464)

Co-authored-by: Oleksandr Nikitin <oleksandr@tvori.info>
This commit is contained in:
N. Taylor Mullen
2026-01-12 20:14:01 -08:00
committed by GitHub
parent b81fe68325
commit 6adae9f775
3 changed files with 22 additions and 22 deletions

View File

@@ -720,10 +720,10 @@ function setWindowTitle(title: string, settings: LoadedSettings) {
showThoughts: !!settings.merged.ui?.showStatusInTitle,
useDynamicTitle: settings.merged.ui?.dynamicWindowTitle ?? true,
});
writeToStdout(`\x1b]2;${windowTitle}\x07`);
writeToStdout(`\x1b]0;${windowTitle}\x07`);
process.on('exit', () => {
writeToStdout(`\x1b]2;\x07`);
writeToStdout(`\x1b]0;\x07`);
});
}
}

View File

@@ -1020,12 +1020,12 @@ describe('AppContainer State Management', () => {
// Assert: Check that title was updated with "Working…"
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
expect(titleWrites[0][0]).toBe(
`\x1b]2;${'✦ Working… (workspace)'.padEnd(80, ' ')}\x07`,
`\x1b]0;${'✦ Working… (workspace)'.padEnd(80, ' ')}\x07`,
);
unmount();
});
@@ -1061,12 +1061,12 @@ describe('AppContainer State Management', () => {
// Assert: Check that legacy title was used
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
expect(titleWrites[0][0]).toBe(
`\x1b]2;${'Gemini CLI (workspace)'.padEnd(80, ' ')}\x07`,
`\x1b]0;${'Gemini CLI (workspace)'.padEnd(80, ' ')}\x07`,
);
unmount();
});
@@ -1092,7 +1092,7 @@ describe('AppContainer State Management', () => {
// Assert: Check that no title-related writes occurred
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(0);
@@ -1131,12 +1131,12 @@ describe('AppContainer State Management', () => {
// Assert: Check that title was updated with thought subject and suffix
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
expect(titleWrites[0][0]).toBe(
`\x1b]2;${`${thoughtSubject} (workspace)`.padEnd(80, ' ')}\x07`,
`\x1b]0;${`${thoughtSubject} (workspace)`.padEnd(80, ' ')}\x07`,
);
unmount();
});
@@ -1172,12 +1172,12 @@ describe('AppContainer State Management', () => {
// Assert: Check that title was updated with default Idle text
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
expect(titleWrites[0][0]).toBe(
`\x1b]2;${'◇ Ready (workspace)'.padEnd(80, ' ')}\x07`,
`\x1b]0;${'◇ Ready (workspace)'.padEnd(80, ' ')}\x07`,
);
unmount();
});
@@ -1218,12 +1218,12 @@ describe('AppContainer State Management', () => {
// Assert: Check that title was updated with confirmation text
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
expect(titleWrites[0][0]).toBe(
`\x1b]2;${'✋ Action Required (workspace)'.padEnd(80, ' ')}\x07`,
`\x1b]0;${'✋ Action Required (workspace)'.padEnd(80, ' ')}\x07`,
);
unmount!();
});
@@ -1269,7 +1269,7 @@ describe('AppContainer State Management', () => {
// Initially it should show the working status
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites[titleWrites.length - 1][0]).toContain(
'✦ Executing shell command',
@@ -1283,7 +1283,7 @@ describe('AppContainer State Management', () => {
// Now it should show Action Required
await waitFor(() => {
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
const lastTitle = titleWrites[titleWrites.length - 1][0];
expect(lastTitle).toContain('✋ Action Required');
@@ -1325,13 +1325,13 @@ describe('AppContainer State Management', () => {
// Assert: Check that title is padded to exactly 80 characters
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
const calledWith = titleWrites[0][0];
const expectedTitle = `${shortTitle} (workspace)`.padEnd(80, ' ');
const expectedEscapeSequence = `\x1b]2;${expectedTitle}\x07`;
const expectedEscapeSequence = `\x1b]0;${expectedTitle}\x07`;
expect(calledWith).toBe(expectedEscapeSequence);
unmount();
});
@@ -1368,11 +1368,11 @@ describe('AppContainer State Management', () => {
// Assert: Check that the correct ANSI escape sequence is used
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
const expectedEscapeSequence = `\x1b]2;${`${title} (workspace)`.padEnd(80, ' ')}\x07`;
const expectedEscapeSequence = `\x1b]0;${`${title} (workspace)`.padEnd(80, ' ')}\x07`;
expect(titleWrites[0][0]).toBe(expectedEscapeSequence);
unmount();
});
@@ -1411,12 +1411,12 @@ describe('AppContainer State Management', () => {
// Assert: Check that title was updated with CLI_TITLE value
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) =>
call[0].includes('\x1b]2;'),
call[0].includes('\x1b]0;'),
);
expect(titleWrites).toHaveLength(1);
expect(titleWrites[0][0]).toBe(
`\x1b]2;${'✦ Working… (Custom Gemini Title)'.padEnd(80, ' ')}\x07`,
`\x1b]0;${'✦ Working… (Custom Gemini Title)'.padEnd(80, ' ')}\x07`,
);
unmount();
});

View File

@@ -1362,7 +1362,7 @@ Logging in with Google... Restarting Gemini CLI to continue.
// Only update the title if it's different from the last value we set
if (lastTitleRef.current !== paddedTitle) {
lastTitleRef.current = paddedTitle;
stdout.write(`\x1b]2;${paddedTitle}\x07`);
stdout.write(`\x1b]0;${paddedTitle}\x07`);
}
// Note: We don't need to reset the window title on exit because Gemini CLI is already doing that elsewhere
}, [