consume the fork source on first bind (T-375)

widget.forkSourceId took precedence over the fresh/resume logic on
EVERY (re)bind, so /clear in a fork pane re-forked the original
conversation instead of clearing, and /resume re-forked the same way.
The source is now copied into one-shot pane state and cleared after
the first successful fork spawn; later respawns operate on the pane's
own session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 01:11:17 +02:00
co-authored by Claude Fable 5
parent 51957eb0ac
commit bbc6899df2
5 changed files with 43 additions and 1 deletions
+9 -1
View File
@@ -81,6 +81,10 @@ class _ClaudePaneState extends State<ClaudePane> {
String? _error;
String _statusLine = 'starting…';
/// One-shot fork source: seeds the first bind, then cleared so /clear,
/// /resume, and respawns operate on this pane's own session (T-375).
late String? _forkSource = widget.forkSourceId;
bool _spawned = false;
/// Per-session composer draft (text + caret), held here so an unsent
@@ -272,7 +276,7 @@ class _ClaudePaneState extends State<ClaudePane> {
}
final ManagedSession managed;
final forkSource = widget.forkSourceId;
final forkSource = _forkSource;
if (forkSource != null) {
// Fork pane: branch source session into a new clide-managed session.
// The clide-internal id is a fresh UUID; the real claude session id is
@@ -286,6 +290,10 @@ class _ClaudePaneState extends State<ClaudePane> {
if (mounted) setState(() => _error = 'Could not start fork: $e');
return;
}
// One-shot: the fork source seeds only the FIRST bind. Leaving it set
// made /clear re-fork the original conversation instead of clearing —
// every later respawn must operate on this pane's own session (T-375).
_forkSource = null;
if (!mounted) return;
setState(() => _statusLine = 'fork of $forkSource');
} else {