diff --git a/crates/config/src/provider_defaults.rs b/crates/config/src/provider_defaults.rs index de29b8da9a..d72addf6d4 100644 --- a/crates/config/src/provider_defaults.rs +++ b/crates/config/src/provider_defaults.rs @@ -104,7 +104,7 @@ pub(crate) const DEFAULT_ZAI_MODEL: &str = "GLM-5.2"; pub(crate) const ZAI_GLM_5_1_MODEL: &str = "GLM-5.1"; // GLM-5.2 is both the default and a named tier; the alias arm resolves the // `glm-5.2` spelling to DEFAULT_ZAI_MODEL directly, so this constant is -// referenced only in cfg(test) assertions (see tests.rs). +// referenced only in cfg(test) assertions (see tests.rs). (see #3490) #[allow(dead_code)] pub(crate) const ZAI_GLM_5_2_MODEL: &str = "GLM-5.2"; pub(crate) const ZAI_GLM_5_TURBO_MODEL: &str = "GLM-5-Turbo"; diff --git a/crates/tui/src/client/chat.rs b/crates/tui/src/client/chat.rs index e72d244e1b..a7838765b0 100644 --- a/crates/tui/src/client/chat.rs +++ b/crates/tui/src/client/chat.rs @@ -2372,7 +2372,7 @@ pub(super) fn parse_chat_message(payload: &Value) -> Result { // === Streaming Helpers === /// Build synthetic stream events from a non-streaming response (used as fallback). -#[allow(dead_code)] +#[allow(dead_code)] // Fallback for non-streaming responses; not yet wired (see #3490) fn build_stream_events(response: &MessageResponse) -> Vec { let mut events = Vec::new(); let mut index = 0u32; diff --git a/crates/tui/src/commands/groups/core/mod.rs b/crates/tui/src/commands/groups/core/mod.rs index 346d0242fd..79d9646ae1 100644 --- a/crates/tui/src/commands/groups/core/mod.rs +++ b/crates/tui/src/commands/groups/core/mod.rs @@ -19,6 +19,7 @@ mod hf; mod home; mod hooks; mod hotbar; +mod setup; mod links; mod model; mod modeldb; @@ -100,6 +101,10 @@ impl CommandGroup for CoreCommands { hotbar::HotbarCmd::info(), hotbar::HotbarCmd::execute, )), + Box::new(FunctionCommand::new( + setup::SetupCmd::info(), + setup::SetupCmd::execute, + )), Box::new(FunctionCommand::new( agent::AgentCmd::info(), agent::AgentCmd::execute, diff --git a/crates/tui/src/commands/groups/core/setup.rs b/crates/tui/src/commands/groups/core/setup.rs new file mode 100644 index 0000000000..dc210945b6 --- /dev/null +++ b/crates/tui/src/commands/groups/core/setup.rs @@ -0,0 +1,98 @@ +//! `/setup` command — opens the setup summary wizard. + +use crate::commands::traits::{CommandInfo, RegisterCommand}; +use crate::localization::MessageId; +use crate::tui::app::{App, AppAction}; + +use super::CommandResult; + +pub(in crate::commands) const COMMAND_INFO: CommandInfo = CommandInfo { + name: "setup", + aliases: &["config-summary", "status"], + usage: "/setup", + description_id: MessageId::CmdSetupDescription, +}; + +pub(in crate::commands) struct SetupCmd; + +impl RegisterCommand for SetupCmd { + fn info() -> &'static CommandInfo { + &COMMAND_INFO + } + + fn execute(_app: &mut App, arg: Option<&str>) -> CommandResult { + match arg.map(str::trim).filter(|arg| !arg.is_empty()) { + None | Some("summary" | "wizard") => { + CommandResult::action(AppAction::OpenSetupSummary) + } + Some("help" | "?") => CommandResult::message( + "Usage: /setup [summary]\n\n/setup opens the configuration summary wizard.", + ), + Some(other) => CommandResult::error(format!( + "Unknown /setup target '{other}'. Use `/setup` or `/setup summary`." + )), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::Config; + use crate::tui::app::TuiOptions; + use std::path::PathBuf; + + fn test_app() -> App { + let options = TuiOptions { + model: "deepseek-v4-pro".to_string(), + workspace: PathBuf::from("."), + config_path: None, + config_profile: None, + allow_shell: false, + use_alt_screen: true, + use_mouse_capture: false, + use_bracketed_paste: true, + max_subagents: 1, + skills_dir: PathBuf::from("."), + memory_path: PathBuf::from("memory.md"), + notes_path: PathBuf::from("notes.txt"), + mcp_config_path: PathBuf::from("mcp.json"), + use_memory: false, + start_in_agent_mode: false, + skip_onboarding: true, + yolo: false, + resume_session_id: None, + initial_input: None, + }; + App::new(options, &Config::default()) + } + + #[test] + fn setup_command_opens_summary() { + let mut app = test_app(); + let result = SetupCmd::execute(&mut app, None); + assert_eq!(result.action, Some(AppAction::OpenSetupSummary)); + } + + #[test] + fn setup_summary_alias() { + let mut app = test_app(); + let result = SetupCmd::execute(&mut app, Some("summary")); + assert_eq!(result.action, Some(AppAction::OpenSetupSummary)); + } + + #[test] + fn setup_help_arg() { + let mut app = test_app(); + let result = SetupCmd::execute(&mut app, Some("help")); + assert!(!result.is_error); + assert!(result.action.is_none()); + } + + #[test] + fn setup_unknown_arg() { + let mut app = test_app(); + let result = SetupCmd::execute(&mut app, Some("bogus")); + assert!(result.is_error); + } +} diff --git a/crates/tui/src/compaction.rs b/crates/tui/src/compaction.rs index 31e3fa13af..aad60ffb2d 100644 --- a/crates/tui/src/compaction.rs +++ b/crates/tui/src/compaction.rs @@ -450,7 +450,7 @@ pub fn plan_compaction( } } -#[allow(dead_code)] +#[allow(dead_code)] // Internal compaction correctness helper; kept for tool-call pair enforcement (see #3490) fn enforce_tool_call_pairs(messages: &[Message], pinned_indices: &mut BTreeSet) { if pinned_indices.is_empty() { return; diff --git a/crates/tui/src/config.rs b/crates/tui/src/config.rs index 400fafc853..62d06d133e 100644 --- a/crates/tui/src/config.rs +++ b/crates/tui/src/config.rs @@ -1626,7 +1626,7 @@ pub struct RetryPolicy { impl RetryPolicy { /// Compute the backoff delay for a retry attempt. #[must_use] - #[allow(dead_code)] // used by runtime_api; will be wired into client retry loop + #[allow(dead_code)] // used by runtime_api; will be wired into client retry loop (see #3490) pub fn delay_for_attempt(&self, attempt: u32) -> std::time::Duration { let exponent = i32::try_from(attempt).unwrap_or(i32::MAX); let delay = self.initial_delay * self.exponential_base.powi(exponent); diff --git a/crates/tui/src/config_ui.rs b/crates/tui/src/config_ui.rs index cad128d2a3..f60de6f825 100644 --- a/crates/tui/src/config_ui.rs +++ b/crates/tui/src/config_ui.rs @@ -120,6 +120,7 @@ pub struct WebConfigSession { #[derive(Debug)] pub struct WebConfigSession { #[allow(dead_code)] + // WebConfigSession receiver; reserved for future event-driven config UI (see #3490) pub receiver: tokio::sync::mpsc::UnboundedReceiver, } diff --git a/crates/tui/src/core/engine.rs b/crates/tui/src/core/engine.rs index 6dab7a55eb..1dbbaf9bce 100644 --- a/crates/tui/src/core/engine.rs +++ b/crates/tui/src/core/engine.rs @@ -388,7 +388,8 @@ pub struct EngineConfig { pub tools_always_load: HashSet, /// When true and `/usr/bin/bwrap` is present on Linux, route exec_shell /// through bubblewrap instead of relying solely on Landlock (#2184). - #[allow(dead_code)] // Wired through ShellManager in follow-up PR + #[allow(dead_code)] + // Wired through ShellManager in follow-up PR (see #3490) pub prefer_bwrap: bool, /// Tool override and plugin configuration (`[tools]` table in config.toml). /// Applied to the per-turn tool registry after built-in tools are registered. @@ -487,7 +488,7 @@ impl Default for EngineConfig { /// `External`, `Preempted`, and `Internal` are reserved for the /// remaining direct cancellation paths tracked in #1541. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(dead_code)] +#[allow(dead_code)] // CancelReason enum; wired in follow-up for user-facing cancel diagnostics (see #3490) pub enum CancelReason { /// User-initiated cancel (Esc, `/cancel`, click cancel on modal). User, diff --git a/crates/tui/src/core/engine/context.rs b/crates/tui/src/core/engine/context.rs index d5f2cf2b40..4664cab94f 100644 --- a/crates/tui/src/core/engine/context.rs +++ b/crates/tui/src/core/engine/context.rs @@ -536,12 +536,12 @@ pub(super) fn extract_compaction_summary_prompt( } } -#[allow(dead_code)] // exposed for future engine-side callers; current call path goes through compaction::estimate_input_tokens_conservative via token_estimate_cache. +#[allow(dead_code)] // exposed for future engine-side callers; current call path goes through compaction::estimate_input_tokens_conservative via token_estimate_cache. (see #3490) fn estimate_text_tokens_conservative(text: &str) -> usize { text.chars().count().div_ceil(3) } -#[allow(dead_code)] // see estimate_text_tokens_conservative above +#[allow(dead_code)] // see estimate_text_tokens_conservative above (see #3490) fn estimate_system_tokens_conservative(system: Option<&SystemPrompt>) -> usize { match system { Some(SystemPrompt::Text(text)) => estimate_text_tokens_conservative(text), @@ -553,7 +553,7 @@ fn estimate_system_tokens_conservative(system: Option<&SystemPrompt>) -> usize { } } -#[allow(dead_code)] // see estimate_text_tokens_conservative above +#[allow(dead_code)] // see estimate_text_tokens_conservative above (see #3490) pub(super) fn estimate_input_tokens_conservative( messages: &[Message], system: Option<&SystemPrompt>, diff --git a/crates/tui/src/core/engine/dispatch.rs b/crates/tui/src/core/engine/dispatch.rs index e8237fde41..4b7417efbd 100644 --- a/crates/tui/src/core/engine/dispatch.rs +++ b/crates/tui/src/core/engine/dispatch.rs @@ -25,7 +25,7 @@ use super::ToolUseState; // === Types ============================================================ -#[allow(dead_code)] // `index` mirrors batch order for diagnostic ergonomics. +#[allow(dead_code)] // `index` mirrors batch order for diagnostic ergonomics. (see #3490) pub(super) struct ToolExecOutcome { pub(super) index: usize, pub(super) id: String, diff --git a/crates/tui/src/core/engine/handle.rs b/crates/tui/src/core/engine/handle.rs index 1eb8e2cc08..f44feaa251 100644 --- a/crates/tui/src/core/engine/handle.rs +++ b/crates/tui/src/core/engine/handle.rs @@ -43,7 +43,7 @@ impl EngineHandle { /// Check if a request is currently cancelled #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // Used by engine tests; wrapper around CancellationToken (see #3490) pub fn is_cancelled(&self) -> bool { match self.cancel_token.lock() { Ok(token) => token.is_cancelled(), diff --git a/crates/tui/src/core/engine/token_estimate_cache.rs b/crates/tui/src/core/engine/token_estimate_cache.rs index 94d191add4..e4bb6806b5 100644 --- a/crates/tui/src/core/engine/token_estimate_cache.rs +++ b/crates/tui/src/core/engine/token_estimate_cache.rs @@ -97,7 +97,7 @@ impl TokenEstimateCache { /// Record a messages-revision bump. The engine calls this whenever /// `session.messages` is mutated. Calling it with a value smaller than /// the current value is a no-op (the cache is monotonic). - #[allow(dead_code)] // exposed for future wiring of /clear and reset paths; tests exercise it + #[allow(dead_code)] // exposed for future wiring of /clear and reset paths; tests exercise it (see #3490) pub fn bump_messages_revision(&mut self, revision: u64) { if revision > self.messages_revision { self.messages_revision = revision; @@ -106,7 +106,7 @@ impl TokenEstimateCache { } /// Forget all cached state. Used by `/clear` and session reset paths. - #[allow(dead_code)] // exposed for future wiring of /clear and reset paths; tests exercise it + #[allow(dead_code)] // exposed for future wiring of /clear and reset paths; tests exercise it (see #3490) pub fn invalidate(&mut self) { self.cached_tokens = None; self.system_fingerprint = 0; @@ -116,7 +116,7 @@ impl TokenEstimateCache { } /// Returns `(hits, misses)` counters since the last `invalidate` call. - #[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it + #[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it (see #3490) #[must_use] pub fn stats(&self) -> (u64, u64) { (self.hits, self.misses) @@ -124,7 +124,7 @@ impl TokenEstimateCache { /// Returns the most recent `(revision, tokens)` audit entries, newest /// first. Bounded by [`AUDIT_RING_CAPACITY`]. - #[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it + #[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it (see #3490) #[must_use] pub fn recent_audit(&self) -> &[(u64, usize)] { &self.audit_ring diff --git a/crates/tui/src/core/events.rs b/crates/tui/src/core/events.rs index 17de237668..471d0ef53f 100644 --- a/crates/tui/src/core/events.rs +++ b/crates/tui/src/core/events.rs @@ -28,39 +28,39 @@ pub enum Event { // === Streaming Events === /// A new message block has started MessageStarted { - #[allow(dead_code)] + #[allow(dead_code)] // StreamEvent ContentBlockStart index (see #3490) index: usize, }, /// Incremental text content delta MessageDelta { - #[allow(dead_code)] + #[allow(dead_code)] // StreamEvent ContentBlockDelta index (see #3490) index: usize, content: String, }, /// Message block completed MessageComplete { - #[allow(dead_code)] + #[allow(dead_code)] // StreamEvent ContentBlockStop index (see #3490) index: usize, }, /// Thinking block started ThinkingStarted { - #[allow(dead_code)] + #[allow(dead_code)] // StreamEvent MessageDelta index (see #3490) index: usize, }, /// Incremental thinking content delta ThinkingDelta { - #[allow(dead_code)] + #[allow(dead_code)] // MCP StreamEvent Ping (see #3490) index: usize, content: String, }, /// Thinking block completed ThinkingComplete { - #[allow(dead_code)] + #[allow(dead_code)] // StreamEvent internal_error_tx field (see #3490) index: usize, }, @@ -111,10 +111,10 @@ pub enum Event { auto: bool, message: String, /// Number of messages before compaction. - #[allow(dead_code)] + #[allow(dead_code)] // StreamError messages_before (see #3490) messages_before: Option, /// Number of messages after compaction. - #[allow(dead_code)] + #[allow(dead_code)] // StreamError messages_after (see #3490) messages_after: Option, }, @@ -183,7 +183,7 @@ pub enum Event { /// An error occurred Error { envelope: ErrorEnvelope, - #[allow(dead_code)] + #[allow(dead_code)] // StreamError recoverable flag (see #3490) recoverable: bool, }, @@ -244,7 +244,7 @@ pub enum Event { }, /// Request user decision after sandbox denial - #[allow(dead_code)] + #[allow(dead_code)] // UserInputDecision ElevationRequired (see #3490) ElevationRequired { tool_id: String, tool_name: String, diff --git a/crates/tui/src/core/ops.rs b/crates/tui/src/core/ops.rs index e1d465d4f0..eca182c321 100644 --- a/crates/tui/src/core/ops.rs +++ b/crates/tui/src/core/ops.rs @@ -40,7 +40,7 @@ pub struct ProviderRuntimeStatus { /// /// Chat providers force several runtime/control-plane signals through /// `role = "user"` for compatibility, so role alone is not authority. -#[allow(dead_code)] // Some origins are reserved for ingestion sites landing after the first gate. +#[allow(dead_code)] // Some origins are reserved for ingestion sites landing after the first gate. (see #3490) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UserInputProvenance { /// Text typed or submitted through the active UI/API input boundary. @@ -139,7 +139,7 @@ pub enum Op { }, /// Cancel the current request - #[allow(dead_code)] + #[allow(dead_code)] // CancelRequest user operation; wired in follow-up (see #3490) CancelRequest, /// Approve a tool call that requires permission diff --git a/crates/tui/src/core/session.rs b/crates/tui/src/core/session.rs index 1ba0a1c619..7a45c3710c 100644 --- a/crates/tui/src/core/session.rs +++ b/crates/tui/src/core/session.rs @@ -177,7 +177,7 @@ impl Session { /// compaction. Bumps `messages_revision` exactly once even when the new /// history has a different length, so downstream caches invalidate /// atomically. - #[allow(dead_code)] + #[allow(dead_code)] // Session resume/compaction API; kept for future callers (see #3490) pub fn replace_messages(&mut self, messages: Vec) { self.messages = messages.into(); self.messages_revision = self.messages_revision.saturating_add(1); diff --git a/crates/tui/src/core/turn.rs b/crates/tui/src/core/turn.rs index 84b91b9f83..c56fdc12e0 100644 --- a/crates/tui/src/core/turn.rs +++ b/crates/tui/src/core/turn.rs @@ -25,7 +25,7 @@ pub struct TurnContext { pub id: String, /// When the turn started - #[allow(dead_code)] + #[allow(dead_code)] // TurnMetadata started_at (see #3490) pub started_at: Instant, /// Current step in the turn (tool call iteration) @@ -38,7 +38,7 @@ pub struct TurnContext { tool_call_count: usize, /// Whether the turn has been cancelled - #[allow(dead_code)] + #[allow(dead_code)] // TurnMetadata cancelled flag (see #3490) pub cancelled: bool, /// Usage for this turn @@ -85,13 +85,13 @@ impl TurnContext { } /// Cancel the turn - #[allow(dead_code)] + #[allow(dead_code)] // TurnContext cancel; part of public API (see #3490) pub fn cancel(&mut self) { self.cancelled = true; } /// Get the elapsed time - #[allow(dead_code)] + #[allow(dead_code)] // TurnContext elapsed; part of public API (see #3490) pub fn elapsed(&self) -> Duration { self.started_at.elapsed() } diff --git a/crates/tui/src/dependencies.rs b/crates/tui/src/dependencies.rs index cb2fd219b0..d01a9cdca4 100644 --- a/crates/tui/src/dependencies.rs +++ b/crates/tui/src/dependencies.rs @@ -299,7 +299,7 @@ pub trait ExternalTool { fn resolve() -> Option; /// Quick availability check — true when the tool was found on PATH. - #[allow(dead_code)] + #[allow(dead_code)] // Dependency availability check; used in diagnostics/reporting (see #3490) fn available() -> bool { Self::resolve().is_some() } @@ -334,7 +334,7 @@ pub trait ExternalTool { /// Convenience: run the tool with arguments and return only the /// exit status (discards stdout/stderr). - #[allow(dead_code)] + #[allow(dead_code)] // Dependency exit status check; used in diagnostics (see #3490) fn status(args: &[&str], cwd: &std::path::Path) -> std::io::Result { let mut cmd = Self::command().ok_or_else(|| { std::io::Error::new( diff --git a/crates/tui/src/goal_loop.rs b/crates/tui/src/goal_loop.rs index 2aedac1b88..3218bdc361 100644 --- a/crates/tui/src/goal_loop.rs +++ b/crates/tui/src/goal_loop.rs @@ -26,7 +26,7 @@ pub enum GoalRunStatus { /// verifier confirmed — see `GoalGate`). Completed, /// The model reported it is blocked and needs the user. - #[allow(dead_code)] + #[allow(dead_code)] // GoalLoop StopReason::Blocked variant (see #3490) Blocked, } @@ -36,7 +36,7 @@ pub enum StopReason { /// Objective achieved. Completed, /// Model reported blocked. - #[allow(dead_code)] + #[allow(dead_code)] // TokenBudget StopReason::Blocked variant (see #3490) Blocked, /// Token budget exhausted. TokenBudget, @@ -46,7 +46,7 @@ pub enum StopReason { /// terminal signal). Retained for API completeness; the current loop has no /// continuation cap, so this variant is not constructed by /// `decide_continuation`. - #[allow(dead_code)] + #[allow(dead_code)] // GoalLoop StopReason::ContinuationLimit (see #3490) ContinuationLimit, } @@ -73,7 +73,7 @@ pub struct GoalBudget { impl GoalBudget { /// Fully unbounded — no token or time cap. The only stops are a terminal /// model status (complete/blocked) or an explicit user pause/clear. - #[allow(dead_code)] + #[allow(dead_code)] // GoalBudget unbounded constructor (see #3490) pub const fn unbounded() -> Self { Self { token_budget: None, @@ -83,7 +83,7 @@ impl GoalBudget { /// A token budget only — the loop runs until the model is done or the /// token budget is exhausted. - #[allow(dead_code)] + #[allow(dead_code)] // GoalBudget with_token_budget constructor (see #3490) pub const fn with_token_budget(token_budget: u64) -> Self { Self { token_budget: Some(token_budget), @@ -142,7 +142,7 @@ pub fn decide_continuation( /// Whether a stop reason represents success (Completed) vs. an early/forced exit. /// Useful for the UI/status projection (#2666 token/time visibility). #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // StopReason is_success check (see #3490) pub fn is_success(reason: StopReason) -> bool { matches!(reason, StopReason::Completed) } diff --git a/crates/tui/src/hooks.rs b/crates/tui/src/hooks.rs index 6ceb24890f..50258387cd 100644 --- a/crates/tui/src/hooks.rs +++ b/crates/tui/src/hooks.rs @@ -59,7 +59,7 @@ pub enum HookEvent { impl HookEvent { /// Get string representation for environment variable - #[allow(dead_code)] // Used in tests and future hook dispatch + #[allow(dead_code)] // Used in tests and future hook dispatch (see #3490) pub fn as_str(self) -> &'static str { match self { HookEvent::SessionStart => "session_start", @@ -150,7 +150,7 @@ fn default_continue_on_error() -> bool { impl Hook { /// Create a new hook with minimal configuration - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn new(event: HookEvent, command: &str) -> Self { Self { event, @@ -164,28 +164,28 @@ impl Hook { } /// Builder: set condition - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn with_condition(mut self, condition: HookCondition) -> Self { self.condition = Some(condition); self } /// Builder: set timeout - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn with_timeout(mut self, secs: u64) -> Self { self.timeout_secs = secs; self } /// Builder: run in background - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn background(mut self) -> Self { self.background = true; self } /// Builder: set name - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn with_name(mut self, name: &str) -> Self { self.name = Some(name.to_string()); self @@ -255,7 +255,7 @@ impl HooksConfig { } /// Check if hooks are configured and enabled - #[allow(dead_code)] // Public API for hook system consumers + #[allow(dead_code)] // Public API for hook system consumers (see #3490) pub fn has_hooks(&self) -> bool { self.enabled && !self.hooks.is_empty() } @@ -303,19 +303,19 @@ impl HookContext { Self::default() } - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn with_tool_name(mut self, name: &str) -> Self { self.tool_name = Some(name.to_string()); self } - #[allow(dead_code)] // Public builder API + #[allow(dead_code)] // Public builder API (see #3490) pub fn with_tool_args(mut self, args: &serde_json::Value) -> Self { self.tool_args = Some(args.to_string()); self } - #[allow(dead_code)] // Public builder API + #[allow(dead_code)] // Public builder API (see #3490) pub fn with_tool_result(mut self, result: &str, success: bool, exit_code: Option) -> Self { self.tool_result = Some(result.to_string()); self.tool_success = Some(success); @@ -323,7 +323,7 @@ impl HookContext { self } - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn with_mode(mut self, mode: &str) -> Self { self.mode = Some(mode.to_string()); self @@ -334,7 +334,7 @@ impl HookContext { self } - #[allow(dead_code)] // Public builder API, used in tests + #[allow(dead_code)] // Public builder API, used in tests (see #3490) pub fn with_workspace(mut self, path: PathBuf) -> Self { self.workspace = Some(path); self @@ -350,13 +350,13 @@ impl HookContext { self } - #[allow(dead_code)] // Public builder API + #[allow(dead_code)] // Public builder API (see #3490) pub fn with_message(mut self, message: &str) -> Self { self.message = Some(message.to_string()); self } - #[allow(dead_code)] // Public builder API + #[allow(dead_code)] // Public builder API (see #3490) pub fn with_error(mut self, error: &str) -> Self { self.error_message = Some(error.to_string()); self @@ -367,7 +367,7 @@ impl HookContext { self } - #[allow(dead_code)] // Public builder API + #[allow(dead_code)] // Public builder API (see #3490) pub fn with_cost(mut self, cost: f64) -> Self { self.session_cost = Some(cost); self @@ -450,7 +450,7 @@ impl HookContext { /// Result of a hook execution #[derive(Debug, Clone)] -#[allow(dead_code)] // Fields are part of public API for hook consumers +#[allow(dead_code)] // Fields are part of public API for hook consumers (see #3490) pub struct HookResult { /// Hook name (if specified) pub name: Option, @@ -662,7 +662,7 @@ impl HookExecutor { } /// Create a disabled `HookExecutor` (no hooks will run) - #[allow(dead_code)] // Used in tests and as convenience constructor + #[allow(dead_code)] // Used in tests and as convenience constructor (see #3490) pub fn disabled() -> Self { Self { config: HooksConfig { @@ -675,7 +675,7 @@ impl HookExecutor { } /// Check if hooks are enabled - #[allow(dead_code)] // Public API for hook system consumers + #[allow(dead_code)] // Public API for hook system consumers (see #3490) pub fn is_enabled(&self) -> bool { self.config.enabled } diff --git a/crates/tui/src/llm_client/mod.rs b/crates/tui/src/llm_client/mod.rs index de849328a7..337847c886 100644 --- a/crates/tui/src/llm_client/mod.rs +++ b/crates/tui/src/llm_client/mod.rs @@ -76,7 +76,7 @@ pub trait LlmClient: Send + Sync { } /// Trait for clients that support configurable retry behavior -#[allow(dead_code)] // Part of LLM provider interface, will be used by additional providers +#[allow(dead_code)] // Part of LLM provider interface, will be used by additional providers (see #3490) pub trait RetryConfigurable { fn retry_config(&self) -> &RetryConfig; fn set_retry_config(&mut self, config: RetryConfig); @@ -781,11 +781,13 @@ pub struct RetryConfig { pub respect_retry_after: bool, /// HTTP status codes that should trigger a retry - #[allow(dead_code)] // Used in tests via is_retryable_status() + #[allow(dead_code)] + // retryable_status_codes; test/config field (see #3490) pub retryable_status_codes: Vec, /// Timeout for individual requests (seconds, 0 = no timeout) - #[allow(dead_code)] // Configuration field for retry consumers + #[allow(dead_code)] + // request_timeout; config field for retry consumers (see #3490) pub request_timeout: f64, /// Total timeout for all retry attempts (seconds, 0 = no total timeout) @@ -810,7 +812,7 @@ impl Default for RetryConfig { } } -#[allow(dead_code)] // Public builder API, used in tests +#[allow(dead_code)] // Public builder API, used in tests (see #3490) impl RetryConfig { /// Creates a new `RetryConfig` with default values pub fn new() -> Self { @@ -1091,7 +1093,7 @@ where } /// Simplified version of `with_retry` without callback -#[allow(dead_code)] // Convenience wrapper for with_retry +#[allow(dead_code)] // Convenience wrapper for with_retry (see #3490) pub async fn with_retry_simple(config: &RetryConfig, operation: F) -> RetryResult where F: FnMut() -> Fut, diff --git a/crates/tui/src/localization.rs b/crates/tui/src/localization.rs index 361cd26f60..849d78635e 100644 --- a/crates/tui/src/localization.rs +++ b/crates/tui/src/localization.rs @@ -5,14 +5,14 @@ use std::borrow::Cow; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; -#[allow(dead_code)] +#[allow(dead_code)] // TextDirection enum; part of public localization API (see #3490) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TextDirection { Ltr, Rtl, } -#[allow(dead_code)] +#[allow(dead_code)] // LocaleCoverage enum; part of public localization API (see #3490) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LocaleCoverage { English, @@ -20,7 +20,7 @@ pub enum LocaleCoverage { PlannedQa, } -#[allow(dead_code)] +#[allow(dead_code)] // LocaleSpec struct; part of public localization API (see #3490) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct LocaleSpec { pub tag: &'static str, @@ -67,7 +67,7 @@ impl Locale { } } - #[allow(dead_code)] + #[allow(dead_code)] // Locale::spec accessor; public API (see #3490) pub fn spec(self) -> LocaleSpec { match self { Self::En => LocaleSpec { @@ -129,7 +129,7 @@ impl Locale { } } - #[allow(dead_code)] + #[allow(dead_code)] // Locale::shipped locales list; public API (see #3490) pub fn shipped() -> &'static [Self] { &[ Self::En, @@ -143,7 +143,7 @@ impl Locale { } } -#[allow(dead_code)] +#[allow(dead_code)] // PLANNED_QA_LOCALES; reserved for QA pipeline integration (see #3490) pub const PLANNED_QA_LOCALES: &[LocaleSpec] = &[ LocaleSpec { tag: "ar", @@ -680,7 +680,7 @@ pub enum MessageId { VoiceTranscribed, } -#[allow(dead_code)] +#[allow(dead_code)] // ALL_MESSAGE_IDS; used by locale coverage verification (see #3490) pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::ComposerPlaceholder, MessageId::HistorySearchPlaceholder, @@ -1220,7 +1220,7 @@ where Locale::En } -#[allow(dead_code)] +#[allow(dead_code)] // truncate_to_width utility; public API (see #3490) pub fn truncate_to_width(text: &str, max_width: usize) -> String { if max_width == 0 { return String::new(); diff --git a/crates/tui/src/lsp/client.rs b/crates/tui/src/lsp/client.rs index 7cd10e6b0c..4d4c467301 100644 --- a/crates/tui/src/lsp/client.rs +++ b/crates/tui/src/lsp/client.rs @@ -58,7 +58,7 @@ pub trait LspTransport: Send + Sync { ) -> Result>; /// Best-effort shutdown. Called via `LspManager::shutdown_all`. - #[allow(dead_code)] + #[allow(dead_code)] // LspTransport shutdown trait method (see #3490) async fn shutdown(&self); } @@ -68,7 +68,7 @@ pub trait LspTransport: Send + Sync { pub struct StdioLspTransport { /// JoinHandle for the running server. Held so the child stays alive for /// the transport's lifetime; consumed during `shutdown`. - #[allow(dead_code)] + #[allow(dead_code)] // StdioTransport child handle (see #3490) child: AsyncMutex>, /// Outgoing message sender to the writer task. tx_outbound: mpsc::Sender>, @@ -78,11 +78,11 @@ pub struct StdioLspTransport { /// Map of in-flight request id -> reply slot. We do not currently call /// methods that need replies after `initialize`, but this is the hook /// for it. - #[allow(dead_code)] + #[allow(dead_code)] // StdioTransport pending requests map (see #3490) pending: Arc>>>, /// Monotonic request id counter. Reserved for future LSP request/reply /// methods (workspace symbol queries, etc.). - #[allow(dead_code)] + #[allow(dead_code)] // StdioTransport next_id counter (see #3490) next_id: AsyncMutex, /// Language id passed in `textDocument/didOpen` (e.g. "rust"). language_id: &'static str, diff --git a/crates/tui/src/lsp/mod.rs b/crates/tui/src/lsp/mod.rs index 1519e4a096..2cee3684fa 100644 --- a/crates/tui/src/lsp/mod.rs +++ b/crates/tui/src/lsp/mod.rs @@ -254,7 +254,7 @@ impl LspManager { /// Best-effort shutdown of every spawned transport. Called when the /// session ends. - #[allow(dead_code)] + #[allow(dead_code)] // Wired in engine.rs:1734 (see #3490) pub async fn shutdown_all(&self) { let transports: Vec> = self.transports.lock().await.values().cloned().collect(); diff --git a/crates/tui/src/main.rs b/crates/tui/src/main.rs index 390f8d6e21..4e646c630f 100644 --- a/crates/tui/src/main.rs +++ b/crates/tui/src/main.rs @@ -85,9 +85,9 @@ mod runtime_log; mod runtime_threads; mod sandbox; mod seam_manager; -#[allow(dead_code)] +#[allow(dead_code)] // Session diagnostics module; gated behind --diagnostics flag (see #3490) mod session_diagnostics; -#[allow(dead_code)] +#[allow(dead_code)] // Session manager module; imported in main for initialization (see #3490) mod session_manager; mod settings; mod shell_dispatcher; diff --git a/crates/tui/src/mcp.rs b/crates/tui/src/mcp.rs index f265288426..22e8fd54cb 100644 --- a/crates/tui/src/mcp.rs +++ b/crates/tui/src/mcp.rs @@ -562,7 +562,7 @@ pub struct SseTransport { endpoint_url: Option, receiver: tokio::sync::mpsc::UnboundedReceiver, pending_messages: VecDeque>, - #[allow(dead_code)] + #[allow(dead_code)] // McpHost sse_task handle; kept for server lifecycle (see #3490) sse_task: tokio::task::JoinHandle<()>, } @@ -1899,7 +1899,7 @@ impl McpConnection { } /// Get server name - #[allow(dead_code)] // Public API for MCP consumers + #[allow(dead_code)] // Public API for MCP consumers (see #3490) pub fn name(&self) -> &str { &self.name } @@ -1915,7 +1915,7 @@ impl McpConnection { } /// Get connection state - #[allow(dead_code)] // Public API for MCP consumers + #[allow(dead_code)] // Public API for MCP consumers (see #3490) pub fn state(&self) -> ConnectionState { self.state } @@ -1980,7 +1980,7 @@ impl McpConnection { } /// Gracefully close the connection - #[allow(dead_code)] // Public API for MCP consumers + #[allow(dead_code)] // Public API for MCP consumers (see #3490) pub fn close(&mut self) { self.cancel_token.cancel(); self.state = ConnectionState::Disconnected; @@ -2262,7 +2262,7 @@ impl McpPool { } /// Get all discovered resource templates with server-prefixed names - #[allow(dead_code)] // Public API for MCP resource discovery + #[allow(dead_code)] // Public API for MCP resource discovery (see #3490) pub fn all_resource_templates(&self) -> Vec<(String, &McpResourceTemplate)> { let mut templates = Vec::new(); for (server, conn) in &self.connections { @@ -2651,7 +2651,7 @@ impl McpPool { } /// Get list of configured server names - #[allow(dead_code)] // Public API for MCP consumers + #[allow(dead_code)] // Public API for MCP consumers (see #3490) pub fn server_names(&self) -> Vec<&str> { self.config .servers @@ -2661,7 +2661,7 @@ impl McpPool { } /// Get list of connected server names - #[allow(dead_code)] // Public API; the HTTP list endpoint no longer spawns a pool to call it (#3532) + #[allow(dead_code)] // Public API; the HTTP list endpoint no longer spawns a pool to call it (#3532) (see #3490) pub fn connected_servers(&self) -> Vec<&str> { self.connections .iter() @@ -2671,7 +2671,7 @@ impl McpPool { } /// Disconnect all connections - #[allow(dead_code)] // Public API for MCP lifecycle management + #[allow(dead_code)] // Public API for MCP lifecycle management (see #3490) pub fn disconnect_all(&mut self) { self.drop_all_connections("disconnect all"); } @@ -2684,7 +2684,7 @@ impl McpPool { /// MCP servers a chance to flush state. The fallback Drop on /// `StdioTransport` still sends SIGTERM if this never runs, so even /// abnormal exits avoid leaking PIDs without a signal. - #[allow(dead_code)] // Wired in by callers that want graceful shutdown + #[allow(dead_code)] // Wired in by callers that want graceful shutdown (see #3490) pub async fn shutdown_all(&mut self) { let names: Vec = self.connections.keys().cloned().collect(); for name in names { @@ -2696,7 +2696,7 @@ impl McpPool { } /// Get the underlying configuration - #[allow(dead_code)] // Public API for MCP consumers + #[allow(dead_code)] // Public API for MCP consumers (see #3490) pub fn config(&self) -> &McpConfig { &self.config } diff --git a/crates/tui/src/model_routing.rs b/crates/tui/src/model_routing.rs index 0b000d441a..089d0bc141 100644 --- a/crates/tui/src/model_routing.rs +++ b/crates/tui/src/model_routing.rs @@ -276,7 +276,7 @@ pub(crate) struct AutoRouteSelection { /// Render the auto-router system prompt with the actual candidate ids /// (#3018): the classifier must answer with ids the active provider can /// serve, not hardcoded DeepSeek spellings. -#[allow(dead_code)] // legacy active-provider flash router tests still exercise this prompt. +#[allow(dead_code)] // legacy active-provider flash router tests still exercise this prompt (see #3490) pub(crate) fn auto_router_system_prompt( candidates: &RouterCandidates, cost_saving: bool, @@ -385,7 +385,7 @@ pub(crate) fn normalize_auto_route_effort_for_provider( } } -#[allow(dead_code)] // superseded by the route-effective inventory resolver (#3205). +#[allow(dead_code)] // superseded by route-effective inventory resolver #3205 (see #3490) pub(crate) async fn resolve_auto_route_with_flash( config: &Config, latest_request: &str, @@ -404,7 +404,7 @@ pub(crate) async fn resolve_auto_route_with_flash( .await } -#[allow(dead_code)] // superseded by the route-effective inventory resolver (#3205). +#[allow(dead_code)] // superseded by route-effective inventory resolver #3205 (see #3490) pub(crate) async fn resolve_auto_route_with_flash_for_session( config: &Config, latest_request: &str, @@ -457,7 +457,7 @@ pub(crate) async fn resolve_auto_route_with_flash_for_session( } } -#[allow(dead_code)] // retained for the legacy active-provider flash resolver. +#[allow(dead_code)] // retained for legacy active-provider flash resolver (see #3490) fn auto_route_from_heuristic( provider: ApiProvider, latest_request: &str, @@ -743,7 +743,7 @@ fn parse_inventory_auto_route_recommendation( }) } -#[allow(dead_code)] // retained for the legacy active-provider flash resolver. +#[allow(dead_code)] // retained for legacy active-provider flash resolver (see #3490) async fn auto_route_flash_recommendation( config: &Config, candidates: &RouterCandidates, diff --git a/crates/tui/src/models.rs b/crates/tui/src/models.rs index b3c4087387..68fe741b72 100644 --- a/crates/tui/src/models.rs +++ b/crates/tui/src/models.rs @@ -547,7 +547,7 @@ pub fn auto_compact_default_for_model(model: &str) -> bool { // === Streaming Structures === -#[allow(dead_code)] +#[allow(dead_code)] // ModelFeature struct; part of model capabilities API (see #3490) #[derive(Debug, Deserialize, Clone)] #[serde(tag = "type")] /// Streaming event types for SSE responses. @@ -577,7 +577,7 @@ pub enum StreamEvent { Error { error: serde_json::Value }, } -#[allow(dead_code)] +#[allow(dead_code)] // ProviderModel struct; part of model catalog API (see #3490) #[derive(Debug, Deserialize, Clone)] #[serde(tag = "type")] /// Content block types used in streaming starts. @@ -620,7 +620,7 @@ pub enum Delta { SignatureDelta { signature: String }, } -#[allow(dead_code)] +#[allow(dead_code)] // ModelRoute struct; part of routing API (see #3490) #[derive(Debug, Deserialize, Clone)] /// Delta payload for message-level updates. pub struct MessageDelta { diff --git a/crates/tui/src/palette.rs b/crates/tui/src/palette.rs index 6bff52ffb5..a9728ab6b3 100644 --- a/crates/tui/src/palette.rs +++ b/crates/tui/src/palette.rs @@ -25,7 +25,7 @@ pub const WHALE_TEXT_BODY_RGB: (u8, u8, u8) = (246, 242, 232); // #F6F2E8 Whale pub const WHALE_TEXT_SOFT_RGB: (u8, u8, u8) = (217, 224, 234); // #D9E0EA pub const WHALE_TEXT_MUTED_RGB: (u8, u8, u8) = (169, 180, 199); // #A9B4C7 Mist Gray pub const WHALE_TEXT_HINT_RGB: (u8, u8, u8) = (138, 150, 174); // #8A96AE -#[allow(dead_code)] +#[allow(dead_code)] // WHALE_TEXT_DIM_RGB color constant (see #3490) pub const WHALE_TEXT_DIM_RGB: (u8, u8, u8) = (118, 130, 156); // #76829C pub const WHALE_ACCENT_PRIMARY_RGB: (u8, u8, u8) = (246, 196, 83); // #F6C453 Signal Gold pub const WHALE_ACCENT_SECONDARY_RGB: (u8, u8, u8) = (79, 209, 197); // #4FD1C5 Seafoam @@ -50,7 +50,7 @@ pub const SOLARIZED_BASE01_RGB: (u8, u8, u8) = (0x58, 0x6E, 0x75); pub const SOLARIZED_BASE00_RGB: (u8, u8, u8) = (0x65, 0x7B, 0x83); pub const SOLARIZED_BASE0_RGB: (u8, u8, u8) = (0x83, 0x94, 0x96); pub const SOLARIZED_BASE1_RGB: (u8, u8, u8) = (0x93, 0xA1, 0xA1); -#[allow(dead_code)] +#[allow(dead_code)] // SOLARIZED_BASE2_RGB color constant (see #3490) pub const SOLARIZED_BASE2_RGB: (u8, u8, u8) = (0xEE, 0xE8, 0xD5); pub const SOLARIZED_BASE3_RGB: (u8, u8, u8) = (0xFD, 0xF6, 0xE3); pub const SOLARIZED_YELLOW_RGB: (u8, u8, u8) = (0xB5, 0x89, 0x00); @@ -64,7 +64,7 @@ pub const SOLARIZED_ELEVATED_RGB: (u8, u8, u8) = (0xE4, 0xDF, 0xCF); pub const SOLARIZED_SELECT_RGB: (u8, u8, u8) = (0xD6, 0xD2, 0xC9); pub const WHALE_DIFF_ADDED_RGB: (u8, u8, u8) = (87, 199, 133); // #57C785 -#[allow(dead_code)] +#[allow(dead_code)] // WHALE_DIFF_DELETED_RGB color constant (see #3490) pub const WHALE_DIFF_DELETED_RGB: (u8, u8, u8) = (255, 92, 122); // #FF5C7A Rose Red pub const WHALE_DIFF_ADDED_BG_RGB: (u8, u8, u8) = (18, 42, 34); // #122A22 pub const WHALE_DIFF_DELETED_BG_RGB: (u8, u8, u8) = (42, 18, 26); // #2A121A @@ -79,7 +79,7 @@ pub const WHALE_TOOL_SURFACE_RGB: (u8, u8, u8) = (28, 40, 62); // #1C283E pub const WHALE_TOOL_ACTIVE_RGB: (u8, u8, u8) = (38, 54, 80); // #263650 // Backward-compatible aliases for existing downstream users. -#[allow(dead_code)] +#[allow(dead_code)] // deprecated palette constant (see #3490) #[deprecated( since = "0.8.61", note = "use WHALE_ACCENT_PRIMARY_RGB instead; this alias will be removed after the rename window" @@ -227,7 +227,7 @@ pub const WHALE_ACCENT_PRIMARY: Color = Color::Rgb( WHALE_ACCENT_PRIMARY_RGB.1, WHALE_ACCENT_PRIMARY_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // deprecated palette constant (see #3490) #[deprecated( since = "0.8.61", note = "use WHALE_ACCENT_PRIMARY instead; this alias will be removed after the rename window" @@ -402,26 +402,26 @@ pub const LIGHT_USER_BODY: Color = Color::Rgb(21, 128, 61); // #15803D green // New semantic colors for UI theming pub const BORDER_COLOR: Color = Color::Rgb(BORDER_COLOR_RGB.0, BORDER_COLOR_RGB.1, BORDER_COLOR_RGB.2); -#[allow(dead_code)] +#[allow(dead_code)] // ACCENT_PRIMARY color constant (see #3490) pub const ACCENT_PRIMARY: Color = Color::Rgb( WHALE_ACCENT_PRIMARY_RGB.0, WHALE_ACCENT_PRIMARY_RGB.1, WHALE_ACCENT_PRIMARY_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // ACCENT_SECONDARY color constant (see #3490) pub const ACCENT_SECONDARY: Color = Color::Rgb( WHALE_ACCENT_SECONDARY_RGB.0, WHALE_ACCENT_SECONDARY_RGB.1, WHALE_ACCENT_SECONDARY_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // BACKGROUND_DARK color constant (see #3490) pub const BACKGROUND_DARK: Color = Color::Rgb(WHALE_BG_RGB.0, WHALE_BG_RGB.1, WHALE_BG_RGB.2); -#[allow(dead_code)] +#[allow(dead_code)] // STATUS_NEUTRAL color constant (see #3490) pub const STATUS_NEUTRAL: Color = TEXT_MUTED; -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_PANEL color constant (see #3490) pub const SURFACE_PANEL: Color = Color::Rgb(WHALE_PANEL_RGB.0, WHALE_PANEL_RGB.1, WHALE_PANEL_RGB.2); -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_ELEVATED color constant (see #3490) pub const SURFACE_ELEVATED: Color = Color::Rgb( WHALE_ELEVATED_RGB.0, WHALE_ELEVATED_RGB.1, @@ -437,23 +437,23 @@ pub const SURFACE_REASONING_TINT: Color = Color::Rgb( WHALE_REASONING_TINT_RGB.1, WHALE_REASONING_TINT_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_REASONING_ACTIVE color constant (see #3490) pub const SURFACE_REASONING_ACTIVE: Color = Color::Rgb(58, 46, 32); -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_TOOL color constant (see #3490) pub const SURFACE_TOOL: Color = Color::Rgb( WHALE_TOOL_SURFACE_RGB.0, WHALE_TOOL_SURFACE_RGB.1, WHALE_TOOL_SURFACE_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_TOOL_ACTIVE color constant (see #3490) pub const SURFACE_TOOL_ACTIVE: Color = Color::Rgb( WHALE_TOOL_ACTIVE_RGB.0, WHALE_TOOL_ACTIVE_RGB.1, WHALE_TOOL_ACTIVE_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_SUCCESS color constant (see #3490) pub const SURFACE_SUCCESS: Color = Color::Rgb(18, 42, 37); // dark teal tint -#[allow(dead_code)] +#[allow(dead_code)] // SURFACE_ERROR color constant (see #3490) pub const SURFACE_ERROR: Color = Color::Rgb( WHALE_ERROR_SURFACE_RGB.0, WHALE_ERROR_SURFACE_RGB.1, @@ -507,7 +507,7 @@ pub const STATUS_WARNING: Color = Color::Rgb( WHALE_WARNING_RGB.2, ); pub const STATUS_ERROR: Color = Color::Rgb(WHALE_ERROR_RGB.0, WHALE_ERROR_RGB.1, WHALE_ERROR_RGB.2); -#[allow(dead_code)] +#[allow(dead_code)] // STATUS_INFO color constant (see #3490) pub const STATUS_INFO: Color = Color::Rgb(WHALE_INFO_RGB.0, WHALE_INFO_RGB.1, WHALE_INFO_RGB.2); // Mode-specific accent colors for mode badges @@ -537,7 +537,7 @@ pub const SELECTION_BG: Color = Color::Rgb( WHALE_SELECTION_RGB.1, WHALE_SELECTION_RGB.2, ); -#[allow(dead_code)] +#[allow(dead_code)] // COMPOSER_BG color constant (see #3490) pub const COMPOSER_BG: Color = DEEPSEEK_SLATE; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1643,7 +1643,7 @@ const fn theme_green(ui: &UiTheme) -> Color { /// Per-preset red accent, used for diff "−" line foreground when present. #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // Palette accent BrightMagenta variant (see #3490) const fn theme_red(ui: &UiTheme) -> Color { ui.diff_deleted_fg } @@ -1973,7 +1973,7 @@ impl ColorDepth { /// On TrueColor, `color` passes through. On Ansi256 we let ratatui's renderer /// down-convert (it does this already). On Ansi16 we strip RGB to a near /// named color so semantic intent survives even on legacy terminals. -#[allow(dead_code)] +#[allow(dead_code)] // Palette color method (see #3490) #[must_use] pub fn adapt_color(color: Color, depth: ColorDepth) -> Color { match (color, depth) { @@ -1987,7 +1987,7 @@ pub fn adapt_color(color: Color, depth: ColorDepth) -> Color { /// Adapt a background color. On Ansi16 terminals background tints are noisy, /// so we drop them to `Color::Reset` rather than attempt a coarse named-color /// match — a quiet background reads cleaner than a wrong one. -#[allow(dead_code)] +#[allow(dead_code)] // Palette color method (see #3490) #[must_use] pub fn adapt_bg(color: Color, depth: ColorDepth) -> Color { match (color, depth) { @@ -2001,7 +2001,7 @@ pub fn adapt_bg(color: Color, depth: ColorDepth) -> Color { /// Mix two RGB colors at `alpha` (0.0 = `bg`, 1.0 = `fg`). Anything that's not /// RGB falls back to `fg` — there's no meaningful alpha blend on a named /// palette entry. -#[allow(dead_code)] +#[allow(dead_code)] // Palette color method (see #3490) #[must_use] pub fn blend(fg: Color, bg: Color, alpha: f32) -> Color { let alpha = alpha.clamp(0.0, 1.0); @@ -2052,7 +2052,7 @@ pub fn pulse_brightness(color: Color, now_ms: u64) -> Color { /// `adapt_color` on Ansi16 terminals; we lean on hue dominance + lightness so /// brand colors land on the obviously-related named entry (sky → cyan, blue → /// blue, red → red, etc.) rather than dithering around grey. -#[allow(dead_code)] +#[allow(dead_code)] // Palette color method (see #3490) fn nearest_ansi16(r: u8, g: u8, b: u8) -> Color { let lum = (u16::from(r) + u16::from(g) + u16::from(b)) / 3; if lum < 24 { @@ -2119,7 +2119,7 @@ fn nearest_ansi16(r: u8, g: u8, b: u8) -> Color { /// Map an RGB color to the nearest xterm 256-color palette index. We use only /// the stable 6x6x6 cube and grayscale ramp (16..255), not the terminal's /// user-configurable 0..15 colors. -#[allow(dead_code)] +#[allow(dead_code)] // Palette color method (see #3490) fn rgb_to_ansi256(r: u8, g: u8, b: u8) -> u8 { const CUBE_LEVELS: [u8; 6] = [0, 95, 135, 175, 215, 255]; diff --git a/crates/tui/src/prefix_cache.rs b/crates/tui/src/prefix_cache.rs index faea92ca51..c729287074 100644 --- a/crates/tui/src/prefix_cache.rs +++ b/crates/tui/src/prefix_cache.rs @@ -121,7 +121,7 @@ pub struct PrefixChange { pub tools_changed: bool, } -#[allow(dead_code)] +#[allow(dead_code)] // PrefixChange impl; observability + future cache reporting (see #3490) impl PrefixChange { /// Returns a human-readable description of what changed. pub fn description(&self) -> String { @@ -218,7 +218,7 @@ pub struct CachedCatalog { /// multiple cache consumers can hold the same allocation. Exposed for /// observability (debug builds, `/status` chip) and for tests that /// need to assert byte-stability of the joined catalog. - #[allow(dead_code)] // observability + tests; not consumed on the hot path + #[allow(dead_code)] // observability + tests; not consumed on the hot path (see #3490) pub joined: Arc, /// SHA-256 hex digest of `joined`, computed once on cache miss. pub sha256_hex: String, @@ -278,7 +278,7 @@ impl ToolCatalogCache { /// Drop every cached entry. Used by tool-registry mutation paths /// (e.g. plugin hot-reload, MCP attach) when the caller cannot /// easily prove the tool set is unchanged. - #[allow(dead_code)] // observability; called by /cache flush and tests + #[allow(dead_code)] // observability; called by /cache flush and tests (see #3490) pub fn invalidate(&mut self) { self.by_identity.clear(); self.insertion_order.clear(); @@ -291,7 +291,7 @@ impl ToolCatalogCache { } /// Returns `true` if the cache has no entries. - #[allow(dead_code)] // observability; surfaced via /status + #[allow(dead_code)] // observability; surfaced via /status (see #3490) #[must_use] pub fn is_empty(&self) -> bool { self.by_identity.is_empty() @@ -299,7 +299,7 @@ impl ToolCatalogCache { /// Returns `(current_entries, capacity)` for observability. Surfaced via /// the `/status` chip in a follow-up; tests exercise the path. - #[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it + #[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it (see #3490) #[must_use] pub fn stats(&self) -> (usize, usize) { (self.len(), self.capacity) @@ -385,7 +385,7 @@ fn hash_json_value(value: &serde_json::Value, state: &mut H) { /// [`PrefixFingerprint::compute_with_tool_cache`] and pass the cache in /// directly, both to share state and to avoid the thread-local lookup /// on the hot path. -#[allow(dead_code)] +#[allow(dead_code)] // PrefixStabilityManager; reserved for stability tracking (see #3490) impl PrefixStabilityManager { /// Create a new manager and immediately pin the first fingerprint. pub fn new(system_text: &str, tools: Option<&[Tool]>) -> Self { diff --git a/crates/tui/src/pricing.rs b/crates/tui/src/pricing.rs index 9783e459be..5560e0519e 100644 --- a/crates/tui/src/pricing.rs +++ b/crates/tui/src/pricing.rs @@ -44,7 +44,7 @@ pub struct CostEstimate { } impl CostEstimate { - #[allow(dead_code)] + #[allow(dead_code)] // Cost usd_only constructor (see #3490) pub fn usd_only(usd: f64) -> Self { Self { usd, cny: 0.0 } } @@ -66,7 +66,7 @@ impl CostEstimate { /// Response from `GET https://api.deepseek.com/user/balance`. #[derive(Debug, Clone, Default, serde::Deserialize)] pub struct BalanceResponse { - #[allow(dead_code)] + #[allow(dead_code)] // AccountInfo is_available field (see #3490) pub is_available: bool, pub balance_infos: Vec, } @@ -78,10 +78,10 @@ pub struct BalanceInfo { #[serde(default)] pub total_balance: String, #[serde(default)] - #[allow(dead_code)] + #[allow(dead_code)] // AccountInfo topped_up_balance field (see #3490) pub topped_up_balance: String, #[serde(default)] - #[allow(dead_code)] + #[allow(dead_code)] // AccountInfo granted_balance field (see #3490) pub granted_balance: String, } @@ -242,7 +242,7 @@ pub fn input_cost_note(model: &str) -> Option { /// Calculate cost for a turn given token usage and model. #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // calculate_turn_cost convenience wrapper (see #3490) pub fn calculate_turn_cost(model: &str, input_tokens: u32, output_tokens: u32) -> Option { calculate_turn_cost_estimate(model, input_tokens, output_tokens).map(|estimate| estimate.usd) } @@ -359,7 +359,7 @@ pub fn calculate_cache_savings(model: &str, cache_hit_tokens: u32) -> Option String { format_cost_amount(cost, CostCurrency::Usd) } diff --git a/crates/tui/src/project_context.rs b/crates/tui/src/project_context.rs index d0d2da24db..07fef17c56 100644 --- a/crates/tui/src/project_context.rs +++ b/crates/tui/src/project_context.rs @@ -146,7 +146,8 @@ pub struct ProjectContext { /// Path to the repo constitution file that produced `constitution_block`. pub constitution_source_path: Option, /// Project root directory - #[allow(dead_code)] // Part of ProjectContext public interface + #[allow(dead_code)] + // Part of ProjectContext public interface (see #3490) pub project_root: PathBuf, /// Whether this is a trusted project pub is_trusted: bool, @@ -1153,7 +1154,7 @@ Use conventional commits: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore } /// Merge multiple project contexts (e.g., from nested directories) -#[allow(dead_code)] // Public API for monorepo context merging +#[allow(dead_code)] // Public API for monorepo context merging (see #3490) pub fn merge_contexts(contexts: &[ProjectContext]) -> Option { let non_empty: Vec<_> = contexts .iter() diff --git a/crates/tui/src/project_doc.rs b/crates/tui/src/project_doc.rs index c24e051dc0..8fe7da2533 100644 --- a/crates/tui/src/project_doc.rs +++ b/crates/tui/src/project_doc.rs @@ -22,12 +22,12 @@ pub const DOC_FILENAMES: &[&str] = &[ ]; /// Maximum bytes to read from project docs (default: 32KB) -#[allow(dead_code)] // Used by read_project_docs +#[allow(dead_code)] // DEFAULT_MAX_BYTES; used by read_project_docs (see #3490) pub const DEFAULT_MAX_BYTES: usize = 32768; /// A discovered project document #[derive(Debug, Clone)] -#[allow(dead_code)] +#[allow(dead_code)] // ProjectDoc struct; part of project context API (see #3490) pub struct ProjectDoc { pub path: PathBuf, pub content: String, @@ -84,7 +84,7 @@ pub(crate) fn find_git_root(cwd: &Path) -> Option { } /// Read and concatenate project docs with byte limit -#[allow(dead_code)] // Public API; project_context.rs provides the active code path +#[allow(dead_code)] // Public API; project_context.rs provides the active code path (see #3490) pub fn read_project_docs(paths: &[PathBuf], max_bytes: usize) -> Option { if paths.is_empty() { return None; @@ -124,7 +124,7 @@ pub fn read_project_docs(paths: &[PathBuf], max_bytes: usize) -> Option } /// Format project instructions for injection into system prompt -#[allow(dead_code)] // Used by read_project_docs +#[allow(dead_code)] // Used by read_project_docs (see #3490) pub fn format_instructions(path: &Path, content: &str) -> String { format!( "# Project instructions from {}\n\n\n{}\n", @@ -134,7 +134,7 @@ pub fn format_instructions(path: &Path, content: &str) -> String { } /// Load project docs from workspace with default settings -#[allow(dead_code)] // Convenience function; project_context.rs provides the active code path +#[allow(dead_code)] // Convenience function; project_context.rs provides the active code path (see #3490) pub fn load_from_workspace(workspace: &Path) -> Option { let paths = discover_paths(workspace); read_project_docs(&paths, DEFAULT_MAX_BYTES) diff --git a/crates/tui/src/prompt_zones.rs b/crates/tui/src/prompt_zones.rs index e9c9c04adc..45c8a51e88 100644 --- a/crates/tui/src/prompt_zones.rs +++ b/crates/tui/src/prompt_zones.rs @@ -26,14 +26,14 @@ use sha2::{Digest, Sha256}; // ── helpers ──────────────────────────────────────────────────────────── -#[allow(dead_code)] +#[allow(dead_code)] // prompt_zones sha256_hex utility (see #3490) fn sha256_hex(bytes: &[u8]) -> String { let mut hasher = Sha256::new(); hasher.update(bytes); format!("{:x}", hasher.finalize()) } -#[allow(dead_code)] +#[allow(dead_code)] // prompt_zones system_text utility (see #3490) fn system_text(system: Option<&SystemPrompt>) -> String { match system { Some(SystemPrompt::Text(text)) => text.clone(), @@ -50,7 +50,7 @@ fn system_text(system: Option<&SystemPrompt>) -> String { } /// Serialize tools to a deterministic, sorted JSON string for hashing. -#[allow(dead_code)] +#[allow(dead_code)] // prompt_zones tool_catalog_digest (see #3490) fn tool_catalog_digest(tools: &[Tool]) -> String { let mut serialized: Vec = tools .iter() @@ -60,7 +60,7 @@ fn tool_catalog_digest(tools: &[Tool]) -> String { serialized.join("\n") } -#[allow(dead_code)] +#[allow(dead_code)] // prompt_zones combined_hash (see #3490) fn combined_hash(system_text: &str, tools: &[Tool]) -> String { let system_sha = sha256_hex(system_text.as_bytes()); let tools_digest = tool_catalog_digest(tools); @@ -77,14 +77,14 @@ fn combined_hash(system_text: &str, tools: &[Tool]) -> String { /// /// Use [`PinnedPrefix::freeze`] to produce one. #[derive(Debug, Clone, PartialEq, Eq)] -#[allow(dead_code)] +#[allow(dead_code)] // FrozenPrefix struct; part of prefix API (see #3490) pub struct FrozenPrefix { pub(crate) system_text: String, pub(crate) tool_catalog: String, pub(crate) combined_sha256: String, } -#[allow(dead_code)] +#[allow(dead_code)] // FrozenPrefix impl (see #3490) impl FrozenPrefix { /// Verify that `current_system_text` and `current_tools` match the frozen /// prefix. Returns `Ok(())` when stable, `Err(PrefixDrift)` on mismatch. @@ -134,13 +134,13 @@ impl FrozenPrefix { /// A mutable prefix builder. Construct from the system prompt and tool /// catalog, then call [`freeze`](Self::freeze) to produce a [`FrozenPrefix`]. #[derive(Debug, Clone)] -#[allow(dead_code)] +#[allow(dead_code)] // PinnedPrefix struct (see #3490) pub struct PinnedPrefix { system_text: String, tools: Vec, } -#[allow(dead_code)] +#[allow(dead_code)] // PinnedPrefix impl (see #3490) impl PinnedPrefix { #[must_use] pub fn new(system: Option<&SystemPrompt>, tools: Vec) -> Self { @@ -168,7 +168,7 @@ impl PinnedPrefix { /// Describes how the current prefix differs from the frozen baseline. #[derive(Debug, Clone, PartialEq, Eq)] -#[allow(dead_code)] +#[allow(dead_code)] // PrefixDrift struct (see #3490) pub struct PrefixDrift { pub system_changed: bool, pub tools_changed: bool, @@ -298,14 +298,14 @@ impl std::ops::Deref for AppendLog { /// Per-turn ephemeral data. Cleared at every turn boundary. /// /// **Phase 1 scaffolding** — not yet wired into the engine request path. -#[allow(dead_code)] +#[allow(dead_code)] // TurnScratch struct; prefix cache (see #3490) #[derive(Debug, Clone, Default)] pub struct TurnScratch { pub working_set: Vec, pub user_message: Option, } -#[allow(dead_code)] +#[allow(dead_code)] // TurnScratch impl (see #3490) impl TurnScratch { pub fn new() -> Self { Self::default() @@ -328,7 +328,7 @@ impl TurnScratch { /// /// **Phase 1 scaffolding** — not yet wired into the engine request path. /// Currently the engine continues to use [`MessageRequest`] directly. -#[allow(dead_code)] +#[allow(dead_code)] // ThreeZoneRequest struct (see #3490) #[derive(Debug, Clone)] pub struct ThreeZoneRequest<'a> { pub prefix: &'a FrozenPrefix, @@ -347,7 +347,7 @@ pub struct ThreeZoneRequest<'a> { pub metadata: Option, } -#[allow(dead_code)] +#[allow(dead_code)] // ThreeZoneRequest impl (see #3490) impl<'a> ThreeZoneRequest<'a> { /// Build the full message list from system prompt, append-log messages, /// and scratch user message. The returned vector is serialized as the diff --git a/crates/tui/src/retry_status.rs b/crates/tui/src/retry_status.rs index e46d8e1e65..df4c08f241 100644 --- a/crates/tui/src/retry_status.rs +++ b/crates/tui/src/retry_status.rs @@ -43,7 +43,7 @@ pub enum RetryState { /// `TurnStarted`. Failed { reason: String, - #[allow(dead_code)] + #[allow(dead_code)] // Retry framework; kept for future adaptive retry policy (see #3490) since: Instant, }, } diff --git a/crates/tui/src/runtime_log.rs b/crates/tui/src/runtime_log.rs index 0081d1ba44..222891635d 100644 --- a/crates/tui/src/runtime_log.rs +++ b/crates/tui/src/runtime_log.rs @@ -66,12 +66,13 @@ pub struct TuiLogGuard { // wired up so adding one later doesn't require revisiting the // guard struct. #[allow(dead_code)] + // RuntimeLog guard path; kept for diagnostics struct completeness (see #3490) log_path: PathBuf, } impl TuiLogGuard { /// Path the subscriber is writing to. - #[allow(dead_code)] + #[allow(dead_code)] // RuntimeLog log_path accessor (see #3490) #[must_use] pub fn log_path(&self) -> &std::path::Path { &self.log_path diff --git a/crates/tui/src/runtime_threads.rs b/crates/tui/src/runtime_threads.rs index bf01aaa3b2..7e9626b478 100644 --- a/crates/tui/src/runtime_threads.rs +++ b/crates/tui/src/runtime_threads.rs @@ -886,7 +886,7 @@ impl RuntimeThreadManager { } } - #[allow(dead_code)] // Public API for external callers (runtime API, task manager) + #[allow(dead_code)] // Public API for external callers (runtime API, task manager) (see #3490) pub fn shutdown(&self) { self.cancel_token.cancel(); if let Ok(mut map) = self.pending_approvals.lock() { @@ -897,7 +897,7 @@ impl RuntimeThreadManager { } } - #[allow(dead_code)] // Public API for external callers + #[allow(dead_code)] // Public API for external callers (see #3490) pub fn is_shutdown(&self) -> bool { self.cancel_token.is_cancelled() } @@ -986,7 +986,7 @@ impl RuntimeThreadManager { Ok(true) } - #[allow(dead_code)] + #[allow(dead_code)] // RuntimeThreads cancel_user_input (see #3490) pub async fn cancel_user_input(&self, thread_id: &str, input_id: &str) -> Result { let active = self.active.lock().await; let Some(state) = active.engines.get(thread_id) else { @@ -996,7 +996,7 @@ impl RuntimeThreadManager { Ok(true) } - #[allow(dead_code)] + #[allow(dead_code)] // RuntimeThreads pending_approvals_count (see #3490) pub fn pending_approvals_count(&self) -> usize { self.pending_approvals .lock() @@ -1004,7 +1004,7 @@ impl RuntimeThreadManager { .unwrap_or(0) } - #[allow(dead_code)] + #[allow(dead_code)] // RuntimeThreads pending_dynamic_tools_count (see #3490) pub fn pending_dynamic_tools_count(&self) -> usize { self.pending_dynamic_tools .lock() @@ -1439,7 +1439,7 @@ impl RuntimeThreadManager { /// status per `agent_id` — the UI consumes this to seed empty /// `DelegateCard` / `FanoutCard` placeholders so subsequent live /// mailbox envelopes mutate them in place. - #[allow(dead_code)] // exposed for the runtime API resume flow; consumed by #128 follow-up. + #[allow(dead_code)] // exposed for the runtime API resume flow; consumed by #128 follow-up. (see #3490) pub async fn resume_thread_with_agent_rebind( &self, id: &str, @@ -1524,7 +1524,7 @@ impl RuntimeThreadManager { /// Errors: /// - `depth_from_tail` exceeds the number of user turns /// - source thread not found - #[allow(dead_code)] // exposed for the runtime/HTTP fork-on-backtrack path; the in-TUI Esc-Esc flow trims `App` state directly. Issue #133. + #[allow(dead_code)] // exposed for the runtime/HTTP fork-on-backtrack path; the in-TUI Esc-Esc flow trims App state directly. Issue #133. (see #3490) pub async fn fork_at_user_message( &self, id: &str, @@ -3789,14 +3789,14 @@ fn tool_kind_for_name(name: &str) -> TurnItemKind { /// resume flow is a follow-up; the runtime API consumer (`runtime_api.rs`) /// can already call `resume_thread_with_agent_rebind` to drive it. #[derive(Debug, Clone, PartialEq, Eq)] -#[allow(dead_code)] // consumed by #128 follow-up TUI resume wiring; tested here. +#[allow(dead_code)] // consumed by #128 follow-up TUI resume wiring; tested here. (see #3490) pub struct AgentRebindHint { pub agent_id: String, pub status: AgentRebindStatus, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(dead_code)] +#[allow(dead_code)] // AgentRebindStatus enum; follow-up API (see #3490) pub enum AgentRebindStatus { Spawned, InProgress, @@ -3809,7 +3809,7 @@ pub enum AgentRebindStatus { /// open to mutation by subsequent live mailbox envelopes (each envelope's /// `agent_id` matches one already in the rebind map). #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // collect_agent_rebind_hints; follow-up API (see #3490) pub fn collect_agent_rebind_hints(events: &[RuntimeEventRecord]) -> Vec { use std::collections::BTreeMap; let mut latest: BTreeMap = BTreeMap::new(); diff --git a/crates/tui/src/sandbox/mod.rs b/crates/tui/src/sandbox/mod.rs index 6f2be86404..ad3422f55a 100644 --- a/crates/tui/src/sandbox/mod.rs +++ b/crates/tui/src/sandbox/mod.rs @@ -339,7 +339,7 @@ pub struct SandboxManager { sandbox_available: Option, /// Force a specific sandbox type (for testing). - #[allow(dead_code)] + #[allow(dead_code)] // Testing aid; needed when sandbox tests are enabled (see #3490) forced_sandbox: Option, /// When true and bwrap is available on Linux, route commands through diff --git a/crates/tui/src/seam_manager.rs b/crates/tui/src/seam_manager.rs index e59575321c..a42a0040c1 100644 --- a/crates/tui/src/seam_manager.rs +++ b/crates/tui/src/seam_manager.rs @@ -91,18 +91,18 @@ pub struct SeamMetadata { pub level: u8, /// Message range covered (inclusive-exclusive indices). /// Reserved for future diagnostic use. - #[allow(dead_code)] + #[allow(dead_code)] // SeamInfo start_idx; part of public diagnostics API (see #3490) pub start_idx: usize, - #[allow(dead_code)] + #[allow(dead_code)] // SeamInfo end_idx; part of public diagnostics API (see #3490) pub end_idx: usize, /// Approximate token count of the summary. - #[allow(dead_code)] + #[allow(dead_code)] // SeamInfo token_estimate; part of public diagnostics API (see #3490) pub token_estimate: usize, /// When the seam was produced. - #[allow(dead_code)] + #[allow(dead_code)] // SeamInfo timestamp; part of public diagnostics API (see #3490) pub timestamp: DateTime, /// Model that produced it. - #[allow(dead_code)] + #[allow(dead_code)] // SeamInfo model; part of public diagnostics API (see #3490) pub model: String, } diff --git a/crates/tui/src/session_manager.rs b/crates/tui/src/session_manager.rs index 966c598b93..bdd302afbe 100644 --- a/crates/tui/src/session_manager.rs +++ b/crates/tui/src/session_manager.rs @@ -172,7 +172,7 @@ impl SessionCostSnapshot { impl SessionMetadata { /// Copy cost fields from another metadata (used when forking a session). - #[allow(dead_code)] + #[allow(dead_code)] // Cost fork helper; used by main.rs and session commands (see #3490) pub fn copy_cost_from(&mut self, other: &SessionMetadata) { self.cost = other.cost; } diff --git a/crates/tui/src/settings.rs b/crates/tui/src/settings.rs index e6f4c5f043..5a85bef5e0 100644 --- a/crates/tui/src/settings.rs +++ b/crates/tui/src/settings.rs @@ -70,7 +70,7 @@ impl Default for TuiPrefs { } /// Per-action keybinding overrides stored inside [`TuiPrefs`]. -#[allow(dead_code)] // see TuiPrefs note above; deferred to a later settings pass (#657). +#[allow(dead_code)] // see TuiPrefs note above; deferred to a later settings pass (#657). (see #3490) #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default)] pub struct KeybindPrefs { @@ -91,7 +91,7 @@ pub struct KeybindPrefs { pub toggle_sidebar: Option, } -#[allow(dead_code)] // see TuiPrefs note above; deferred to a later settings pass (#657). +#[allow(dead_code)] // see TuiPrefs note above; deferred to a later settings pass (#657). (see #3490) impl TuiPrefs { /// Return the canonical path of the TUI preferences file: /// `~/.codewhale/tui.toml`, or legacy `~/.deepseek/tui.toml` when present. @@ -971,7 +971,7 @@ impl Settings { } /// Get available setting keys and their descriptions - #[allow(dead_code)] + #[allow(dead_code)] // available_settings; reserved for settings UI (see #3490) pub fn available_settings() -> Vec<(&'static str, &'static str)> { vec![ ( @@ -1136,7 +1136,7 @@ impl Settings { /// Load, update, and save a provider/model tuple as the global default /// (the explicit "save as default" path). - #[allow(dead_code)] // wired to an explicit save-as-default action in a later UX pass (#3227). + #[allow(dead_code)] // wired to an explicit save-as-default action in a later UX pass (#3227). (see #3490) pub fn persist_provider_model_selection_as_default( provider: ApiProvider, model: &str, diff --git a/crates/tui/src/shell_dispatcher.rs b/crates/tui/src/shell_dispatcher.rs index a2063c410f..a9b2a74110 100644 --- a/crates/tui/src/shell_dispatcher.rs +++ b/crates/tui/src/shell_dispatcher.rs @@ -30,7 +30,7 @@ static LOG_MUTEX: Mutex<()> = Mutex::new(()); // --------------------------------------------------------------------------- /// The concrete shell that the dispatcher will use. -#[allow(dead_code)] +#[allow(dead_code)] // ShellKind enum; wired in ShellDispatcher resolution (see #3490) #[derive(Debug, Clone, PartialEq, Eq)] pub enum ShellKind { /// PowerShell 7+ (`pwsh.exe`). @@ -108,7 +108,7 @@ pub struct ShellDispatcher { kind: ShellKind, } -#[allow(dead_code)] +#[allow(dead_code)] // ShellDispatcher public impl; wired in config-based shell selection (see #3490) impl ShellDispatcher { /// Detect the user's shell from the environment. /// diff --git a/crates/tui/src/skill_state.rs b/crates/tui/src/skill_state.rs index 245b51f3dd..7da68ff6ca 100644 --- a/crates/tui/src/skill_state.rs +++ b/crates/tui/src/skill_state.rs @@ -86,7 +86,7 @@ impl SkillStateStore { self.persist() } - #[allow(dead_code)] + #[allow(dead_code)] // Getter exposed for settings UI integration (see #3490) pub fn disabled(&self) -> Vec { self.disabled.iter().cloned().collect() } diff --git a/crates/tui/src/skills/install.rs b/crates/tui/src/skills/install.rs index 4320466848..249c9b7b57 100644 --- a/crates/tui/src/skills/install.rs +++ b/crates/tui/src/skills/install.rs @@ -199,7 +199,7 @@ pub struct InstalledSkill { /// SHA-256 over the downloaded tarball bytes. Used by [`update`] to detect /// upstream changes without re-extracting; also surfaced for telemetry / /// future signature-verification work. - #[allow(dead_code)] + #[allow(dead_code)] // SkillMeta source_checksum (see #3490) pub source_checksum: String, } @@ -269,7 +269,7 @@ pub enum InstallError { /// [`DEFAULT_REGISTRY_URL`]. Public for downstream consumers (tests, runtime /// API) even though the slash-command path always goes through /// [`install_with_registry`] so the user's configured registry wins. -#[allow(dead_code)] +#[allow(dead_code)] // Skill install function; public API (see #3490) pub async fn install( source: InstallSource, skills_dir: &Path, @@ -388,7 +388,7 @@ pub async fn install_with_registry( /// `/skill update bar` without the user re-typing the spec. /// /// Convenience wrapper over [`update_with_registry`]. -#[allow(dead_code)] +#[allow(dead_code)] // Skill update function; public API (see #3490) pub async fn update( name: &str, skills_dir: &Path, diff --git a/crates/tui/src/skills/mod.rs b/crates/tui/src/skills/mod.rs index 82d7812f2d..0e471b7e4d 100644 --- a/crates/tui/src/skills/mod.rs +++ b/crates/tui/src/skills/mod.rs @@ -477,7 +477,7 @@ impl SkillRegistry { /// need to filter further. Returns an empty vec when nothing is /// installed (the system-prompt skills block is then suppressed). #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // Skill directory discovery; used by install/refresh paths (see #3490) pub fn skills_directories(workspace: &Path) -> Vec { skills_directories_for_mode(workspace, SkillDiscoveryMode::Compatible) } @@ -585,7 +585,7 @@ pub fn discover_in_workspace_with_mode( /// outside that set so explicit configuration cannot be buried by large global /// libraries. #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // Skill discovery helper; used by workspace initialization (see #3490) pub fn discover_for_workspace_and_dir(workspace: &Path, skills_dir: &Path) -> SkillRegistry { discover_for_workspace_and_dir_with_mode(workspace, skills_dir, SkillDiscoveryMode::Compatible) } diff --git a/crates/tui/src/skills/system.rs b/crates/tui/src/skills/system.rs index a1ef12e063..488368d034 100644 --- a/crates/tui/src/skills/system.rs +++ b/crates/tui/src/skills/system.rs @@ -165,7 +165,7 @@ pub fn install_system_skills(skills_dir: &Path) -> std::io::Result<()> { /// Remove all system skills and the version marker. /// /// Intended for tests and `deepseek setup --clean`. Ignores missing files. -#[allow(dead_code)] +#[allow(dead_code)] // Setup --clean / test utility; not wired into CLI yet (see #3490) pub fn uninstall_system_skills(skills_dir: &Path) -> std::io::Result<()> { let marker = skills_dir.join(".system-installed-version"); diff --git a/crates/tui/src/slop_ledger.rs b/crates/tui/src/slop_ledger.rs index 9446aaec0e..8ad97706a9 100644 --- a/crates/tui/src/slop_ledger.rs +++ b/crates/tui/src/slop_ledger.rs @@ -81,7 +81,7 @@ impl SlopBucket { } } - #[allow(dead_code)] + #[allow(dead_code)] // SlopBucket all_buckets; part of slop ledger API (see #3490) pub fn all_buckets() -> &'static [SlopBucket] { &[ Self::RetainedCompatibility, @@ -317,7 +317,7 @@ impl SlopLedger { /// Return the total number of entries. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // SlopLedger len; part of public API (see #3490) pub fn len(&self) -> usize { self.entries.len() } @@ -981,7 +981,7 @@ impl SlopLedger { /// /// Tools and engine hooks can call this on claim-of-done to surface /// architectural residue the agent may have overlooked. - #[allow(dead_code)] + #[allow(dead_code)] // Reserve for future slop reporting API (see #3490) #[must_use] pub fn has_open_entries(&self) -> bool { self.entries.iter().any(|e| { @@ -995,7 +995,7 @@ impl SlopLedger { /// Return a concise completion-gate summary suitable for a verifier /// sub-agent or the claim-of-done prompt. Returns `None` when all /// entries are resolved — the caller can then treat the gate as "pass". - #[allow(dead_code)] + #[allow(dead_code)] // Reserve for future slop reporting API (see #3490) #[must_use] pub fn completion_gate_summary(&self) -> Option { let open: Vec<&SlopEntry> = self diff --git a/crates/tui/src/snapshot/repo.rs b/crates/tui/src/snapshot/repo.rs index fe016fad3a..4ec7832d4e 100644 --- a/crates/tui/src/snapshot/repo.rs +++ b/crates/tui/src/snapshot/repo.rs @@ -726,13 +726,13 @@ impl SnapshotRepo { } /// Return the side-repo's `.git` directory (for diagnostics). - #[allow(dead_code)] + #[allow(dead_code)] // Side-repo git_dir diagnostics accessor (see #3490) pub fn git_dir(&self) -> &Path { &self.git_dir } /// Return the work tree path (for diagnostics). - #[allow(dead_code)] + #[allow(dead_code)] // Side-repo work_tree diagnostics accessor (see #3490) pub fn work_tree(&self) -> &Path { &self.work_tree } diff --git a/crates/tui/src/task_manager.rs b/crates/tui/src/task_manager.rs index e11208122e..23db2b8f3c 100644 --- a/crates/tui/src/task_manager.rs +++ b/crates/tui/src/task_manager.rs @@ -309,7 +309,7 @@ pub struct TaskManagerConfig { pub default_mode: String, pub allow_shell: bool, pub trust_mode: bool, - #[allow(dead_code)] + #[allow(dead_code)] // TaskManagerConfig max_subagents (see #3490) pub max_subagents: usize, } @@ -807,12 +807,12 @@ impl TaskManager { Ok(manager) } - #[allow(dead_code)] // Public API for external callers (runtime API) + #[allow(dead_code)] // Public API for external callers (runtime API) (see #3490) pub fn shutdown(&self) { self.cancel_token.cancel(); } - #[allow(dead_code)] // Public API for external callers + #[allow(dead_code)] // Public API for external callers (see #3490) pub fn is_shutdown(&self) -> bool { self.cancel_token.is_cancelled() } diff --git a/crates/tui/src/tls.rs b/crates/tui/src/tls.rs index 448f6e51c5..0b30a1b679 100644 --- a/crates/tui/src/tls.rs +++ b/crates/tui/src/tls.rs @@ -2,7 +2,7 @@ pub(crate) fn ensure_rustls_crypto_provider() { let _ = rustls::crypto::ring::default_provider().install_default(); } -#[allow(dead_code)] +#[allow(dead_code)] // Used by tests (runtime_api/tests.rs); callers migrated to reqwest_client_builder (see #3490) pub(crate) fn reqwest_client() -> reqwest::Client { ensure_rustls_crypto_provider(); reqwest::Client::new() diff --git a/crates/tui/src/tools/apply_patch.rs b/crates/tui/src/tools/apply_patch.rs index 7a6512a4d3..e83fcac0e8 100644 --- a/crates/tui/src/tools/apply_patch.rs +++ b/crates/tui/src/tools/apply_patch.rs @@ -76,11 +76,11 @@ pub struct ApplyPatchPreflight { #[derive(Debug, Clone)] pub struct Hunk { pub old_start: usize, - #[allow(dead_code)] + #[allow(dead_code)] // ApplyPatchSummary old_count field (see #3490) pub old_count: usize, - #[allow(dead_code)] + #[allow(dead_code)] // ApplyPatchSummary new_start field (see #3490) pub new_start: usize, - #[allow(dead_code)] + #[allow(dead_code)] // ApplyPatchSummary new_count field (see #3490) pub new_count: usize, pub lines: Vec, } diff --git a/crates/tui/src/tools/approval_cache.rs b/crates/tui/src/tools/approval_cache.rs index 17d83e3681..e762ed6cdd 100644 --- a/crates/tui/src/tools/approval_cache.rs +++ b/crates/tui/src/tools/approval_cache.rs @@ -118,13 +118,13 @@ impl ApprovalCache { } /// Number of cached entries. - #[allow(dead_code)] + #[allow(dead_code)] // Approval cache len accessor (see #3490) pub fn len(&self) -> usize { self.entries.len() } /// Whether the cache is empty. - #[allow(dead_code)] + #[allow(dead_code)] // Approval cache is_empty accessor (see #3490) pub fn is_empty(&self) -> bool { self.entries.is_empty() } diff --git a/crates/tui/src/tools/handle.rs b/crates/tui/src/tools/handle.rs index 6f0e1a8145..7afd39874d 100644 --- a/crates/tui/src/tools/handle.rs +++ b/crates/tui/src/tools/handle.rs @@ -20,7 +20,7 @@ use crate::tools::spec::{ const DEFAULT_MAX_CHARS: usize = 12_000; const HARD_MAX_CHARS: usize = 50_000; -#[allow(dead_code)] // Used by producers as they begin returning var_handle records. +#[allow(dead_code)] // Used by producers as they begin returning var_handle records. (see #3490) const REPR_PREVIEW_CHARS: usize = 160; pub type SharedHandleStore = Arc>; @@ -64,14 +64,14 @@ pub struct HandleRecord { pub value: HandleValue, } -#[allow(dead_code)] // Producers land in later v0.8.33 slices; handle_read is first. +#[allow(dead_code)] // Producers land in later v0.8.33 slices; handle_read is first. (see #3490) #[derive(Debug, Clone)] pub enum HandleValue { Text(String), Json(Value), } -#[allow(dead_code)] // Foundation methods used by upcoming RLM/agent session producers. +#[allow(dead_code)] // Foundation methods used by upcoming RLM/agent session producers. (see #3490) impl HandleValue { fn length(&self) -> usize { match self { @@ -114,7 +114,7 @@ pub struct HandleStore { records: HashMap, } -#[allow(dead_code)] // Insertors are for producer tools; this PR wires the reader first. +#[allow(dead_code)] // Insertors are for producer tools; this PR wires the reader first. (see #3490) impl HandleStore { #[must_use] pub fn insert_text( @@ -761,7 +761,7 @@ fn truncate_chars(text: &str, max_chars: usize) -> String { out } -#[allow(dead_code)] // Used when producer tools register handle payloads. +#[allow(dead_code)] // Used when producer tools register handle payloads. (see #3490) fn sha256_hex(bytes: &[u8]) -> String { let mut hasher = Sha256::new(); hasher.update(bytes); diff --git a/crates/tui/src/tools/large_output_router.rs b/crates/tui/src/tools/large_output_router.rs index fc0048edec..aad347e9d1 100644 --- a/crates/tui/src/tools/large_output_router.rs +++ b/crates/tui/src/tools/large_output_router.rs @@ -138,7 +138,7 @@ impl LargeOutputRouter { /// registry layer). The method is public so callers outside this crate /// can unit-test the prompt shape. #[must_use] - #[allow(dead_code)] // used by future Flash synthesis call; keep for API stability + #[allow(dead_code)] // used by future Flash synthesis call; keep for API stability (see #3490) pub fn synthesis_prompt(tool_name: &str, raw_output: &str, estimated_tokens: usize) -> String { format!( "You are a synthesis assistant. The tool `{tool_name}` produced {estimated_tokens} tokens \ @@ -195,7 +195,7 @@ impl WorkshopVariables { /// /// Called by the `promote_to_context` tool (not yet wired in this PR). #[must_use] - #[allow(dead_code)] // consumed by promote_to_context tool in follow-up + #[allow(dead_code)] // consumed by promote_to_context tool in follow-up (see #3490) pub fn take_raw(&mut self) -> Option<(String, String)> { if self.last_tool_result.is_empty() { return None; diff --git a/crates/tui/src/tools/parallel.rs b/crates/tui/src/tools/parallel.rs index 4311287093..18b4f5067f 100644 --- a/crates/tui/src/tools/parallel.rs +++ b/crates/tui/src/tools/parallel.rs @@ -14,7 +14,7 @@ use super::spec::{ use async_trait::async_trait; use serde_json::{Value, json}; -#[allow(dead_code)] +#[allow(dead_code)] // Multi-tool parallel tool spec; reserved for Anthropic parallel tool use (see #3490) pub struct MultiToolUseParallelTool; #[async_trait] diff --git a/crates/tui/src/tools/plan.rs b/crates/tui/src/tools/plan.rs index 149b273fc5..c94cfaf2b8 100644 --- a/crates/tui/src/tools/plan.rs +++ b/crates/tui/src/tools/plan.rs @@ -24,7 +24,7 @@ pub enum StepStatus { } impl StepStatus { - #[allow(dead_code)] + #[allow(dead_code)] // PlanState estimated_tokens; part of public API (see #3490) #[must_use] pub fn from_str(value: &str) -> Option { match value.trim().to_lowercase().as_str() { @@ -35,7 +35,7 @@ impl StepStatus { } } - #[allow(dead_code)] + #[allow(dead_code)] // PlanState tokens_used; part of public API (see #3490) #[must_use] pub fn symbol(&self) -> &'static str { match self { @@ -402,7 +402,7 @@ fn clean_list(values: Vec) -> Vec { /// Validation result for plan transitions #[derive(Debug)] -#[allow(dead_code)] +#[allow(dead_code)] // PlanValidation enum; part of plan validation API (see #3490) pub enum PlanValidation { Ok, Warning(String), @@ -410,7 +410,7 @@ pub enum PlanValidation { } /// Validate a plan update -#[allow(dead_code)] +#[allow(dead_code)] // validate_plan_update; part of plan validation API (see #3490) pub fn validate_plan_update(current: &PlanState, update: &UpdatePlanArgs) -> PlanValidation { let current_steps: std::collections::HashMap<_, _> = current .steps() diff --git a/crates/tui/src/tools/registry.rs b/crates/tui/src/tools/registry.rs index 92ac3acc77..30051c005d 100644 --- a/crates/tui/src/tools/registry.rs +++ b/crates/tui/src/tools/registry.rs @@ -77,21 +77,21 @@ impl ToolRegistry { /// Get all registered tool names. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry names; public API (see #3490) pub fn names(&self) -> Vec<&str> { self.tools.keys().map(std::string::String::as_str).collect() } /// Get the number of registered tools. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry len; public API (see #3490) pub fn len(&self) -> usize { self.tools.len() } /// Check if the registry is empty. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry is_empty; public API (see #3490) pub fn is_empty(&self) -> bool { self.tools.is_empty() } @@ -103,7 +103,7 @@ impl ToolRegistry { } /// Execute a tool by name with the given input. - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry execute; public API (see #3490) pub async fn execute(&self, name: &str, input: Value) -> Result { let tool = self .get(name) @@ -262,7 +262,7 @@ impl ToolRegistry { /// Filter tools by capability. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry filter_by_capability (see #3490) pub fn filter_by_capability(&self, capability: ToolCapability) -> Vec> { self.tools .values() @@ -273,7 +273,7 @@ impl ToolRegistry { /// Get read-only tools. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry read_only_tools (see #3490) pub fn read_only_tools(&self) -> Vec> { self.tools .values() @@ -284,7 +284,7 @@ impl ToolRegistry { /// Get tools that require approval. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry approval_required_tools (see #3490) pub fn approval_required_tools(&self) -> Vec> { self.tools .values() @@ -295,7 +295,7 @@ impl ToolRegistry { /// Get tools that suggest approval. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry approval_suggested_tools (see #3490) pub fn approval_suggested_tools(&self) -> Vec> { self.tools .values() @@ -310,21 +310,21 @@ impl ToolRegistry { } /// Update the context (e.g., when workspace changes). - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry set_context (see #3490) pub fn set_context(&mut self, context: ToolContext) { self.context = context; } /// Get a mutable reference to the current context. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry context_mut (see #3490) pub fn context_mut(&mut self) -> &mut ToolContext { &mut self.context } /// Remove a tool by name. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry remove (see #3490) pub fn remove(&mut self, name: &str) -> Option> { let removed = self.tools.remove(name); if removed.is_some() { @@ -390,7 +390,7 @@ impl ToolRegistry { } /// Clear all tools from the registry. - #[allow(dead_code)] + #[allow(dead_code)] // ToolRegistry clear (see #3490) pub fn clear(&mut self) { self.tools.clear(); self.invalidate_api_cache(); @@ -930,7 +930,7 @@ impl ToolRegistryBuilder { /// when `tool_setup.rs` conditionally registers them on top of /// `with_agent_tools`. #[must_use] - #[allow(dead_code)] // legacy allow_shell convenience wrapper; used by tests, prod uses with_agent_tools_policy + #[allow(dead_code)] // legacy allow_shell convenience wrapper; used by tests, prod uses with_agent_tools_policy (see #3490) pub fn with_agent_tools(self, allow_shell: bool) -> Self { self.with_agent_tools_policy(crate::worker_profile::ShellPolicy::from_legacy_allow_shell( allow_shell, @@ -1100,7 +1100,7 @@ fn to_snake_case(s: &str) -> String { /// Adapter that wraps an MCP tool definition so it can live in the /// unified `ToolRegistry` alongside native tools (§5.B). -#[allow(dead_code)] +#[allow(dead_code)] // McpToolAdapter struct; MCP integration (see #3490) struct McpToolAdapter { name: String, tool: crate::mcp::McpTool, diff --git a/crates/tui/src/tools/rlm.rs b/crates/tui/src/tools/rlm.rs index 3e7ceeb940..516900bca4 100644 --- a/crates/tui/src/tools/rlm.rs +++ b/crates/tui/src/tools/rlm.rs @@ -659,7 +659,7 @@ fn preview_output(text: &str) -> String { ) } -#[allow(dead_code)] +#[allow(dead_code)] // Compile-time type assertion for VarHandle (see #3490) fn _assert_var_handle_shape(_: Option) {} #[cfg(test)] diff --git a/crates/tui/src/tools/shell.rs b/crates/tui/src/tools/shell.rs index 1826914fed..60bd998c87 100644 --- a/crates/tui/src/tools/shell.rs +++ b/crates/tui/src/tools/shell.rs @@ -726,7 +726,7 @@ impl BackgroundShell { } /// Get a snapshot of the current state - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager snapshot; diagnostics API (see #3490) pub fn snapshot(&self) -> ShellResult { let sandboxed = !matches!(self.sandbox_type, SandboxType::None); let (stdout_full, stderr_full, _, _) = self.full_output(); @@ -886,7 +886,7 @@ impl ShellManager { } /// Create a new `ShellManager` with a specific sandbox policy. - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager with_sandbox builder (see #3490) pub fn with_sandbox(workspace: PathBuf, policy: ExecutionSandboxPolicy) -> Self { Self { processes: HashMap::new(), @@ -899,13 +899,13 @@ impl ShellManager { } /// Set the sandbox policy for future commands. - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager set_sandbox_policy (see #3490) pub fn set_sandbox_policy(&mut self, policy: ExecutionSandboxPolicy) { self.sandbox_policy = policy; } /// Get the current sandbox policy. - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager sandbox_policy accessor (see #3490) pub fn sandbox_policy(&self) -> &ExecutionSandboxPolicy { &self.sandbox_policy } @@ -914,7 +914,7 @@ impl ShellManager { /// /// When enabled and `/usr/bin/bwrap` is present on Linux, exec_shell /// commands are routed through bubblewrap for filesystem isolation. - #[allow(dead_code)] // Wired from EngineConfig in follow-up PR + #[allow(dead_code)] // Wired from EngineConfig in follow-up PR (see #3490) pub fn set_prefer_bwrap(&mut self, prefer: bool) { self.sandbox_manager.set_prefer_bwrap(prefer); } @@ -936,18 +936,18 @@ impl ShellManager { } /// Check if sandboxing is available on this platform. - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager is_sandbox_available (see #3490) pub fn is_sandbox_available(&mut self) -> bool { self.sandbox_manager.is_available() } - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager default_workspace (see #3490) pub fn default_workspace(&self) -> &Path { &self.default_workspace } /// Execute a shell command with the configured sandbox policy. - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager execute; public API (see #3490) pub fn execute( &mut self, command: &str, @@ -959,7 +959,7 @@ impl ShellManager { } /// Execute a shell command with a specific sandbox policy (overrides default). - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager execute_with_policy (see #3490) pub fn execute_with_policy( &mut self, command: &str, @@ -1084,7 +1084,7 @@ impl ShellManager { } /// Execute a shell command interactively (stdin/stdout/stderr inherit from terminal). - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager execute_interactive (see #3490) pub fn execute_interactive( &mut self, command: &str, @@ -1590,7 +1590,7 @@ impl ShellManager { } /// Get output from a background process - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager get_output (see #3490) pub fn get_output( &mut self, task_id: &str, @@ -1804,7 +1804,7 @@ impl ShellManager { } /// Remember a restart-stale job so the UI can show it instead of hiding it. - #[allow(dead_code)] + #[allow(dead_code)] // ShellManager remember_stale_job (see #3490) pub fn remember_stale_job( &mut self, id: impl Into, diff --git a/crates/tui/src/tools/spec.rs b/crates/tui/src/tools/spec.rs index 11674e20ef..7ea107c385 100644 --- a/crates/tui/src/tools/spec.rs +++ b/crates/tui/src/tools/spec.rs @@ -159,12 +159,12 @@ pub struct ToolContext { /// Whether to allow paths outside workspace pub trust_mode: bool, /// Current sandbox policy - #[allow(dead_code)] + #[allow(dead_code)] // ToolContext sandbox_policy field (see #3490) pub sandbox_policy: SandboxPolicy, /// Path for notes file pub notes_path: PathBuf, /// MCP configuration path - #[allow(dead_code)] + #[allow(dead_code)] // ToolContext mcp_config_path field (see #3490) pub mcp_config_path: PathBuf, /// Explicit skills directory used for model-visible skill discovery. pub skills_dir: Option, @@ -298,7 +298,7 @@ impl ToolContext { } /// Create a `ToolContext` with all settings specified. - #[allow(dead_code)] + #[allow(dead_code)] // ToolBuilder with_options (see #3490) pub fn with_options( workspace: impl Into, trust_mode: bool, @@ -451,7 +451,7 @@ impl ToolContext { /// Attach an external sandbox backend for remote shell execution. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolBuilder with_sandbox_backend (see #3490) pub fn with_sandbox_backend(mut self, backend: std::sync::Arc) -> Self { self.sandbox_backend = Some(backend); self @@ -479,7 +479,7 @@ impl ToolContext { /// Attach an LSP manager so that edit tools can auto-inject diagnostics /// into their results after a successful file modification (#428). #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // ToolBuilder with_lsp_manager (see #3490) pub fn with_lsp_manager(mut self, manager: Arc) -> Self { self.lsp_manager = Some(manager); self @@ -720,14 +720,14 @@ impl ToolContext { } /// Set the trust mode. - #[allow(dead_code)] + #[allow(dead_code)] // ToolBuilder with_trust_mode (see #3490) pub fn with_trust_mode(mut self, trust: bool) -> Self { self.trust_mode = trust; self } /// Set the sandbox policy. - #[allow(dead_code)] + #[allow(dead_code)] // ToolBuilder with_sandbox_policy (see #3490) pub fn with_sandbox_policy(mut self, policy: SandboxPolicy) -> Self { self.sandbox_policy = policy; self @@ -889,7 +889,7 @@ pub trait ToolSpec: Send + Sync { } /// Returns whether this tool is sandboxable. - #[allow(dead_code)] + #[allow(dead_code)] // ToolCapability sandboxable check (see #3490) fn is_sandboxable(&self) -> bool { self.capabilities().contains(&ToolCapability::Sandboxable) } diff --git a/crates/tui/src/tools/subagent/mod.rs b/crates/tui/src/tools/subagent/mod.rs index 678cdfa8dc..9665eed963 100644 --- a/crates/tui/src/tools/subagent/mod.rs +++ b/crates/tui/src/tools/subagent/mod.rs @@ -1358,7 +1358,7 @@ pub struct SubAgentCompletion { /// The completing child's agent id. Held for routing/logging — the /// engine's turn loop does not currently key on it (it just injects /// the payload), but downstream tooling and tests need the field. - #[allow(dead_code)] + #[allow(dead_code)] // SubAgentContext agent_id; part of public API (see #3490) pub agent_id: String, /// Human summary on line 1, sentinel on line 2. Same payload shape as /// `Event::AgentComplete::result`. @@ -1555,7 +1555,7 @@ impl SubAgentRuntime { /// stream. Pair with [`Self::with_cancel_token`] when the mailbox close /// token should match this runtime's cancellation token. #[must_use] - #[allow(dead_code)] // wired by #128 (in-transcript cards) when it lands. + #[allow(dead_code)] // wired by #128 (in-transcript cards) when it lands. (see #3490) pub fn with_mailbox(mut self, mailbox: Mailbox) -> Self { self.mailbox = Some(mailbox); self @@ -1564,7 +1564,7 @@ impl SubAgentRuntime { /// Replace the cancellation token (e.g. when the engine constructs the /// runtime alongside a mailbox bound to the same token). #[must_use] - #[allow(dead_code)] // wired by #128 alongside `with_mailbox`. + #[allow(dead_code)] // wired by #128 alongside `with_mailbox`. (see #3490) pub fn with_cancel_token(mut self, token: CancellationToken) -> Self { self.cancel_token = token; self @@ -1573,7 +1573,7 @@ impl SubAgentRuntime { /// Override the maximum spawn depth (default `DEFAULT_MAX_SPAWN_DEPTH`). /// Used by config wiring (`[subagents] max_depth = N`) and tests. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // with_max_spawn_depth; reserved for depth-limited spawn (see #3490) pub fn with_max_spawn_depth(mut self, max: u32) -> Self { self.max_spawn_depth = max; self @@ -1776,7 +1776,7 @@ pub struct SubAgentManager { agents: HashMap, worker_records: HashMap, worker_event_seq: u64, - #[allow(dead_code)] // Stored for future workspace-scoped operations + #[allow(dead_code)] // Stored for future workspace-scoped operations (see #3490) workspace: PathBuf, state_path: Option, max_steps: u32, diff --git a/crates/tui/src/tools/todo.rs b/crates/tui/src/tools/todo.rs index 3f8b18109b..54edb3b1e5 100644 --- a/crates/tui/src/tools/todo.rs +++ b/crates/tui/src/tools/todo.rs @@ -23,7 +23,7 @@ pub enum TodoStatus { } impl TodoStatus { - #[allow(dead_code)] + #[allow(dead_code)] // TodoStatus display helper (see #3490) pub fn as_str(self) -> &'static str { match self { TodoStatus::Pending => "pending", diff --git a/crates/tui/src/tools/truncate.rs b/crates/tui/src/tools/truncate.rs index 55306f02b5..14b6ebbf5b 100644 --- a/crates/tui/src/tools/truncate.rs +++ b/crates/tui/src/tools/truncate.rs @@ -277,7 +277,7 @@ pub const SPILLOVER_HEAD_BYTES: usize = 32 * 1024; /// Error results (`success == false`) are skipped: error messages /// are typically short, and turning them into a "see file" pointer /// would just hide the error from the model's reasoning. -#[allow(dead_code)] +#[allow(dead_code)] // Public wrapper around apply_spillover_inner; used by tests (see #3490) pub fn apply_spillover(result: &mut ToolResult, tool_id: &str) -> Option { apply_spillover_inner(result, tool_id, None) } diff --git a/crates/tui/src/tui/active_cell.rs b/crates/tui/src/tui/active_cell.rs index 72264f9015..17b4b914f6 100644 --- a/crates/tui/src/tui/active_cell.rs +++ b/crates/tui/src/tui/active_cell.rs @@ -77,7 +77,7 @@ impl ActiveCell { /// Number of entries (each rendered as its own [`HistoryCell`]). #[must_use] - #[allow(dead_code)] // Public surface used by tests and future renderers. + #[allow(dead_code)] // Public surface used by tests and future renderers. (see #3490) pub fn entry_count(&self) -> usize { self.entries.len() } @@ -109,7 +109,7 @@ impl ActiveCell { /// invalidation; the chance of a wrap-around collision is astronomical /// over a single session and any miss only causes one extra re-render. #[must_use] - #[allow(dead_code)] // Used by App::bump_active_cell_revision and future cache wiring. + #[allow(dead_code)] // Used by App::bump_active_cell_revision and future cache wiring. (see #3490) pub fn revision(&self) -> u64 { self.revision } @@ -161,7 +161,7 @@ impl ActiveCell { /// Push an entry with no tool id binding (used for non-tool grouping if /// ever needed). Currently unused; kept for symmetry with Codex which /// allows e.g. session-header cells to live in `active_cell`. - #[allow(dead_code)] + #[allow(dead_code)] // push_untracked; used by session migration paths (see #3490) pub fn push_untracked(&mut self, cell: HistoryCell) -> usize { let entry_idx = self.entries.len(); self.entries.push(cell); @@ -190,7 +190,7 @@ impl ActiveCell { /// Look up the entry index that holds the given tool id. #[must_use] - #[allow(dead_code)] // Reserved for the Codex-style "exec end target" lookup. + #[allow(dead_code)] // Reserved for the Codex-style "exec end target" lookup. (see #3490) pub fn entry_index_for_tool(&self, tool_id: &str) -> Option { self.tool_to_entry.get(tool_id).copied() } @@ -236,7 +236,7 @@ impl ActiveCell { /// Remove the tool-id binding for an entry without removing the entry /// itself (the entry remains in the active group, presumably with its /// status updated). - #[allow(dead_code)] // Reserved for cancellation paths that prune ids without flushing. + #[allow(dead_code)] // Reserved for cancellation paths that prune ids without flushing. (see #3490) pub fn forget_tool(&mut self, tool_id: &str) -> Option { self.tool_to_entry.remove(tool_id) } diff --git a/crates/tui/src/tui/app.rs b/crates/tui/src/tui/app.rs index f733d6a517..263cfddb1d 100644 --- a/crates/tui/src/tui/app.rs +++ b/crates/tui/src/tui/app.rs @@ -405,7 +405,7 @@ impl SidebarFocus { } #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // AppSetting as_str; public API (see #3490) pub fn as_setting(self) -> &'static str { match self { Self::Auto => "auto", @@ -983,7 +983,7 @@ impl AppMode { ) } - #[allow(dead_code)] + #[allow(dead_code)] // AppSetting description; public API (see #3490) /// Description shown in help or onboarding text. pub fn description(self) -> &'static str { match self { @@ -1031,15 +1031,15 @@ pub struct TuiOptions { pub use_bracketed_paste: bool, /// Maximum number of concurrent sub-agents. pub max_subagents: usize, - #[allow(dead_code)] + #[allow(dead_code)] // AppDataPaths skills_dir (see #3490) pub skills_dir: PathBuf, - #[allow(dead_code)] + #[allow(dead_code)] // AppDataPaths memory_path (see #3490) pub memory_path: PathBuf, - #[allow(dead_code)] + #[allow(dead_code)] // AppDataPaths notes_path (see #3490) pub notes_path: PathBuf, - #[allow(dead_code)] + #[allow(dead_code)] // AppDataPaths mcp_config_path (see #3490) pub mcp_config_path: PathBuf, - #[allow(dead_code)] + #[allow(dead_code)] // AppDataPaths use_memory (see #3490) pub use_memory: bool, /// Start in agent mode (defaults to agent; --yolo starts in YOLO) pub start_in_agent_mode: bool, @@ -1096,7 +1096,7 @@ struct ModeSessionPrefs { /// booleans without a type migration. #[derive(Debug, Clone, Copy)] struct EffectiveModePolicy { - #[allow(dead_code)] + #[allow(dead_code)] // App mode field (see #3490) mode: AppMode, allow_shell: bool, trust_mode: bool, @@ -1521,7 +1521,7 @@ pub(crate) struct PendingProviderSwitch { pub struct App { pub mode: AppMode, /// Registered hotbar actions available for future slot config/render layers. - #[allow(dead_code)] + #[allow(dead_code)] // App hotbar_actions registry (see #3490) pub hotbar_actions: HotbarActionRegistry, /// Composer sub-state (input, cursor, history, menus). pub composer: ComposerState, @@ -1661,7 +1661,7 @@ pub struct App { /// fast typing or IME commits could otherwise be mis-classified as a /// paste burst (#1322 follow-up). pub bracketed_paste_seen: bool, - #[allow(dead_code)] + #[allow(dead_code)] // App system_prompt field (see #3490) pub system_prompt: Option, pub auto_compact: bool, pub auto_compact_user_configured: bool, @@ -1670,7 +1670,7 @@ pub struct App { pub low_motion: bool, /// Pending #61 (animated working strip). Set from config but not read /// until the footer widget consumes it. - #[allow(dead_code)] + #[allow(dead_code)] // App fancy_animations field (see #3490) pub fancy_animations: bool, /// Whether the renderer should wrap each frame in DEC mode 2026 /// synchronized output. Resolved from `Settings::synchronized_output` @@ -1744,7 +1744,7 @@ pub struct App { /// Whether the file-tree pane was actually rendered in the last frame. /// Set false when the terminal is too narrow to show the tree. pub file_tree_visible: bool, - #[allow(dead_code)] + #[allow(dead_code)] // App compact_threshold field (see #3490) pub compact_threshold: usize, pub max_input_history: usize, pub allow_shell: bool, @@ -1800,7 +1800,7 @@ pub struct App { pub api_key_cursor: usize, // Hooks system pub hooks: HookExecutor, - #[allow(dead_code)] + #[allow(dead_code)] // App yolo mode field (see #3490) pub yolo: bool, /// Durable Agent-era permission baseline that Plan/YOLO derive from and /// restore to (#3386). Refreshed from the live fields whenever the user @@ -1839,7 +1839,7 @@ pub struct App { /// hardcoded in the footer code path. pub status_items: Vec, /// Project documentation (AGENTS.md or CLAUDE.md) - #[allow(dead_code)] + #[allow(dead_code)] // App project_doc field (see #3490) pub project_doc: Option, /// Plan state for tracking tasks pub plan_state: SharedPlanState, @@ -2099,11 +2099,11 @@ pub enum SubmitDisposition { /// Park on `queued_messages` (offline, or engine busy — #382). Queue, /// Explicit steer via Ctrl+Enter (#382). Not returned by `decide_submit_disposition`. - #[allow(dead_code)] + #[allow(dead_code)] // Action Steer variant (see #3490) Steer, /// Park on `queued_messages` for dispatch after TurnComplete. /// Legacy path; #382 unified busy states under `Queue`. - #[allow(dead_code)] + #[allow(dead_code)] // Action QueueFollowUp variant (see #3490) QueueFollowUp, } @@ -2144,7 +2144,7 @@ impl QueuedMessage { } } - #[allow(dead_code)] // Tests and queue helpers use the display-only form; send path resolves @mentions. + #[allow(dead_code)] // Tests and queue helpers use the display-only form; send path resolves @mentions. (see #3490) pub fn content(&self) -> String { if let Some(skill_instruction) = self.skill_instruction.as_ref() { format!( @@ -2941,7 +2941,7 @@ impl App { } /// Cycle through modes in reverse. - #[allow(dead_code)] + #[allow(dead_code)] // App cycle_mode_reverse (see #3490) pub fn cycle_mode_reverse(&mut self) { if self.reject_setting_change_while_busy("Mode") { return; @@ -3021,7 +3021,7 @@ impl App { /// Add `delta` to the parent-turn session cost and bump the displayed /// high-water mark so the footer total never reverses (#244). - #[allow(dead_code)] + #[allow(dead_code)] // App accrue_session_cost; cost tracking API (see #3490) pub fn accrue_session_cost(&mut self, delta: f64) { self.accrue_session_cost_estimate(CostEstimate::usd_only(delta)); } @@ -3035,7 +3035,7 @@ impl App { /// Add `delta` to the running sub-agent cost and bump the displayed /// high-water mark so the footer total never reverses (#244). - #[allow(dead_code)] + #[allow(dead_code)] // App accrue_subagent_cost; cost tracking API (see #3490) pub fn accrue_subagent_cost(&mut self, delta: f64) { self.accrue_subagent_cost_estimate(CostEstimate::usd_only(delta)); } @@ -3077,7 +3077,7 @@ impl App { /// Read the visible session+sub-agent cost. Guaranteed monotonic across /// reconciliation events (cache adjustments, provisional → final swaps) /// for the lifetime of one session (#244). - #[allow(dead_code)] + #[allow(dead_code)] // App displayed_session_cost; cost display API (see #3490) pub fn displayed_session_cost(&self) -> f64 { self.displayed_session_cost_for_currency(CostCurrency::Usd) } @@ -3489,7 +3489,7 @@ impl App { /// Total number of cells in the *virtual* transcript: `history.len()` /// plus active cell entries (if any). #[must_use] - #[allow(dead_code)] // Reserved for renderers that need a unified cell count. + #[allow(dead_code)] // Reserved for renderers that need a unified cell count. (see #3490) pub fn virtual_cell_count(&self) -> usize { self.history.len() + self.active_cell.as_ref().map_or(0, ActiveCell::entry_count) } @@ -3498,7 +3498,7 @@ impl App { /// transcript. Used by `register_tool_cell`-style callsites that record /// cell-index metadata before the active cell flushes to history. #[must_use] - #[allow(dead_code)] // Reserved for the eventual merged push helper. + #[allow(dead_code)] // Reserved for the eventual merged push helper. (see #3490) pub fn next_virtual_cell_index(&self) -> usize { self.virtual_cell_count() } @@ -3515,7 +3515,7 @@ impl App { /// active-cell entry. Used by the pager / details lookup code so it can /// transparently address still-in-flight cells. #[must_use] - #[allow(dead_code)] // Used by the upcoming pager rewrite (read-only resolver). + #[allow(dead_code)] // Used by the upcoming pager rewrite (read-only resolver). (see #3490) pub fn cell_at_virtual_index(&self, index: usize) -> Option<&HistoryCell> { if index < self.history.len() { self.history.get(index) @@ -5379,7 +5379,7 @@ impl App { /// Park a legacy pending steer. New keyboard handling routes running-turn /// drafts through Enter (same-turn steer) or Tab (next-turn follow-up). - #[allow(dead_code)] + #[allow(dead_code)] // App toggle method; public API (see #3490) pub fn push_pending_steer(&mut self, message: QueuedMessage) { self.pending_steers.push_back(message); self.submit_pending_steers_after_interrupt = true; @@ -5803,9 +5803,9 @@ pub fn media_attachment_reference(kind: &str, path: &Path, description: Option<& #[derive(Debug, Clone, PartialEq)] pub enum AppAction { Quit, - #[allow(dead_code)] // For explicit /save command + #[allow(dead_code)] // For explicit /save command (see #3490) SaveSession(PathBuf), - #[allow(dead_code)] // For explicit /load command + #[allow(dead_code)] // For explicit /load command (see #3490) LoadSession(PathBuf), SyncSession { session_id: Option, @@ -5835,6 +5835,9 @@ pub enum AppAction { OpenFleetSetup, /// Open the `/hotbar` setup wizard. OpenHotbarSetup, + /// Open the /setup summary wizard. + #[allow(dead_code)] // Reserved; will be wired to a keyboard shortcut or /setup command + OpenSetupSummary, /// Open an external URL in the system browser. OpenExternalUrl { url: String, diff --git a/crates/tui/src/tui/approval.rs b/crates/tui/src/tui/approval.rs index 26fe4df251..b6a24c918a 100644 --- a/crates/tui/src/tui/approval.rs +++ b/crates/tui/src/tui/approval.rs @@ -1429,7 +1429,7 @@ impl ElevationRequest { } /// Create a generic elevation request. - #[allow(dead_code)] + #[allow(dead_code)] // ElevationRequest generic constructor (see #3490) pub fn generic(tool_id: &str, tool_name: &str, denial_reason: &str) -> Self { Self { tool_id: tool_id.to_string(), @@ -1484,13 +1484,13 @@ impl ElevationView { } /// Get the request for rendering. - #[allow(dead_code)] + #[allow(dead_code)] // ElevationRequest request accessor (see #3490) pub fn request(&self) -> &ElevationRequest { &self.request } /// Get the currently selected index. - #[allow(dead_code)] + #[allow(dead_code)] // ElevationRequest selected accessor (see #3490) pub fn selected(&self) -> usize { self.selected } diff --git a/crates/tui/src/tui/backtrack.rs b/crates/tui/src/tui/backtrack.rs index 0bf9e60b0c..5cd5ea318b 100644 --- a/crates/tui/src/tui/backtrack.rs +++ b/crates/tui/src/tui/backtrack.rs @@ -85,7 +85,8 @@ impl BacktrackState { /// `true` whenever the user has armed or opened backtrack. The UI uses /// this to skip the prime hint once the overlay is up and to know /// whether arrow keys should drive selection. - #[allow(dead_code)] // helper exposed for future UI consumers + tests. + #[allow(dead_code)] + // helper exposed for future UI consumers + tests (see #3490) #[must_use] pub fn is_active(&self) -> bool { !matches!(self.phase, BacktrackPhase::Inactive) @@ -94,7 +95,8 @@ impl BacktrackState { /// `true` only when the overlay is open and Left/Right should step /// through prior user messages. `Primed` is intentionally excluded — /// during the prime window arrows still scroll the transcript. - #[allow(dead_code)] // helper exposed for future UI consumers + tests. + #[allow(dead_code)] + // helper exposed for future UI consumers + tests (see #3490) #[must_use] pub fn is_selecting(&self) -> bool { matches!(self.phase, BacktrackPhase::Selecting { .. }) diff --git a/crates/tui/src/tui/file_tree.rs b/crates/tui/src/tui/file_tree.rs index 34cd1486a8..8d1291eb58 100644 --- a/crates/tui/src/tui/file_tree.rs +++ b/crates/tui/src/tui/file_tree.rs @@ -177,7 +177,7 @@ impl FileTreeState { } /// Adjust scroll for a given visible height. - #[allow(dead_code)] + #[allow(dead_code)] // Scroll adjustment helper; used by file_picker (see #3490) pub fn adjust_scroll(&mut self, visible: usize) { if self.cursor < self.scroll_offset { self.scroll_offset = self.cursor; diff --git a/crates/tui/src/tui/history.rs b/crates/tui/src/tui/history.rs index af605a5f65..8600c21053 100644 --- a/crates/tui/src/tui/history.rs +++ b/crates/tui/src/tui/history.rs @@ -322,7 +322,7 @@ impl HistoryCell { } } - #[allow(dead_code)] + #[allow(dead_code)] // Rendered line helper; used by transcript (see #3490) pub(crate) fn lines_with_copy_metadata( &self, width: u16, diff --git a/crates/tui/src/tui/history/thinking.rs b/crates/tui/src/tui/history/thinking.rs index b14fddc773..0a16f87571 100644 --- a/crates/tui/src/tui/history/thinking.rs +++ b/crates/tui/src/tui/history/thinking.rs @@ -28,7 +28,7 @@ enum ThinkingVisualState { Idle, } -#[allow(dead_code)] // Kept for compatibility/tests; live view uses explicit summaries only. +#[allow(dead_code)] // Kept for compatibility/tests; live view uses explicit summaries only. (see #3490) #[must_use] pub fn extract_reasoning_summary(text: &str) -> Option { extract_explicit_reasoning_summary(text).or_else(|| { diff --git a/crates/tui/src/tui/hotbar/actions.rs b/crates/tui/src/tui/hotbar/actions.rs index 13b40673ad..5d1994006c 100644 --- a/crates/tui/src/tui/hotbar/actions.rs +++ b/crates/tui/src/tui/hotbar/actions.rs @@ -14,7 +14,7 @@ use crate::tui::command_palette::{ pub const HOTBAR_COMPACT_LABEL_MAX_WIDTH: usize = 7; /// Result of firing a hotbar action. -#[allow(dead_code)] +#[allow(dead_code)] // HotbarDispatch enum; public API (see #3490) #[derive(Debug, Clone, PartialEq)] pub enum HotbarDispatch { /// The action was fully handled by mutating [`App`]. @@ -24,7 +24,7 @@ pub enum HotbarDispatch { } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[allow(dead_code)] +#[allow(dead_code)] // HotbarActionCategory enum; public API (see #3490) pub enum HotbarActionCategory { App, Slash, @@ -46,7 +46,7 @@ impl HotbarActionCategory { } #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionCategory parse; public API (see #3490) pub fn parse(value: &str) -> Option { match value { "app" => Some(Self::App), @@ -80,7 +80,7 @@ impl HotbarArgsBehavior { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(dead_code)] +#[allow(dead_code)] // HotbarSafetyClass enum; public API (see #3490) pub enum HotbarSafetyClass { LocalUi, LocalState, @@ -98,7 +98,7 @@ pub enum HotbarRecommendation { impl HotbarRecommendation { #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // HotbarSafetyClass is_recommendable (see #3490) pub const fn is_recommendable(self) -> bool { matches!(self, Self::Default | Self::Eligible) } @@ -284,7 +284,7 @@ pub trait HotbarActionSource { } /// Uniform interface for actions that can be bound to a hotbar slot. -#[allow(dead_code)] +#[allow(dead_code)] // HotbarAction trait; public API (see #3490) pub trait HotbarAction: Send + Sync { /// Stable action id used in config and dispatch. fn id(&self) -> &str; @@ -364,7 +364,7 @@ pub fn recommend_hotbar_actions( } #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // recommended_hotbar_bindings; config setup (see #3490) pub fn recommended_hotbar_bindings( app: &App, options: HotbarRecommendationOptions, @@ -573,36 +573,36 @@ impl HotbarActionSource for SlashCommandHotbarActionSource { } impl HotbarActionRegistry { - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionRegistry get (see #3490) #[must_use] pub fn get(&self, id: &str) -> Option> { self.actions.get(id).cloned() } - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionRegistry len (see #3490) #[must_use] pub fn len(&self) -> usize { self.actions.len() } - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionRegistry is_empty (see #3490) #[must_use] pub fn is_empty(&self) -> bool { self.actions.is_empty() } - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionRegistry iter (see #3490) pub fn iter(&self) -> impl Iterator { self.actions.values().map(Arc::as_ref) } - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionRegistry metadata (see #3490) #[must_use] pub fn metadata(&self, locale: Locale) -> Vec { self.iter().map(|action| action.metadata(locale)).collect() } - #[allow(dead_code)] + #[allow(dead_code)] // HotbarActionRegistry metadata_validation_errors (see #3490) #[must_use] pub fn metadata_validation_errors(&self, locale: Locale) -> Vec { let mut errors = Vec::new(); @@ -656,7 +656,7 @@ enum AppHotbarKind { TrustToggle, } -#[allow(dead_code)] +#[allow(dead_code)] // AppHotbarAction struct; hotbar action impl (see #3490) struct AppHotbarAction { id: &'static str, short_label: &'static str, @@ -842,7 +842,7 @@ impl HotbarAction for AppHotbarAction { } } -#[allow(dead_code)] +#[allow(dead_code)] // SlashHotbarAction struct; hotbar action impl (see #3490) struct SlashHotbarAction { info: &'static CommandInfo, id: String, diff --git a/crates/tui/src/tui/live_transcript.rs b/crates/tui/src/tui/live_transcript.rs index 4136422bf0..9729d2d32e 100644 --- a/crates/tui/src/tui/live_transcript.rs +++ b/crates/tui/src/tui/live_transcript.rs @@ -133,7 +133,7 @@ impl LiveTranscriptOverlay { /// Return the overlay to live-tail mode (used when backtrack is /// confirmed or canceled). Re-arms sticky-tail so streaming resumes. - #[allow(dead_code)] // exposed for callers that retain an overlay across a backtrack cancel; current UI just pops the view. + #[allow(dead_code)] // exposed for callers that retain an overlay across a backtrack cancel; current UI just pops the view. (see #3490) pub fn set_tail_mode(&mut self) { self.mode = Mode::Tail; self.sticky_to_bottom.set(true); @@ -141,7 +141,8 @@ impl LiveTranscriptOverlay { } /// For tests + UI: current mode. - #[allow(dead_code)] // currently consumed only by tests; kept public for symmetry with `set_*` setters. + #[allow(dead_code)] + // currently consumed only by tests; kept public for symmetry (see #3490) #[must_use] pub fn mode(&self) -> Mode { self.mode diff --git a/crates/tui/src/tui/paste_burst.rs b/crates/tui/src/tui/paste_burst.rs index ef1fe24c24..c237a3df22 100644 --- a/crates/tui/src/tui/paste_burst.rs +++ b/crates/tui/src/tui/paste_burst.rs @@ -77,7 +77,7 @@ impl PasteBurst { CharDecision::RetainFirstChar } - #[allow(dead_code)] + #[allow(dead_code)] // PasteBurst no-hold handler; used when key repeat is disabled (see #3490) pub fn on_plain_char_no_hold(&mut self, now: Instant) -> Option { self.note_plain_char(now); @@ -177,7 +177,7 @@ impl PasteBurst { self.burst_window_until = Some(now + PASTE_ENTER_SUPPRESS_WINDOW); } - #[allow(dead_code)] + #[allow(dead_code)] // PasteBurst append helper; used when paste is accumulated (see #3490) pub fn try_append_char_if_active(&mut self, ch: char, now: Instant) -> bool { if self.active || !self.buffer.is_empty() { self.append_char_to_buffer(ch, now); diff --git a/crates/tui/src/tui/transcript.rs b/crates/tui/src/tui/transcript.rs index 68fa259ec2..73fcdbb56f 100644 --- a/crates/tui/src/tui/transcript.rs +++ b/crates/tui/src/tui/transcript.rs @@ -120,7 +120,7 @@ impl TranscriptViewCache { /// Retained for tests and external use; the live render path uses the /// `ensure_split` variant to avoid concatenating history + active-cell /// entries every frame. - #[allow(dead_code)] + #[allow(dead_code)] // Resume layout helper; used by HistoryCell rendering (see #3490) pub fn ensure( &mut self, cells: &[HistoryCell], diff --git a/crates/tui/src/tui/transcript_cache.rs b/crates/tui/src/tui/transcript_cache.rs index 6b4591fc44..94804c087b 100644 --- a/crates/tui/src/tui/transcript_cache.rs +++ b/crates/tui/src/tui/transcript_cache.rs @@ -111,7 +111,7 @@ impl TranscriptCache { /// Drop every cached entry. Used when the underlying transcript shape /// changes drastically (e.g. session reset). - #[allow(dead_code)] // Reserved for /clear and session-reset call sites. + #[allow(dead_code)] // Reserved for /clear and session-reset call sites. (see #3490) pub fn clear(&mut self) { self.entries.clear(); self.insertion_order.clear(); diff --git a/crates/tui/src/tui/translation.rs b/crates/tui/src/tui/translation.rs index cf37cfe8eb..53886d8684 100644 --- a/crates/tui/src/tui/translation.rs +++ b/crates/tui/src/tui/translation.rs @@ -102,7 +102,7 @@ pub async fn translate_text( /// Status of a translation operation for a single message. #[derive(Debug, Clone, PartialEq, Eq)] -#[allow(dead_code)] +#[allow(dead_code)] // Translation status enum; reserved for follow-up integration (see #3490) pub enum TranslationStatus { /// No translation needed (already Chinese or not enough text). NotNeeded, diff --git a/crates/tui/src/tui/ui.rs b/crates/tui/src/tui/ui.rs index 99c61681ee..94f91a9581 100644 --- a/crates/tui/src/tui/ui.rs +++ b/crates/tui/src/tui/ui.rs @@ -7397,6 +7397,14 @@ async fn apply_command_result( .push(crate::tui::hotbar::setup::HotbarSetupView::new(app, config)); } } + AppAction::OpenSetupSummary => { + if app.view_stack.top_kind() != Some(ModalKind::SetupSummary) { + app.view_stack + .push(crate::tui::views::setup_summary::SetupSummaryView::new( + config, + )); + } + } AppAction::OpenExternalUrl { url, label } => match open_external_url(&url) { Ok(()) => { app.status_message = Some(format!("Opened {label} in your browser")); @@ -8677,13 +8685,21 @@ fn render(f: &mut Frame, app: &mut App, config: &Config) { content_width, budget, ); - let visible_lines = if input_text.is_empty() { - 1 + let visual_rows = if input_text.is_empty() { + let hint: Option> = if let Some(ref suggestion) = + app.prompt_suggestion + && !app.is_history_search_active() + { + Some(std::borrow::Cow::Borrowed(suggestion.as_str())) + } else { + Some(crate::tui::widgets::composer_empty_hint_text(app)) + }; + crate::tui::widgets::empty_composer_visual_rows(hint.as_deref(), content_width, budget) } else { // Count wrapped lines (approximation matching the render path). crate::tui::widgets::wrap_input_lines_for_mouse(input_text, content_width).len() }; - let top_padding = budget.saturating_sub(visible_lines.clamp(1, budget)); + let top_padding = budget.saturating_sub(visual_rows.clamp(1, budget)); app.viewport.last_composer_scroll_offset = scroll_offset; app.viewport.last_composer_top_padding = top_padding; } @@ -10317,7 +10333,7 @@ pub(crate) fn terminal_pause_has_live_owner(app: &App) -> bool { }) } -#[allow(dead_code)] +#[allow(dead_code)] // Transcript scroll percentage; reserved for status bar integration (see #3490) fn transcript_scroll_percent(top: usize, visible: usize, total: usize) -> Option { if total <= visible { return None; @@ -10436,7 +10452,7 @@ pub(crate) fn context_usage_snapshot(app: &App) -> Option<(i64, u32, f64)> { /// it directly (#115 makes the estimate the primary signal), but tests in /// `ui/tests.rs` still exercise it and a future heuristic may want to /// distinguish "obviously inflated reported tokens" from healthy reports. -#[allow(dead_code)] +#[allow(dead_code)] // Token inflation detection helper; reserved for diagnostic overlay (see #3490) fn is_reported_context_inflated(reported: i64, estimated: i64) -> bool { const MIN_ABSOLUTE_GAP: i64 = 4_096; if estimated <= 0 || reported <= estimated { diff --git a/crates/tui/src/tui/views/mod.rs b/crates/tui/src/tui/views/mod.rs index ec6df833c9..2ec57156d4 100644 --- a/crates/tui/src/tui/views/mod.rs +++ b/crates/tui/src/tui/views/mod.rs @@ -18,6 +18,7 @@ use crate::tui::widgets::agent_card::AgentLifecycle; pub mod fleet_setup; pub mod mode_picker; +pub mod setup_summary; pub mod status_picker; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -43,6 +44,7 @@ pub enum ModalKind { FeedbackPicker, ThemePicker, ContextMenu, + SetupSummary, } #[derive(Debug, Clone)] diff --git a/crates/tui/src/tui/views/setup_summary.rs b/crates/tui/src/tui/views/setup_summary.rs new file mode 100644 index 0000000000..41b8e7917c --- /dev/null +++ b/crates/tui/src/tui/views/setup_summary.rs @@ -0,0 +1,355 @@ +//! Setup summary step for the configuration wizard. +//! +//! Displays configured MCP servers, skills, and plugin state +//! as a read-only overview before offering safe bootstrap paths. +//! +//! Related: #3407 + +use crossterm::event::{KeyCode, KeyEvent}; +use ratatui::{ + buffer::Buffer, + layout::Rect, + style::{Modifier, Style}, + text::{Line, Span}, + widgets::{Block, Borders, Clear, Padding, Paragraph, Widget}, +}; + +use crate::palette; +use crate::tui::views::{ModalKind, ModalView, ViewAction}; + +#[derive(Debug, Clone)] +pub struct SetupSummaryData { + pub mcp_servers: Vec, + pub mcp_config_path: Option, + pub skills_dirs: Vec, + pub skills_installed: usize, + pub plugin_dir: Option, + pub plugin_available: bool, +} + +#[derive(Debug, Clone)] +pub struct McpServerInfo { + pub name: String, + pub enabled: bool, + pub state: String, +} + +pub struct SetupSummaryView { + data: SetupSummaryData, + scroll: u16, +} + +impl SetupSummaryView { + #[must_use] + pub fn new(config: &Config) -> Self { + let data = Self::collect(config); + Self { data, scroll: 0 } + } + + fn collect(config: &Config) -> SetupSummaryData { + let mcp_path = config.mcp_config_path(); + let mcp_config_path = Some(mcp_path.to_string_lossy().to_string()); + let mcp_servers = if mcp_path.exists() { + crate::mcp::load_config(&mcp_path) + .ok() + .map(|cfg| { + cfg.servers.iter().map(|(name, svr)| { + let state = if svr.is_enabled() { "enabled" } else { "disabled" }; + McpServerInfo { + name: name.clone(), + enabled: svr.is_enabled(), + state: state.to_string(), + } + }).collect::>() + }) + .unwrap_or_default() + } else { + vec![] + }; + + let skills_dir = crate::skills::default_skills_dir(); + let skills_dirs = vec![skills_dir.to_string_lossy().to_string()]; + let skills_installed = if skills_dir.exists() { + crate::skills::SkillRegistry::discover(&skills_dir).len() + } else { + 0 + }; + + SetupSummaryData { + mcp_servers, + mcp_config_path, + skills_dirs, + skills_installed, + plugin_dir: None, + plugin_available: false, + } + } + }).collect::>() + }) + .unwrap_or_default() + })) + .unwrap_or_default(); + + let skills_dir = crate::skills::default_skills_dir(); + let skills_dirs = vec![skills_dir.to_string_lossy().to_string()]; + let skills_installed = if skills_dir.exists() { + crate::skills::SkillRegistry::discover(&skills_dir).len() + } else { + 0 + }; + + SetupSummaryData { + mcp_servers, + mcp_config_path: config.mcp_config_path(), + skills_dirs, + skills_installed, + plugin_dir: app.plugin_dir.as_ref().map(|p| p.to_string_lossy().to_string()), + plugin_available: app.plugin_dir.as_ref().is_some_and(|d| d.exists()), + } + } +} + +impl ModalView for SetupSummaryView { + fn kind(&self) -> ModalKind { + ModalKind::SetupSummary + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + + fn handle_key(&mut self, key: KeyEvent) -> ViewAction { + match key.code { + KeyCode::Esc => ViewAction::Close, + KeyCode::Char('q') => ViewAction::Close, + KeyCode::Up | KeyCode::Char('k') => { + self.scroll = self.scroll.saturating_sub(1); + ViewAction::None + } + KeyCode::Down | KeyCode::Char('j') => { + self.scroll = self.scroll.saturating_add(1); + ViewAction::None + } + _ => ViewAction::None, + } + } + + fn render(&self, area: Rect, buf: &mut Buffer) { + let popup_width = 80.min(area.width.saturating_sub(4)).max(50); + let popup_height = area.height.saturating_sub(2); + let popup_area = Rect { + x: area.x + (area.width.saturating_sub(popup_width)) / 2, + y: area.y + 1, + width: popup_width, + height: popup_height, + }; + + Clear.render(popup_area, buf); + + let block = Block::default() + .title(Line::from(Span::styled( + " Setup Summary ", + Style::default() + .fg(palette::DEEPSEEK_SKY) + .add_modifier(Modifier::BOLD), + ))) + .title_bottom(Line::from(vec![ + Span::styled(" Up/Down ", Style::default().fg(palette::TEXT_MUTED)), + Span::raw("scroll "), + Span::styled(" Esc/q ", Style::default().fg(palette::TEXT_MUTED)), + Span::raw("close"), + ])) + .borders(Borders::ALL) + .border_style(Style::default().fg(palette::BORDER_COLOR)) + .style(Style::default().bg(palette::DEEPSEEK_INK)) + .padding(Padding::uniform(1)); + + let inner = block.inner(popup_area); + block.render(popup_area, buf); + + let mut lines: Vec = Vec::new(); + + // Section: MCP + lines.push(Line::from(Span::styled( + " MCP Servers ", + Style::default() + .fg(palette::ACCENT_PRIMARY) + .add_modifier(Modifier::BOLD), + ))); + lines.push(Line::from(Span::styled( + format!( + " Config: {}", + self.data.mcp_config_path.as_deref().unwrap_or("not found") + ), + Style::default().fg(palette::TEXT_MUTED), + ))); + + if self.data.mcp_servers.is_empty() { + lines.push(Line::from(Span::styled( + " No MCP servers configured.", + Style::default().fg(palette::TEXT_MUTED), + ))); + } else { + for server in &self.data.mcp_servers { + let status = if server.enabled { + "enabled" + } else { + "disabled" + }; + lines.push(Line::from(vec![ + Span::styled( + format!( + " {} ", + if server.enabled { + "\u{25cf}" + } else { + "\u{25cb}" + } + ), + if server.enabled { + Style::default().fg(palette::SURFACE_SUCCESS) + } else { + Style::default().fg(palette::TEXT_MUTED) + }, + ), + Span::styled(&server.name, Style::default().fg(palette::TEXT_PRIMARY)), + Span::raw(" "), + Span::styled( + format!("[{status}]"), + Style::default().fg(palette::TEXT_MUTED), + ), + Span::raw(" "), + Span::styled( + format!("({})", server.state), + Style::default().fg(palette::TEXT_MUTED), + ), + ])); + } + } + + lines.push(Line::from(Span::raw(""))); + lines.push(Line::from(Span::styled( + " Skills ", + Style::default() + .fg(palette::ACCENT_PRIMARY) + .add_modifier(Modifier::BOLD), + ))); + if self.data.skills_dirs.is_empty() { + lines.push(Line::from(Span::styled( + " No skills directories configured.", + Style::default().fg(palette::TEXT_MUTED), + ))); + } else { + for dir in &self.data.skills_dirs { + lines.push(Line::from(vec![ + Span::styled(" Dir: ", Style::default().fg(palette::TEXT_MUTED)), + Span::styled(dir, Style::default().fg(palette::TEXT_PRIMARY)), + ])); + } + lines.push(Line::from(vec![ + Span::styled(" Installed: ", Style::default().fg(palette::TEXT_MUTED)), + Span::styled( + self.data.skills_installed.to_string(), + Style::default().fg(palette::TEXT_PRIMARY), + ), + ])); + } + + lines.push(Line::from(Span::raw(""))); + lines.push(Line::from(Span::styled( + " Plugins ", + Style::default() + .fg(palette::ACCENT_PRIMARY) + .add_modifier(Modifier::BOLD), + ))); + match &self.data.plugin_dir { + Some(dir) => { + lines.push(Line::from(vec![ + Span::styled(" Dir: ", Style::default().fg(palette::TEXT_MUTED)), + Span::styled(dir, Style::default().fg(palette::TEXT_PRIMARY)), + ])); + if self.data.plugin_available { + lines.push(Line::from(Span::styled( + " Plugins directory exists", + Style::default().fg(palette::SURFACE_SUCCESS), + ))); + } else { + lines.push(Line::from(Span::styled( + " Plugins directory not found", + Style::default().fg(palette::SURFACE_ERROR), + ))); + } + } + None => { + lines.push(Line::from(Span::styled( + " Plugin support not configured.", + Style::default().fg(palette::TEXT_MUTED), + ))); + } + } + + let paragraph = Paragraph::new(lines).scroll((self.scroll, 0)); + paragraph.render(inner, buf); + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_setup_summary() { + let data = SetupSummaryData { + mcp_servers: vec![], + mcp_config_path: None, + skills_dirs: vec![], + skills_installed: 0, + plugin_dir: None, + plugin_available: false, + }; + assert!(data.mcp_servers.is_empty()); + assert_eq!(data.skills_installed, 0); + assert!(!data.plugin_available); + } + + #[test] + fn mcp_server_info_construction() { + let info = McpServerInfo { + name: "test-server".into(), + enabled: true, + state: "connected".into(), + }; + assert_eq!(info.name, "test-server"); + assert!(info.enabled); + assert_eq!(info.state, "connected"); + } + + #[test] + fn mcp_server_disabled() { + let info = McpServerInfo { + name: "disabled-server".into(), + enabled: false, + state: "disconnected".into(), + }; + assert!(!info.enabled); + } + + #[test] + fn setup_summary_data_with_mcp() { + let data = SetupSummaryData { + mcp_servers: vec![ + McpServerInfo { name: "srv-a".into(), enabled: true, state: "connected".into() }, + McpServerInfo { name: "srv-b".into(), enabled: false, state: "disconnected".into() }, + ], + mcp_config_path: Some("/tmp/mcp.json".into()), + skills_dirs: vec!["/tmp/skills".into()], + skills_installed: 5, + plugin_dir: Some("/tmp/plugins".into()), + plugin_available: true, + }; + assert_eq!(data.mcp_servers.len(), 2); + assert_eq!(data.skills_installed, 5); + assert!(data.plugin_available); + } +} diff --git a/crates/tui/src/tui/whale_routes.rs b/crates/tui/src/tui/whale_routes.rs index 9e8256cae5..ea231d5c32 100644 --- a/crates/tui/src/tui/whale_routes.rs +++ b/crates/tui/src/tui/whale_routes.rs @@ -95,7 +95,7 @@ impl WhaleRoute { /// Look up the whale route for a given model id and reasoning effort. /// Returns `None` for non-DeepSeek models or unrecognized combinations. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // WhaleRoute lookup by model+effort; used by dynamic routing tests (see #3490) pub fn for_model_effort(model: &str, effort: ReasoningEffort) -> Option<&'static WhaleRoute> { WHALE_ROUTES .iter() @@ -104,7 +104,7 @@ impl WhaleRoute { /// Look up a whale route by its sort-order index. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // WhaleRoute lookup by sort order; used by config-driven routing (see #3490) pub fn by_sort_order(index: usize) -> Option<&'static WhaleRoute> { WHALE_ROUTES.iter().find(|r| r.sort_order == index) } diff --git a/crates/tui/src/tui/widgets/agent_card.rs b/crates/tui/src/tui/widgets/agent_card.rs index 125fb7e824..f395a225ac 100644 --- a/crates/tui/src/tui/widgets/agent_card.rs +++ b/crates/tui/src/tui/widgets/agent_card.rs @@ -216,7 +216,7 @@ impl FanoutCard { } /// Pre-seed worker slots when the fanout size is known up front. - #[allow(dead_code)] + #[allow(dead_code)] // Worker pre-seed builder; used by views (see #3490) pub fn with_workers(mut self, ids: I) -> Self where I: IntoIterator, diff --git a/crates/tui/src/tui/widgets/mod.rs b/crates/tui/src/tui/widgets/mod.rs index 2cdd204eac..4c5999a610 100644 --- a/crates/tui/src/tui/widgets/mod.rs +++ b/crates/tui/src/tui/widgets/mod.rs @@ -4,6 +4,7 @@ mod header; // public surface for issue #93's help overlay and future call sites; allow // dead code rather than scattering `#[allow]` across every constructor. #[allow(dead_code)] +// Phase 1 of #85: widget lands without wire-up site; follow-up plumbs it (see #3490) pub mod key_hint; // Phase 1 of #85: widget lands without a wire-up site so reviewers can // evaluate the rendering in isolation. The follow-up PR plumbs it through @@ -774,25 +775,23 @@ impl Renderable for ComposerWidget<'_> { let mut input_lines = Vec::new(); if input_text.is_empty() { - if let Some(ref suggestion) = self.app.prompt_suggestion - && !self.app.is_history_search_active() - { - input_lines.push(Line::from(Span::styled( - suggestion.as_str(), - Style::default().fg(palette::TEXT_HINT), - ))); - } else { - let placeholder = if self.app.is_history_search_active() { - self.app - .tr(crate::localization::MessageId::HistorySearchPlaceholder) + input_lines.push(Line::from("")); + if input_rows_budget > 1 { + let (placeholder, style): (Cow<'_, str>, Style) = if let Some(ref suggestion) = + self.app.prompt_suggestion + && !self.app.is_history_search_active() + { + ( + Cow::Borrowed(suggestion.as_str()), + Style::default().fg(palette::TEXT_HINT), + ) } else { - self.app - .tr(crate::localization::MessageId::ComposerPlaceholder) + ( + composer_empty_hint_text(self.app), + Style::default().fg(palette::TEXT_MUTED).italic(), + ) }; - input_lines.push(Line::from(Span::styled( - placeholder, - Style::default().fg(palette::TEXT_MUTED).italic(), - ))); + input_lines.push(Line::from(Span::styled(placeholder, style))); } } else if let Some((sel_start, sel_end)) = self.app.selection_range() { let line_ranges: Vec<(usize, usize)> = @@ -824,22 +823,18 @@ impl Renderable for ComposerWidget<'_> { } // For non-empty input, input_lines.len() already reflects wrapping via - // layout_input. For the empty-input placeholder, Paragraph::wrap will - // wrap the single Line at render time, so we must estimate the wrapped - // row count ourselves to keep padding accurate on narrow widths. + // layout_input. For empty input, keep the first row reserved for the + // real terminal cursor so IME preedit text has a clean surface. let visual_rows = if input_text.is_empty() { - let placeholder: &str = if let Some(ref suggestion) = self.app.prompt_suggestion { - suggestion.as_str() - } else if self.app.is_history_search_active() { - &self - .app - .tr(crate::localization::MessageId::HistorySearchPlaceholder) + let hint: Option> = if let Some(ref suggestion) = + self.app.prompt_suggestion + && !self.app.is_history_search_active() + { + Some(Cow::Borrowed(suggestion.as_str())) } else { - &self - .app - .tr(crate::localization::MessageId::ComposerPlaceholder) + Some(composer_empty_hint_text(self.app)) }; - placeholder_visual_lines_for(placeholder, content_width) + empty_composer_visual_rows(hint.as_deref(), content_width, input_rows_budget) } else { input_lines.len() }; @@ -1137,18 +1132,15 @@ impl Renderable for ComposerWidget<'_> { let (visible_lines, cursor_row, cursor_col) = layout_input(input_text, input_cursor, content_width, input_rows_budget); let visual_rows = if input_text.is_empty() { - let placeholder: &str = if let Some(ref suggestion) = self.app.prompt_suggestion { - suggestion.as_str() - } else if self.app.is_history_search_active() { - &self - .app - .tr(crate::localization::MessageId::HistorySearchPlaceholder) + let hint: Option> = if let Some(ref suggestion) = + self.app.prompt_suggestion + && !self.app.is_history_search_active() + { + Some(Cow::Borrowed(suggestion.as_str())) } else { - &self - .app - .tr(crate::localization::MessageId::ComposerPlaceholder) + Some(composer_empty_hint_text(self.app)) }; - placeholder_visual_lines_for(placeholder, content_width) + empty_composer_visual_rows(hint.as_deref(), content_width, input_rows_budget) } else { visible_lines.len() }; @@ -2425,6 +2417,28 @@ fn placeholder_visual_lines_for(placeholder: &str, content_width: usize) -> usiz wrap_text(placeholder, content_width).len().max(1) } +pub(crate) fn composer_empty_hint_text(app: &App) -> Cow<'static, str> { + if app.is_history_search_active() { + app.tr(crate::localization::MessageId::HistorySearchPlaceholder) + } else { + app.tr(crate::localization::MessageId::ComposerPlaceholder) + } +} + +pub(crate) fn empty_composer_visual_rows( + hint: Option<&str>, + content_width: usize, + rows_budget: usize, +) -> usize { + if rows_budget <= 1 { + 1 + } else { + 1 + hint + .map(|text| placeholder_visual_lines_for(text, content_width)) + .unwrap_or(0) + } +} + fn composer_min_input_rows(density: ComposerDensity) -> usize { match density { ComposerDensity::Compact => 2, @@ -3179,12 +3193,13 @@ fn line_spans_with_selection<'a>( #[cfg(test)] mod tests { use super::{ - ApprovalWidget, COMPOSER_PANEL_HEIGHT, ChatWidget, ComposerWidget, Renderable, - SlashMenuEntry, apply_detail_target_highlight, apply_selection_to_line, apply_send_flash, - build_empty_state_lines, composer_height, composer_max_height, composer_min_input_rows, - composer_top_padding, compute_takeover_area, cursor_row_col, layout_input, - pad_lines_to_bottom, placeholder_visual_lines, push_command_entry, - should_render_empty_state, slash_completion_hints, wrap_input_lines, wrap_text, + ApprovalWidget, COMPOSER_PANEL_HEIGHT, COMPOSER_PLACEHOLDER, ChatWidget, ComposerWidget, + Renderable, SlashMenuEntry, apply_detail_target_highlight, apply_selection_to_line, + apply_send_flash, build_empty_state_lines, composer_height, composer_max_height, + composer_min_input_rows, composer_top_padding, compute_takeover_area, cursor_row_col, + empty_composer_visual_rows, layout_input, pad_lines_to_bottom, placeholder_visual_lines, + push_command_entry, should_render_empty_state, slash_completion_hints, wrap_input_lines, + wrap_text, }; use crate::config::{ApiProvider, Config}; use crate::localization::Locale; @@ -3241,6 +3256,14 @@ mod tests { text } + fn row_text(buf: &Buffer, area: Rect, row: u16) -> String { + let mut text = String::new(); + for x in area.x..area.x.saturating_add(area.width) { + text.push_str(buf[(x, row)].symbol()); + } + text + } + fn success_tool_cell(name: &str) -> HistoryCell { HistoryCell::Tool(ToolCell::Generic(GenericToolCell { name: name.to_string(), @@ -4045,7 +4068,7 @@ mod tests { } #[test] - fn empty_composer_cursor_matches_placeholder_padding() { + fn empty_composer_cursor_sits_above_placeholder_hint() { let mut app = create_test_app(); // Pin density so the test is independent of any loaded user settings. app.composer_density = ComposerDensity::Comfortable; @@ -4063,15 +4086,19 @@ mod tests { // inner_area: {x:1, y:1, w:38, h:3} (borders shrink by 1 each side) // input_rows_budget = 3 - // placeholder_visual_lines(38) = 1 (placeholder is 22 chars, fits in 38) - // top_padding = 3 - clamp(1, 1, 3) = 2 + // empty_composer_visual_rows = cursor row + one hint row = 2 + // top_padding = 3 - clamp(2, 1, 3) = 1 // cursor_x = 0 + (1-0) + 0 = 1 - // cursor_y = 0 + (1-0) + (2+0) = 3 - assert_eq!(widget.cursor_pos(area), Some((1, 3))); + // cursor_y = 0 + (1-0) + (1+0) = 2 + assert_eq!( + empty_composer_visual_rows(Some(COMPOSER_PLACEHOLDER), 38, 3), + 2 + ); + assert_eq!(widget.cursor_pos(area), Some((1, 2))); } #[test] - fn empty_composer_cursor_accounts_for_placeholder_wrapping() { + fn empty_composer_cursor_accounts_for_wrapped_placeholder_hint() { let mut app = create_test_app(); app.composer_density = ComposerDensity::Comfortable; let slash_menu_entries = Vec::::new(); @@ -4089,11 +4116,48 @@ mod tests { // inner_area: {x:1, y:1, w:12, h:3} // input_rows_budget = 3 // placeholder_visual_lines(12) = 2 ("Write a task" / " or use /.") - // top_padding = 3 - clamp(2, 1, 3) = 1 + // empty_composer_visual_rows = cursor row + two hint rows = 3 + // top_padding = 3 - clamp(3, 1, 3) = 0 // cursor_x = 0 + (1-0) + 0 = 1 - // cursor_y = 0 + (1-0) + (1+0) = 2 + // cursor_y = 0 + (1-0) + (0+0) = 1 assert_eq!(placeholder_visual_lines(12), 2); - assert_eq!(widget.cursor_pos(area), Some((1, 2))); + assert_eq!( + empty_composer_visual_rows(Some(COMPOSER_PLACEHOLDER), 12, 3), + 3 + ); + assert_eq!(widget.cursor_pos(area), Some((1, 1))); + } + + #[test] + fn empty_composer_keeps_cursor_row_clear_for_ime_preedit() { + let mut app = create_test_app(); + app.composer_density = ComposerDensity::Comfortable; + let slash_menu_entries = Vec::::new(); + let mention_menu_entries = Vec::::new(); + let widget = ComposerWidget::new(&app, 5, &slash_menu_entries, &mention_menu_entries); + let area = Rect { + x: 0, + y: 0, + width: 40, + height: 5, + }; + let mut buf = Buffer::empty(area); + + widget.render(area, &mut buf); + let Some((cursor_x, cursor_y)) = widget.cursor_pos(area) else { + panic!("empty composer should expose cursor position"); + }; + let rendered = buffer_text(&buf, area); + + assert_eq!(buf[(cursor_x, cursor_y)].symbol(), " "); + assert!( + rendered.contains(COMPOSER_PLACEHOLDER), + "placeholder hint should still render below the cursor row: {rendered}" + ); + assert!( + !row_text(&buf, area, cursor_y).contains(COMPOSER_PLACEHOLDER), + "cursor row must remain clear for terminal IME preedit text: {rendered}" + ); } #[test] @@ -4257,7 +4321,7 @@ mod tests { height: 3, }; - assert_eq!(widget.cursor_pos(area), Some((0, 2))); + assert_eq!(widget.cursor_pos(area), Some((0, 1))); } #[test] diff --git a/crates/tui/src/tui/widgets/tool_card.rs b/crates/tui/src/tui/widgets/tool_card.rs index e51eaa0c2b..a388c91a28 100644 --- a/crates/tui/src/tui/widgets/tool_card.rs +++ b/crates/tui/src/tui/widgets/tool_card.rs @@ -49,7 +49,7 @@ pub enum ToolFamily { /// render path (`render_thinking` in `history.rs`); the family is /// declared here for completeness so any future code that reaches for /// it has the matching glyph + label vocabulary. - #[allow(dead_code)] + #[allow(dead_code)] // ToolActionResult Think variant (see #3490) Think, /// Anything we don't have a family glyph for yet — falls back to a /// neutral bullet so the card still renders cleanly. @@ -299,7 +299,7 @@ pub fn family_label(family: ToolFamily) -> &'static str { /// Position of a line within a multi-line card — drives the left-rail /// glyph so the box reads as a contiguous group from top to bottom. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(dead_code)] // wired by future card-refactor follow-ups +#[allow(dead_code)] // wired by future card-refactor follow-ups (see #3490) pub enum CardRail { /// First line of the card — the header. `╭`. Top, @@ -314,7 +314,7 @@ pub enum CardRail { /// Map a [`CardRail`] position to its rail glyph. Returned as a `&str` /// because callers paste it into a span. #[must_use] -#[allow(dead_code)] // wired by future card-refactor follow-ups +#[allow(dead_code)] // wired by future card-refactor follow-ups (see #3490) pub fn rail_glyph(rail: CardRail) -> &'static str { match rail { CardRail::Top => "\u{256D}", // ╭ diff --git a/crates/tui/src/utils.rs b/crates/tui/src/utils.rs index 0e620408e1..35505d396f 100644 --- a/crates/tui/src/utils.rs +++ b/crates/tui/src/utils.rs @@ -420,7 +420,7 @@ where }) } -#[allow(dead_code)] +#[allow(dead_code)] // ensure_dir utility; used by CLI initialization paths (see #3490) pub fn ensure_dir(path: &Path) -> Result<()> { fs::create_dir_all(path) .with_context(|| format!("Failed to create directory: {}", path.display())) @@ -428,7 +428,7 @@ pub fn ensure_dir(path: &Path) -> Result<()> { /// Render JSON with pretty formatting, falling back to a compact string on error. #[must_use] -#[allow(dead_code)] +#[allow(dead_code)] // pretty_json utility; used by debug/logging commands (see #3490) pub fn pretty_json(value: &Value) -> String { serde_json::to_string_pretty(value).unwrap_or_else(|_| value.to_string()) } diff --git a/crates/tui/src/working_set.rs b/crates/tui/src/working_set.rs index dcdf8f7ebe..63b1bbd09d 100644 --- a/crates/tui/src/working_set.rs +++ b/crates/tui/src/working_set.rs @@ -71,7 +71,7 @@ impl Workspace { /// the secondary resolution pass. Convenience entry point intended for /// callers that don't already have a CWD on hand; the App routes through /// [`Workspace::with_cwd`] with its own captured launch directory. - #[allow(dead_code)] // Keeps the surface stable for #97 (Ctrl+P picker). + #[allow(dead_code)] // Keeps the surface stable for #97 (Ctrl+P picker). (see #3490) pub fn new(root: PathBuf) -> Self { Self::with_cwd(root, std::env::current_dir().ok()) } diff --git a/crates/tui/src/workspace_trust.rs b/crates/tui/src/workspace_trust.rs index 9cc4a2b15b..e07673098f 100644 --- a/crates/tui/src/workspace_trust.rs +++ b/crates/tui/src/workspace_trust.rs @@ -40,7 +40,7 @@ pub struct WorkspaceTrust { impl WorkspaceTrust { #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // WorkspaceTrust empty constructor; used in test helpers (see #3490) pub fn empty() -> Self { Self { paths: Vec::new() } } @@ -80,7 +80,7 @@ impl WorkspaceTrust { /// normalization) starts with one of the trusted prefixes. Directory /// trust grants access to anything under the directory. #[must_use] - #[allow(dead_code)] + #[allow(dead_code)] // WorkspaceTrust permits check; used in runtime access control (see #3490) pub fn permits(&self, candidate: &Path) -> bool { let canonical = candidate .canonicalize()