From 0523423c1b904375b3e843847c1c68bfd5aec236 Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 19:59:25 -0400 Subject: [PATCH 01/10] chore(clippy): relocate cfg(test)-gated imports into test modules EnvPlaceholder (mcp_registry.rs) and DEFAULT_MCP_SERVER_PORT (mcp_server.rs) were imported at module level but only consumed inside #[cfg(test)] blocks. This made them look unused to clippy's lib pass and invited a cargo-fix regression that would strip them and break the test build. Moving the imports into the test module where they are used eliminates the warning without risking the test build. Co-Authored-By: Claude --- src-tauri/src/commands/mcp_registry.rs | 3 ++- src-tauri/src/commands/mcp_server.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/commands/mcp_registry.rs b/src-tauri/src/commands/mcp_registry.rs index d946f47d..9e913250 100644 --- a/src-tauri/src/commands/mcp_registry.rs +++ b/src-tauri/src/commands/mcp_registry.rs @@ -1,5 +1,5 @@ use crate::db::Database; -use crate::services::mcp_registry::{EnvPlaceholder, RegistryClient, RegistryMcpEntry}; +use crate::services::mcp_registry::{RegistryClient, RegistryMcpEntry}; use rusqlite::params; use serde::{Deserialize, Serialize}; use std::sync::{Arc, Mutex}; @@ -166,6 +166,7 @@ pub fn get_registry_mcp_by_id(db: &Database, id: i64) -> Result>>) -> Result Date: Wed, 22 Apr 2026 19:59:33 -0400 Subject: [PATCH 02/10] chore(clippy): prefix unused variables with underscore Resolves 'unused variable' warnings across 6 files by adding the _ prefix idiom. In claude_settings.rs the mut binding was also dropped because the variable was never mutated after the read. All sites are in test code or Tauri command handlers where the variable captures a value kept for lifetime purposes (app_handle.clone()) but not referenced directly. Co-Authored-By: Claude --- src-tauri/src/commands/docker_hosts.rs | 10 +++++----- src-tauri/src/commands/mcp.rs | 2 +- src-tauri/src/commands/permissions.rs | 2 +- src-tauri/src/commands/skills.rs | 2 +- src-tauri/src/services/claude_settings.rs | 2 +- src-tauri/src/services/docker/client.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src-tauri/src/commands/docker_hosts.rs b/src-tauri/src/commands/docker_hosts.rs index c7eb05bd..cfad7d5a 100644 --- a/src-tauri/src/commands/docker_hosts.rs +++ b/src-tauri/src/commands/docker_hosts.rs @@ -14,7 +14,7 @@ pub fn get_all_docker_hosts( #[tauri::command] pub fn create_docker_host( db: State<'_, Arc>>, - request: CreateDockerHostRequest, + _request: CreateDockerHostRequest, ) -> Result { let _db = db.lock().map_err(|e| e.to_string())?; Err("Docker host feature not yet implemented".to_string()) @@ -23,20 +23,20 @@ pub fn create_docker_host( #[tauri::command] pub fn update_docker_host( db: State<'_, Arc>>, - id: i64, - request: CreateDockerHostRequest, + _id: i64, + _request: CreateDockerHostRequest, ) -> Result { let _db = db.lock().map_err(|e| e.to_string())?; Err("Docker host feature not yet implemented".to_string()) } #[tauri::command] -pub fn delete_docker_host(db: State<'_, Arc>>, id: i64) -> Result<(), String> { +pub fn delete_docker_host(db: State<'_, Arc>>, _id: i64) -> Result<(), String> { let _db = db.lock().map_err(|e| e.to_string())?; Err("Docker host feature not yet implemented".to_string()) } #[tauri::command] -pub fn test_docker_host(id: i64) -> Result { +pub fn test_docker_host(_id: i64) -> Result { Err("Docker host feature not yet implemented".to_string()) } diff --git a/src-tauri/src/commands/mcp.rs b/src-tauri/src/commands/mcp.rs index 48f51053..8898ac6b 100644 --- a/src-tauri/src/commands/mcp.rs +++ b/src-tauri/src/commands/mcp.rs @@ -708,7 +708,7 @@ mod tests { let db = Database::in_memory().unwrap(); let req = sample_stdio_mcp(); let created = create_mcp_in_db(&db, &req).unwrap(); - let original_updated = created.updated_at.clone(); + let _original_updated = created.updated_at.clone(); // Small delay to ensure timestamp changes std::thread::sleep(std::time::Duration::from_millis(10)); diff --git a/src-tauri/src/commands/permissions.rs b/src-tauri/src/commands/permissions.rs index 3c28cc3b..67d4027b 100644 --- a/src-tauri/src/commands/permissions.rs +++ b/src-tauri/src/commands/permissions.rs @@ -366,7 +366,7 @@ pub(crate) fn seed_permission_templates_impl(db: &Database) -> Result<(), String ), ]; - let count = templates.len(); + let _count = templates.len(); for (name, desc, category, rule, tool_name, tag) in templates { let tags_json = serde_json::to_string(&vec![tag]).unwrap(); db.conn() diff --git a/src-tauri/src/commands/skills.rs b/src-tauri/src/commands/skills.rs index 49172585..49160407 100644 --- a/src-tauri/src/commands/skills.rs +++ b/src-tauri/src/commands/skills.rs @@ -1205,7 +1205,7 @@ mod tests { let db = Database::in_memory().unwrap(); let skill = create_skill_in_db(&db, &sample_skill()).unwrap(); - let file = create_skill_file_in_db( + let _file = create_skill_file_in_db( &db, &CreateSkillFileRequest { skill_id: skill.id, diff --git a/src-tauri/src/services/claude_settings.rs b/src-tauri/src/services/claude_settings.rs index 16112292..51d187e5 100644 --- a/src-tauri/src/services/claude_settings.rs +++ b/src-tauri/src/services/claude_settings.rs @@ -2380,7 +2380,7 @@ mod tests { }; // Write directly to file (bypassing scope resolution) - let mut file_settings = read_settings_file(&path).unwrap(); + let _file_settings = read_settings_file(&path).unwrap(); // Test sandbox serialization with null network let sandbox_value = serde_json::to_value(&settings.sandbox.as_ref().unwrap()).unwrap(); diff --git a/src-tauri/src/services/docker/client.rs b/src-tauri/src/services/docker/client.rs index 38a4d2bd..31207ad2 100644 --- a/src-tauri/src/services/docker/client.rs +++ b/src-tauri/src/services/docker/client.rs @@ -707,7 +707,7 @@ impl DockerClientManager { }); // Spawn task to listen for input events - let app_clone2 = app_handle.clone(); + let _app_clone2 = app_handle.clone(); let session_id_clone2 = session_id.clone(); tokio::spawn(async move { let (tx, mut rx) = tokio::sync::mpsc::channel::(256); From b003bbb1354a87d5cfd03967253d1abda8c0ccd7 Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 19:59:43 -0400 Subject: [PATCH 03/10] chore(clippy): replace useless vec! with arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sites in test code that collect JSONL lines or MCP configs into a temporary collection only to call .join() or pass as a slice. Array literal is cheaper (no heap allocation) and expresses intent more directly. 26 sites in session_explorer.rs tests, 2 in config_writer.rs tests — all previously flagged by 'clippy::useless_vec'. Co-Authored-By: Claude --- src-tauri/src/services/config_writer.rs | 4 +- src-tauri/src/services/session_explorer.rs | 136 +++++++-------------- 2 files changed, 45 insertions(+), 95 deletions(-) diff --git a/src-tauri/src/services/config_writer.rs b/src-tauri/src/services/config_writer.rs index 3480509c..d85bf46b 100644 --- a/src-tauri/src/services/config_writer.rs +++ b/src-tauri/src/services/config_writer.rs @@ -451,7 +451,7 @@ mod tests { None, None, // no env ); - let config = generate_mcp_config(&vec![mcp]); + let config = generate_mcp_config(&[mcp]); assert_json_snapshot!(config); } @@ -466,7 +466,7 @@ mod tests { None, None, ); - let config = generate_mcp_config(&vec![mcp]); + let config = generate_mcp_config(&[mcp]); let servers = config.get("mcpServers").unwrap().as_object().unwrap(); assert_eq!(servers.len(), 0); } diff --git a/src-tauri/src/services/session_explorer.rs b/src-tauri/src/services/session_explorer.rs index d8cef2a2..89331016 100644 --- a/src-tauri/src/services/session_explorer.rs +++ b/src-tauri/src/services/session_explorer.rs @@ -927,11 +927,9 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test-session.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","sessionId":"test-session","timestamp":"2026-01-15T10:00:00.000Z","version":"2.1.39","gitBranch":"main","cwd":"/code/test","message":{"role":"user","content":"Fix the bug"}}"#, + let lines = [r#"{"type":"user","uuid":"u1","sessionId":"test-session","timestamp":"2026-01-15T10:00:00.000Z","version":"2.1.39","gitBranch":"main","cwd":"/code/test","message":{"role":"user","content":"Fix the bug"}}"#, r#"{"type":"assistant","uuid":"a1","sessionId":"test-session","timestamp":"2026-01-15T10:00:05.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"I'll fix that for you."},{"type":"tool_use","name":"Read","id":"t1"}],"usage":{"input_tokens":100,"output_tokens":50,"cache_read_input_tokens":10,"cache_creation_input_tokens":5}}}"#, - r#"{"type":"assistant","uuid":"a2","sessionId":"test-session","timestamp":"2026-01-15T10:00:10.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"I'll fix that for you. Done!"},{"type":"tool_use","name":"Read","id":"t1"},{"type":"tool_use","name":"Edit","id":"t2"}],"usage":{"input_tokens":100,"output_tokens":80,"cache_read_input_tokens":10,"cache_creation_input_tokens":5}}}"#, - ]; + r#"{"type":"assistant","uuid":"a2","sessionId":"test-session","timestamp":"2026-01-15T10:00:10.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"I'll fix that for you. Done!"},{"type":"tool_use","name":"Read","id":"t1"},{"type":"tool_use","name":"Edit","id":"t2"}],"usage":{"input_tokens":100,"output_tokens":80,"cache_read_input_tokens":10,"cache_creation_input_tokens":5}}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); @@ -952,12 +950,10 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("detail-session.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"Hello"}}"#, + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"Hello"}}"#, r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:02.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"Hi"}],"usage":{"input_tokens":10,"output_tokens":5}}}"#, r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:00:04.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"Hi there!"}],"usage":{"input_tokens":10,"output_tokens":15}}}"#, - r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:10.000Z","message":{"role":"user","content":"Thanks"}}"#, - ]; + r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:10.000Z","message":{"role":"user","content":"Thanks"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); @@ -1079,13 +1075,11 @@ mod tests { fn test_parse_session_summary_skips_file_history_snapshot() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"file-history-snapshot","data":{}}"#, + let lines = [r#"{"type":"file-history-snapshot","data":{}}"#, r#"{"type":"progress","data":{}}"#, r#"{"type":"bash_progress","data":{}}"#, r#"{"type":"summary","data":{}}"#, - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"test"}}"#, - ]; + r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"test"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1096,10 +1090,8 @@ mod tests { fn test_parse_session_summary_skips_invalid_json_lines() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - "not valid json", - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"ok"}}"#, - ]; + let lines = ["not valid json", + r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"ok"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1110,9 +1102,7 @@ mod tests { fn test_parse_session_summary_tool_result_tracked() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"tool","content":"result"}}"#, - ]; + let lines = [r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"tool","content":"result"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1127,9 +1117,7 @@ mod tests { fn test_parse_session_summary_assistant_without_request_id() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"hi"}],"usage":{"input_tokens":50,"output_tokens":25}}}"#, - ]; + let lines = [r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"hi"}],"usage":{"input_tokens":50,"output_tokens":25}}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1142,9 +1130,7 @@ mod tests { fn test_parse_session_summary_assistant_tool_calls_no_request_id() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"assistant","content":[{"type":"tool_use","name":"Bash","id":"t1"}]}}"#, - ]; + let lines = [r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"assistant","content":[{"type":"tool_use","name":"Bash","id":"t1"}]}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1155,10 +1141,8 @@ mod tests { fn test_parse_session_detail_tool_result_included() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"hi"}}"#, - r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:01.000Z","message":{"role":"tool","content":"result data"}}"#, - ]; + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"hi"}}"#, + r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:01.000Z","message":{"role":"tool","content":"result data"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1171,7 +1155,7 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); let lines = - vec![r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:01.000Z"}"#]; + [r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:01.000Z"}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1183,9 +1167,7 @@ mod tests { fn test_parse_session_detail_assistant_without_request_id() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"hello"}],"usage":{"input_tokens":10,"output_tokens":5}}}"#, - ]; + let lines = [r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"hello"}],"usage":{"input_tokens":10,"output_tokens":5}}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1198,10 +1180,8 @@ mod tests { fn test_parse_session_detail_unknown_type_skipped() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"unknown_type","uuid":"x1","timestamp":"2026-01-15T10:00:00.000Z"}"#, - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:01.000Z","message":{"role":"user","content":"hi"}}"#, - ]; + let lines = [r#"{"type":"unknown_type","uuid":"x1","timestamp":"2026-01-15T10:00:00.000Z"}"#, + r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:01.000Z","message":{"role":"user","content":"hi"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1260,10 +1240,8 @@ mod tests { fn test_session_summary_duration_calculation() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"start"}}"#, - r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:05:00.000Z","message":{"role":"user","content":"end"}}"#, - ]; + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"start"}}"#, + r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:05:00.000Z","message":{"role":"user","content":"end"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1274,9 +1252,7 @@ mod tests { fn test_session_summary_invalid_timestamps() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"not-a-date","message":{"role":"user","content":"hi"}}"#, - ]; + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"not-a-date","message":{"role":"user","content":"hi"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1294,11 +1270,9 @@ mod tests { fn test_parse_session_summary_earliest_latest_tracking() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T12:00:00.000Z","message":{"role":"user","content":"mid"}}"#, + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T12:00:00.000Z","message":{"role":"user","content":"mid"}}"#, r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"early"}}"#, - r#"{"type":"user","uuid":"u3","timestamp":"2026-01-15T14:00:00.000Z","message":{"role":"user","content":"late"}}"#, - ]; + r#"{"type":"user","uuid":"u3","timestamp":"2026-01-15T14:00:00.000Z","message":{"role":"user","content":"late"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1320,12 +1294,10 @@ mod tests { fn test_parse_session_summary_multiple_request_ids() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"q1"}}"#, + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"q1"}}"#, r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:01.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"answer 1"}],"usage":{"input_tokens":100,"output_tokens":50}}}"#, r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:01:00.000Z","message":{"role":"user","content":"q2"}}"#, - r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:01:01.000Z","requestId":"req_002","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"answer 2"}],"usage":{"input_tokens":200,"output_tokens":100}}}"#, - ]; + r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:01:01.000Z","requestId":"req_002","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"answer 2"}],"usage":{"input_tokens":200,"output_tokens":100}}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1339,9 +1311,7 @@ mod tests { fn test_parse_session_summary_no_usage_in_assistant() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"hi"}]}}"#, - ]; + let lines = [r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"hi"}]}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1354,9 +1324,7 @@ mod tests { fn test_parse_session_summary_user_message_content_array() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":[{"type":"text","text":"Hello from array content"}]}}"#, - ]; + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":[{"type":"text","text":"Hello from array content"}]}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1370,10 +1338,8 @@ mod tests { fn test_parse_session_summary_first_user_message_empty_content() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":""}}"#, - r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:01.000Z","message":{"role":"user","content":"Second message"}}"#, - ]; + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":""}}"#, + r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:01.000Z","message":{"role":"user","content":"Second message"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1388,9 +1354,7 @@ mod tests { fn test_parse_session_summary_cwd_and_version() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","version":"2.3.0","cwd":"/home/user/project","message":{"role":"user","content":"hi"}}"#, - ]; + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","version":"2.3.0","cwd":"/home/user/project","message":{"role":"user","content":"hi"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1406,10 +1370,8 @@ mod tests { fn test_parse_session_detail_streaming_updates_tool_calls() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"step1"}]}}"#, - r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:00:01.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"step1 done"},{"type":"tool_use","name":"Read","id":"t1"}],"usage":{"input_tokens":100,"output_tokens":50}}}"#, - ]; + let lines = [r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"step1"}]}}"#, + r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:00:01.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"text","text":"step1 done"},{"type":"tool_use","name":"Read","id":"t1"}],"usage":{"input_tokens":100,"output_tokens":50}}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1424,12 +1386,10 @@ mod tests { fn test_parse_session_detail_preserves_order() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"first"}}"#, + let lines = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"first"}}"#, r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:01.000Z","requestId":"req_001","message":{"role":"assistant","content":[{"type":"text","text":"response"}]}}"#, r#"{"type":"tool_result","uuid":"t1","timestamp":"2026-01-15T10:00:02.000Z","message":{"role":"tool","content":"result"}}"#, - r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:03.000Z","message":{"role":"user","content":"followup"}}"#, - ]; + r#"{"type":"user","uuid":"u2","timestamp":"2026-01-15T10:00:03.000Z","message":{"role":"user","content":"followup"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1543,13 +1503,11 @@ mod tests { fn test_parse_session_detail_skips_progress_types() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"file-history-snapshot","data":{}}"#, + let lines = [r#"{"type":"file-history-snapshot","data":{}}"#, r#"{"type":"progress","data":{}}"#, r#"{"type":"bash_progress","data":{}}"#, r#"{"type":"summary","data":{}}"#, - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"hello"}}"#, - ]; + r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"hello"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1561,11 +1519,9 @@ mod tests { fn test_parse_session_detail_invalid_json_lines_skipped() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - "not json", + let lines = ["not json", "", - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"ok"}}"#, - ]; + r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"ok"}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let detail = parse_session_detail(&session_file, "test").unwrap(); @@ -1580,10 +1536,8 @@ mod tests { fn test_parse_session_summary_merges_tool_counts() { let dir = tempfile::tempdir().unwrap(); let session_file = dir.path().join("test.jsonl"); - let lines = vec![ - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","requestId":"req_001","message":{"role":"assistant","content":[{"type":"tool_use","name":"Read","id":"t1"},{"type":"tool_use","name":"Read","id":"t2"}]}}"#, - r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:01:00.000Z","requestId":"req_002","message":{"role":"assistant","content":[{"type":"tool_use","name":"Read","id":"t3"},{"type":"tool_use","name":"Edit","id":"t4"}]}}"#, - ]; + let lines = [r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:00.000Z","requestId":"req_001","message":{"role":"assistant","content":[{"type":"tool_use","name":"Read","id":"t1"},{"type":"tool_use","name":"Read","id":"t2"}]}}"#, + r#"{"type":"assistant","uuid":"a2","timestamp":"2026-01-15T10:01:00.000Z","requestId":"req_002","message":{"role":"assistant","content":[{"type":"tool_use","name":"Read","id":"t3"},{"type":"tool_use","name":"Edit","id":"t4"}]}}"#]; std::fs::write(&session_file, lines.join("\n")).unwrap(); let summary = parse_session_summary(&session_file, "test").unwrap(); @@ -1799,17 +1753,13 @@ mod tests { std::fs::create_dir(&proj).unwrap(); // Session 1: uses Read and Write - let lines1 = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"q1"}}"#, - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:01.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"tool_use","name":"Read","id":"t1"},{"type":"tool_use","name":"Write","id":"t2"}],"usage":{"input_tokens":100,"output_tokens":50}}}"#, - ]; + let lines1 = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-15T10:00:00.000Z","message":{"role":"user","content":"q1"}}"#, + r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-15T10:00:01.000Z","requestId":"req_001","message":{"role":"assistant","model":"claude-opus-4-6","content":[{"type":"tool_use","name":"Read","id":"t1"},{"type":"tool_use","name":"Write","id":"t2"}],"usage":{"input_tokens":100,"output_tokens":50}}}"#]; std::fs::write(proj.join("s1.jsonl"), lines1.join("\n")).unwrap(); // Session 2: uses Read and Bash - let lines2 = vec![ - r#"{"type":"user","uuid":"u1","timestamp":"2026-01-20T10:00:00.000Z","message":{"role":"user","content":"q2"}}"#, - r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-20T10:00:01.000Z","requestId":"req_002","message":{"role":"assistant","model":"claude-sonnet-4-20250514","content":[{"type":"tool_use","name":"Read","id":"t3"},{"type":"tool_use","name":"Bash","id":"t4"}],"usage":{"input_tokens":200,"output_tokens":100}}}"#, - ]; + let lines2 = [r#"{"type":"user","uuid":"u1","timestamp":"2026-01-20T10:00:00.000Z","message":{"role":"user","content":"q2"}}"#, + r#"{"type":"assistant","uuid":"a1","timestamp":"2026-01-20T10:00:01.000Z","requestId":"req_002","message":{"role":"assistant","model":"claude-sonnet-4-20250514","content":[{"type":"tool_use","name":"Read","id":"t3"},{"type":"tool_use","name":"Bash","id":"t4"}],"usage":{"input_tokens":200,"output_tokens":100}}}"#]; std::fs::write(proj.join("s2.jsonl"), lines2.join("\n")).unwrap(); let result = list_projects_from_dir(dir.path()).unwrap(); From 00626c5c28321643445d9ad64d894b776c9b1d2e Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 20:02:28 -0400 Subject: [PATCH 04/10] chore(clippy): resolve dead-code warnings via targeted allows 66 dead-code warnings broken into four sub-patterns, each with its own appropriate fix: 1. Test-helper pub(crate) fns (45 sites across 9 files): #[cfg_attr(not(test), allow(dead_code))]. These are #[cfg(test)]-consumed helpers exposed as pub(crate) so the test module can bypass Tauri State<> wrappers. The attr suppresses the warning for non-test builds while preserving genuine dead-code detection in test builds. 2. Vestigial typed-parser vendor hierarchy: 4 enums (CodexMcp, CopilotMcp, CursorMcp, GeminiMcp) + 8 Stdio/Http variant structs. These were scaffolded for a typed intermediate-representation parse path that was never wired up; current code uses ParsedXxxMcp normalization directly. Annotated with #[allow(dead_code)] + a comment noting the design intent so they remain available for future typed-parse work. 3. Serde-deser false positives (DevcontainerConfig, ProfileItem, SpinnerVerbConfig, 3 fields on RawRecord/RawMessage/ToolManagerServer). Clippy's 'never constructed' lint does not see serde's Deserialize-generated constructors. Standard #[allow(dead_code)] idiom. 4. One genuine deletion: Database::from_connection in db/schema.rs. Already #[cfg(test)]-gated with zero callers; sibling Database::in_memory() is the actual entry point used throughout tests. Dead-code warning count: 66 -> 0. Total clippy warnings: 134 -> 68. Co-Authored-By: Claude --- src-tauri/src/commands/hooks.rs | 8 ++++++++ src-tauri/src/commands/mcp.rs | 6 ++++++ src-tauri/src/commands/mcp_session.rs | 1 + src-tauri/src/commands/mcp_test.rs | 2 ++ src-tauri/src/commands/projects.rs | 5 +++++ src-tauri/src/commands/repos.rs | 7 +++++++ src-tauri/src/commands/settings.rs | 1 + src-tauri/src/commands/skills.rs | 4 ++++ src-tauri/src/db/models.rs | 2 ++ src-tauri/src/db/schema.rs | 6 ------ src-tauri/src/mcp_server/tools.rs | 1 + src-tauri/src/services/codex_config.rs | 6 ++++++ src-tauri/src/services/copilot_config.rs | 7 +++++++ src-tauri/src/services/cursor_config.rs | 6 ++++++ src-tauri/src/services/docker/devcontainer.rs | 2 ++ src-tauri/src/services/gemini_config.rs | 6 ++++++ src-tauri/src/services/rule_writer.rs | 1 + src-tauri/src/services/session_explorer.rs | 2 ++ src-tauri/src/services/statusline_writer.rs | 2 ++ 19 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src-tauri/src/commands/hooks.rs b/src-tauri/src/commands/hooks.rs index c7e8e6ba..e65a6e1f 100644 --- a/src-tauri/src/commands/hooks.rs +++ b/src-tauri/src/commands/hooks.rs @@ -910,6 +910,7 @@ pub fn duplicate_hook( // ============================================================================ /// Create a hook in the database (no file sync) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn create_hook_in_db(db: &Database, hook: &CreateHookRequest) -> Result { let tags_json = hook .tags @@ -939,6 +940,7 @@ pub(crate) fn create_hook_in_db(db: &Database, hook: &CreateHookRequest) -> Resu } /// Get a hook by ID from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_hook_by_id(db: &Database, id: i64) -> Result { let mut stmt = db .conn() @@ -971,6 +973,7 @@ pub(crate) fn get_all_hooks_from_db(db: &Database) -> Result, String> } /// Update a hook in the database (no file sync) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn update_hook_in_db( db: &Database, id: i64, @@ -1020,6 +1023,7 @@ pub(crate) fn update_hook_in_db( } /// Delete a hook from the database (no file sync) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn delete_hook_from_db(db: &Database, id: i64) -> Result<(), String> { db.conn() .execute("DELETE FROM hooks WHERE id = ?", [id]) @@ -1028,6 +1032,7 @@ pub(crate) fn delete_hook_from_db(db: &Database, id: i64) -> Result<(), String> } /// Add a hook to global hooks in the database (no file sync) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn add_global_hook_in_db(db: &Database, hook_id: i64) -> Result<(), String> { db.conn() .execute( @@ -1039,6 +1044,7 @@ pub(crate) fn add_global_hook_in_db(db: &Database, hook_id: i64) -> Result<(), S } /// Get all global hooks from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_global_hooks_from_db(db: &Database) -> Result, String> { let mut stmt = db .conn() @@ -1068,6 +1074,7 @@ pub(crate) fn get_global_hooks_from_db(db: &Database) -> Result, } /// Toggle a global hook in the database (no file sync) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn toggle_global_hook_in_db( db: &Database, id: i64, @@ -1083,6 +1090,7 @@ pub(crate) fn toggle_global_hook_in_db( } /// Remove a global hook from the database (no file sync) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn remove_global_hook_from_db(db: &Database, hook_id: i64) -> Result<(), String> { db.conn() .execute("DELETE FROM global_hooks WHERE hook_id = ?", [hook_id]) diff --git a/src-tauri/src/commands/mcp.rs b/src-tauri/src/commands/mcp.rs index 8898ac6b..ddfa8b37 100644 --- a/src-tauri/src/commands/mcp.rs +++ b/src-tauri/src/commands/mcp.rs @@ -319,18 +319,22 @@ pub(crate) fn generate_duplicate_name(name: &str) -> String { } // Convenience aliases (promoted from #[cfg(test)] for cross-module reuse) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn create_mcp_in_db(db: &Database, mcp: &CreateMcpRequest) -> Result { create_mcp_impl(db, mcp) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_mcp_by_id(db: &Database, id: i64) -> Result { get_mcp_impl(db, id) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_all_mcps_from_db(db: &Database) -> Result, String> { get_all_mcps_impl(db) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn update_mcp_in_db( db: &Database, id: i64, @@ -339,10 +343,12 @@ pub(crate) fn update_mcp_in_db( update_mcp_impl(db, id, mcp) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn delete_mcp_from_db(db: &Database, id: i64) -> Result<(), String> { delete_mcp_impl(db, id) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn toggle_global_mcp_in_db(db: &Database, id: i64, enabled: bool) -> Result<(), String> { toggle_global_mcp_impl(db, id, enabled) } diff --git a/src-tauri/src/commands/mcp_session.rs b/src-tauri/src/commands/mcp_session.rs index 36311d74..a032159c 100644 --- a/src-tauri/src/commands/mcp_session.rs +++ b/src-tauri/src/commands/mcp_session.rs @@ -84,6 +84,7 @@ pub(crate) fn get_mcp_session_data_from_db( } /// Validate MCP session data before starting a session +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn validate_mcp_session_data(data: &McpSessionData) -> Result<(), String> { if data.source == "system" { if data.url.is_none() { diff --git a/src-tauri/src/commands/mcp_test.rs b/src-tauri/src/commands/mcp_test.rs index c6477c8b..279832a4 100644 --- a/src-tauri/src/commands/mcp_test.rs +++ b/src-tauri/src/commands/mcp_test.rs @@ -163,6 +163,7 @@ pub fn test_mcp_config( // ============================================================================ /// Extract MCP data from database for testing +#[cfg_attr(not(test), allow(dead_code))] pub fn get_mcp_test_data_from_db( db: &Database, mcp_id: i64, @@ -217,6 +218,7 @@ pub fn get_mcp_test_data_from_db( } /// Validate MCP config before testing +#[cfg_attr(not(test), allow(dead_code))] pub fn validate_mcp_config( mcp_type: &str, command: Option<&str>, diff --git a/src-tauri/src/commands/projects.rs b/src-tauri/src/commands/projects.rs index 381e110f..42c71dfa 100644 --- a/src-tauri/src/commands/projects.rs +++ b/src-tauri/src/commands/projects.rs @@ -498,6 +498,7 @@ pub fn sync_project_config( // ============================================================================ /// Create a project in the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn create_project_in_db( db: &Database, project: &CreateProjectRequest, @@ -515,6 +516,7 @@ pub(crate) fn create_project_in_db( } /// Get a project by ID from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_project_by_id(db: &Database, id: i64) -> Result { db.conn() .query_row( @@ -541,6 +543,7 @@ pub(crate) fn get_project_by_id(db: &Database, id: i64) -> Result Result { db.conn() .query_row( @@ -567,6 +570,7 @@ pub(crate) fn get_project_by_path(db: &Database, path: &str) -> Result Result, String> { let mut stmt = db .conn() @@ -765,6 +769,7 @@ pub(crate) fn toggle_project_mcp_in_db( } /// Get project MCP assignments from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_project_mcps_from_db( db: &Database, project_id: i64, diff --git a/src-tauri/src/commands/repos.rs b/src-tauri/src/commands/repos.rs index 8b2a770f..935334fd 100644 --- a/src-tauri/src/commands/repos.rs +++ b/src-tauri/src/commands/repos.rs @@ -505,23 +505,28 @@ pub(crate) fn remove_repo_impl(db: &Database, id: i64) -> Result<(), String> { } // Convenience aliases (promoted from #[cfg(test)] for cross-module reuse) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn add_repo_in_db(db: &Database, request: &CreateRepoRequest) -> Result { add_repo_impl(db, request) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_repo_by_id(db: &Database, id: i64) -> Result { get_repo_impl(db, id) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn toggle_repo_in_db(db: &Database, id: i64, enabled: bool) -> Result<(), String> { toggle_repo_impl(db, id, enabled) } +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn remove_repo_in_db(db: &Database, id: i64) -> Result<(), String> { remove_repo_impl(db, id) } /// Add a repo item directly in the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn add_repo_item_in_db( db: &Database, repo_id: i64, @@ -543,6 +548,7 @@ pub(crate) fn add_repo_item_in_db( } /// Get a repo item by ID directly from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_repo_item_by_id(db: &Database, id: i64) -> Result { db.conn() .query_row( @@ -573,6 +579,7 @@ pub(crate) fn get_repo_item_by_id(db: &Database, id: i64) -> Result Res } /// Check if a specific editor is enabled +#[cfg_attr(not(test), allow(dead_code))] pub fn is_editor_enabled(db: &Database, editor_id: &str) -> bool { get_enabled_editors_from_db(db).contains(&editor_id.to_string()) } diff --git a/src-tauri/src/commands/skills.rs b/src-tauri/src/commands/skills.rs index 49160407..02e56eb1 100644 --- a/src-tauri/src/commands/skills.rs +++ b/src-tauri/src/commands/skills.rs @@ -776,6 +776,7 @@ pub(crate) fn create_skill_in_db( } /// Create a skill without validation (useful for testing edge cases or imports) +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn create_skill_in_db_unvalidated( db: &Database, skill: &CreateSkillRequest, @@ -887,6 +888,7 @@ pub(crate) fn delete_skill_from_db(db: &Database, id: i64) -> Result<(), String> } /// Create a skill file directly in the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn create_skill_file_in_db( db: &Database, file: &CreateSkillFileRequest, @@ -914,6 +916,7 @@ pub(crate) fn create_skill_file_in_db( } /// Get skill files directly from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn get_skill_files_from_db( db: &Database, skill_id: i64, @@ -936,6 +939,7 @@ pub(crate) fn get_skill_files_from_db( } /// Delete a skill file directly from the database +#[cfg_attr(not(test), allow(dead_code))] pub(crate) fn delete_skill_file_from_db(db: &Database, id: i64) -> Result<(), String> { db.conn() .execute("DELETE FROM skill_files WHERE id = ?", [id]) diff --git a/src-tauri/src/db/models.rs b/src-tauri/src/db/models.rs index f5c44e59..09188453 100644 --- a/src-tauri/src/db/models.rs +++ b/src-tauri/src/db/models.rs @@ -605,6 +605,7 @@ pub struct CreateProfileRequest { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[allow(dead_code)] pub struct ProfileItem { pub id: i64, pub profile_id: i64, @@ -767,6 +768,7 @@ pub struct SpinnerVerb { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[allow(dead_code)] pub struct SpinnerVerbConfig { pub mode: String, // "append" or "replace" pub verbs: Vec, diff --git a/src-tauri/src/db/schema.rs b/src-tauri/src/db/schema.rs index a5329a20..712683b7 100644 --- a/src-tauri/src/db/schema.rs +++ b/src-tauri/src/db/schema.rs @@ -13,12 +13,6 @@ impl Database { Ok(Self { conn }) } - /// Create a Database from an existing connection (for testing with in-memory databases) - #[cfg(test)] - pub fn from_connection(conn: Connection) -> Self { - Self { conn } - } - /// Create an in-memory database for testing #[cfg(test)] pub fn in_memory() -> Result { diff --git a/src-tauri/src/mcp_server/tools.rs b/src-tauri/src/mcp_server/tools.rs index 2866c353..5dcd3d79 100644 --- a/src-tauri/src/mcp_server/tools.rs +++ b/src-tauri/src/mcp_server/tools.rs @@ -21,6 +21,7 @@ use crate::db::Database; #[derive(Clone)] pub struct ToolManagerServer { pub db: Arc>, + #[allow(dead_code)] tool_router: ToolRouter, } diff --git a/src-tauri/src/services/codex_config.rs b/src-tauri/src/services/codex_config.rs index ac829b80..acdf2d51 100644 --- a/src-tauri/src/services/codex_config.rs +++ b/src-tauri/src/services/codex_config.rs @@ -6,6 +6,7 @@ use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table}; /// Codex MCP server configuration (STDIO transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CodexMcpStdio { #[serde(default)] pub enabled: Option, @@ -28,6 +29,7 @@ pub struct CodexMcpStdio { /// Codex MCP server configuration (HTTP transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CodexMcpHttp { #[serde(default)] pub enabled: Option, @@ -42,6 +44,8 @@ pub struct CodexMcpHttp { /// Codex MCP config (either STDIO or HTTP) #[derive(Debug, Clone)] +// Reserved for typed parse path; current impl uses ParsedCodexMcp. +#[allow(dead_code)] pub enum CodexMcp { Stdio(CodexMcpStdio), Http(CodexMcpHttp), @@ -315,6 +319,7 @@ pub fn write_codex_config(path: &Path, mcps: &[McpTuple]) -> Result<()> { } /// Add a single MCP to Codex config +#[cfg_attr(not(test), allow(dead_code))] pub fn add_mcp_to_codex_config(path: &Path, mcp: &McpTuple) -> Result<()> { // Read existing MCPs let existing_mcps = if path.exists() { @@ -352,6 +357,7 @@ pub fn add_mcp_to_codex_config(path: &Path, mcp: &McpTuple) -> Result<()> { } /// Remove an MCP from Codex config +#[cfg_attr(not(test), allow(dead_code))] pub fn remove_mcp_from_codex_config(path: &Path, name: &str) -> Result<()> { if !path.exists() { return Ok(()); diff --git a/src-tauri/src/services/copilot_config.rs b/src-tauri/src/services/copilot_config.rs index 1049d66a..ee322e99 100644 --- a/src-tauri/src/services/copilot_config.rs +++ b/src-tauri/src/services/copilot_config.rs @@ -6,6 +6,7 @@ use std::path::Path; /// GitHub Copilot CLI MCP server configuration (STDIO transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CopilotMcpStdio { pub command: String, #[serde(default)] @@ -16,6 +17,7 @@ pub struct CopilotMcpStdio { /// HTTP request initialization options #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CopilotRequestInit { #[serde(default)] pub headers: Option>, @@ -23,6 +25,7 @@ pub struct CopilotRequestInit { /// GitHub Copilot CLI MCP server configuration (HTTP/SSE transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CopilotMcpHttp { pub url: String, #[serde(default, rename = "type")] @@ -33,6 +36,8 @@ pub struct CopilotMcpHttp { /// Copilot MCP config (either STDIO or HTTP) #[derive(Debug, Clone)] +// Reserved for typed parse path; current impl uses ParsedCopilotMcp. +#[allow(dead_code)] pub enum CopilotMcp { Stdio(CopilotMcpStdio), Http(CopilotMcpHttp), @@ -287,6 +292,7 @@ pub fn write_copilot_config(path: &Path, mcps: &[McpTuple]) -> Result<()> { } /// Add a single MCP to Copilot config +#[cfg_attr(not(test), allow(dead_code))] pub fn add_mcp_to_copilot_config(path: &Path, mcp: &McpTuple) -> Result<()> { // Read existing MCPs let existing_mcps = if path.exists() { @@ -324,6 +330,7 @@ pub fn add_mcp_to_copilot_config(path: &Path, mcp: &McpTuple) -> Result<()> { } /// Remove an MCP from Copilot config +#[cfg_attr(not(test), allow(dead_code))] pub fn remove_mcp_from_copilot_config(path: &Path, name: &str) -> Result<()> { if !path.exists() { return Ok(()); diff --git a/src-tauri/src/services/cursor_config.rs b/src-tauri/src/services/cursor_config.rs index 2eb4e018..26599aa8 100644 --- a/src-tauri/src/services/cursor_config.rs +++ b/src-tauri/src/services/cursor_config.rs @@ -6,6 +6,7 @@ use std::path::Path; /// Cursor IDE MCP server configuration (STDIO transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CursorMcpStdio { pub command: String, #[serde(default)] @@ -18,6 +19,7 @@ pub struct CursorMcpStdio { /// Cursor IDE MCP server configuration (HTTP/SSE transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct CursorMcpHttp { pub url: String, #[serde(default)] @@ -26,6 +28,8 @@ pub struct CursorMcpHttp { /// Cursor MCP config (either STDIO or HTTP) #[derive(Debug, Clone)] +// Reserved for typed parse path; current impl uses ParsedCursorMcp. +#[allow(dead_code)] pub enum CursorMcp { Stdio(CursorMcpStdio), Http(CursorMcpHttp), @@ -266,6 +270,7 @@ pub fn write_cursor_config(path: &Path, mcps: &[McpTuple]) -> Result<()> { } /// Add a single MCP to Cursor config +#[cfg_attr(not(test), allow(dead_code))] pub fn add_mcp_to_cursor_config(path: &Path, mcp: &McpTuple) -> Result<()> { // Read existing MCPs let existing_mcps = if path.exists() { @@ -303,6 +308,7 @@ pub fn add_mcp_to_cursor_config(path: &Path, mcp: &McpTuple) -> Result<()> { } /// Remove an MCP from Cursor config +#[cfg_attr(not(test), allow(dead_code))] pub fn remove_mcp_from_cursor_config(path: &Path, name: &str) -> Result<()> { if !path.exists() { return Ok(()); diff --git a/src-tauri/src/services/docker/devcontainer.rs b/src-tauri/src/services/docker/devcontainer.rs index 6230e8a9..e25f739b 100644 --- a/src-tauri/src/services/docker/devcontainer.rs +++ b/src-tauri/src/services/docker/devcontainer.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; /// Represents a devcontainer.json configuration #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[allow(dead_code)] pub struct DevcontainerConfig { #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, @@ -104,6 +105,7 @@ impl DevcontainerConfig { } } +#[cfg_attr(not(test), allow(dead_code))] fn strip_json_comments(input: &str) -> String { let mut result = String::with_capacity(input.len()); let mut chars = input.chars().peekable(); diff --git a/src-tauri/src/services/gemini_config.rs b/src-tauri/src/services/gemini_config.rs index cd70d1e0..a97818d0 100644 --- a/src-tauri/src/services/gemini_config.rs +++ b/src-tauri/src/services/gemini_config.rs @@ -6,6 +6,7 @@ use std::path::Path; /// Gemini CLI MCP server configuration (STDIO transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct GeminiMcpStdio { pub command: String, #[serde(default)] @@ -22,6 +23,7 @@ pub struct GeminiMcpStdio { /// Gemini CLI MCP server configuration (HTTP/SSE transport) #[derive(Debug, Clone, Deserialize, Serialize)] +#[allow(dead_code)] pub struct GeminiMcpHttp { #[serde(default)] pub url: Option, // SSE endpoint @@ -37,6 +39,8 @@ pub struct GeminiMcpHttp { /// Gemini MCP config (either STDIO or HTTP) #[derive(Debug, Clone)] +// Reserved for typed parse path; current impl uses ParsedGeminiMcp. +#[allow(dead_code)] pub enum GeminiMcp { Stdio(GeminiMcpStdio), Http(GeminiMcpHttp), @@ -305,6 +309,7 @@ pub fn write_gemini_config(path: &Path, mcps: &[McpTuple]) -> Result<()> { } /// Add a single MCP to Gemini config +#[cfg_attr(not(test), allow(dead_code))] pub fn add_mcp_to_gemini_config(path: &Path, mcp: &McpTuple) -> Result<()> { // Read existing MCPs let existing_mcps = if path.exists() { @@ -342,6 +347,7 @@ pub fn add_mcp_to_gemini_config(path: &Path, mcp: &McpTuple) -> Result<()> { } /// Remove an MCP from Gemini config +#[cfg_attr(not(test), allow(dead_code))] pub fn remove_mcp_from_gemini_config(path: &Path, name: &str) -> Result<()> { if !path.exists() { return Ok(()); diff --git a/src-tauri/src/services/rule_writer.rs b/src-tauri/src/services/rule_writer.rs index 1582a480..a1f6a0b0 100644 --- a/src-tauri/src/services/rule_writer.rs +++ b/src-tauri/src/services/rule_writer.rs @@ -87,6 +87,7 @@ pub fn delete_project_rule(project_path: &Path, rule: &Rule) -> Result<()> { /// Create a symlink from one rule to another location #[cfg(unix)] +#[cfg_attr(not(test), allow(dead_code))] pub fn create_rule_symlink(source_path: &Path, target_path: &Path) -> Result<()> { if let Some(parent) = target_path.parent() { std::fs::create_dir_all(parent)?; diff --git a/src-tauri/src/services/session_explorer.rs b/src-tauri/src/services/session_explorer.rs index 89331016..0851712d 100644 --- a/src-tauri/src/services/session_explorer.rs +++ b/src-tauri/src/services/session_explorer.rs @@ -105,6 +105,7 @@ struct RawRecord { record_type: Option, uuid: Option, #[serde(default)] + #[allow(dead_code)] session_id: Option, #[serde(default)] timestamp: Option, @@ -124,6 +125,7 @@ struct RawRecord { #[serde(rename_all = "camelCase")] struct RawMessage { #[serde(default)] + #[allow(dead_code)] role: Option, #[serde(default)] model: Option, diff --git a/src-tauri/src/services/statusline_writer.rs b/src-tauri/src/services/statusline_writer.rs index 3cd8f2b5..59cd771b 100644 --- a/src-tauri/src/services/statusline_writer.rs +++ b/src-tauri/src/services/statusline_writer.rs @@ -91,6 +91,7 @@ pub fn write_statusline_script(script_content: &str) -> Result String { generate_script_from_segments_with_theme(segments, "default") } @@ -1397,6 +1398,7 @@ fn color_name_to_rgb(color: &str) -> (u8, u8, u8) { } /// Get ANSI 24-bit true color foreground escape code for a color name +#[cfg_attr(not(test), allow(dead_code))] fn get_ansi_color_code(color: &str) -> String { let (r, g, b) = color_name_to_rgb(color); format!("\\033[38;2;{};{};{}m", r, g, b) From 7fd4be24258da587c86a769ac1cca0aca7520c16 Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 20:06:30 -0400 Subject: [PATCH 05/10] chore(clippy): apply mechanical autofix suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broad pass applying clippy's machine-applicable suggestions now that the cfg(test)-gated-import and unused-variable landmines have been resolved. Covers: - manual Option::map rewrites (several sites in mcp_client.rs, skills.rs, session_explorer.rs) - assert_eq!(x, true/false) -> assert!(x) / assert!(!x) - useless format! dropped - redundant closures replaced with the function itself - Iterator::last on DoubleEndedIterator -> .next_back() - map_or simplification - Option::map().flatten() -> and_then - map().values() iteration cleanup - assorted rustfmt normalization introduced by the rewrites Additionally: replaced a tautological bool assertion in debug_logger.rs (assert!(enabled == true || enabled == false)) with 'let _ = is_debug_enabled();' matching the adjacent test's 'let _ = path;' pattern — the assertion was already always-true before clippy rewrote it, and the newer nonminimal_bool lint now flags the explicit form as an error under -D warnings. Clippy warning count: 68 -> 33. Co-Authored-By: Claude --- src-tauri/src/commands/commands.rs | 18 +-- src-tauri/src/commands/mcp_registry.rs | 9 +- src-tauri/src/commands/mcp_server.rs | 4 +- src-tauri/src/commands/skills.rs | 24 +-- src-tauri/src/services/claude_settings.rs | 8 +- src-tauri/src/services/debug_logger.rs | 5 +- src-tauri/src/services/gist_sync.rs | 2 +- src-tauri/src/services/github_client.rs | 2 +- src-tauri/src/services/mcp_client.rs | 108 ++++++------- src-tauri/src/services/mcp_registry.rs | 6 +- src-tauri/src/services/repo_parser.rs | 10 +- src-tauri/src/services/session_explorer.rs | 152 ++++++++++++------- src-tauri/src/services/statusline_gallery.rs | 2 +- 13 files changed, 183 insertions(+), 167 deletions(-) diff --git a/src-tauri/src/commands/commands.rs b/src-tauri/src/commands/commands.rs index 3009440b..3594c443 100644 --- a/src-tauri/src/commands/commands.rs +++ b/src-tauri/src/commands/commands.rs @@ -329,13 +329,11 @@ pub fn get_global_commands( db: State<'_, Arc>>, ) -> Result, String> { let db = db.lock().map_err(|e| e.to_string())?; - let query = format!( - "SELECT gc.id, gc.command_id, gc.is_enabled, + let query = "SELECT gc.id, gc.command_id, gc.is_enabled, c.id, c.name, c.description, c.content, c.allowed_tools, c.argument_hint, c.model, c.tags, c.source, c.source_path, c.is_favorite, c.created_at, c.updated_at FROM global_commands gc JOIN commands c ON gc.command_id = c.id - ORDER BY c.name" - ); + ORDER BY c.name".to_string(); let mut stmt = db.conn().prepare(&query).map_err(|e| e.to_string())?; let commands = stmt @@ -644,13 +642,11 @@ pub fn toggle_project_command( .map_err(|e| e.to_string())?; // Get the command and project path - let query = format!( - "SELECT c.id, c.name, c.description, c.content, c.allowed_tools, c.argument_hint, c.model, c.tags, c.source, c.source_path, c.is_favorite, c.created_at, c.updated_at, p.path + let query = "SELECT c.id, c.name, c.description, c.content, c.allowed_tools, c.argument_hint, c.model, c.tags, c.source, c.source_path, c.is_favorite, c.created_at, c.updated_at, p.path FROM project_commands pc JOIN commands c ON pc.command_id = c.id JOIN projects p ON pc.project_id = p.id - WHERE pc.id = ?" - ); + WHERE pc.id = ?".to_string(); let mut stmt = db_guard.conn().prepare(&query).map_err(|e| e.to_string())?; let (command, project_path): (Command, String) = stmt @@ -706,14 +702,12 @@ pub fn get_project_commands( project_id: i64, ) -> Result, String> { let db = db.lock().map_err(|e| e.to_string())?; - let query = format!( - "SELECT pc.id, pc.command_id, pc.is_enabled, + let query = "SELECT pc.id, pc.command_id, pc.is_enabled, c.id, c.name, c.description, c.content, c.allowed_tools, c.argument_hint, c.model, c.tags, c.source, c.source_path, c.is_favorite, c.created_at, c.updated_at FROM project_commands pc JOIN commands c ON pc.command_id = c.id WHERE pc.project_id = ? - ORDER BY c.name" - ); + ORDER BY c.name".to_string(); let mut stmt = db.conn().prepare(&query).map_err(|e| e.to_string())?; let commands = stmt diff --git a/src-tauri/src/commands/mcp_registry.rs b/src-tauri/src/commands/mcp_registry.rs index 9e913250..283dd8f8 100644 --- a/src-tauri/src/commands/mcp_registry.rs +++ b/src-tauri/src/commands/mcp_registry.rs @@ -94,18 +94,15 @@ pub fn import_mcp_from_registry_in_db( let args_json = entry .args .as_ref() - .map(|a| serde_json::to_string(a).ok()) - .flatten(); + .and_then(|a| serde_json::to_string(a).ok()); let headers_json = entry .headers .as_ref() - .map(|h| serde_json::to_string(h).ok()) - .flatten(); + .and_then(|h| serde_json::to_string(h).ok()); let env_json = entry .env .as_ref() - .map(|e| serde_json::to_string(e).ok()) - .flatten(); + .and_then(|e| serde_json::to_string(e).ok()); db.conn() .execute( diff --git a/src-tauri/src/commands/mcp_server.rs b/src-tauri/src/commands/mcp_server.rs index 2315b995..9be9ece0 100644 --- a/src-tauri/src/commands/mcp_server.rs +++ b/src-tauri/src/commands/mcp_server.rs @@ -3,9 +3,7 @@ //! These commands allow the frontend to start/stop and configure the MCP server. use crate::db::Database; -use crate::mcp_server::server::{ - generate_self_mcp_entry, McpServerConfig, McpServerStatus, -}; +use crate::mcp_server::server::{generate_self_mcp_entry, McpServerConfig, McpServerStatus}; use crate::mcp_server::McpServerState; use log::info; use serde_json::Value; diff --git a/src-tauri/src/commands/skills.rs b/src-tauri/src/commands/skills.rs index 02e56eb1..0facdb46 100644 --- a/src-tauri/src/commands/skills.rs +++ b/src-tauri/src/commands/skills.rs @@ -280,13 +280,11 @@ pub(crate) fn delete_skill_with_cleanup(db: &Database, id: i64) -> Result<(), St #[tauri::command] pub fn get_global_skills(db: State<'_, Arc>>) -> Result, String> { let db = db.lock().map_err(|e| e.to_string())?; - let query = format!( - "SELECT gs.id, gs.skill_id, gs.is_enabled, + let query = "SELECT gs.id, gs.skill_id, gs.is_enabled, s.id, s.name, s.description, s.content, s.allowed_tools, s.model, s.disable_model_invocation, s.tags, s.source, s.source_path, s.is_favorite, s.created_at, s.updated_at FROM global_skills gs JOIN skills s ON gs.skill_id = s.id - ORDER BY s.name" - ); + ORDER BY s.name".to_string(); let mut stmt = db.conn().prepare(&query).map_err(|e| e.to_string())?; let skills = stmt @@ -400,12 +398,10 @@ pub fn toggle_global_skill( .map_err(|e| e.to_string())?; // Get the skill details - let query = format!( - "SELECT s.id, s.name, s.description, s.content, s.allowed_tools, s.model, s.disable_model_invocation, s.tags, s.source, s.source_path, s.is_favorite, s.created_at, s.updated_at + let query = "SELECT s.id, s.name, s.description, s.content, s.allowed_tools, s.model, s.disable_model_invocation, s.tags, s.source, s.source_path, s.is_favorite, s.created_at, s.updated_at FROM global_skills gs JOIN skills s ON gs.skill_id = s.id - WHERE gs.id = ?" - ); + WHERE gs.id = ?".to_string(); let mut stmt = db_guard.conn().prepare(&query).map_err(|e| e.to_string())?; let skill: Skill = stmt @@ -571,13 +567,11 @@ pub fn toggle_project_skill( .map_err(|e| e.to_string())?; // Get project path and skill details - let query = format!( - "SELECT p.path, s.id, s.name, s.description, s.content, s.allowed_tools, s.model, s.disable_model_invocation, s.tags, s.source, s.source_path, s.is_favorite, s.created_at, s.updated_at + let query = "SELECT p.path, s.id, s.name, s.description, s.content, s.allowed_tools, s.model, s.disable_model_invocation, s.tags, s.source, s.source_path, s.is_favorite, s.created_at, s.updated_at FROM project_skills ps JOIN projects p ON ps.project_id = p.id JOIN skills s ON ps.skill_id = s.id - WHERE ps.id = ?" - ); + WHERE ps.id = ?".to_string(); let mut stmt = db_guard.conn().prepare(&query).map_err(|e| e.to_string())?; let (project_path, skill): (String, Skill) = stmt @@ -631,14 +625,12 @@ pub fn get_project_skills( project_id: i64, ) -> Result, String> { let db = db.lock().map_err(|e| e.to_string())?; - let query = format!( - "SELECT ps.id, ps.skill_id, ps.is_enabled, + let query = "SELECT ps.id, ps.skill_id, ps.is_enabled, s.id, s.name, s.description, s.content, s.allowed_tools, s.model, s.disable_model_invocation, s.tags, s.source, s.source_path, s.is_favorite, s.created_at, s.updated_at FROM project_skills ps JOIN skills s ON ps.skill_id = s.id WHERE ps.project_id = ? - ORDER BY s.name" - ); + ORDER BY s.name".to_string(); let mut stmt = db.conn().prepare(&query).map_err(|e| e.to_string())?; let skills = stmt diff --git a/src-tauri/src/services/claude_settings.rs b/src-tauri/src/services/claude_settings.rs index 51d187e5..5fc305a1 100644 --- a/src-tauri/src/services/claude_settings.rs +++ b/src-tauri/src/services/claude_settings.rs @@ -500,7 +500,7 @@ pub fn write_claude_settings( set_or_remove_string_in(&mut attribution, "pr", &settings.attribution_pr); // If attribution object is now empty, remove it - if attribution.as_object().map_or(true, |o| o.is_empty()) { + if attribution.as_object().is_none_or(|o| o.is_empty()) { if let Some(obj) = file_settings.as_object_mut() { obj.remove("attribution"); } @@ -521,7 +521,7 @@ pub fn write_claude_settings( // Check if the serialized sandbox object has any non-null values if sandbox_value .as_object() - .map_or(true, |o| o.values().all(|v| v.is_null())) + .is_none_or(|o| o.values().all(|v| v.is_null())) { if let Some(obj) = file_settings.as_object_mut() { obj.remove("sandbox"); @@ -633,7 +633,7 @@ pub fn write_claude_settings( &settings.file_suggestion_command, ); - if file_suggestion.as_object().map_or(true, |o| o.is_empty()) { + if file_suggestion.as_object().is_none_or(|o| o.is_empty()) { if let Some(obj) = file_settings.as_object_mut() { obj.remove("fileSuggestion"); } @@ -2383,7 +2383,7 @@ mod tests { let _file_settings = read_settings_file(&path).unwrap(); // Test sandbox serialization with null network - let sandbox_value = serde_json::to_value(&settings.sandbox.as_ref().unwrap()).unwrap(); + let sandbox_value = serde_json::to_value(settings.sandbox.as_ref().unwrap()).unwrap(); assert!(sandbox_value.get("enabled").is_some()); // Verify the sandbox has an enabled field diff --git a/src-tauri/src/services/debug_logger.rs b/src-tauri/src/services/debug_logger.rs index 36b2ec96..6f45250c 100644 --- a/src-tauri/src/services/debug_logger.rs +++ b/src-tauri/src/services/debug_logger.rs @@ -261,9 +261,8 @@ mod tests { fn test_is_debug_enabled_initially_false() { // Note: This may fail if another test enabled debug mode // The global state makes this tricky - let enabled = is_debug_enabled(); - // Just verify it returns a bool - the actual value depends on test order - assert!(enabled == true || enabled == false); + // Value depends on test order; just verify the function doesn't panic. + let _ = is_debug_enabled(); } #[test] diff --git a/src-tauri/src/services/gist_sync.rs b/src-tauri/src/services/gist_sync.rs index 103d3382..8d1e5991 100644 --- a/src-tauri/src/services/gist_sync.rs +++ b/src-tauri/src/services/gist_sync.rs @@ -1054,7 +1054,7 @@ mod tests { }; let json = serde_json::to_string(&config).unwrap(); let deserialized: SyncConfig = serde_json::from_str(&json).unwrap(); - assert_eq!(deserialized.sync_skills, true); + assert!(deserialized.sync_skills); assert_eq!(deserialized.sync_project_claude_mds.len(), 2); } diff --git a/src-tauri/src/services/github_client.rs b/src-tauri/src/services/github_client.rs index 5795fab2..e7dbcaf0 100644 --- a/src-tauri/src/services/github_client.rs +++ b/src-tauri/src/services/github_client.rs @@ -235,7 +235,7 @@ impl GitHubClient { match (&file_content.content, &file_content.encoding) { (Some(content), Some(encoding)) if encoding == "base64" => { // Remove newlines from base64 content - let clean_content = content.replace('\n', "").replace('\r', ""); + let clean_content = content.replace(['\n', '\r'], ""); let decoded = STANDARD.decode(&clean_content)?; Ok(String::from_utf8(decoded)?) } diff --git a/src-tauri/src/services/mcp_client.rs b/src-tauri/src/services/mcp_client.rs index 75ccdfdc..0ee8a85b 100644 --- a/src-tauri/src/services/mcp_client.rs +++ b/src-tauri/src/services/mcp_client.rs @@ -278,21 +278,17 @@ impl StdioMcpClient { let init_result = self.send_request("initialize", Some(init_params))?; // Parse server info and capabilities - self.server_info = if let Some(info) = init_result.get("serverInfo") { - Some(McpServerInfo { - name: info - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or("unknown") - .to_string(), - version: info - .get("version") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - }) - } else { - None - }; + self.server_info = init_result.get("serverInfo").map(|info| McpServerInfo { + name: info + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("unknown") + .to_string(), + version: info + .get("version") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + }); let capabilities = init_result.get("capabilities"); self.resources_supported = capabilities.and_then(|c| c.get("resources")).is_some(); @@ -1274,21 +1270,17 @@ impl StreamableHttpMcpClient { .ok_or_else(|| anyhow!("Empty initialize result"))?; // Parse server info - self.server_info = if let Some(info) = init_result.get("serverInfo") { - Some(McpServerInfo { - name: info - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or("unknown") - .to_string(), - version: info - .get("version") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - }) - } else { - None - }; + self.server_info = init_result.get("serverInfo").map(|info| McpServerInfo { + name: info + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("unknown") + .to_string(), + version: info + .get("version") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + }); let capabilities = init_result.get("capabilities"); self.resources_supported = capabilities.and_then(|c| c.get("resources")).is_some(); @@ -3698,9 +3690,9 @@ data: "result":{}} let json = serde_json::to_string(&original).unwrap(); let parsed: ToolCallResult = serde_json::from_str(&json).unwrap(); - assert_eq!(parsed.success, true); + assert!(parsed.success); assert_eq!(parsed.content.len(), 2); - assert_eq!(parsed.is_error, false); + assert!(!parsed.is_error); assert!(parsed.error.is_none()); assert_eq!(parsed.execution_time_ms, 123); } @@ -4738,21 +4730,17 @@ data: "result":{}} } }); - let server_info = if let Some(info) = init_result.get("serverInfo") { - Some(McpServerInfo { - name: info - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or("unknown") - .to_string(), - version: info - .get("version") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - }) - } else { - None - }; + let server_info = init_result.get("serverInfo").map(|info| McpServerInfo { + name: info + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("unknown") + .to_string(), + version: info + .get("version") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + }); assert!(server_info.is_some()); let si = server_info.unwrap(); assert_eq!(si.name, "my-mcp-server"); @@ -4771,21 +4759,17 @@ data: "result":{}} "capabilities": {} }); - let server_info = if let Some(info) = init_result.get("serverInfo") { - Some(McpServerInfo { - name: info - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or("unknown") - .to_string(), - version: info - .get("version") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - }) - } else { - None - }; + let server_info = init_result.get("serverInfo").map(|info| McpServerInfo { + name: info + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("unknown") + .to_string(), + version: info + .get("version") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + }); assert!(server_info.is_none()); } diff --git a/src-tauri/src/services/mcp_registry.rs b/src-tauri/src/services/mcp_registry.rs index f2482a92..82076424 100644 --- a/src-tauri/src/services/mcp_registry.rs +++ b/src-tauri/src/services/mcp_registry.rs @@ -406,7 +406,11 @@ impl RegistryServer { fn extract_short_name(full_name: &str) -> String { // "io.github.user/my-mcp-server" -> "my-mcp-server" - full_name.split('/').last().unwrap_or(full_name).to_string() + full_name + .split('/') + .next_back() + .unwrap_or(full_name) + .to_string() } fn package_to_mcp_entry(server: &RegistryServer, package: &Package) -> Result { diff --git a/src-tauri/src/services/repo_parser.rs b/src-tauri/src/services/repo_parser.rs index 23b5137d..cc1ff31c 100644 --- a/src-tauri/src/services/repo_parser.rs +++ b/src-tauri/src/services/repo_parser.rs @@ -41,10 +41,10 @@ const JUNK_DIRS: &[&str] = &[ /// Check if a file path should be skipped pub fn should_skip_file(path: &str) -> bool { let path_lower = path.to_lowercase(); - let file_name = path_lower.split('/').last().unwrap_or(&path_lower); + let file_name = path_lower.split('/').next_back().unwrap_or(&path_lower); // Check if it's a junk file - if JUNK_FILES.iter().any(|junk| file_name == *junk) { + if JUNK_FILES.contains(&file_name) { return true; } @@ -240,7 +240,7 @@ pub fn parse_readme_for_skills(content: &str) -> Vec { // Extract name from URL path (e.g., /commands/commit.md -> commit) let name = url .split('/') - .last() + .next_back() .unwrap_or("") .trim_end_matches(".md") .to_string(); @@ -359,7 +359,7 @@ pub fn parse_readme_for_skills(content: &str) -> Vec { /// Parse a markdown skill/command file /// Extracts frontmatter and content pub fn parse_skill_file(content: &str, file_path: &str) -> Option { - let file_name = file_path.split('/').last().unwrap_or(file_path); + let file_name = file_path.split('/').next_back().unwrap_or(file_path); let name = file_name.trim_end_matches(".md"); // Parse YAML frontmatter if present @@ -390,7 +390,7 @@ pub fn parse_skill_file(content: &str, file_path: &str) -> Option { /// Parse a markdown subagent file pub fn parse_subagent_file(content: &str, file_path: &str) -> Option { - let file_name = file_path.split('/').last().unwrap_or(file_path); + let file_name = file_path.split('/').next_back().unwrap_or(file_path); let name = file_name.trim_end_matches(".md"); let (frontmatter, body) = parse_frontmatter(content); diff --git a/src-tauri/src/services/session_explorer.rs b/src-tauri/src/services/session_explorer.rs index 0851712d..60575f81 100644 --- a/src-tauri/src/services/session_explorer.rs +++ b/src-tauri/src/services/session_explorer.rs @@ -516,19 +516,17 @@ fn parse_session_summary(path: &Path, session_id: &str) -> Result Result= 1); + assert!(!result.sessions.is_empty()); } // ========================================================================= diff --git a/src-tauri/src/services/statusline_gallery.rs b/src-tauri/src/services/statusline_gallery.rs index 776eddfb..127dba8a 100644 --- a/src-tauri/src/services/statusline_gallery.rs +++ b/src-tauri/src/services/statusline_gallery.rs @@ -32,7 +32,7 @@ pub async fn fetch_gallery_from_url( /// Get the gallery URL from app_settings, falling back to default pub fn get_gallery_url(db: &Database) -> String { db.get_setting("statusline_gallery_url") - .unwrap_or_else(|| get_default_gallery_url()) + .unwrap_or_else(get_default_gallery_url) } /// Set the gallery URL in app_settings From 9dd1538c1f1060c625b1989d529b2b43fbfd2589 Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 20:08:37 -0400 Subject: [PATCH 06/10] chore(clippy): accept &Path instead of &PathBuf in helper signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clippy::ptr_arg prefers &Path over &PathBuf because the former is a slice type and avoids a pointless heap indirection. 10 sites across 3 files: - src/services/debug_logger.rs (enable_debug_logging, get_logs_dir, get_debug_flag_path) - src/utils/paths.rs (project_mcp_file, project_settings_file) - src/utils/opencode_paths.rs (5 project_opencode_* helpers) Call sites already pass &PathBuf, which auto-dereferences to &Path — no caller changes required. Co-Authored-By: Claude --- src-tauri/src/services/debug_logger.rs | 8 ++++---- src-tauri/src/utils/opencode_paths.rs | 12 ++++++------ src-tauri/src/utils/paths.rs | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src-tauri/src/services/debug_logger.rs b/src-tauri/src/services/debug_logger.rs index 6f45250c..b146df29 100644 --- a/src-tauri/src/services/debug_logger.rs +++ b/src-tauri/src/services/debug_logger.rs @@ -2,7 +2,7 @@ use anyhow::Result; use chrono::Local; use std::fs::{self, File, OpenOptions}; use std::io::Write; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Mutex; @@ -22,7 +22,7 @@ pub fn get_log_file_path() -> Option { } /// Enable debug logging, creating a new log file -pub fn enable_debug_logging(app_data_dir: &PathBuf) -> Result { +pub fn enable_debug_logging(app_data_dir: &Path) -> Result { // Create logs directory let logs_dir = app_data_dir.join("logs"); fs::create_dir_all(&logs_dir)?; @@ -168,12 +168,12 @@ pub fn write_log_with_context( } /// Get the logs directory path -pub fn get_logs_dir(app_data_dir: &PathBuf) -> PathBuf { +pub fn get_logs_dir(app_data_dir: &Path) -> PathBuf { app_data_dir.join("logs") } /// Get the path to the debug persistence flag file -fn get_debug_flag_path(app_data_dir: &PathBuf) -> PathBuf { +fn get_debug_flag_path(app_data_dir: &Path) -> PathBuf { app_data_dir.join("debug_enabled") } diff --git a/src-tauri/src/utils/opencode_paths.rs b/src-tauri/src/utils/opencode_paths.rs index 500cb30c..d553973a 100644 --- a/src-tauri/src/utils/opencode_paths.rs +++ b/src-tauri/src/utils/opencode_paths.rs @@ -1,6 +1,6 @@ use anyhow::Result; use directories::BaseDirs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; /// OpenCode configuration paths /// OpenCode stores its config in ~/.config/opencode/ on all platforms @@ -50,31 +50,31 @@ pub fn is_opencode_installed() -> bool { /// Get project-level OpenCode directory #[cfg(test)] -pub fn project_opencode_dir(project_path: &PathBuf) -> PathBuf { +pub fn project_opencode_dir(project_path: &Path) -> PathBuf { project_path.join(".opencode") } /// Get project-level OpenCode config file #[cfg(test)] -pub fn project_opencode_config(project_path: &PathBuf) -> PathBuf { +pub fn project_opencode_config(project_path: &Path) -> PathBuf { project_path.join("opencode.json") } /// Get project-level OpenCode command directory #[cfg(test)] -pub fn project_opencode_command_dir(project_path: &PathBuf) -> PathBuf { +pub fn project_opencode_command_dir(project_path: &Path) -> PathBuf { project_path.join(".opencode").join("command") } /// Get project-level OpenCode agent directory #[cfg(test)] -pub fn project_opencode_agent_dir(project_path: &PathBuf) -> PathBuf { +pub fn project_opencode_agent_dir(project_path: &Path) -> PathBuf { project_path.join(".opencode").join("agent") } /// Get project-level OpenCode plugin directory #[cfg(test)] -pub fn project_opencode_plugin_dir(project_path: &PathBuf) -> PathBuf { +pub fn project_opencode_plugin_dir(project_path: &Path) -> PathBuf { project_path.join(".opencode").join("plugin") } diff --git a/src-tauri/src/utils/paths.rs b/src-tauri/src/utils/paths.rs index 31d6bd20..050047a5 100644 --- a/src-tauri/src/utils/paths.rs +++ b/src-tauri/src/utils/paths.rs @@ -1,6 +1,6 @@ use anyhow::Result; use directories::BaseDirs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; pub struct ClaudePathsInternal { #[allow(dead_code)] @@ -43,12 +43,12 @@ pub fn normalize_path(path: &str) -> String { } #[allow(dead_code)] -pub fn project_mcp_file(project_path: &PathBuf) -> PathBuf { +pub fn project_mcp_file(project_path: &Path) -> PathBuf { project_path.join(".claude").join(".mcp.json") } #[allow(dead_code)] -pub fn project_settings_file(project_path: &PathBuf) -> PathBuf { +pub fn project_settings_file(project_path: &Path) -> PathBuf { project_path.join(".claude").join("settings.local.json") } From 414b4d010fca2aedca2a76a8310584b360ed494d Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 20:10:28 -0400 Subject: [PATCH 07/10] chore(clippy): allow type_complexity on DB-row-tuple helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 7 command helpers use multi-field tuples (7-10 fields) for rusqlite row extraction. These tuples ARE the domain shape — introducing type aliases would just duplicate the tuple next to the fn without adding meaning, and the existing file-local McpTuple aliases in services/*_config.rs follow a different shape (writer tuples, not reader tuples). Annotating with #[allow(clippy::type_complexity)] on the containing fn matches the established pattern for 'this IS the data shape' cases. Co-Authored-By: Claude --- src-tauri/src/commands/config.rs | 1 + src-tauri/src/commands/mcp.rs | 1 + src-tauri/src/commands/mcp_session.rs | 1 + src-tauri/src/commands/mcp_test.rs | 2 ++ src-tauri/src/commands/permissions.rs | 1 + src-tauri/src/commands/projects.rs | 1 + 6 files changed, 7 insertions(+) diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs index 0225bf60..e7163bbd 100644 --- a/src-tauri/src/commands/config.rs +++ b/src-tauri/src/commands/config.rs @@ -70,6 +70,7 @@ pub fn sync_global_config(db: State<'_, Arc>>) -> Result<(), Str } /// Sync global config from database to disk (reusable helper without Tauri State) +#[allow(clippy::type_complexity)] pub(crate) fn sync_global_config_from_db(db: &Database) -> Result<(), String> { use crate::commands::settings::get_enabled_editors_from_db; use crate::services::{ diff --git a/src-tauri/src/commands/mcp.rs b/src-tauri/src/commands/mcp.rs index ddfa8b37..0db923bb 100644 --- a/src-tauri/src/commands/mcp.rs +++ b/src-tauri/src/commands/mcp.rs @@ -235,6 +235,7 @@ pub(crate) fn delete_mcp_impl(db: &Database, id: i64) -> Result<(), String> { } /// Duplicate an MCP in the database +#[allow(clippy::type_complexity)] pub(crate) fn duplicate_mcp_impl(db: &Database, id: i64) -> Result { // Get original let mut stmt = db diff --git a/src-tauri/src/commands/mcp_session.rs b/src-tauri/src/commands/mcp_session.rs index a032159c..481d42aa 100644 --- a/src-tauri/src/commands/mcp_session.rs +++ b/src-tauri/src/commands/mcp_session.rs @@ -25,6 +25,7 @@ pub struct McpSessionData { } /// Extract MCP session data from the database (no Tauri State dependency) +#[allow(clippy::type_complexity)] pub(crate) fn get_mcp_session_data_from_db( db: &Database, mcp_id: i64, diff --git a/src-tauri/src/commands/mcp_test.rs b/src-tauri/src/commands/mcp_test.rs index 279832a4..b535e5df 100644 --- a/src-tauri/src/commands/mcp_test.rs +++ b/src-tauri/src/commands/mcp_test.rs @@ -10,6 +10,7 @@ use std::sync::{Arc, Mutex}; use tauri::State; /// Extract MCP test data including source field from the database (no Tauri State dependency) +#[allow(clippy::type_complexity)] pub fn get_mcp_test_data_with_source_from_db( db: &Database, mcp_id: i64, @@ -164,6 +165,7 @@ pub fn test_mcp_config( /// Extract MCP data from database for testing #[cfg_attr(not(test), allow(dead_code))] +#[allow(clippy::type_complexity)] pub fn get_mcp_test_data_from_db( db: &Database, mcp_id: i64, diff --git a/src-tauri/src/commands/permissions.rs b/src-tauri/src/commands/permissions.rs index 67d4027b..5a159ac6 100644 --- a/src-tauri/src/commands/permissions.rs +++ b/src-tauri/src/commands/permissions.rs @@ -227,6 +227,7 @@ pub fn get_permission_templates( } /// Seed default permission templates (no Tauri State dependency) +#[allow(clippy::type_complexity)] pub(crate) fn seed_permission_templates_impl(db: &Database) -> Result<(), String> { // Check if templates already exist let count: i64 = db diff --git a/src-tauri/src/commands/projects.rs b/src-tauri/src/commands/projects.rs index 42c71dfa..6ab79e41 100644 --- a/src-tauri/src/commands/projects.rs +++ b/src-tauri/src/commands/projects.rs @@ -246,6 +246,7 @@ pub fn toggle_project_mcp( } #[tauri::command] +#[allow(clippy::type_complexity)] pub fn sync_project_config( db: State<'_, Arc>>, project_id: i64, From 958b06117d09299adad9f7f2f50a682efc4bd618 Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 20:16:09 -0400 Subject: [PATCH 08/10] chore(clippy): resolve long-tail warnings to reach zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Final cleanup batch: - opencode_paths.rs: #[cfg(test)] use std::path::Path; — Path is only needed by the cfg(test)-gated helpers that now take &Path. - debug_logger.rs: &PathBuf -> &Path on 3 more helpers (persist_debug_enabled, is_debug_persisted, init_from_persisted). Missed in the first PathBuf pass. - db/models.rs: #[cfg_attr(not(test), allow(dead_code))] on is_powerline and is_powerline_round — test-only consumers. - docker/client.rs: #[allow(dead_code)] on connect_with_params (private helper used via ping_host) and ping_host (public API held for future use). - docker/devcontainer.rs: #[allow(dead_code)] on the impl block — several methods are defined for the DevcontainerConfig API shape but not all are consumed today. - commands/mod.rs: #[allow(clippy::module_inception)] on `pub mod commands` — the nested name mirrors the Claude Code commands domain concept; renaming would cascade through imports. - mcp_gateway/tools.rs: #[allow(clippy::manual_async_fn)] on impl ServerHandler — rmcp's trait uses impl Future return shape; async fn in traits isn't usable here without widening the bound. - commands/scanner.rs: removed tautological assert!(true) in the compilation-smoke-test (comment documents intent instead). - services/scanner.rs: - #[allow(clippy::too_many_arguments)] on get_or_create_mcp (9/7) - strip_prefix("---") rewrite in parse_frontmatter - assert!(!fm.contains_key("empty_key")) replaces .get().is_none() - #[allow(non_snake_case)] on test_parse_skill_file_with_allowedTools_camelCase where the camelCase mirrors the schema field under test. - services/mcp_registry.rs: filter_map always-Some -> map. Clippy warning count: 17 -> 0. Tests: 2021 passing. Ready to flip CI gate. Co-Authored-By: Claude --- src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/scanner.rs | 3 ++- src-tauri/src/db/models.rs | 2 ++ src-tauri/src/mcp_gateway/tools.rs | 3 +++ src-tauri/src/services/debug_logger.rs | 6 +++--- src-tauri/src/services/docker/client.rs | 2 ++ src-tauri/src/services/docker/devcontainer.rs | 1 + src-tauri/src/services/mcp_registry.rs | 4 ++-- src-tauri/src/services/scanner.rs | 12 +++++++----- src-tauri/src/utils/opencode_paths.rs | 4 +++- 10 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index aada2029..3de6dcaf 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -3,6 +3,7 @@ pub mod analytics; pub mod claude_json; pub mod claude_settings; pub mod cloud_sync; +#[allow(clippy::module_inception)] pub mod commands; pub mod config; pub mod containers; diff --git a/src-tauri/src/commands/scanner.rs b/src-tauri/src/commands/scanner.rs index 7c18132e..245de2bd 100644 --- a/src-tauri/src/commands/scanner.rs +++ b/src-tauri/src/commands/scanner.rs @@ -25,6 +25,7 @@ mod tests { #[test] fn test_scanner_module_compiles() { // Compilation test: ensures imports and function signatures are valid. - assert!(true); + // No runtime behavior to check — the fact that this file compiles is + // the assertion. } } diff --git a/src-tauri/src/db/models.rs b/src-tauri/src/db/models.rs index 09188453..eafdf6fc 100644 --- a/src-tauri/src/db/models.rs +++ b/src-tauri/src/db/models.rs @@ -714,10 +714,12 @@ impl SegmentsPayload { } } + #[cfg_attr(not(test), allow(dead_code))] pub fn is_powerline(&self) -> bool { self.theme == "powerline" || self.theme == "powerline_round" } + #[cfg_attr(not(test), allow(dead_code))] pub fn is_powerline_round(&self) -> bool { self.theme == "powerline_round" } diff --git a/src-tauri/src/mcp_gateway/tools.rs b/src-tauri/src/mcp_gateway/tools.rs index 2b7fb4bb..7aa8f9f9 100644 --- a/src-tauri/src/mcp_gateway/tools.rs +++ b/src-tauri/src/mcp_gateway/tools.rs @@ -70,6 +70,9 @@ impl GatewayServer { } } +// rmcp's ServerHandler trait uses `impl Future` return shape; async fn in traits +// isn't usable here without widening the trait bound. +#[allow(clippy::manual_async_fn)] impl ServerHandler for GatewayServer { fn get_info(&self) -> ServerInfo { ServerInfo::new(ServerCapabilities::builder().enable_tools().build()).with_instructions( diff --git a/src-tauri/src/services/debug_logger.rs b/src-tauri/src/services/debug_logger.rs index b146df29..8fc01536 100644 --- a/src-tauri/src/services/debug_logger.rs +++ b/src-tauri/src/services/debug_logger.rs @@ -178,7 +178,7 @@ fn get_debug_flag_path(app_data_dir: &Path) -> PathBuf { } /// Persist debug mode setting to disk -pub fn persist_debug_enabled(app_data_dir: &PathBuf, enabled: bool) -> Result<()> { +pub fn persist_debug_enabled(app_data_dir: &Path, enabled: bool) -> Result<()> { let flag_path = get_debug_flag_path(app_data_dir); if enabled { // Create the flag file @@ -193,12 +193,12 @@ pub fn persist_debug_enabled(app_data_dir: &PathBuf, enabled: bool) -> Result<() } /// Check if debug mode was persisted (for startup) -pub fn is_debug_persisted(app_data_dir: &PathBuf) -> bool { +pub fn is_debug_persisted(app_data_dir: &Path) -> bool { get_debug_flag_path(app_data_dir).exists() } /// Initialize debug mode from persisted state (call early in startup) -pub fn init_from_persisted(app_data_dir: &PathBuf) -> Result> { +pub fn init_from_persisted(app_data_dir: &Path) -> Result> { if is_debug_persisted(app_data_dir) { let log_path = enable_debug_logging(app_data_dir)?; write_log("INFO", "debug", "Debug mode restored from persisted state")?; diff --git a/src-tauri/src/services/docker/client.rs b/src-tauri/src/services/docker/client.rs index 31207ad2..1205610a 100644 --- a/src-tauri/src/services/docker/client.rs +++ b/src-tauri/src/services/docker/client.rs @@ -50,6 +50,7 @@ impl DockerClientManager { } /// Connect to Docker based on host parameters (for testing connections) + #[allow(dead_code)] fn connect_with_params( host_type: &str, connection_uri: Option<&str>, @@ -76,6 +77,7 @@ impl DockerClientManager { } /// Ping a Docker host by connection parameters + #[allow(dead_code)] pub async fn ping_host( &self, host_type: &str, diff --git a/src-tauri/src/services/docker/devcontainer.rs b/src-tauri/src/services/docker/devcontainer.rs index e25f739b..35a78731 100644 --- a/src-tauri/src/services/docker/devcontainer.rs +++ b/src-tauri/src/services/docker/devcontainer.rs @@ -36,6 +36,7 @@ pub struct DevcontainerConfig { pub container_env: Option>, } +#[allow(dead_code)] impl DevcontainerConfig { pub fn parse(json_str: &str) -> Result { // Strip JSON comments (// and /* */) before parsing diff --git a/src-tauri/src/services/mcp_registry.rs b/src-tauri/src/services/mcp_registry.rs index 82076424..c96b88a4 100644 --- a/src-tauri/src/services/mcp_registry.rs +++ b/src-tauri/src/services/mcp_registry.rs @@ -540,13 +540,13 @@ fn remote_to_mcp_entry(server: &RegistryServer, remote: &Remote) -> RegistryMcpE // Convert Vec to HashMap let headers = remote.headers.as_ref().map(|hdrs| { hdrs.iter() - .filter_map(|h| { + .map(|h| { // Use the value if present, otherwise use a placeholder let value = h .value .clone() .unwrap_or_else(|| format!("${{{}}}", h.name)); - Some((h.name.clone(), value)) + (h.name.clone(), value) }) .collect::>() }); diff --git a/src-tauri/src/services/scanner.rs b/src-tauri/src/services/scanner.rs index f4ca7831..9efa9955 100644 --- a/src-tauri/src/services/scanner.rs +++ b/src-tauri/src/services/scanner.rs @@ -339,6 +339,7 @@ fn get_or_create_project(db: &Database, name: &str, path: &str) -> Result { } /// Get or create an MCP in the library +#[allow(clippy::too_many_arguments)] fn get_or_create_mcp( db: &Database, name: &str, @@ -1043,11 +1044,11 @@ pub(crate) fn parse_frontmatter( ) -> (std::collections::HashMap, String) { let mut frontmatter = std::collections::HashMap::new(); - if content.starts_with("---") { + if let Some(after_prefix) = content.strip_prefix("---") { // Find the closing --- - if let Some(end_pos) = content[3..].find("\n---") { - let fm_content = &content[3..end_pos + 3]; - let body = content[end_pos + 7..].trim_start().to_string(); + if let Some(end_pos) = after_prefix.find("\n---") { + let fm_content = &after_prefix[..end_pos]; + let body = after_prefix[end_pos + 4..].trim_start().to_string(); // Parse simple key: value pairs for line in fm_content.lines() { @@ -2270,7 +2271,7 @@ Body"#; assert_eq!(fm.get("name"), Some(&"test".to_string())); assert_eq!(fm.get("another"), Some(&"value".to_string())); - assert!(fm.get("empty_key").is_none()); + assert!(!fm.contains_key("empty_key")); assert_eq!(body, "Body"); } @@ -3442,6 +3443,7 @@ Skill body."#, // ========================================================================= #[test] + #[allow(non_snake_case)] // Test name mirrors the camelCase field under test. fn test_parse_skill_file_with_allowedTools_camelCase() { let temp_dir = TempDir::new().unwrap(); let skill_path = temp_dir.path().join("camel.md"); diff --git a/src-tauri/src/utils/opencode_paths.rs b/src-tauri/src/utils/opencode_paths.rs index d553973a..298fcaeb 100644 --- a/src-tauri/src/utils/opencode_paths.rs +++ b/src-tauri/src/utils/opencode_paths.rs @@ -1,6 +1,8 @@ use anyhow::Result; use directories::BaseDirs; -use std::path::{Path, PathBuf}; +#[cfg(test)] +use std::path::Path; +use std::path::PathBuf; /// OpenCode configuration paths /// OpenCode stores its config in ~/.config/opencode/ on all platforms From d18601744888e513cf853fd43729a279d44bb1ae Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Wed, 22 Apr 2026 20:16:24 -0400 Subject: [PATCH 09/10] ci(clippy): enforce -D warnings on lib + tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flips the Clippy job to block CI on warnings. Two tightenings: - Drop 'continue-on-error: true'. The comment said 'initially' — eight commits of cleanup later, the baseline is zero warnings, so the gate becomes meaningful. - Add '--lib --tests' to the clippy invocation so the ~120 warnings that lived exclusively in the test target are covered too. Without this the prior gate (if enforced) would have allowed test-only lint debt to accumulate invisibly. All other CI jobs untouched. No policy change beyond Clippy enforcement. Co-Authored-By: Claude --- .github/workflows/rust-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml index f51cb7f2..6dc8f07d 100644 --- a/.github/workflows/rust-tests.yml +++ b/.github/workflows/rust-tests.yml @@ -92,8 +92,7 @@ jobs: - name: Run Clippy working-directory: src-tauri - run: cargo clippy --all-features -- -D warnings - continue-on-error: true # Don't fail the build on clippy warnings initially + run: cargo clippy --lib --tests --all-features -- -D warnings fmt: name: Format From 502b0f41c0080fafd6184e53104d44cef5da0bc6 Mon Sep 17 00:00:00 2001 From: Scot Campbell Date: Thu, 23 Apr 2026 09:36:32 -0400 Subject: [PATCH 10/10] fix(clippy): address rust 1.95 warnings --- .github/workflows/rust-tests.yml | 2 +- src-tauri/src/services/docker/devcontainer.rs | 8 +++----- src-tauri/src/services/sound_player.rs | 5 +++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml index 6dc8f07d..70d28d68 100644 --- a/.github/workflows/rust-tests.yml +++ b/.github/workflows/rust-tests.yml @@ -92,7 +92,7 @@ jobs: - name: Run Clippy working-directory: src-tauri - run: cargo clippy --lib --tests --all-features -- -D warnings + run: cargo clippy --all-targets --all-features -- -D warnings fmt: name: Format diff --git a/src-tauri/src/services/docker/devcontainer.rs b/src-tauri/src/services/docker/devcontainer.rs index 35a78731..7368feb4 100644 --- a/src-tauri/src/services/docker/devcontainer.rs +++ b/src-tauri/src/services/docker/devcontainer.rs @@ -149,11 +149,9 @@ fn strip_json_comments(input: &str) -> String { chars.next(); // consume * loop { match chars.next() { - Some('*') => { - if chars.peek() == Some(&'/') { - chars.next(); - break; - } + Some('*') if chars.peek() == Some(&'/') => { + chars.next(); + break; } Some('\n') => result.push('\n'), None => break, diff --git a/src-tauri/src/services/sound_player.rs b/src-tauri/src/services/sound_player.rs index 6bd9c9b3..d0465e3e 100644 --- a/src-tauri/src/services/sound_player.rs +++ b/src-tauri/src/services/sound_player.rs @@ -119,7 +119,7 @@ pub fn list_system_sounds() -> Result, String> { } } - sounds.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); + sounds.sort_by_key(|a| a.name.to_lowercase()); info!("[SoundPlayer] Found {} system sounds", sounds.len()); Ok(sounds) } @@ -165,7 +165,7 @@ pub fn list_custom_sounds() -> Result, String> { } } - sounds.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); + sounds.sort_by_key(|a| a.name.to_lowercase()); info!("[SoundPlayer] Found {} custom sounds", sounds.len()); Ok(sounds) } @@ -645,6 +645,7 @@ mod tests { // On macOS this should be Some #[cfg(target_os = "macos")] assert!(path.is_some()); + let _ = path; } // =========================================================================