anthropics / anthropics/claude-code

[BUG] Stealth update restarts over an open `/btw` side chat and discards it

Offen
#93,122 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:desktop bug has repro platform:macos
Vorherrschende Sprache
Python
Sterne
145k
Forks
23.1k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code

### What's Wrong?

## Summary

The stealth auto-update relaunch treats an open `/btw` side chat as idle, restarts
on top of it, and loses it. Side chat state is in-memory only, so the "seamless"
relaunch cannot restore it — and the idle gate that exists to prevent exactly this
does not count side chats as active work.

## Environment

- Claude Desktop, update 1.46388.1 → 1.49585.0 (macOS, arm64)
- Claude Code 2.1.260 (bundled)
- macOS 26.6.2

## What happened

1. Desktop launched cold after several days closed; updater staged an update.
2. In a Claude Code session, ran `/btw ` — side chat panel mounted and
remained open with content in it.
3. Focus moved to another app (terminal). Desktop window unfocused, not fullscreen.
4. After ~10 minutes idle, the stealth updater fired, quit, installed, relaunched.
5. Main view and navigation came back. The side chat and its answer were gone.

Elapsed from first update check to install: ~41 minutes. The 72h enforcement
window was nowhere near expiry — this was the idle path, not the deadline path.

## Actual

The side chat is destroyed with no warning and no recovery path.

### What Should Happen?

## Expected

Either the restart is deferred while a side chat is open, or the side chat is
restored alongside the navigation state.

### Error Messages/Logs

```shell
## Evidence

Relevant log lines (relative times; T0 = quit):

T-0m01s [popout-restore] Saving 0 session + 0 pane popout(s) for next launch
T+0m00s [stealth-update] Triggering stealth update after idle timeout
T+0m01s Successfully run onQuitCleanup: local-session-stop-all
T+0m19s [stealth-relaunch] Restoring navigation (3 entries, active=2, dropped=0)

`Restoring navigation` restores which views were open, not live session state.
`Saving 0 session + 0 pane popout(s)` is the app correctly reporting it had
nothing persistable to carry forward.
```

### Steps to Reproduce

1. Launch Claude Desktop after updater staged an update.
2. In a Claude Code session, ran `/btw ` — side chat panel mounted and
remained open with content in it.
3. Switch window focus to another app so that Claude Desktop window is unfocused, not fullscreen.
4. After ~10 minutes idle, the stealth updater will fire, quit, install the update, and relaunch the app.
5. Main view and navigation will come back. The side chat and its answer will be gone.

### Claude Model

_No response_

### Is this a regression?

I don't know

### Last Working Version

_No response_

### Claude Code Version

1.49585.0

### Platform

Anthropic API

### Operating System

macOS

### Terminal/Shell

iTerm2

### Additional Information

## Claude's Analysis

The idle gate blocks the restart on any of:

```js
idleBlocker() {
... "update not ready"
: "install of this version keeps failing"
: hasAnyActiveSession() ? "sessions active"
: isWindowFocused() ? "window focused"
: isWindowFullScreen() ? "window fullscreen"
: null
}
```

`hasAnyActiveSession()` evidently does not return true for an open side chat, so
the gate cleared. Meanwhile side chats are held in an in-memory Map with no
persistence:

```js
this.sideChats = new Map
spawnReadOnlyFork(a, {sessionId: e, logTag: "SideChat", ...})
history: r?.recovery?.history.cloneForRespawn() ?? new jl
```

Nothing is written to disk — a filesystem search of the Claude config tree for
`SideChat` / `sideQuery` / side-question markers returns no transcript, and no
`/btw` invocation appears in any parent session transcript.

So the two halves disagree: the gate exists to avoid restarting on top of live
work, but the one kind of live work with zero persistence is invisible to it.

Note this is not update-specific — an ordinary quit or a crash loses `/btw`
content identically. The update path just makes it happen unprompted.

## Suggested fix

Either of these closes it; the first is cheaper:

1. Count an open side chat in `hasAnyActiveSession()` so the idle gate defers the
restart, consistent with its existing intent.
2. Persist side chat history alongside the parent session so `stealth-relaunch`
can restore it with the navigation state.

A warning before a stealth restart that will discard unsaved side chat content
would also be an improvement over silent loss.

Possibly related issue, but not exactly the same: https://github.com/anthropics/claude-code/issues/90867

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

No source file or test is named. Start by locating idleBlocker(), hasAnyActiveSession(), stealth-relaunch, and the sideChats Map or spawnReadOnlyFork entry points, then trace the idle update path. Done means an open /btw chat is not silently lost during relaunch, with a regression check for the reported behavior.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
javascript
Bereich
desktop, release
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
42/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.