fork a Claude conversation into a new pane

Adds fork-into-a-pane: /fork in the composer, a roster Fork button, and a
clide.agent.fork command all branch a session via
--resume <source> --fork-session, so the branch gets its own claude
session id and diverges without touching the original. SpawnSpec/
ManagedSession gain forkSourceSessionId; the orchestrator selects the
fork argv via a new forkSessionArgs helper; the session host opens the
fork as a new secondary pane.

The branch's real claude session-id (assigned by --fork-session, arriving
in the init event) is not yet captured back — tracked as T-185.

T-172.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-30 23:34:50 +02:00
co-authored by Claude
parent 2888efbe5f
commit e3c0b0146b
13 changed files with 412 additions and 40 deletions
@@ -74,6 +74,14 @@ String primarySessionId(String repoRoot) => _deterministicUuid(_primarySessionSe
/// (T-161). Appended after the stream-json flags by [ClaudeStreamJsonProcess].
List<String> claudeLaunchArgs(String sessionId, {required bool resume}) => resume ? ['--resume', sessionId] : ['--session-id', sessionId];
/// The session-selection args for forking a session (T-172, D-77).
///
/// `--resume <sourceSessionId> --fork-session` resumes [sourceSessionId] but
/// creates a NEW claude session id so the branch diverges without touching the
/// original. No `--session-id` is passed — the fork gets its own id from the
/// `init` event.
List<String> forkSessionArgs(String sourceSessionId) => ['--resume', sourceSessionId, '--fork-session'];
/// A fresh random session id for a secondary pane — secondaries are
/// always clean sessions, never resumed.
String freshSessionId() {