@@ -62,6 +62,39 @@ impl SessionSnapshotV1 {
6262 )
6363 }
6464
65+ /// Rebind a complete snapshot to a new session and workspace.
66+ ///
67+ /// Session forks retain historical artifacts, traces, run ids, and child
68+ /// session ids. Top-level run ownership and subagent parent ownership must
69+ /// move with the new session or the aggregate would no longer be loadable.
70+ pub fn fork_for_session (
71+ mut self ,
72+ session_id : impl Into < String > ,
73+ workspace : impl Into < String > ,
74+ ) -> Result < Self > {
75+ let source_session_id = self . session . id . clone ( ) ;
76+ self . validate_for_session ( & source_session_id) ?;
77+
78+ let session_id = session_id. into ( ) ;
79+ if session_id. trim ( ) . is_empty ( ) {
80+ bail ! ( "forked session id cannot be empty" ) ;
81+ }
82+
83+ self . session . id = session_id. clone ( ) ;
84+ self . session . config . workspace = workspace. into ( ) ;
85+ for record in & mut self . run_records {
86+ record. snapshot . session_id . clone_from ( & session_id) ;
87+ }
88+ for task in & mut self . subagent_tasks {
89+ if !task. parent_session_id . is_empty ( ) {
90+ task. parent_session_id . clone_from ( & session_id) ;
91+ }
92+ }
93+
94+ self . validate_for_session ( & session_id) ?;
95+ Ok ( self )
96+ }
97+
6598 pub fn artifact_store ( & self ) -> ArtifactStore {
6699 artifact_store_from ( & self . artifacts )
67100 }
0 commit comments