From 33ac5c30d33162b6972ce79a82b28381d95c4e70 Mon Sep 17 00:00:00 2001 From: bellman Date: Fri, 15 May 2026 11:05:35 +0900 Subject: [PATCH] omx(team): auto-checkpoint worker-1 [1] --- rust/crates/runtime/src/session_control.rs | 4 +- rust/crates/rusty-claude-cli/src/main.rs | 77 ++++++++++++++++++++-- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/rust/crates/runtime/src/session_control.rs b/rust/crates/runtime/src/session_control.rs index c04ccb02..561da6ca 100644 --- a/rust/crates/runtime/src/session_control.rs +++ b/rust/crates/runtime/src/session_control.rs @@ -606,8 +606,7 @@ mod tests { 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, + ManagedSessionSummary, SessionControlError, SessionStore, LATEST_SESSION_REFERENCE, }; use crate::session::Session; use std::fs; @@ -1031,7 +1030,6 @@ 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 diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 91af6665..d552b938 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -3527,7 +3527,7 @@ fn render_resume_usage() -> String { format!( "Resume Usage /resume - Auto-save .claw/sessions/.{PRIMARY_SESSION_EXTENSION} + Auto-save .claw/sessions//.{PRIMARY_SESSION_EXTENSION} Tip use /session list to inspect saved sessions" ) } @@ -4092,6 +4092,29 @@ fn run_resume_command( }) } SlashCommand::Unknown(name) => Err(format_unknown_slash_command(name).into()), + SlashCommand::Session { + action: Some(ref act), + target: Some(ref target), + } if act == "exists" => { + let exists = session_reference_exists(target).unwrap_or(false); + let resolved = resolve_session_reference(target).ok(); + Ok(ResumeCommandOutcome { + session: session.clone(), + message: Some(format!( + "Session exists\n Session {target}\n Exists {exists}{}", + resolved + .as_ref() + .map(|handle| format!("\n File {}", handle.path.display())) + .unwrap_or_default() + )), + json: Some(serde_json::json!({ + "kind": "session_exists", + "session": target, + "exists": exists, + "path": resolved.map(|handle| handle.path.display().to_string()), + })), + }) + } // /session list can be served from the sessions directory without a live session. SlashCommand::Session { action: Some(ref act), @@ -5687,6 +5710,22 @@ impl LiveCli { println!("{}", render_session_list(&self.session.id)?); Ok(false) } + Some("exists") => { + let Some(target) = target else { + println!("Usage: /session exists "); + return Ok(false); + }; + let exists = session_reference_exists(target)?; + let handle = resolve_session_reference(target).ok(); + println!( + "Session exists\n Session {target}\n Exists {exists}{}", + handle + .as_ref() + .map(|handle| format!("\n File {}", handle.path.display())) + .unwrap_or_default() + ); + Ok(false) + } Some("switch") => { let Some(target) = target else { println!("Usage: /session switch "); @@ -5801,7 +5840,7 @@ impl LiveCli { } Some(other) => { println!( - "Unknown /session action '{other}'. Use /session list, /session switch , /session fork [branch-name], or /session delete [--force]." + "Unknown /session action '{other}'. Use /session list, /session exists , /session switch , /session fork [branch-name], or /session delete [--force]." ); Ok(false) } @@ -5982,6 +6021,10 @@ fn resolve_session_reference(reference: &str) -> Result Result> { + Ok(current_session_store()?.session_exists(reference)) +} + fn resolve_managed_session_path(session_id: &str) -> Result> { current_session_store()? .resolve_managed_path(session_id) @@ -6148,7 +6191,8 @@ fn render_repl_help() -> String { " Tab Complete commands, modes, and recent sessions".to_string(), " Ctrl-C Clear input (or exit on empty prompt)".to_string(), " Shift+Enter/Ctrl+J Insert a newline".to_string(), - " Auto-save .claw/sessions/.jsonl".to_string(), + " Auto-save .claw/sessions//.jsonl" + .to_string(), " Resume latest /resume latest".to_string(), " Browse sessions /session list".to_string(), " Show prompt history /history [count]".to_string(), @@ -12561,7 +12605,8 @@ mod tests { assert!(help.contains("/export [file]")); // Batch 5 added `/session delete`; match on the stable core rather than // the trailing bracket so future additions don't re-break this. - assert!(help.contains("/session [list|switch |fork [branch-name]")); + assert!(help + .contains("/session [list|exists |switch |fork [branch-name]")); assert!(help.contains( "/plugin [list|install |enable |disable |uninstall |update ]" )); @@ -12569,7 +12614,9 @@ mod tests { assert!(help.contains("/agents")); assert!(help.contains("/skills")); assert!(help.contains("/exit")); - assert!(help.contains("Auto-save .claw/sessions/.jsonl")); + assert!(help.contains( + "Auto-save .claw/sessions//.jsonl" + )); assert!(help.contains("Resume latest /resume latest")); } @@ -12699,6 +12746,26 @@ mod tests { assert!(names.contains(&"compact")); } + #[test] + fn session_exists_resume_command_reports_json_contract() { + let session = Session::new(); + let path = PathBuf::from("missing-session.jsonl"); + let outcome = run_resume_command( + &path, + &session, + &SlashCommand::Session { + action: Some("exists".to_string()), + target: Some("definitely-missing-session".to_string()), + }, + ) + .expect("exists command should not fail for missing sessions"); + + let json = outcome.json.expect("json contract"); + assert_eq!(json["kind"], "session_exists"); + assert_eq!(json["exists"], false); + assert_eq!(json["session"], "definitely-missing-session"); + } + #[test] fn resume_report_uses_sectioned_layout() { let report = format_resume_report("session.jsonl", 14, 6);