From fc35dc878c7bf62140991d3107a7ce5efa506078 Mon Sep 17 00:00:00 2001 From: bellman Date: Fri, 15 May 2026 11:03:35 +0900 Subject: [PATCH] omx(team): auto-checkpoint worker-1 [1] --- rust/crates/commands/src/lib.rs | 27 +++++++-- rust/crates/runtime/src/session_control.rs | 68 +++++++++++++++++++++- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/rust/crates/commands/src/lib.rs b/rust/crates/commands/src/lib.rs index 9e9a3ced..f08ae700 100644 --- a/rust/crates/commands/src/lib.rs +++ b/rust/crates/commands/src/lib.rs @@ -221,9 +221,9 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[ SlashCommandSpec { name: "session", aliases: &[], - summary: "List, switch, fork, or delete managed local sessions", + summary: "List, check, switch, fork, or delete managed local sessions", argument_hint: Some( - "[list|switch |fork [branch-name]|delete [--force]]", + "[list|exists |switch |fork [branch-name]|delete [--force]]", ), resume_supported: false, }, @@ -1590,7 +1590,17 @@ fn parse_session_command(args: &[&str]) -> Result Err(usage_error("session", "[list|switch |fork [branch-name]|delete [--force]]")), + ["list", ..] => Err(usage_error("session", "[list|exists |switch |fork [branch-name]|delete [--force]]")), + ["exists"] => Err(usage_error("session exists", "")), + ["exists", target] => Ok(SlashCommand::Session { + action: Some("exists".to_string()), + target: Some((*target).to_string()), + }), + ["exists", ..] => Err(command_error( + "Unexpected arguments for /session exists.", + "session", + "/session exists ", + )), ["switch"] => Err(usage_error("session switch", "")), ["switch", target] => Ok(SlashCommand::Session { action: Some("switch".to_string()), @@ -1637,10 +1647,10 @@ fn parse_session_command(args: &[&str]) -> Result Err(command_error( &format!( - "Unknown /session action '{action}'. Use list, switch , fork [branch-name], or delete [--force]." + "Unknown /session action '{action}'. Use list, exists , switch , fork [branch-name], or delete [--force]." ), "session", - "/session [list|switch |fork [branch-name]|delete [--force]]", + "/session [list|exists |switch |fork [branch-name]|delete [--force]]", )), } } @@ -4585,6 +4595,13 @@ mod tests { path: Some("notes.txt".to_string()) })) ); + assert_eq!( + SlashCommand::parse("/session exists abc123"), + Ok(Some(SlashCommand::Session { + action: Some("exists".to_string()), + target: Some("abc123".to_string()) + })) + ); assert_eq!( SlashCommand::parse("/session switch abc123"), Ok(Some(SlashCommand::Session { diff --git a/rust/crates/runtime/src/session_control.rs b/rust/crates/runtime/src/session_control.rs index 743ae7d5..c04ccb02 100644 --- a/rust/crates/runtime/src/session_control.rs +++ b/rust/crates/runtime/src/session_control.rs @@ -163,6 +163,16 @@ impl SessionStore { }) } + pub fn session_exists(&self, reference: &str) -> bool { + self.resolve_reference(reference).is_ok() + } + + pub fn delete_session(&self, reference: &str) -> Result { + let handle = self.resolve_reference(reference)?; + fs::remove_file(&handle.path)?; + Ok(handle) + } + pub fn load_session( &self, reference: &str, @@ -480,6 +490,30 @@ pub fn load_managed_session(reference: &str) -> Result Result { + managed_session_exists_for(env::current_dir()?, reference) +} + +pub fn managed_session_exists_for( + base_dir: impl AsRef, + reference: &str, +) -> Result { + let store = SessionStore::from_cwd(base_dir)?; + Ok(store.session_exists(reference)) +} + +pub fn delete_managed_session(reference: &str) -> Result { + delete_managed_session_for(env::current_dir()?, reference) +} + +pub fn delete_managed_session_for( + base_dir: impl AsRef, + reference: &str, +) -> Result { + let store = SessionStore::from_cwd(base_dir)?; + store.delete_session(reference) +} + pub fn load_managed_session_for( base_dir: impl AsRef, reference: &str, @@ -569,9 +603,10 @@ fn path_is_within_workspace(path: &Path, workspace_root: &Path) -> bool { #[cfg(test)] mod tests { use super::{ - create_managed_session_handle_for, fork_managed_session_for, is_session_reference_alias, - list_managed_sessions_for, load_managed_session_for, resolve_session_reference_for, - workspace_fingerprint, ManagedSessionSummary, SessionControlError, SessionStore, + create_managed_session_handle_for, delete_managed_session_for, fork_managed_session_for, + is_session_reference_alias, list_managed_sessions_for, load_managed_session_for, + managed_session_exists_for, resolve_session_reference_for, workspace_fingerprint, + ManagedSessionSummary, SessionControlError, SessionStore, LATEST_SESSION_REFERENCE, }; use crate::session::Session; @@ -996,6 +1031,33 @@ mod tests { fs::remove_dir_all(base).expect("temp dir should clean up"); } + + #[test] + fn session_exists_and_delete_are_scoped_to_workspace_store() { + // given + let base = temp_dir(); + fs::create_dir_all(&base).expect("base dir should exist"); + let store = SessionStore::from_cwd(&base).expect("store should build"); + let session = persist_session_via_store(&store, "delete me"); + + // when + assert!( + managed_session_exists_for(&base, &session.session_id).expect("exists should run"), + "persisted session should exist before deletion" + ); + let deleted = + delete_managed_session_for(&base, &session.session_id).expect("delete should succeed"); + + // then + assert_eq!(deleted.id, session.session_id); + assert!(!deleted.path.exists(), "session file should be removed"); + assert!( + !managed_session_exists_for(&base, &session.session_id).expect("exists should run"), + "deleted session should not exist" + ); + fs::remove_dir_all(base).expect("temp dir should clean up"); + } + #[test] fn session_store_fork_stays_in_same_namespace() { // given