Terminal: empty rename does not restore dynamic tab title — stale staticTitle is never cleared
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Does this issue occur when all extensions are disabled?: Yes (core terminal behavior)
- VS Code Version: 1.135.0 (08d4889f9ec4a1685d257b9b95de036c8e1ce1e5)
- OS Version: macOS (Darwin 25.5.0)
### Summary
Renaming a terminal tab to an **empty name** is supposed to clear the custom (static) title and restore the dynamic title (process/sequence-based, including the agentic CLI live title from `terminal.integrated.tabs.allowAgentCliTitle`). In practice the dynamic title reappears only for a moment and then reverts to the previously set custom name on the next title update from the shell/CLI.
Root cause: `_staticTitle` is never cleared on the empty-rename path.
### Steps to Reproduce
1. Open an integrated terminal running an agentic CLI (e.g. Claude Code) — with the default `terminal.integrated.tabs.allowAgentCliTitle: true`, the tab title live-updates via the escape-sequence title (`${sequence}`).
2. Right-click the terminal tab → **Rename** → enter `my-agent` → Enter. The tab now shows the static name (expected).
3. Rename again, clear the input to empty, press Enter.
4. The tab briefly shows the dynamic title again, but as soon as the CLI emits its next title escape sequence, the tab **reverts to `my-agent`**.
Expected: step 3 permanently removes the custom name and the tab follows the dynamic title again. The only workaround today is killing the terminal and opening a new one.
### Analysis
In `src/vs/workbench/contrib/terminal/browser/terminalInstance.ts`:
`rename()` maps an empty string to `undefined` and calls `_setTitle(undefined, TitleEventSource.Api)`:
```ts
async rename(title?: string, source?: TitleEventSource) {
if (title !== undefined && !title) {
title = undefined;
}
this._setTitle(title, source ?? TitleEventSource.Api);
}
```
`_updateTitleProperties()` returns early for `undefined` **before** reaching the `case TitleEventSource.Api:` branch that assigns `_staticTitle`, so the stale `_staticTitle` from the earlier rename survives (and `_titleSource` also stays `Api`):
```ts
private _updateTitleProperties(title: string | undefined, eventSource: TitleEventSource): string {
if (title === undefined) {
return this._processName; // <-- early return: _staticTitle NOT cleared
}
switch (eventSource) {
...
case TitleEventSource.Api:
this._staticTitle = title; // only reachable when title is defined
...
```
`_setTitle` then calls `refreshLabel(this, reset = true)`, and `computeLabel` bypasses the static title **once** because of the `!reset` guard:
```ts
if (!reset && instance.staticTitle && labelType === TerminalLabelType.Title) {
return instance.staticTitle... // stale staticTitle wins again on every later refresh
}
```
Every subsequent `refreshLabel` (triggered by process/sequence title events) runs with `reset === false`, hits the guard, and the stale `_staticTitle` wins again — producing the observed flash-then-revert behavior.
### Suggested fix
When `rename` is called with an empty/undefined title from the Api source, clear `_staticTitle` (and arguably reset `_titleSource` to `Process`) so later label refreshes fall through to the configured template / agent CLI sequence title.
Contributor guide
Assessment
This issue has not been assessed yet.