diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml index f51cb7f..70d28d6 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 --all-targets --all-features -- -D warnings fmt: name: Format diff --git a/src-tauri/src/commands/commands.rs b/src-tauri/src/commands/commands.rs index 3009440..3594c44 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/config.rs b/src-tauri/src/commands/config.rs index 0225bf6..e7163bb 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/docker_hosts.rs b/src-tauri/src/commands/docker_hosts.rs index c7eb05b..cfad7d5 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/hooks.rs b/src-tauri/src/commands/hooks.rs index c7e8e6b..e65a6e1 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 48f5105..0db923b 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 @@ -319,18 +320,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 +344,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) } @@ -708,7 +715,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/mcp_registry.rs b/src-tauri/src/commands/mcp_registry.rs index d946f47..283dd8f 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}; @@ -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( @@ -166,6 +163,7 @@ pub fn get_registry_mcp_by_id(db: &Database, id: i64) -> Result>>) -> Result 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 c6477c8..b535e5d 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, @@ -163,6 +164,8 @@ 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, @@ -217,6 +220,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/mod.rs b/src-tauri/src/commands/mod.rs index aada202..3de6dca 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/permissions.rs b/src-tauri/src/commands/permissions.rs index 3c28cc3..5a159ac 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 @@ -366,7 +367,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/projects.rs b/src-tauri/src/commands/projects.rs index 381e110..6ab79e4 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, @@ -498,6 +499,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 +517,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 +544,7 @@ pub(crate) fn get_project_by_id(db: &Database, id: i64) -> Result Result { db.conn() .query_row( @@ -567,6 +571,7 @@ pub(crate) fn get_project_by_path(db: &Database, path: &str) -> Result Result, String> { let mut stmt = db .conn() @@ -765,6 +770,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 8b2a770..935334f 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 4917258..0facdb4 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 @@ -776,6 +768,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 +880,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 +908,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 +931,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]) @@ -1205,7 +1201,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/db/models.rs b/src-tauri/src/db/models.rs index f5c44e5..eafdf6f 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, @@ -713,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" } @@ -767,6 +770,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 a5329a2..712683b 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_gateway/tools.rs b/src-tauri/src/mcp_gateway/tools.rs index 2b7fb4b..7aa8f9f 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/mcp_server/tools.rs b/src-tauri/src/mcp_server/tools.rs index 2866c35..5dcd3d7 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/claude_settings.rs b/src-tauri/src/services/claude_settings.rs index 1611229..5fc305a 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"); } @@ -2380,10 +2380,10 @@ 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(); + 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/codex_config.rs b/src-tauri/src/services/codex_config.rs index ac829b8..acdf2d5 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/config_writer.rs b/src-tauri/src/services/config_writer.rs index 3480509..d85bf46 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/copilot_config.rs b/src-tauri/src/services/copilot_config.rs index 1049d66..ee322e9 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 2eb4e01..26599aa 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/debug_logger.rs b/src-tauri/src/services/debug_logger.rs index 36b2ec9..8fc0153 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,17 +168,17 @@ 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") } /// 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")?; @@ -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/docker/client.rs b/src-tauri/src/services/docker/client.rs index 38a4d2b..1205610 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, @@ -707,7 +709,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); diff --git a/src-tauri/src/services/docker/devcontainer.rs b/src-tauri/src/services/docker/devcontainer.rs index 6230e8a..7368feb 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, @@ -35,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 @@ -104,6 +106,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(); @@ -146,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/gemini_config.rs b/src-tauri/src/services/gemini_config.rs index cd70d1e..a97818d 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/gist_sync.rs b/src-tauri/src/services/gist_sync.rs index 103d338..8d1e599 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 5795fab..e7dbcaf 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 75ccdfd..0ee8a85 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 f2482a9..c96b88a 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 { @@ -536,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/repo_parser.rs b/src-tauri/src/services/repo_parser.rs index 23b5137..cc1ff31 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/rule_writer.rs b/src-tauri/src/services/rule_writer.rs index 1582a48..a1f6a0b 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/scanner.rs b/src-tauri/src/services/scanner.rs index f4ca783..9efa995 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/services/session_explorer.rs b/src-tauri/src/services/session_explorer.rs index d8cef2a..60575f8 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, @@ -514,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/sound_player.rs b/src-tauri/src/services/sound_player.rs index 6bd9c9b..d0465e3 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; } // ========================================================================= diff --git a/src-tauri/src/services/statusline_gallery.rs b/src-tauri/src/services/statusline_gallery.rs index 776eddf..127dba8 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 diff --git a/src-tauri/src/services/statusline_writer.rs b/src-tauri/src/services/statusline_writer.rs index 3cd8f2b..59cd771 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) diff --git a/src-tauri/src/utils/opencode_paths.rs b/src-tauri/src/utils/opencode_paths.rs index 500cb30..298fcae 100644 --- a/src-tauri/src/utils/opencode_paths.rs +++ b/src-tauri/src/utils/opencode_paths.rs @@ -1,5 +1,7 @@ use anyhow::Result; use directories::BaseDirs; +#[cfg(test)] +use std::path::Path; use std::path::PathBuf; /// OpenCode configuration paths @@ -50,31 +52,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 31d6bd2..050047a 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") }