返回 CodeWhale
save.rs
根目录 / crates / tui / src / commands / groups / session / save.rs
1 //! `/save` command — persist the current session.
2
3 use super::CommandResult;
4
5 use codewhale_command_contract::facets::CommandSessionLifecycleContext;
6 use codewhale_command_contract::handler::{CommandContexts, CommandHandler};
7 use codewhale_command_contract::metadata::{
8 CommandInfo as ContractInfo, RegisterCommand as ContractRegisterCommand,
9 };
10
11 pub(in crate::commands) struct SaveCmd;
12
13 // ---------------------------------------------------------------------------
14 // FEAT-023 Phase 4 (D3/D5/D6): portable contextual registration and handler.
15 // ---------------------------------------------------------------------------
16
17 pub(in crate::commands) const CONTRACT_INFO: ContractInfo = ContractInfo {
18 name: "save",
19 aliases: &[],
20 usage: "/save [path]",
21 description_key: "cmd_save_description",
22 };
23
24 impl ContractRegisterCommand<CommandResult> for SaveCmd {
25 fn info() -> &'static ContractInfo {
26 &CONTRACT_INFO
27 }
28 fn handler() -> CommandHandler<CommandResult> {
29 CommandHandler::Contextual {
30 capabilities:
31 codewhale_command_contract::handler::CommandCapabilities::SESSION_LIFECYCLE,
32 handler: save_contextual,
33 }
34 }
35 }
36
37 pub(in crate::commands) fn save_contextual(
38 contexts: CommandContexts<'_>,
39 arg: Option<&str>,
40 ) -> CommandResult {
41 let mut parts = contexts.into_parts();
42 let Some(lifecycle) = parts.lifecycle.as_deref_mut() else {
43 return CommandResult::error(
44 "Command capability unavailable: session_lifecycle".to_string(),
45 );
46 };
47 save_portable(lifecycle, arg)
48 }
49
50 pub(in crate::commands) fn save_portable(
51 lifecycle: &mut dyn CommandSessionLifecycleContext,
52 arg: Option<&str>,
53 ) -> CommandResult {
54 let explicit = arg
55 .map(str::trim)
56 .filter(|p| !p.is_empty())
57 .map(str::to_string);
58 match lifecycle.save_session(explicit) {
59 Ok(receipt) => CommandResult::message(format!(
60 "Session saved to {} (ID: {})",
61 receipt.display_path, receipt.truncated_id
62 )),
63 Err(error) => CommandResult::error(error),
64 }
65 }
66
66 lines RUST