refactor: extract args.rs and session.rs, merge remote refactoring

This commit is contained in:
zhaoyanchao 2026-05-26 17:40:50 +08:00
parent 59d6e9d58c
commit 3d011a50a7
4 changed files with 1475 additions and 1710 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,15 +7,6 @@ use std::path::{Path, PathBuf};
use std::time::Duration;
use std::time::UNIX_EPOCH;
pub(crate) struct LiveCli {
model: String,
allowed_tools: Option<AllowedToolSet>,
permission_mode: PermissionMode,
system_prompt: Vec<String>,
runtime: BuiltRuntime,
session: SessionHandle,
prompt_history: Vec<PromptHistoryEntry>,
}
impl LiveCli {
pub(crate) fn new(

View File

@ -0,0 +1,233 @@
use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::time::UNIX_EPOCH;
use commands::{render_slash_command_help_filtered, SlashCommand};
use runtime::Session;
use crate::constants::*;
use crate::models::*;
pub(crate) fn current_session_store() -> Result<runtime::SessionStore, Box<dyn std::error::Error>> {
let cwd = env::current_dir()?;
runtime::SessionStore::from_cwd(&cwd).map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
}
pub(crate) fn sessions_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
Ok(current_session_store()?.sessions_dir().to_path_buf())
}
pub(crate) fn new_cli_session() -> Result<Session, Box<dyn std::error::Error>> {
Ok(Session::new().with_workspace_root(env::current_dir()?))
}
pub(crate) fn create_managed_session_handle(
session_id: &str,
) -> Result<SessionHandle, Box<dyn std::error::Error>> {
let handle = current_session_store()?.create_handle(session_id);
Ok(SessionHandle {
id: handle.id,
path: handle.path,
})
}
pub(crate) fn resolve_session_reference(reference: &str) -> Result<SessionHandle, Box<dyn std::error::Error>> {
let handle = current_session_store()?
.resolve_reference(reference)
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
Ok(SessionHandle {
id: handle.id,
path: handle.path,
})
}
pub(crate) fn resolve_managed_session_path(session_id: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
current_session_store()?
.resolve_managed_path(session_id)
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
}
pub(crate) fn list_managed_sessions() -> Result<Vec<ManagedSessionSummary>, Box<dyn std::error::Error>> {
Ok(current_session_store()?
.list_sessions()
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?
.into_iter()
.map(|session| ManagedSessionSummary {
id: session.id,
path: session.path,
updated_at_ms: session.updated_at_ms,
modified_epoch_millis: session.modified_epoch_millis,
message_count: session.message_count,
parent_session_id: session.parent_session_id,
branch_name: session.branch_name,
lifecycle: SessionLifecycleSummary {
kind: SessionLifecycleKind::SavedOnly,
pane_id: None,
pane_command: None,
pane_path: None,
workspace_dirty: false,
abandoned: false,
},
})
.collect())
}
pub(crate) fn latest_managed_session() -> Result<ManagedSessionSummary, Box<dyn std::error::Error>> {
let session = current_session_store()?
.latest_session()
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
Ok(ManagedSessionSummary {
id: session.id,
path: session.path,
updated_at_ms: session.updated_at_ms,
modified_epoch_millis: session.modified_epoch_millis,
message_count: session.message_count,
parent_session_id: session.parent_session_id,
branch_name: session.branch_name,
lifecycle: SessionLifecycleSummary {
kind: SessionLifecycleKind::SavedOnly,
pane_id: None,
pane_command: None,
pane_path: None,
workspace_dirty: false,
abandoned: false,
},
})
}
pub(crate) fn load_session_reference(
reference: &str,
) -> Result<(SessionHandle, Session), Box<dyn std::error::Error>> {
let loaded = current_session_store()?
.load_session(reference)
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
Ok((
SessionHandle {
id: loaded.handle.id,
path: loaded.handle.path,
},
loaded.session,
))
}
pub(crate) fn delete_managed_session(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
if !path.exists() {
return Err(format!("session file does not exist: {}", path.display()).into());
}
fs::remove_file(path)?;
Ok(())
}
pub(crate) fn confirm_session_deletion(session_id: &str) -> bool {
print!("Delete session '{session_id}'? This cannot be undone. [y/N]: ");
io::stdout().flush().unwrap_or(());
let mut answer = String::new();
if io::stdin().read_line(&mut answer).is_err() {
return false;
}
matches!(answer.trim(), "y" | "Y" | "yes" | "Yes" | "YES")
}
pub(crate) fn render_session_list(active_session_id: &str) -> Result<String, Box<dyn std::error::Error>> {
let sessions = list_managed_sessions()?;
let mut lines = vec![
"Sessions".to_string(),
format!(" Directory {}", sessions_dir()?.display()),
];
if sessions.is_empty() {
lines.push(" No managed sessions saved yet.".to_string());
return Ok(lines.join("\n"));
}
for session in sessions {
let marker = if session.id == active_session_id {
"● current"
} else {
"○ saved"
};
let lineage = match (
session.branch_name.as_deref(),
session.parent_session_id.as_deref(),
) {
(Some(branch_name), Some(parent_session_id)) => {
format!(" branch={branch_name} from={parent_session_id}")
}
(None, Some(parent_session_id)) => format!(" from={parent_session_id}"),
(Some(branch_name), None) => format!(" branch={branch_name}"),
(None, None) => String::new(),
};
lines.push(format!(
" {id:<20} {marker:<10} msgs={msgs:<4} modified={modified}{lineage} path={path}",
id = session.id,
msgs = session.message_count,
modified = format_session_modified_age(session.modified_epoch_millis),
lineage = lineage,
path = session.path.display(),
));
}
Ok(lines.join("\n"))
}
pub(crate) fn format_session_modified_age(modified_epoch_millis: u128) -> String {
let now = std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
.ok()
.map_or(modified_epoch_millis, |duration| duration.as_millis());
let delta_seconds = now
.saturating_sub(modified_epoch_millis)
.checked_div(1_000)
.unwrap_or_default();
match delta_seconds {
0..=4 => "just-now".to_string(),
5..=59 => format!("{delta_seconds}s-ago"),
60..=3_599 => format!("{}m-ago", delta_seconds / 60),
3_600..=86_399 => format!("{}h-ago", delta_seconds / 3_600),
_ => format!("{}d-ago", delta_seconds / 86_400),
}
}
pub(crate) fn write_session_clear_backup(
session: &Session,
session_path: &Path,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
let backup_path = session_clear_backup_path(session_path);
session.save_to_path(&backup_path)?;
Ok(backup_path)
}
pub(crate) fn session_clear_backup_path(session_path: &Path) -> PathBuf {
let timestamp = std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
.ok()
.map_or(0, |duration| duration.as_millis());
let file_name = session_path
.file_name()
.and_then(|value| value.to_str())
.unwrap_or("session.jsonl");
session_path.with_file_name(format!("{file_name}.before-clear-{timestamp}.bak"))
}
pub(crate) fn render_repl_help() -> String {
[
"REPL".to_string(),
" /exit Quit the REPL".to_string(),
" /quit Quit the REPL".to_string(),
" Up/Down Navigate prompt history".to_string(),
" Ctrl-R Reverse-search prompt history".to_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/<session-id>.jsonl".to_string(),
" Resume latest /resume latest".to_string(),
" Browse sessions /session list".to_string(),
" Show prompt history /history [count]".to_string(),
String::new(),
render_slash_command_help_filtered(STUB_COMMANDS),
]
.join(
"
",
)
}