aboutsummaryrefslogtreecommitdiff
path: root/src/terminal
diff options
context:
space:
mode:
Diffstat (limited to 'src/terminal')
-rw-r--r--src/terminal/state.rs110
1 files changed, 96 insertions, 14 deletions
diff --git a/src/terminal/state.rs b/src/terminal/state.rs
index 96580b7d..eebf0fb0 100644
--- a/src/terminal/state.rs
+++ b/src/terminal/state.rs
@@ -416,8 +416,16 @@ impl TerminalState {
return None;
}
let session_ref = session_ref.map(|session_ref| {
- self.conflicting_same_owner_session_ref(&source, &agent_label, &session_ref, None)
- .unwrap_or(session_ref)
+ if self.lifecycle_hook_report_replaces_persisted_session(
+ &source,
+ &agent_label,
+ &session_ref,
+ ) {
+ session_ref
+ } else {
+ self.conflicting_same_owner_session_ref(&source, &agent_label, &session_ref, None)
+ .unwrap_or(session_ref)
+ }
});
if self.live_full_lifecycle_hook_authority_conflicts_with_session(
&source,
@@ -855,6 +863,26 @@ impl TerminalState {
)
}
+ fn lifecycle_hook_report_replaces_persisted_session(
+ &self,
+ source: &str,
+ agent_label: &str,
+ session_ref: &crate::agent_resume::AgentSessionRef,
+ ) -> bool {
+ self.hook_authority.is_none()
+ && (source, agent_label) == ("herdr:mastracode", "mastracode")
+ && self
+ .persisted_agent_session
+ .as_ref()
+ .is_some_and(|session| {
+ session.source == source
+ && session.agent == agent_label
+ && session.session_ref.kind == crate::agent_resume::AgentSessionRefKind::Id
+ && session_ref.kind == crate::agent_resume::AgentSessionRefKind::Id
+ && session.session_ref.value != session_ref.value
+ })
+ }
+
fn session_start_source_allows_session_replacement(
source: &str,
agent_label: &str,
@@ -2307,40 +2335,94 @@ mod tests {
// Regression for #614: a same-pane restart must reacquire lifecycle authority.
#[test]
fn omp_reacquires_full_lifecycle_hook_after_release_with_fresh_session_ref() {
+ assert_full_lifecycle_hook_reacquires_after_release_with_fresh_session_ref(
+ "herdr:omp",
+ "omp",
+ );
+ }
+
+ #[test]
+ fn mastracode_reacquires_full_lifecycle_hook_after_release_with_fresh_session_ref() {
+ assert_full_lifecycle_hook_reacquires_after_release_with_fresh_session_ref(
+ "herdr:mastracode",
+ "mastracode",
+ );
+ }
+
+ #[test]
+ fn mastracode_lifecycle_report_replaces_restored_thread_ref() {
let mut terminal = test_terminal();
+ terminal.set_persisted_agent_session(crate::agent_resume::PersistedAgentSession {
+ source: "herdr:mastracode".into(),
+ agent: "mastracode".into(),
+ session_ref: crate::agent_resume::AgentSessionRef::id("mastracode-old").unwrap(),
+ });
+
+ let mutation = terminal
+ .set_hook_authority_with_session_ref(
+ "herdr:mastracode".into(),
+ "mastracode".into(),
+ AgentState::Working,
+ None,
+ None,
+ crate::agent_resume::AgentSessionRef::id("mastracode-new"),
+ Some(20),
+ )
+ .expect("fresh MastraCode thread should replace restored thread id");
+
+ assert!(mutation.session_ref_changed);
+ assert_eq!(
+ terminal.current_session_identity_for_persistence(),
+ Some((
+ "herdr:mastracode".into(),
+ "mastracode".into(),
+ crate::agent_resume::AgentSessionRefKind::Id,
+ "mastracode-new".into()
+ ))
+ );
+ }
+
+ fn assert_full_lifecycle_hook_reacquires_after_release_with_fresh_session_ref(
+ source: &str,
+ agent_label: &str,
+ ) {
+ let mut terminal = test_terminal();
+ let old_session = format!("{agent_label}-old");
+ let new_session = format!("{agent_label}-new");
+
terminal.set_hook_authority_with_session_ref(
- "herdr:omp".into(),
- "omp".into(),
+ source.into(),
+ agent_label.into(),
AgentState::Working,
None,
None,
- crate::agent_resume::AgentSessionRef::id("omp-old"),
+ crate::agent_resume::AgentSessionRef::id(&old_session),
Some(20),
);
- terminal.release_agent("herdr:omp", "omp", Some(21));
+ terminal.release_agent(source, agent_label, Some(21));
// A late report from the released run keeps its old session ref and stays
- // suppressed, so a just-exited omp cannot resurrect the pane.
+ // suppressed, so a just-exited agent cannot resurrect the pane.
let stale = terminal.set_hook_authority_with_session_ref(
- "herdr:omp".into(),
- "omp".into(),
+ source.into(),
+ agent_label.into(),
AgentState::Working,
None,
None,
- crate::agent_resume::AgentSessionRef::id("omp-old"),
+ crate::agent_resume::AgentSessionRef::id(&old_session),
Some(22),
);
assert!(stale.is_none());
assert!(terminal.hook_authority.is_none());
- // A fresh omp run carries a new session ref and reacquires authority.
+ // A fresh run carries a new session ref and reacquires authority.
let fresh = terminal.set_hook_authority_with_session_ref(
- "herdr:omp".into(),
- "omp".into(),
+ source.into(),
+ agent_label.into(),
AgentState::Working,
None,
None,
- crate::agent_resume::AgentSessionRef::id("omp-new"),
+ crate::agent_resume::AgentSessionRef::id(&new_session),
Some(23),
);
assert!(fresh.is_some());