aboutsummaryrefslogtreecommitdiff
path: root/src/persist
diff options
context:
space:
mode:
Diffstat (limited to 'src/persist')
-rw-r--r--src/persist/restore.rs110
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);