diff options
Diffstat (limited to 'src/persist')
| -rw-r--r-- | src/persist/restore.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/persist/restore.rs b/src/persist/restore.rs index 31ee0a37..265b4874 100644 --- a/src/persist/restore.rs +++ b/src/persist/restore.rs @@ -561,6 +561,10 @@ fn restore_tab( .unwrap_or_default(); let imported_runtime = old_pane_id.and_then(|old_id| imported_panes.remove(&old_id)); let was_imported = imported_runtime.is_some(); + #[cfg(unix)] + let handoff_agent_state = imported_runtime + .as_ref() + .and_then(|imported| imported.state.agent_state.clone()); let pending_native_agent_restore = if was_imported { None } else { @@ -693,6 +697,10 @@ fn restore_tab( std::time::Instant::now(), ); } + #[cfg(unix)] + if let Some(agent_state) = handoff_agent_state { + terminal.restore_handoff_agent_state(agent_state); + } panes.insert(*id, PaneState::new(terminal_id.clone())); terminal_runtimes.insert(terminal_id, runtime); terminals.push(terminal); @@ -1709,6 +1717,108 @@ mod tests { } #[tokio::test] + #[cfg(unix)] + async fn live_handoff_preserves_hook_status_until_next_report() { + for state_before_handoff in [AgentState::Working, AgentState::Blocked] { + let (snapshot, _) = snapshot_with_saved_pane_history(); + let (events, _events_rx) = mpsc::channel(32); + let (workspaces, mut terminals, runtimes) = restore( + &snapshot, + None, + 24, + 80, + 4096, + test_restore_shell(), + crate::config::ShellModeConfig::NonLogin, + false, + events.clone(), + Arc::new(Notify::new()), + Arc::new(RenderSignal::new()), + ); + let terminal = terminals.values_mut().next().unwrap(); + terminal + .set_detected_agent_process_at(crate::detect::Agent::Pi, std::time::Instant::now()); + terminal.set_persisted_agent_session(crate::agent_resume::PersistedAgentSession { + source: "herdr:pi".into(), + agent: "pi".into(), + session_ref: crate::agent_resume::AgentSessionRef::path( + "/var/tmp/handoff-test.jsonl", + ) + .unwrap(), + }); + terminal.set_hook_authority_with_session_ref( + "herdr:pi".into(), + "pi".into(), + state_before_handoff, + None, + Some( + crate::agent_resume::AgentSessionRef::path("/var/tmp/handoff-test.jsonl") + .unwrap(), + ), + Some(1), + ); + assert_eq!(terminal.state, state_before_handoff); + let runtimes = crate::terminal::TerminalRuntimeRegistry::from(runtimes); + let snapshot = crate::persist::capture(&workspaces, &terminals, &runtimes, Some(0), 0); + let pane_id = workspaces[0].tabs[0].panes.keys().next().copied().unwrap(); + let runtime = runtimes.values().next().unwrap(); + runtime + .pause_handoff_reader(std::time::Duration::from_secs(2)) + .unwrap(); + let mut state = runtime.handoff_runtime_state(pane_id.raw()); + state.agent_state = terminals.values().next().unwrap().handoff_agent_state(); + let state = serde_json::from_value(serde_json::to_value(state).unwrap()).unwrap(); + let mut imports = HashMap::from([( + pane_id.raw(), + crate::handoff_runtime::ImportedHandoffRuntime { + master_fd: runtime.duplicate_handoff_fd().unwrap(), + state, + }, + )]); + let (_, mut restored_terminals, restored_runtimes) = restore_handoff( + &snapshot, + 4096, + test_restore_shell(), + crate::config::ShellModeConfig::NonLogin, + &mut imports, + events, + Arc::new(Notify::new()), + Arc::new(RenderSignal::new()), + ) + .unwrap(); + drop(restored_runtimes); + drop(runtimes); + let terminal = restored_terminals.values_mut().next().unwrap(); + assert_eq!(terminal.state, state_before_handoff); + terminal.set_detected_state(Some(crate::detect::Agent::Pi), AgentState::Idle); + assert_eq!( + terminal.state, state_before_handoff, + "screen fallback must not erase the transferred hook status" + ); + terminal.set_hook_authority_with_session_ref( + "herdr:pi".into(), + "pi".into(), + AgentState::Idle, + None, + Some( + crate::agent_resume::AgentSessionRef::path("/var/tmp/handoff-test.jsonl") + .unwrap(), + ), + Some(2), + ); + assert_eq!( + terminal.state, + AgentState::Idle, + "the next hook report must take effect immediately" + ); + assert_eq!( + terminal.finish_agent_process_acquisition(), + state_before_handoff == AgentState::Blocked + ); + } + } + + #[tokio::test] async fn restore_seeds_saved_pane_history_into_runtime() { let (snapshot, history) = snapshot_with_saved_pane_history(); let (events, _events_rx) = mpsc::channel(8); |
