返回 CodeWhale
new.rs
根目录 / crates / tui / src / commands / groups / session / new.rs
1 //! `/new` command — start a fresh saved session from the current TUI state.
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 NewCmd;
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: "new",
19 aliases: &[],
20 usage: "/new [--force]",
21 description_key: "cmd_new_description",
22 };
23
24 impl ContractRegisterCommand<CommandResult> for NewCmd {
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: new_contextual,
33 }
34 }
35 }
36
37 pub(in crate::commands) fn new_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 new_portable(lifecycle, arg)
48 }
49
50 pub(in crate::commands) fn new_portable(
51 lifecycle: &mut dyn CommandSessionLifecycleContext,
52 arg: Option<&str>,
53 ) -> CommandResult {
54 let force = match arg.map(str::trim).filter(|s| !s.is_empty()) {
55 None => false,
56 Some("--force" | "force") => true,
57 Some(other) => {
58 return CommandResult::error(format!(
59 "Usage: /new [--force]\n\nUnknown argument: {other}"
60 ));
61 }
62 };
63 if lifecycle.transition_blocked() {
64 return CommandResult::error(
65 "Cannot start a new session while runtime work is active. Wait for the current turn, maintenance, and background tasks to finish, or cancel that specific work. `/new --force` only discards draft or queued input."
66 .to_string(),
67 );
68 }
69 match lifecycle.fresh_session(force) {
70 Ok(receipt) => CommandResult::with_message_and_action(
71 format!(
72 "Started new session {} (New Session). Previous sessions remain available via /resume.",
73 receipt.truncated_id
74 ),
75 super::sync_session_action(receipt.sync),
76 ),
77 Err(error) => CommandResult::error(error),
78 }
79 }
80
80 lines RUST