From ecad06f6d62a2c589722b7bc7c062562c39ed780 Mon Sep 17 00:00:00 2001 From: albertoelopez Date: Wed, 10 Jun 2026 21:15:59 -0700 Subject: [PATCH] chore: satisfy workspace clippy gate --- rust/crates/runtime/src/policy_engine.rs | 2 +- rust/crates/runtime/src/trident.rs | 37 +++--------- rust/crates/rusty-claude-cli/src/main.rs | 59 +++++++++---------- .../tests/output_format_contract.rs | 20 +++---- 4 files changed, 47 insertions(+), 71 deletions(-) diff --git a/rust/crates/runtime/src/policy_engine.rs b/rust/crates/runtime/src/policy_engine.rs index 34343766..aa19f0ec 100644 --- a/rust/crates/runtime/src/policy_engine.rs +++ b/rust/crates/runtime/src/policy_engine.rs @@ -731,7 +731,7 @@ mod tests { } #[test] - #[allow(clippy::duration_suboptimal_units, clippy::too_many_lines)] + #[allow(clippy::too_many_lines)] fn executable_decision_table_emits_retry_rebase_merge_escalate_cleanup_and_approval_events() { let engine = PolicyEngine::new(vec![ PolicyRule::new( diff --git a/rust/crates/runtime/src/trident.rs b/rust/crates/runtime/src/trident.rs index 2346a4ea..22a0ab9b 100644 --- a/rust/crates/runtime/src/trident.rs +++ b/rust/crates/runtime/src/trident.rs @@ -29,7 +29,7 @@ impl Default for TridentConfig { } /// Statistics from a Trident compaction run. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct TridentStats { pub superseded_count: usize, pub collapsed_chains: usize, @@ -41,21 +41,6 @@ pub struct TridentStats { pub final_message_count: usize, } -impl Default for TridentStats { - fn default() -> Self { - Self { - superseded_count: 0, - collapsed_chains: 0, - messages_collapsed: 0, - clusters_found: 0, - messages_clustered: 0, - tokens_saved_estimate: 0, - original_message_count: 0, - final_message_count: 0, - } - } -} - impl TridentStats { pub fn format_report(&self) -> String { let compression = if self.final_message_count > 0 { @@ -192,7 +177,7 @@ fn stage1_supersede(messages: &[ConversationMessage]) -> (Vec = BTreeSet::new(); - for (_path, ops) in &file_ops { + for ops in file_ops.values() { if ops.len() < 2 { continue; } @@ -205,11 +190,7 @@ fn stage1_supersede(messages: &[ConversationMessage]) -> (Vec = Vec::new(); let mut cluster_buffers: BTreeMap> = BTreeMap::new(); @@ -677,7 +658,7 @@ fn truncate_text(text: &str, max_chars: usize) -> String { mod tests { use super::*; use crate::compact::CompactionConfig; - use crate::session::{ContentBlock, ConversationMessage, MessageRole, Session}; + use crate::session::{ContentBlock, ConversationMessage, Session}; #[test] fn stage1_removes_obsolete_file_reads() { @@ -736,7 +717,7 @@ mod tests { fn stage2_collapses_chatty_messages() { let mut messages = vec![]; for i in 0..6 { - messages.push(ConversationMessage::user_text(&format!("ok {i}"))); + messages.push(ConversationMessage::user_text(format!("ok {i}"))); messages.push(ConversationMessage::assistant(vec![ContentBlock::Text { text: format!("got {i}"), }])); @@ -767,9 +748,9 @@ mod tests { }, ])); messages.push(ConversationMessage::tool_result( - &format!("read_{i}"), + format!("read_{i}"), "read_file", - &format!(r#"{{"path":"src/{i}.rs","content":"data {i}"}}"#), + format!(r#"{{"path":"src/{i}.rs","content":"data {i}"}}"#), false, )); } diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 665ce632..c961baeb 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -3452,11 +3452,7 @@ impl DiagnosticCheck { fn json_value(&self) -> Value { // Derive a stable snake_case id from the check name for machine-readable keying (#704). - let id = self - .name - .to_ascii_lowercase() - .replace(' ', "_") - .replace('-', "_"); + let id = self.name.to_ascii_lowercase().replace([' ', '-'], "_"); let mut value = Map::from_iter([ ("id".to_string(), Value::String(id.clone())), ( @@ -6730,16 +6726,15 @@ fn run_resume_command( } SlashCommand::Plugins { action, target } => { // Only list is supported in resume mode (no runtime to reload) - match action.as_deref() { - Some(action @ ("install" | "uninstall" | "enable" | "disable" | "update")) => { - // #777: use interactive_only: prefix + \n hint so #776's classify/split - // emits error_kind:interactive_only + non-null hint instead of unknown+null. - // Orchestrators can now detect this and switch to a live REPL instead of retrying. - return Err(format!( - "interactive_only: /plugins {action} requires a live session to reload the plugin runtime.\nStart `claw` and run `/plugins {action}` inside the REPL, or use `claw plugins {action}` as a direct CLI command." - ).into()); - } - _ => {} + if let Some(action @ ("install" | "uninstall" | "enable" | "disable" | "update")) = + action.as_deref() + { + // #777: use interactive_only: prefix + \n hint so #776's classify/split + // emits error_kind:interactive_only + non-null hint instead of unknown+null. + // Orchestrators can now detect this and switch to a live REPL instead of retrying. + return Err(format!( + "interactive_only: /plugins {action} requires a live session to reload the plugin runtime.\nStart `claw` and run `/plugins {action}` inside the REPL, or use `claw plugins {action}` as a direct CLI command." + ).into()); } let cwd = env::current_dir()?; let payload = plugins_command_payload_for( @@ -7852,8 +7847,12 @@ impl LiveCli { let max_compact_rounds = 4; let preserve_schedule = [4, 2, 1, 0]; - for round in 0..max_compact_rounds { - let preserve = preserve_schedule[round]; + for (round, preserve) in preserve_schedule + .iter() + .copied() + .enumerate() + .take(max_compact_rounds) + { println!( " Auto-compacting session (round {}/{}, preserving {} recent messages)...", round + 1, @@ -8611,8 +8610,8 @@ impl LiveCli { let cwd = env::current_dir()?; // #803: reject flag-shaped tokens in list filter for BOTH text and JSON modes. // Previously the guard was JSON-only (#793); text mode silently returned empty success. - if action.as_deref() == Some("list") { - if let Some(filter) = target.as_deref() { + if action == Some("list") { + if let Some(filter) = target { if filter.starts_with('-') { if matches!(output_format, CliOutputFormat::Json) { // ROADMAP #817: this is a handled local inventory parse error. @@ -10073,9 +10072,7 @@ fn sandbox_json_value(status: &runtime::SandboxStatus) -> serde_json::Value { // (#731: "not supported on macOS" is a degraded state, not a hard error; // filesystem_active:true means partial containment is working) // error = enabled but unsupported AND no filesystem sandbox either (nothing active) - let top_status = if !status.enabled { - "ok" - } else if status.active { + let top_status = if !status.enabled || status.active { "ok" } else if status.supported { "warn" @@ -14008,39 +14005,37 @@ fn convert_messages(messages: &[ConversationMessage]) -> Vec { let content = message .blocks .iter() - .filter_map(|block| match block { - ContentBlock::Text { text } => { - Some(InputContentBlock::Text { text: text.clone() }) - } + .map(|block| match block { + ContentBlock::Text { text } => InputContentBlock::Text { text: text.clone() }, ContentBlock::Thinking { thinking, signature, } => { // 保留 Thinking 块:OpenAI 兼容协议会把它转成 reasoning_content 字段 // 回传给 DeepSeek V4(避免 400 "reasoning_content must be passed back" 错误) - Some(InputContentBlock::Thinking { + InputContentBlock::Thinking { thinking: thinking.clone(), signature: signature.clone(), - }) + } } - ContentBlock::ToolUse { id, name, input } => Some(InputContentBlock::ToolUse { + ContentBlock::ToolUse { id, name, input } => InputContentBlock::ToolUse { id: id.clone(), name: name.clone(), input: serde_json::from_str(input) .unwrap_or_else(|_| serde_json::json!({ "raw": input })), - }), + }, ContentBlock::ToolResult { tool_use_id, output, is_error, .. - } => Some(InputContentBlock::ToolResult { + } => InputContentBlock::ToolResult { tool_use_id: tool_use_id.clone(), content: vec![ToolResultContentBlock::Text { text: output.clone(), }], is_error: *is_error, - }), + }, }) .collect::>(); (!content.is_empty()).then(|| InputMessage { diff --git a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs index c9ba752b..b5df5c82 100644 --- a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs +++ b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs @@ -1007,13 +1007,13 @@ fn inventory_commands_emit_structured_json_when_requested() { assert!( !plugins .as_object() - .map_or(false, |o| o.contains_key("reload_runtime")), + .is_some_and(|o| o.contains_key("reload_runtime")), "plugins list should not include reload_runtime" ); assert!( !plugins .as_object() - .map_or(false, |o| o.contains_key("target")), + .is_some_and(|o| o.contains_key("target")), "plugins list should not include target" ); // #703: structured summary replaces prose message @@ -1706,13 +1706,13 @@ fn resumed_inventory_commands_emit_structured_json_when_requested() { assert!( !plugins .as_object() - .map_or(false, |o| o.contains_key("reload_runtime")), + .is_some_and(|o| o.contains_key("reload_runtime")), "plugins list should not include reload_runtime" ); assert!( !plugins .as_object() - .map_or(false, |o| o.contains_key("target")), + .is_some_and(|o| o.contains_key("target")), "plugins list should not include target" ); assert!( @@ -2983,9 +2983,9 @@ fn flag_value_errors_have_error_kind_and_hint_756() { "invalid --reasoning-effort must be invalid_flag_value (#756): {parsed}" ); assert!( - parsed["hint"].as_str().map_or(false, |h| h.contains("low") - || h.contains("medium") - || h.contains("high")), + parsed["hint"] + .as_str() + .is_some_and(|h| h.contains("low") || h.contains("medium") || h.contains("high")), "hint must mention valid values (#756): {parsed}" ); @@ -3011,7 +3011,7 @@ fn flag_value_errors_have_error_kind_and_hint_756() { "missing --model value must be missing_flag_value (#756): {parsed2}" ); assert!( - parsed2["hint"].as_str().map_or(false, |h| !h.is_empty()), + parsed2["hint"].as_str().is_some_and(|h| !h.is_empty()), "missing --model hint must be non-empty (#756): {parsed2}" ); } @@ -3255,7 +3255,7 @@ fn short_p_flag_swallows_no_flags_755() { "flag-like token after -p must be rejected as missing_prompt (#755): {parsed2}" ); assert!( - parsed2["hint"].as_str().map_or(false, |h| !h.is_empty()), + parsed2["hint"].as_str().is_some_and(|h| !h.is_empty()), "missing_prompt hint must be non-empty (#755)" ); } @@ -3397,7 +3397,7 @@ fn config_unsupported_section_json_hint_741() { assert!( parsed["supported_sections"] .as_array() - .map_or(false, |a| !a.is_empty()), + .is_some_and(|a| !a.is_empty()), "config {section} JSON must include supported_sections (#741)" ); }