chore: satisfy workspace clippy gate

This commit is contained in:
albertoelopez 2026-06-10 21:15:59 -07:00
parent 3588bbcf94
commit ecad06f6d6
4 changed files with 47 additions and 71 deletions

View File

@ -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(

View File

@ -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<ConversationMessag
let mut obsolete_indices: BTreeSet<usize> = 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<ConversationMessag
if let Some(last_write) = last_write_idx {
for op in ops {
if op.op_type == FileOp::Read && op.index < last_write {
obsolete_indices.insert(op.index);
} else if (op.op_type == FileOp::Write || op.op_type == FileOp::Edit)
&& op.index < last_write
{
if op.index < last_write {
obsolete_indices.insert(op.index);
}
}
@ -325,7 +306,7 @@ fn stage2_collapse(
usage: None,
});
} else {
result.extend(buffer.drain(..));
result.append(&mut buffer);
}
buffer.clear();
result.push(msg.clone());
@ -476,7 +457,7 @@ fn stage3_cluster(
}
let total_clustered: usize = cluster_assignments.len();
let clusters_found = cluster_id as usize;
let clusters_found = cluster_id;
let mut result: Vec<ConversationMessage> = Vec::new();
let mut cluster_buffers: BTreeMap<usize, Vec<usize>> = 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,
));
}

View File

@ -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<InputMessage> {
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::<Vec<_>>();
(!content.is_empty()).then(|| InputMessage {

View File

@ -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)"
);
}