omx(team): auto-checkpoint worker-1 [1]

This commit is contained in:
bellman
2026-05-15 11:03:35 +09:00
parent e199a392fb
commit fc35dc878c
2 changed files with 87 additions and 8 deletions

View File

@@ -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 <session-id>|fork [branch-name]|delete <session-id> [--force]]",
"[list|exists <session-id>|switch <session-id>|fork [branch-name]|delete <session-id> [--force]]",
),
resume_supported: false,
},
@@ -1590,7 +1590,17 @@ fn parse_session_command(args: &[&str]) -> Result<SlashCommand, SlashCommandPars
action: Some("list".to_string()),
target: None,
}),
["list", ..] => Err(usage_error("session", "[list|switch <session-id>|fork [branch-name]|delete <session-id> [--force]]")),
["list", ..] => Err(usage_error("session", "[list|exists <session-id>|switch <session-id>|fork [branch-name]|delete <session-id> [--force]]")),
["exists"] => Err(usage_error("session exists", "<session-id>")),
["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 <session-id>",
)),
["switch"] => Err(usage_error("session switch", "<session-id>")),
["switch", target] => Ok(SlashCommand::Session {
action: Some("switch".to_string()),
@@ -1637,10 +1647,10 @@ fn parse_session_command(args: &[&str]) -> Result<SlashCommand, SlashCommandPars
)),
[action, ..] => Err(command_error(
&format!(
"Unknown /session action '{action}'. Use list, switch <session-id>, fork [branch-name], or delete <session-id> [--force]."
"Unknown /session action '{action}'. Use list, exists <session-id>, switch <session-id>, fork [branch-name], or delete <session-id> [--force]."
),
"session",
"/session [list|switch <session-id>|fork [branch-name]|delete <session-id> [--force]]",
"/session [list|exists <session-id>|switch <session-id>|fork [branch-name]|delete <session-id> [--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 {

View File

@@ -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<SessionHandle, SessionControlError> {
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<LoadedManagedSession, Ses
load_managed_session_for(env::current_dir()?, reference)
}
pub fn managed_session_exists(reference: &str) -> Result<bool, SessionControlError> {
managed_session_exists_for(env::current_dir()?, reference)
}
pub fn managed_session_exists_for(
base_dir: impl AsRef<Path>,
reference: &str,
) -> Result<bool, SessionControlError> {
let store = SessionStore::from_cwd(base_dir)?;
Ok(store.session_exists(reference))
}
pub fn delete_managed_session(reference: &str) -> Result<SessionHandle, SessionControlError> {
delete_managed_session_for(env::current_dir()?, reference)
}
pub fn delete_managed_session_for(
base_dir: impl AsRef<Path>,
reference: &str,
) -> Result<SessionHandle, SessionControlError> {
let store = SessionStore::from_cwd(base_dir)?;
store.delete_session(reference)
}
pub fn load_managed_session_for(
base_dir: impl AsRef<Path>,
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