fix Claude secondary pane copy + false "session exited"
Two things surfaced in the secondary pane: the tab said "session 1" while the banner said "secondary 1" — now both say "session N". And the banner showed "session exited" right after starting, even though Claude was alive: a transient tmux client process can exit during spawn while the session itself is fine. pane.exit now verifies via `tmux has-session` and only reports exited when the session is actually gone. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -275,10 +275,18 @@ class _ClaudePaneState extends State<ClaudePane> {
|
||||
final kernel = _kernel();
|
||||
if (kernel == null) return;
|
||||
// Lifecycle only — content comes from the transcript, not pane.output.
|
||||
_eventSub = kernel.events.on<DaemonEvent>().listen((e) {
|
||||
_eventSub = kernel.events.on<DaemonEvent>().listen((e) async {
|
||||
if (e.subsystem != 'pane' || e.data['id'] != _paneId) return;
|
||||
switch (e.kind) {
|
||||
case 'pane.exit':
|
||||
// A transient tmux client can exit (e.g. during spawn/respawn)
|
||||
// while the session — and Claude — stay alive. Don't report
|
||||
// "exited" then; only when the tmux session is actually gone.
|
||||
// (The no-tmux fallback has no session, so the exit is real.)
|
||||
if (_usingTmux && _sessionName != null && await tmux.hasSession(_sessionName!)) {
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() => _statusLine = widget.isPrimary ? 'session exited — restart clide to retry' : 'session exited');
|
||||
case 'pane.closed':
|
||||
_paneId = null;
|
||||
@@ -317,7 +325,7 @@ class _ClaudePaneState extends State<ClaudePane> {
|
||||
child: ConversationView(
|
||||
controller: _conversation!,
|
||||
emptyState: ClaudeBanner(
|
||||
role: widget.isPrimary ? 'primary' : 'secondary ${widget.secondaryIndex}',
|
||||
role: widget.isPrimary ? 'primary' : 'session ${widget.secondaryIndex}',
|
||||
workspace: _repoRoot,
|
||||
statusLine: _statusLine,
|
||||
),
|
||||
|
||||
@@ -24,6 +24,14 @@ Future<void> killSession(String name) async {
|
||||
await tmuxRunner([..._socket, 'kill-session', '-t', name]);
|
||||
}
|
||||
|
||||
/// Whether [name] is a live session on the clide socket. Used to suppress
|
||||
/// a spurious "session exited" when a transient tmux client process exits
|
||||
/// but the session itself is fine (T-149 follow-up).
|
||||
Future<bool> hasSession(String name) async {
|
||||
final r = await tmuxRunner([..._socket, 'has-session', '-t', name]);
|
||||
return r.exitCode == 0;
|
||||
}
|
||||
|
||||
/// Return the names of all sessions currently alive on the clide
|
||||
/// socket. Empty list if the server is not running.
|
||||
Future<List<String>> listClideSessions() async {
|
||||
|
||||
Reference in New Issue
Block a user