From b3fd0b02bfbd5e7cd6bfc90e2268909c3398a40f Mon Sep 17 00:00:00 2001 From: Harry19081 <20519290+Harry19081@users.noreply.github.com> Date: Sat, 1 Aug 2026 17:07:04 +0800 Subject: [PATCH 1/2] chore(rust): enforce warning-free clippy baseline --- .github/workflows/ci.yml | 14 ++-- .../src/core/definitions/tests_extended.rs | 2 + .../src/core/interaction/mode_switch.rs | 12 +-- .../providers/cursor_native/interaction.rs | 3 + .../core/providers/cursor_native/provider.rs | 3 + .../agent-core/src/core/providers/factory.rs | 17 ++-- .../src/core/session/launch/launch_helpers.rs | 3 + .../agent-core/src/core/session/turn/entry.rs | 64 +++++++-------- .../impls/orchestration/agent/helpers.rs | 2 + .../orchestration/suggest_mode_switch.rs | 56 ++++++------- .../agent-core/src/core/tools/metadata.rs | 4 +- .../core/turn_executor/tool_execution/mod.rs | 2 + .../src/core/turn_executor/types.rs | 4 +- .../persistence/session_snapshots.rs | 3 + .../src/foundation/utils/pill_resolver.rs | 9 +-- src-tauri/crates/agent-core/src/init/mod.rs | 42 +++++----- .../src/integrations/channels/feishu/api.rs | 2 +- .../src/specialization/skills/prefetch.rs | 3 + .../src/state/commands/session/launch.rs | 2 +- .../crates/bin-gateway-chat-cli/src/main.rs | 80 +++++++++---------- .../src/agent_org_tasks_and_exec_mode.rs | 3 + .../crates/git-api/src/commands/branch.rs | 26 +++--- .../git-api/src/commands/diff/numstat.rs | 9 ++- .../crates/git-api/src/commands/remote.rs | 27 +++---- .../crates/git-api/src/routes/remotes.rs | 12 +-- .../crates/git-api/src/routes/worktrees.rs | 64 +++++++-------- .../src/commands/registry/commands.rs | 6 +- .../src/commands/registry/data/cli_agents.rs | 6 +- .../commands/registry/data/install_methods.rs | 52 ++++++------ .../src/commands/registry/data/types.rs | 6 +- .../key-vault/src/key_store/service/keys.rs | 3 + .../src/sources/codex/app/transcript.rs | 15 ++-- .../src/sources/imported_history/watermark.rs | 2 +- .../orgtrack-core/src/sources/kimi/history.rs | 16 ++-- .../src/usage_dashboard/overview.rs | 3 + src-tauri/crates/perf-utils/src/tests/mod.rs | 1 - .../projects/io/work_items/atomic_tests.rs | 4 + .../src/projects/io/work_items/batch.rs | 2 + .../src/projects/io/work_items/enrichment.rs | 2 + .../src/sync/collab_bridge/tests.rs | 4 + .../session-persistence/src/turn_intents.rs | 2 +- src-tauri/crates/test-runner/src/tests/mod.rs | 3 - .../src/agent_sessions/cli/commands/create.rs | 4 +- .../cli/parsers/acp_common/mod.rs | 3 + .../cursor/session_capture.rs | 3 + .../event_pipeline/agent_core_bridge.rs | 3 + .../session_directory/aggregation.rs | 8 +- src-tauri/src/api/agent/dto_extended_tests.rs | 22 +++-- .../src/orgtrack/external_cli_detection.rs | 3 + .../src/orgtrack/file_session_history.rs | 4 +- src-tauri/src/orgtrack/mod.rs | 3 + .../session_provenance/historical_backfill.rs | 11 ++- .../session_provenance/hook_capture.rs | 11 +-- .../src/orgtrack/usage_dashboard_commands.rs | 3 + 54 files changed, 361 insertions(+), 312 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cad5a8b440..f9375f64dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,13 +73,9 @@ jobs: workspaces: "./src-tauri -> target" shared-key: "ci-macos" - # Clippy runs the full compiler front-end, so it subsumes `cargo check` — - # a compile error fails this step regardless of the lint level. - # - # The current develop baseline has pre-existing Clippy warnings across - # multiple crates. Keep Clippy visible and compilation-blocking without - # letting toolchain lint drift block every feature PR; restore - # `-- -D warnings` after the baseline cleanup lands. - - name: cargo clippy (advisory warnings) + # Clippy runs the full compiler front-end, so it subsumes `cargo check`. + # Check every target and reject new warnings now that the workspace + # baseline is clean. + - name: cargo clippy (all targets, warnings denied) working-directory: src-tauri - run: cargo clippy --workspace + run: cargo clippy --workspace --all-targets -- -D warnings diff --git a/src-tauri/crates/agent-core/src/core/definitions/tests_extended.rs b/src-tauri/crates/agent-core/src/core/definitions/tests_extended.rs index 38ac2f3da7..5dca0dc10f 100644 --- a/src-tauri/crates/agent-core/src/core/definitions/tests_extended.rs +++ b/src-tauri/crates/agent-core/src/core/definitions/tests_extended.rs @@ -5,6 +5,8 @@ //! #[cfg(test)] #[path = "tests_extended.rs"] mod tests_extended; #[cfg(test)] +#[allow(clippy::module_inception)] +// This wrapper keeps the large extended suite isolated when included from resolved.rs. mod tests_extended { use crate::core::definitions::builtin::{ get_builtin_agent, get_builtin_agents, is_builtin_agent, ADE_MANAGER_ID, diff --git a/src-tauri/crates/agent-core/src/core/interaction/mode_switch.rs b/src-tauri/crates/agent-core/src/core/interaction/mode_switch.rs index d4407241e4..0e44d32d04 100644 --- a/src-tauri/crates/agent-core/src/core/interaction/mode_switch.rs +++ b/src-tauri/crates/agent-core/src/core/interaction/mode_switch.rs @@ -260,6 +260,12 @@ impl ModeSwitchManager { } } +impl Default for ModeSwitchManager { + fn default() -> Self { + Self::new() + } +} + #[cfg(test)] mod tests { use super::ModeSwitchManager; @@ -283,9 +289,3 @@ mod tests { assert!(receiver.await.is_err()); } } - -impl Default for ModeSwitchManager { - fn default() -> Self { - Self::new() - } -} diff --git a/src-tauri/crates/agent-core/src/core/providers/cursor_native/interaction.rs b/src-tauri/crates/agent-core/src/core/providers/cursor_native/interaction.rs index ab1f9542db..08d0d9e29c 100644 --- a/src-tauri/crates/agent-core/src/core/providers/cursor_native/interaction.rs +++ b/src-tauri/crates/agent-core/src/core/providers/cursor_native/interaction.rs @@ -21,6 +21,9 @@ use crate::tools::names as tool_names; /// /// Returns `Some(ToolCallRequest)` when the server has completed an MCP or /// task tool call that ORGII should now execute. +#[allow(clippy::too_many_arguments)] +// Keep the stream reducer's mutable accumulators explicit; a relay context +// would obscure which fields this update is allowed to mutate. pub(super) fn handle_interaction_update( update: pb::InteractionUpdate, content: &mut String, diff --git a/src-tauri/crates/agent-core/src/core/providers/cursor_native/provider.rs b/src-tauri/crates/agent-core/src/core/providers/cursor_native/provider.rs index 8754326b4e..6a440281e4 100644 --- a/src-tauri/crates/agent-core/src/core/providers/cursor_native/provider.rs +++ b/src-tauri/crates/agent-core/src/core/providers/cursor_native/provider.rs @@ -534,6 +534,9 @@ impl LLMProvider for CursorNativeProvider { /// `tool_definitions` are the `McpToolDefinition` list we hand back when the /// server asks via `ExecServerMessage::RequestContextArgs`. Empty when the /// caller didn't pass tools. +#[allow(clippy::too_many_arguments)] +// A run combines owned stream state with borrowed execution callbacks. A +// one-use relay struct would add indirection without creating a reusable domain. async fn drive_run( mut stream: RunStream, mut blobs: BlobStore, diff --git a/src-tauri/crates/agent-core/src/core/providers/factory.rs b/src-tauri/crates/agent-core/src/core/providers/factory.rs index ceb3aba876..7b7c6dddc4 100644 --- a/src-tauri/crates/agent-core/src/core/providers/factory.rs +++ b/src-tauri/crates/agent-core/src/core/providers/factory.rs @@ -921,18 +921,17 @@ fn find_api_key_for_provider( ))) } +type AvailableModelCredential = ( + &'static ProviderSpec, + String, + Option, + ProviderProtocol, +); + fn find_credential_by_available_model( model: &str, creds: &[ModelKey], -) -> Result< - Option<( - &'static ProviderSpec, - String, - Option, - ProviderProtocol, - )>, - ProviderError, -> { +) -> Result, ProviderError> { let model_lower = model.to_lowercase(); for cred in creds { if !cred.enabled { diff --git a/src-tauri/crates/agent-core/src/core/session/launch/launch_helpers.rs b/src-tauri/crates/agent-core/src/core/session/launch/launch_helpers.rs index 54e3fd4730..122ec142be 100644 --- a/src-tauri/crates/agent-core/src/core/session/launch/launch_helpers.rs +++ b/src-tauri/crates/agent-core/src/core/session/launch/launch_helpers.rs @@ -15,6 +15,9 @@ use crate::session::turn::streaming::{ use super::launch_workspace::release_work_item_execution_lock_if_present; +#[allow(clippy::too_many_arguments)] +// Failure handling deliberately receives each durable identifier and log +// message explicitly so cleanup cannot accidentally reuse stale launch state. pub(super) async fn handle_background_launch_failure( session_id: &str, agent_org_run_id: Option<&str>, diff --git a/src-tauri/crates/agent-core/src/core/session/turn/entry.rs b/src-tauri/crates/agent-core/src/core/session/turn/entry.rs index efa0ea0f37..e265b20972 100644 --- a/src-tauri/crates/agent-core/src/core/session/turn/entry.rs +++ b/src-tauri/crates/agent-core/src/core/session/turn/entry.rs @@ -99,38 +99,6 @@ fn expand_skill_slash_command(content: &str, workspace: Option<&std::path::Path> } } -#[cfg(test)] -mod tests { - use super::expand_skill_slash_command; - - #[test] - fn skill_slash_command_accepts_newline_after_name() { - let workspace = tempfile::tempdir().expect("create temporary workspace"); - let skill_dir = workspace.path().join(".orgii/skills/newline-skill"); - std::fs::create_dir_all(&skill_dir).expect("create temporary skill directory"); - std::fs::write( - skill_dir.join("SKILL.md"), - "# Newline Skill\n\nFollow the test instructions.", - ) - .expect("write temporary skill"); - - let expanded = expand_skill_slash_command( - "/newline-skill\nrun the relevant frontend spec", - Some(workspace.path()), - ); - - assert!( - expanded.contains("# Newline Skill"), - "expected workspace skill content, got prefix: {:?}", - &expanded[..expanded.len().min(120)] - ); - assert!( - expanded.contains("User task: run the relevant frontend spec"), - "expected newline tail to become the user task" - ); - } -} - // ============================================ // Unified Process Function // ============================================ @@ -246,3 +214,35 @@ pub async fn process_message( .process(&session.id, &content, processing_context) .await } + +#[cfg(test)] +mod tests { + use super::expand_skill_slash_command; + + #[test] + fn skill_slash_command_accepts_newline_after_name() { + let workspace = tempfile::tempdir().expect("create temporary workspace"); + let skill_dir = workspace.path().join(".orgii/skills/newline-skill"); + std::fs::create_dir_all(&skill_dir).expect("create temporary skill directory"); + std::fs::write( + skill_dir.join("SKILL.md"), + "# Newline Skill\n\nFollow the test instructions.", + ) + .expect("write temporary skill"); + + let expanded = expand_skill_slash_command( + "/newline-skill\nrun the relevant frontend spec", + Some(workspace.path()), + ); + + assert!( + expanded.contains("# Newline Skill"), + "expected workspace skill content, got prefix: {:?}", + &expanded[..expanded.len().min(120)] + ); + assert!( + expanded.contains("User task: run the relevant frontend spec"), + "expected newline tail to become the user task" + ); + } +} diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent/helpers.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent/helpers.rs index 5b0a1217f9..b781b0dd62 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent/helpers.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent/helpers.rs @@ -607,6 +607,8 @@ pub(super) fn with_full_result_pointer(session_id: &str, result: String) -> Stri } #[cfg(test)] +#[allow(clippy::field_reassign_with_default)] +// The fixture exposes each optional model field as a separate scenario input. mod resolve_subagent_model_tests { use super::*; use crate::core::config::ReliabilityConfig; diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/suggest_mode_switch.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/suggest_mode_switch.rs index 833f493082..db550f84af 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/suggest_mode_switch.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/suggest_mode_switch.rs @@ -30,34 +30,6 @@ pub struct ModeSwitchToolContext { pub current_mode: std::sync::Mutex>, } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn timeout_choice_defaults_to_skip() { - let choice = mode_switch_timeout_choice(PresencePolicy::default(), "plan"); - - assert!(matches!(choice, ModeSwitchChoice::Skip)); - } - - #[test] - fn timeout_choice_switches_to_plan_when_presence_allows_it() { - let choice = mode_switch_timeout_choice( - PresencePolicy { - mode_switch_auto_plan: true, - ..PresencePolicy::default() - }, - "plan", - ); - - match choice { - ModeSwitchChoice::Switch(mode) => assert_eq!(mode, "plan"), - ModeSwitchChoice::Skip => panic!("expected auto switch"), - } - } -} - impl ModeSwitchToolContext { pub fn new(manager: Arc) -> Self { Self { @@ -283,3 +255,31 @@ impl Tool for SuggestModeSwitchTool { *self.context.session_id.lock().await = Some(session_key.to_string()); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn timeout_choice_defaults_to_skip() { + let choice = mode_switch_timeout_choice(PresencePolicy::default(), "plan"); + + assert!(matches!(choice, ModeSwitchChoice::Skip)); + } + + #[test] + fn timeout_choice_switches_to_plan_when_presence_allows_it() { + let choice = mode_switch_timeout_choice( + PresencePolicy { + mode_switch_auto_plan: true, + ..PresencePolicy::default() + }, + "plan", + ); + + match choice { + ModeSwitchChoice::Switch(mode) => assert_eq!(mode, "plan"), + ModeSwitchChoice::Skip => panic!("expected auto switch"), + } + } +} diff --git a/src-tauri/crates/agent-core/src/core/tools/metadata.rs b/src-tauri/crates/agent-core/src/core/tools/metadata.rs index 614987a335..6216d90521 100644 --- a/src-tauri/crates/agent-core/src/core/tools/metadata.rs +++ b/src-tauri/crates/agent-core/src/core/tools/metadata.rs @@ -44,7 +44,7 @@ impl ToolSchemaCacheScope { } } - pub fn from_str(value: &str) -> Option { + pub fn from_wire_value(value: &str) -> Option { match value { "stable_prefix" => Some(Self::StablePrefix), "live_suffix" => Some(Self::LiveSuffix), @@ -59,7 +59,7 @@ pub fn tool_schema_cache_scope(schema: &Value) -> ToolSchemaCacheScope { schema .get(ORGII_TOOL_SCHEMA_CACHE_SCOPE_KEY) .and_then(Value::as_str) - .and_then(ToolSchemaCacheScope::from_str) + .and_then(ToolSchemaCacheScope::from_wire_value) .unwrap_or(ToolSchemaCacheScope::StablePrefix) } diff --git a/src-tauri/crates/agent-core/src/core/turn_executor/tool_execution/mod.rs b/src-tauri/crates/agent-core/src/core/turn_executor/tool_execution/mod.rs index 829a2e0d12..2157321dd9 100644 --- a/src-tauri/crates/agent-core/src/core/turn_executor/tool_execution/mod.rs +++ b/src-tauri/crates/agent-core/src/core/turn_executor/tool_execution/mod.rs @@ -359,6 +359,8 @@ pub(crate) async fn execute_tool_calls( } #[cfg(test)] +#[allow(clippy::field_reassign_with_default)] +// Budget tests mutate the one field whose boundary behavior they exercise. mod tests { use super::*; use crate::tools::traits::{Tool, ToolError}; diff --git a/src-tauri/crates/agent-core/src/core/turn_executor/types.rs b/src-tauri/crates/agent-core/src/core/turn_executor/types.rs index 4830951e62..0b68aa81b9 100644 --- a/src-tauri/crates/agent-core/src/core/turn_executor/types.rs +++ b/src-tauri/crates/agent-core/src/core/turn_executor/types.rs @@ -208,7 +208,9 @@ pub struct ToolHookIntervention { /// Implementors handle streaming deltas, tool call/result events, /// and persistence. Each agent type provides its own implementation. #[async_trait] -#[allow(unused_variables)] +#[allow(unused_variables, clippy::too_many_arguments)] +// Event implementations share this callback contract across providers; keep +// its event fields explicit instead of introducing provider-specific wrappers. pub trait TurnEventHandler: Send + Sync { /// Called for each streaming text delta from the LLM. fn on_message_delta(&self, session_id: &str, content: &str); diff --git a/src-tauri/crates/agent-core/src/foundation/persistence/session_snapshots.rs b/src-tauri/crates/agent-core/src/foundation/persistence/session_snapshots.rs index bbcc5edc77..8b136834e2 100644 --- a/src-tauri/crates/agent-core/src/foundation/persistence/session_snapshots.rs +++ b/src-tauri/crates/agent-core/src/foundation/persistence/session_snapshots.rs @@ -707,6 +707,9 @@ fn column_exists(conn: &Connection, table_name: &str, column_name: &str) -> Sqli Ok(false) } +#[allow(clippy::too_many_arguments)] +// The column identifiers describe one dynamic SQL projection and remain +// explicit so callers can audit every selected column at the call site. fn query_session_file_tool_rows( conn: &Connection, table_name: &str, diff --git a/src-tauri/crates/agent-core/src/foundation/utils/pill_resolver.rs b/src-tauri/crates/agent-core/src/foundation/utils/pill_resolver.rs index 2d62cbeaa1..7306eef49d 100644 --- a/src-tauri/crates/agent-core/src/foundation/utils/pill_resolver.rs +++ b/src-tauri/crates/agent-core/src/foundation/utils/pill_resolver.rs @@ -28,6 +28,8 @@ struct ResolvedRef { content: String, } +type SkillLoader<'a> = dyn Fn(&str) -> Option + 'a; + /// Expand pill references in a user message, returning the enriched message. /// /// - `message`: the raw user message containing `[type:path]` references @@ -42,7 +44,7 @@ pub fn expand_pill_references( workspace: &Path, ide_repo_path: Option<&str>, workspace_folders: &[String], - skill_loader: Option<&dyn Fn(&str) -> Option>, + skill_loader: Option<&SkillLoader<'_>>, ) -> String { let mut resolved: Vec = Vec::new(); @@ -201,10 +203,7 @@ fn resolve_project_ref(slug: &str) -> Option { /// The leading `/` is stripped to get the bare skill name. The actual loading /// is delegated to `skill_loader` to avoid a downward dependency from the /// foundation layer into the intelligence layer. -fn resolve_skill_ref( - path: &str, - skill_loader: Option<&dyn Fn(&str) -> Option>, -) -> Option { +fn resolve_skill_ref(path: &str, skill_loader: Option<&SkillLoader<'_>>) -> Option { let skill_name = path.trim_start_matches('/'); if skill_name.is_empty() { return None; diff --git a/src-tauri/crates/agent-core/src/init/mod.rs b/src-tauri/crates/agent-core/src/init/mod.rs index 8588e3bcdd..5377c5b946 100644 --- a/src-tauri/crates/agent-core/src/init/mod.rs +++ b/src-tauri/crates/agent-core/src/init/mod.rs @@ -642,27 +642,6 @@ async fn ensure_session_initialized( Ok(runtime) } -#[cfg(test)] -mod tests { - use super::is_model_override_strict; - - #[test] - fn inherited_effective_model_matching_launch_model_is_not_strict_override() { - assert!(!is_model_override_strict( - Some("anthropic/claude-sonnet-4"), - "anthropic/claude-sonnet-4" - )); - } - - #[test] - fn launch_model_different_from_effective_model_is_strict_override() { - assert!(is_model_override_strict( - Some("anthropic/claude-sonnet-4"), - "openai/gpt-4.1" - )); - } -} - /// Register an `AgentSession` object in the in-memory state and rehydrate /// any per-session managers whose state lives in sqlite between app runs. /// @@ -717,3 +696,24 @@ pub async fn register_session_with_definition_and_rehydrate( } } } + +#[cfg(test)] +mod tests { + use super::is_model_override_strict; + + #[test] + fn inherited_effective_model_matching_launch_model_is_not_strict_override() { + assert!(!is_model_override_strict( + Some("anthropic/claude-sonnet-4"), + "anthropic/claude-sonnet-4" + )); + } + + #[test] + fn launch_model_different_from_effective_model_is_strict_override() { + assert!(is_model_override_strict( + Some("anthropic/claude-sonnet-4"), + "openai/gpt-4.1" + )); + } +} diff --git a/src-tauri/crates/agent-core/src/integrations/channels/feishu/api.rs b/src-tauri/crates/agent-core/src/integrations/channels/feishu/api.rs index 6222b07ab7..b798a2ff95 100644 --- a/src-tauri/crates/agent-core/src/integrations/channels/feishu/api.rs +++ b/src-tauri/crates/agent-core/src/integrations/channels/feishu/api.rs @@ -251,7 +251,7 @@ pub(super) async fn download_file( /// Resolve `feishu:image:{key}` / `feishu:file:{key}` media references in an /// InboundMessage to local file paths by downloading from Feishu API and /// persisting to `~/.orgii/session-images/`. -pub(super) async fn resolve_feishu_media(auth: &FeishuAuth, media: &mut Vec) { +pub(super) async fn resolve_feishu_media(auth: &FeishuAuth, media: &mut [String]) { let images_dir = app_paths::session_images_dir(); let _ = std::fs::create_dir_all(&images_dir); tracing::info!( diff --git a/src-tauri/crates/agent-core/src/specialization/skills/prefetch.rs b/src-tauri/crates/agent-core/src/specialization/skills/prefetch.rs index 284658f1ba..d7dace4199 100644 --- a/src-tauri/crates/agent-core/src/specialization/skills/prefetch.rs +++ b/src-tauri/crates/agent-core/src/specialization/skills/prefetch.rs @@ -108,6 +108,9 @@ fn build_selection_query(user_message: &str, skills: &[SkillInfo]) -> String { /// /// Returns a `PrefetchResult` with selected skill names and their full content. /// On failure, returns an empty result (graceful fallback). +#[allow(clippy::too_many_arguments)] +// These values come from distinct runtime owners; wrapping them solely for +// this call would create a relay request with no additional invariant. pub async fn select_skills( provider: &dyn LLMProvider, user_message: &str, diff --git a/src-tauri/crates/agent-core/src/state/commands/session/launch.rs b/src-tauri/crates/agent-core/src/state/commands/session/launch.rs index b37377ba7b..21d38ea9b7 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/launch.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/launch.rs @@ -151,7 +151,7 @@ fn validate_workspace_launch_fields( let has_base_ref = worktree_base_ref.is_some_and(|base| !base.trim().is_empty()); if (isolate || has_existing_worktree) - && !workspace_path.is_some_and(|path| !path.trim().is_empty()) + && workspace_path.is_none_or(|path| path.trim().is_empty()) { return Err("Worktree mode requires workspacePath".to_string()); } diff --git a/src-tauri/crates/bin-gateway-chat-cli/src/main.rs b/src-tauri/crates/bin-gateway-chat-cli/src/main.rs index 8e91b82c08..1ae399e32c 100644 --- a/src-tauri/crates/bin-gateway-chat-cli/src/main.rs +++ b/src-tauri/crates/bin-gateway-chat-cli/src/main.rs @@ -483,46 +483,6 @@ fn parse_script(raw: &str) -> Vec { out } -#[cfg(test)] -mod script_parse_tests { - use super::{parse_script, ScriptStep}; - - #[test] - fn header_before_separator_is_ignored() { - let src = "# Scenario: foo\n\nA user does X. Probes Y.\nAnother prose line.\n\n# === turn-by-turn ===\n\nhi\n\n@wait 2\n\nnext turn\n"; - let steps = parse_script(src); - let users: Vec<&str> = steps - .iter() - .filter_map(|s| match s { - ScriptStep::User(u) => Some(u.as_str()), - _ => None, - }) - .collect(); - assert_eq!(users, vec!["hi", "next turn"]); - } - - #[test] - fn missing_separator_falls_back_to_whole_file() { - let src = "# comment\nhello\nworld\n"; - let steps = parse_script(src); - let users: Vec<&str> = steps - .iter() - .filter_map(|s| match s { - ScriptStep::User(u) => Some(u.as_str()), - _ => None, - }) - .collect(); - assert_eq!(users, vec!["hello", "world"]); - } - - #[test] - fn comments_and_blank_lines_ignored_after_separator() { - let src = "# === turn-by-turn ===\n\n# this is a comment\n\nactual user line\n# another comment\n"; - let steps = parse_script(src); - assert_eq!(steps.len(), 1); - } -} - enum ScriptStep { User(String), Wait(Duration), @@ -719,3 +679,43 @@ impl TranscriptBuffer { fs::write(path, out) } } + +#[cfg(test)] +mod script_parse_tests { + use super::{parse_script, ScriptStep}; + + #[test] + fn header_before_separator_is_ignored() { + let src = "# Scenario: foo\n\nA user does X. Probes Y.\nAnother prose line.\n\n# === turn-by-turn ===\n\nhi\n\n@wait 2\n\nnext turn\n"; + let steps = parse_script(src); + let users: Vec<&str> = steps + .iter() + .filter_map(|s| match s { + ScriptStep::User(u) => Some(u.as_str()), + _ => None, + }) + .collect(); + assert_eq!(users, vec!["hi", "next turn"]); + } + + #[test] + fn missing_separator_falls_back_to_whole_file() { + let src = "# comment\nhello\nworld\n"; + let steps = parse_script(src); + let users: Vec<&str> = steps + .iter() + .filter_map(|s| match s { + ScriptStep::User(u) => Some(u.as_str()), + _ => None, + }) + .collect(); + assert_eq!(users, vec!["hello", "world"]); + } + + #[test] + fn comments_and_blank_lines_ignored_after_separator() { + let src = "# === turn-by-turn ===\n\n# this is a comment\n\nactual user line\n# another comment\n"; + let steps = parse_script(src); + assert_eq!(steps.len(), 1); + } +} diff --git a/src-tauri/crates/e2e-test/src/agent_org_tasks_and_exec_mode.rs b/src-tauri/crates/e2e-test/src/agent_org_tasks_and_exec_mode.rs index ce9557e6ea..de507f18a4 100644 --- a/src-tauri/crates/e2e-test/src/agent_org_tasks_and_exec_mode.rs +++ b/src-tauri/crates/e2e-test/src/agent_org_tasks_and_exec_mode.rs @@ -170,6 +170,9 @@ async fn seed_task( seed_task_with_dependencies(cfg, run_id, id, subject, owner, status, &[], &[]).await } +#[allow(clippy::too_many_arguments)] +// Keeping fixture fields visible makes each orchestration scenario readable at +// the call site; the helper immediately maps them to the canonical seed DTO. async fn seed_task_with_dependencies( cfg: &Config, run_id: &str, diff --git a/src-tauri/crates/git-api/src/commands/branch.rs b/src-tauri/crates/git-api/src/commands/branch.rs index dc668dfc46..7f80b7fdfd 100644 --- a/src-tauri/crates/git-api/src/commands/branch.rs +++ b/src-tauri/crates/git-api/src/commands/branch.rs @@ -260,6 +260,19 @@ pub fn get_default_branch(repo_path: &Path, remote: Option<&str>) -> Result Result { + // Get all branches + let branches_data = list_branches(repo_path)?; + + // Find and return the current branch + branches_data + .branches + .into_iter() + .find(|b| b.is_current) + .ok_or_else(|| "Current branch not found in branch list".to_string()) +} + #[cfg(test)] mod tests { use super::remote_tracking_branch; @@ -292,16 +305,3 @@ mod tests { assert_eq!(remote_tracking_branch("develop"), None); } } - -/// Get current branch with full info -pub fn get_current_branch_info(repo_path: &Path) -> Result { - // Get all branches - let branches_data = list_branches(repo_path)?; - - // Find and return the current branch - branches_data - .branches - .into_iter() - .find(|b| b.is_current) - .ok_or_else(|| "Current branch not found in branch list".to_string()) -} diff --git a/src-tauri/crates/git-api/src/commands/diff/numstat.rs b/src-tauri/crates/git-api/src/commands/diff/numstat.rs index d837865c38..7ebf7b0a35 100644 --- a/src-tauri/crates/git-api/src/commands/diff/numstat.rs +++ b/src-tauri/crates/git-api/src/commands/diff/numstat.rs @@ -17,12 +17,13 @@ struct NumstatCacheEntry { result: CombinedDiffNumstatResult, } +type NumstatCacheKey = (String, String, String); +type NumstatCache = Mutex>; + /// `(repo_path_string, from_ref_string, head_sha)` → cached result. -static NUMSTAT_CACHE: std::sync::OnceLock< - Mutex>, -> = std::sync::OnceLock::new(); +static NUMSTAT_CACHE: std::sync::OnceLock = std::sync::OnceLock::new(); -fn numstat_cache() -> &'static Mutex> { +fn numstat_cache() -> &'static NumstatCache { NUMSTAT_CACHE.get_or_init(|| Mutex::new(HashMap::new())) } diff --git a/src-tauri/crates/git-api/src/commands/remote.rs b/src-tauri/crates/git-api/src/commands/remote.rs index b0ab2aa1fa..746b8b265d 100644 --- a/src-tauri/crates/git-api/src/commands/remote.rs +++ b/src-tauri/crates/git-api/src/commands/remote.rs @@ -392,17 +392,8 @@ pub(crate) fn detect_push_error_type(message: &str) -> GitErrorType { } /// Push to remote -pub fn push_to_remote( - repo_path: &Path, - remote: Option<&str>, - branch: Option<&str>, - set_upstream: bool, - force: bool, - auth_username: Option<&str>, - auth_token: Option<&str>, - store_auth: bool, -) -> Result { - let remote_name = remote.unwrap_or("origin"); +pub fn push_to_remote(repo_path: &Path, request: &PushRequest) -> Result { + let remote_name = request.remote.as_deref().unwrap_or("origin"); // Get current branch name let current_branch = run_git(repo_path, &["rev-parse", "--abbrev-ref", "HEAD"]) @@ -424,7 +415,7 @@ pub fn push_to_remote( // 1. Explicitly requested // 2. No upstream exists // 3. Upstream branch name doesn't match local branch name (renamed branch scenario) - let needs_set_upstream = set_upstream + let needs_set_upstream = request.set_upstream || upstream_branch.as_ref().is_none_or(|upstream| { if let Some(ref current) = current_branch { // Extract branch name from "origin/branch-name" @@ -441,14 +432,14 @@ pub fn push_to_remote( args.push("-u"); } - if force { + if request.force { args.push("--force"); } args.push(remote_name); // Use explicit branch name if provided, otherwise use current branch - if let Some(b) = branch { + if let Some(b) = request.branch.as_deref() { args.push(b); } else if let Some(ref cb) = current_branch { // Push current branch to same-named remote branch @@ -457,7 +448,13 @@ pub fn push_to_remote( log::info!("[GitAPI] Executing: git {:?}", args); - let output = run_remote_git(repo_path, &args, auth_username, auth_token, store_auth)?; + let output = run_remote_git( + repo_path, + &args, + request.auth_username.as_deref(), + request.auth_token.as_deref(), + request.store_auth, + )?; let message = if output.status.success() { let stdout = String::from_utf8_lossy(&output.stdout); diff --git a/src-tauri/crates/git-api/src/routes/remotes.rs b/src-tauri/crates/git-api/src/routes/remotes.rs index d1de761510..3ca2819b91 100644 --- a/src-tauri/crates/git-api/src/routes/remotes.rs +++ b/src-tauri/crates/git-api/src/routes/remotes.rs @@ -196,17 +196,7 @@ pub async fn push( ) -> GitApiResult> { let repo_path = resolve_repo_path(&repo_id, query.path.as_deref())?; - let result = commands::push_to_remote( - &repo_path, - req.remote.as_deref(), - req.branch.as_deref(), - req.set_upstream, - req.force, - req.auth_username.as_deref(), - req.auth_token.as_deref(), - req.store_auth, - ) - .map_err(GitApiError::from_git_error)?; + let result = commands::push_to_remote(&repo_path, &req).map_err(GitApiError::from_git_error)?; Ok(Json(serde_json::json!({ "status": 0, diff --git a/src-tauri/crates/git-api/src/routes/worktrees.rs b/src-tauri/crates/git-api/src/routes/worktrees.rs index 283032c9d7..43f852347a 100644 --- a/src-tauri/crates/git-api/src/routes/worktrees.rs +++ b/src-tauri/crates/git-api/src/routes/worktrees.rs @@ -281,6 +281,38 @@ fn is_pathological_worktree_checkout(files: u32, additions: u32, deletions: u32) files > 100 && deletions > 100_000 && additions < deletions / 100 } +fn validate_new_worktree_path(path: &str) -> GitApiResult { + if path.contains("..") { + return Err(GitApiError::InvalidPath { + path: path.to_string(), + reason: "Path traversal is not allowed".to_string(), + }); + } + let target = PathBuf::from(path); + let Some(parent) = target.parent() else { + return Err(GitApiError::InvalidPath { + path: path.to_string(), + reason: "Worktree path must have a parent directory".to_string(), + }); + }; + let Some(name) = target.file_name() else { + return Err(GitApiError::InvalidPath { + path: path.to_string(), + reason: "Worktree path must have a directory name".to_string(), + }); + }; + let parent = validate_path(&parent.to_string_lossy())?; + Ok(parent.join(name)) +} + +fn resolve_repo_path(repo_id: &str, query_path: Option<&str>) -> GitApiResult { + if let Some(path) = query_path { + validate_path(path) + } else { + lookup_repo_path(repo_id) + } +} + #[cfg(test)] mod tests { use super::{ @@ -317,35 +349,3 @@ mod tests { assert_eq!(cache.len(), DIFF_CACHE_MAX_ENTRIES); } } - -fn validate_new_worktree_path(path: &str) -> GitApiResult { - if path.contains("..") { - return Err(GitApiError::InvalidPath { - path: path.to_string(), - reason: "Path traversal is not allowed".to_string(), - }); - } - let target = PathBuf::from(path); - let Some(parent) = target.parent() else { - return Err(GitApiError::InvalidPath { - path: path.to_string(), - reason: "Worktree path must have a parent directory".to_string(), - }); - }; - let Some(name) = target.file_name() else { - return Err(GitApiError::InvalidPath { - path: path.to_string(), - reason: "Worktree path must have a directory name".to_string(), - }); - }; - let parent = validate_path(&parent.to_string_lossy())?; - Ok(parent.join(name)) -} - -fn resolve_repo_path(repo_id: &str, query_path: Option<&str>) -> GitApiResult { - if let Some(path) = query_path { - validate_path(path) - } else { - lookup_repo_path(repo_id) - } -} diff --git a/src-tauri/crates/key-vault/src/commands/registry/commands.rs b/src-tauri/crates/key-vault/src/commands/registry/commands.rs index ae8f51415e..77dbfdbe90 100644 --- a/src-tauri/crates/key-vault/src/commands/registry/commands.rs +++ b/src-tauri/crates/key-vault/src/commands/registry/commands.rs @@ -124,11 +124,11 @@ fn detect_cli_installation( fn resolve_cli_config_path(kind: CliConfigPathKind, relative_path: &str) -> String { let base = match kind { - CliConfigPathKind::HomeRelative => app_paths::home_dir(), - CliConfigPathKind::XdgConfigRelative => std::env::var_os("XDG_CONFIG_HOME") + CliConfigPathKind::Home => app_paths::home_dir(), + CliConfigPathKind::XdgConfig => std::env::var_os("XDG_CONFIG_HOME") .map(std::path::PathBuf::from) .unwrap_or_else(|| app_paths::home_dir().join(".config")), - CliConfigPathKind::AppDataRelative => std::env::var_os("APPDATA") + CliConfigPathKind::AppData => std::env::var_os("APPDATA") .map(std::path::PathBuf::from) .unwrap_or_else(|| app_paths::home_dir().join(".config")), }; diff --git a/src-tauri/crates/key-vault/src/commands/registry/data/cli_agents.rs b/src-tauri/crates/key-vault/src/commands/registry/data/cli_agents.rs index 5f9ecc2eed..3942ad340e 100644 --- a/src-tauri/crates/key-vault/src/commands/registry/data/cli_agents.rs +++ b/src-tauri/crates/key-vault/src/commands/registry/data/cli_agents.rs @@ -14,7 +14,7 @@ const fn home_config( CliConfigFileEntry { id, label, - path_kind: CliConfigPathKind::HomeRelative, + path_kind: CliConfigPathKind::Home, relative_path, format, secret_bearing, @@ -31,7 +31,7 @@ const fn xdg_config( CliConfigFileEntry { id, label, - path_kind: CliConfigPathKind::XdgConfigRelative, + path_kind: CliConfigPathKind::XdgConfig, relative_path, format, secret_bearing, @@ -48,7 +48,7 @@ const fn app_data_config( CliConfigFileEntry { id, label, - path_kind: CliConfigPathKind::AppDataRelative, + path_kind: CliConfigPathKind::AppData, relative_path, format, secret_bearing, diff --git a/src-tauri/crates/key-vault/src/commands/registry/data/install_methods.rs b/src-tauri/crates/key-vault/src/commands/registry/data/install_methods.rs index 2e6fd4bfca..14b05dc49f 100644 --- a/src-tauri/crates/key-vault/src/commands/registry/data/install_methods.rs +++ b/src-tauri/crates/key-vault/src/commands/registry/data/install_methods.rs @@ -328,32 +328,6 @@ pub(crate) fn cli_uninstall_methods(name: &str) -> Vec { } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn qoder_cli_exposes_official_installers() { - let methods = cli_install_methods("qoder_cli"); - - assert_eq!(methods.len(), 3); - assert!(methods - .iter() - .any(|method| method.command == "curl -fsSL https://qoder.com/install | bash")); - assert!(methods - .iter() - .any(|method| method.command.contains("qoder.com/install.ps1"))); - assert!(methods - .iter() - .any(|method| method.command.contains("qoder.com/install.cmd"))); - } - - #[test] - fn trae_cli_does_not_offer_an_undocumented_installer() { - assert!(cli_install_methods("trae_cli").is_empty()); - } -} - /// Infer install method from the binary path returned by `which`/`where`. /// /// Resolves symlinks first so that e.g. `~/.local/bin/poetry` → @@ -440,3 +414,29 @@ pub(crate) fn infer_install_method(binary_path: &str) -> Option { None } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn qoder_cli_exposes_official_installers() { + let methods = cli_install_methods("qoder_cli"); + + assert_eq!(methods.len(), 3); + assert!(methods + .iter() + .any(|method| method.command == "curl -fsSL https://qoder.com/install | bash")); + assert!(methods + .iter() + .any(|method| method.command.contains("qoder.com/install.ps1"))); + assert!(methods + .iter() + .any(|method| method.command.contains("qoder.com/install.cmd"))); + } + + #[test] + fn trae_cli_does_not_offer_an_undocumented_installer() { + assert!(cli_install_methods("trae_cli").is_empty()); + } +} diff --git a/src-tauri/crates/key-vault/src/commands/registry/data/types.rs b/src-tauri/crates/key-vault/src/commands/registry/data/types.rs index ac333e95dd..8a30dafbf4 100644 --- a/src-tauri/crates/key-vault/src/commands/registry/data/types.rs +++ b/src-tauri/crates/key-vault/src/commands/registry/data/types.rs @@ -22,9 +22,9 @@ pub enum CliConfigFormat { #[derive(Debug, Clone, Copy)] pub(crate) enum CliConfigPathKind { - HomeRelative, - XdgConfigRelative, - AppDataRelative, + Home, + XdgConfig, + AppData, } #[derive(Debug, Clone, Copy)] diff --git a/src-tauri/crates/key-vault/src/key_store/service/keys.rs b/src-tauri/crates/key-vault/src/key_store/service/keys.rs index 4500b7955f..9279341734 100644 --- a/src-tauri/crates/key-vault/src/key_store/service/keys.rs +++ b/src-tauri/crates/key-vault/src/key_store/service/keys.rs @@ -169,6 +169,9 @@ impl KeyService { } /// Update key health status + #[allow(clippy::too_many_arguments)] + // Health refreshes atomically merge independent optional facets. Keeping + // them explicit avoids a second DTO that would mirror the stored key patch. pub fn update_key_health( &self, key_id: &str, diff --git a/src-tauri/crates/orgtrack-core/src/sources/codex/app/transcript.rs b/src-tauri/crates/orgtrack-core/src/sources/codex/app/transcript.rs index e9239b8c45..14c17fb762 100644 --- a/src-tauri/crates/orgtrack-core/src/sources/codex/app/transcript.rs +++ b/src-tauri/crates/orgtrack-core/src/sources/codex/app/transcript.rs @@ -970,20 +970,19 @@ fn observe_codex_catalog_line( *lines_since_boundary = 0; } +type CodexTranscriptLoad = ( + Vec, + Vec, + Vec, +); + fn load_codex_app_from_path_with_mode<'a>( session_id: &'a str, path: &Path, mode: CodexTranscriptCollectionMode<'a>, start_offset: u64, initial_sequence: usize, -) -> Result< - ( - Vec, - Vec, - Vec, - ), - String, -> { +) -> Result { let mut file = fs::File::open(path) .map_err(|err| format!("Failed to open Codex history {}: {err}", path.display()))?; if start_offset > 0 { diff --git a/src-tauri/crates/orgtrack-core/src/sources/imported_history/watermark.rs b/src-tauri/crates/orgtrack-core/src/sources/imported_history/watermark.rs index 6f9931ad0c..0e6a4dc720 100644 --- a/src-tauri/crates/orgtrack-core/src/sources/imported_history/watermark.rs +++ b/src-tauri/crates/orgtrack-core/src/sources/imported_history/watermark.rs @@ -183,7 +183,7 @@ impl BoundaryFingerprint { } } -fn source_file_identity(path: &Path, metadata: &std::fs::Metadata) -> Option { +fn source_file_identity(_path: &Path, metadata: &std::fs::Metadata) -> Option { #[cfg(unix)] { use std::os::unix::fs::MetadataExt; diff --git a/src-tauri/crates/orgtrack-core/src/sources/kimi/history.rs b/src-tauri/crates/orgtrack-core/src/sources/kimi/history.rs index df91aa987f..1680289308 100644 --- a/src-tauri/crates/orgtrack-core/src/sources/kimi/history.rs +++ b/src-tauri/crates/orgtrack-core/src/sources/kimi/history.rs @@ -220,10 +220,11 @@ fn kimi_code_home_for(home: &Path, configured: Option<&std::ffi::OsStr>) -> Path let canonical_home = fs::canonicalize(home).unwrap_or_else(|_| home.to_path_buf()); let canonical_candidate = fs::canonicalize(&candidate).unwrap_or_else(|_| candidate.to_path_buf()); - canonical_candidate - .starts_with(&canonical_home) - .then_some(candidate) - .unwrap_or(fallback) + if canonical_candidate.starts_with(&canonical_home) { + candidate + } else { + fallback + } } fn sync_kimi_history_cache(conn: &mut Connection) -> Result<(), String> { @@ -391,6 +392,9 @@ fn discover_kimi_records_in( }) } +#[allow(clippy::too_many_arguments)] +// Scanner roots and output accumulators have distinct lifetimes and ownership; +// spelling them out keeps filesystem boundaries visible during traversal. fn collect_layout_records( walker: &mut scan_snapshot::SnapshotDirWalker<'_>, root: &Path, @@ -1075,7 +1079,7 @@ fn legacy_timestamp_ms(value: &Value) -> Option { return None; } let millis = timestamp * 1000.0; - (millis.is_finite() && millis > 0.0 && millis <= i64::MAX as f64).then(|| millis as i64) + (millis.is_finite() && millis > 0.0 && millis <= i64::MAX as f64).then_some(millis as i64) } fn code_timestamp_ms(value: &Value) -> Option { @@ -1092,7 +1096,7 @@ fn first_string<'a>(value: &'a Value, keys: &[&str]) -> Option<&'a str> { .filter(|text| !text.is_empty()) } -fn code_context_message<'a>(value: &'a Value) -> Option<(&'a str, &'a Value)> { +fn code_context_message(value: &Value) -> Option<(&str, &Value)> { if value.get("type").and_then(Value::as_str) != Some("context.append_message") { return None; } diff --git a/src-tauri/crates/orgtrack-core/src/usage_dashboard/overview.rs b/src-tauri/crates/orgtrack-core/src/usage_dashboard/overview.rs index e444c5cc29..a1476488c8 100644 --- a/src-tauri/crates/orgtrack-core/src/usage_dashboard/overview.rs +++ b/src-tauri/crates/orgtrack-core/src/usage_dashboard/overview.rs @@ -153,6 +153,9 @@ pub struct UsageOverview { pub has_unknown_round_model: bool, } +#[allow(clippy::too_many_arguments)] +// The overview executes one coordinated scan whose filters, page controls, and +// requested sections must remain independently selectable by CLI and desktop callers. pub fn usage_overview( conn: &Connection, filter: &UsageFilter, diff --git a/src-tauri/crates/perf-utils/src/tests/mod.rs b/src-tauri/crates/perf-utils/src/tests/mod.rs index 075ce97e38..2afefea374 100644 --- a/src-tauri/crates/perf-utils/src/tests/mod.rs +++ b/src-tauri/crates/perf-utils/src/tests/mod.rs @@ -1,4 +1,3 @@ -mod binary_detection_tests; mod diff_patch_tests; mod hash_tests; mod image_luminance_tests; diff --git a/src-tauri/crates/project-management/src/projects/io/work_items/atomic_tests.rs b/src-tauri/crates/project-management/src/projects/io/work_items/atomic_tests.rs index 5830366b79..ca10ad40ef 100644 --- a/src-tauri/crates/project-management/src/projects/io/work_items/atomic_tests.rs +++ b/src-tauri/crates/project-management/src/projects/io/work_items/atomic_tests.rs @@ -1,5 +1,9 @@ //! Tests for the atomic RMW and partial-update wrappers in `super`. +#![allow(clippy::field_reassign_with_default)] +// These tests intentionally build partial updates one field at a time so each +// mutation remains adjacent to the behavior it exercises. + use super::*; use crate::projects::io::projects::write_project; use crate::projects::io::work_items::{ diff --git a/src-tauri/crates/project-management/src/projects/io/work_items/batch.rs b/src-tauri/crates/project-management/src/projects/io/work_items/batch.rs index a63baf4641..fe86327987 100644 --- a/src-tauri/crates/project-management/src/projects/io/work_items/batch.rs +++ b/src-tauri/crates/project-management/src/projects/io/work_items/batch.rs @@ -94,6 +94,8 @@ pub fn batch_update_work_items( } #[cfg(test)] +#[allow(clippy::field_reassign_with_default)] +// Batch tests construct sparse updates incrementally for scenario readability. mod tests { use super::*; use crate::projects::io::labels::write_labels; diff --git a/src-tauri/crates/project-management/src/projects/io/work_items/enrichment.rs b/src-tauri/crates/project-management/src/projects/io/work_items/enrichment.rs index 74a1bfcd1e..cab680589a 100644 --- a/src-tauri/crates/project-management/src/projects/io/work_items/enrichment.rs +++ b/src-tauri/crates/project-management/src/projects/io/work_items/enrichment.rs @@ -282,6 +282,8 @@ fn build_member_map(members: &[MemberEntry]) -> HashMap { } #[cfg(test)] +#[allow(clippy::field_reassign_with_default)] +// Enrichment tests construct sparse updates incrementally for scenario readability. mod tests { use super::*; use crate::projects::io::labels::write_labels; diff --git a/src-tauri/crates/project-management/src/sync/collab_bridge/tests.rs b/src-tauri/crates/project-management/src/sync/collab_bridge/tests.rs index cd69b45979..d714c61297 100644 --- a/src-tauri/crates/project-management/src/sync/collab_bridge/tests.rs +++ b/src-tauri/crates/project-management/src/sync/collab_bridge/tests.rs @@ -1,3 +1,7 @@ +#![allow(clippy::field_reassign_with_default)] +// Sync scenarios intentionally mutate one partial-update field at a time to +// mirror the sequence of local changes under test. + use super::outbox::store_remote_version; use super::wire::now_ms; use super::*; diff --git a/src-tauri/crates/session-persistence/src/turn_intents.rs b/src-tauri/crates/session-persistence/src/turn_intents.rs index 7763f5a033..1283ec94d1 100644 --- a/src-tauri/crates/session-persistence/src/turn_intents.rs +++ b/src-tauri/crates/session-persistence/src/turn_intents.rs @@ -345,7 +345,7 @@ pub fn upsert_initial_on( params![session_id, turn_intent_id, org_run_id], )?; } - let existing = get_intent(&conn, session_id, turn_intent_id)? + let existing = get_intent(conn, session_id, turn_intent_id)? .ok_or_else(|| IntentError::NotFound(turn_intent_id.to_string(), session_id.to_string()))?; if let (Some(existing_org_run_id), Some(requested_org_run_id)) = (existing.org_run_id.as_deref(), org_run_id) diff --git a/src-tauri/crates/test-runner/src/tests/mod.rs b/src-tauri/crates/test-runner/src/tests/mod.rs index 0b334d252c..1bd3c4d100 100644 --- a/src-tauri/crates/test-runner/src/tests/mod.rs +++ b/src-tauri/crates/test-runner/src/tests/mod.rs @@ -1,6 +1,3 @@ -pub mod detection_tests; -pub mod discovery_tests; - const SOURCE_FILES: &[(&str, &str)] = &[ ("commands.rs", include_str!("../commands.rs")), ("discovery.rs", include_str!("../discovery.rs")), diff --git a/src-tauri/src/agent_sessions/cli/commands/create.rs b/src-tauri/src/agent_sessions/cli/commands/create.rs index 3c36d76a48..24eb7071a0 100644 --- a/src-tauri/src/agent_sessions/cli/commands/create.rs +++ b/src-tauri/src/agent_sessions/cli/commands/create.rs @@ -96,9 +96,9 @@ pub async fn cli_agent_create(mut params: CreateCodeSessionParams) -> Result Result; + struct ExternalHistorySourceLoader { source: &'static str, - load_page: fn(&mut rusqlite::Connection, usize, usize) -> Result, + load_page: ExternalHistoryPageLoader, /// Filtered cache-snapshot reader for continuation pages. Sources whose /// page-zero loader filters beyond the generic cache predicate (Cursor /// IDE's listable-session check) must re-apply that filter on "Load /// more", or offsets computed against page zero's filtered stream /// misalign — duplicating rows already shown and surfacing rows page /// zero hides. `None` = the generic cache page matches page zero. - load_continuation_page: - Option Result>, + load_continuation_page: Option, } fn load_claude_code_external_history_page( diff --git a/src-tauri/src/api/agent/dto_extended_tests.rs b/src-tauri/src/api/agent/dto_extended_tests.rs index b51d0402ce..22671ba10f 100644 --- a/src-tauri/src/api/agent/dto_extended_tests.rs +++ b/src-tauri/src/api/agent/dto_extended_tests.rs @@ -2,6 +2,8 @@ // Included from dto.rs via: #[cfg(test)] #[path = "dto_extended_tests.rs"] mod dto_extended_tests_ext; #[cfg(test)] +#[allow(clippy::field_reassign_with_default)] +// DTO scenarios mutate only the configuration field relevant to each conversion. mod dto_extended_tests { // Use full paths since this module is included at the root level of dto.rs use crate::api::agent::dto::{ @@ -2650,17 +2652,21 @@ mod dto_extended_tests { #[test] fn integrations_view_version_constant_not_zero() { - assert!( - IntegrationsView::VERSION > 0, - "IntegrationsView::VERSION must be > 0" - ); + const { + assert!( + IntegrationsView::VERSION > 0, + "IntegrationsView::VERSION must be > 0" + ); + } } #[test] fn agent_runtime_view_version_constant_not_zero() { - assert!( - AgentRuntimeView::VERSION > 0, - "AgentRuntimeView::VERSION must be > 0" - ); + const { + assert!( + AgentRuntimeView::VERSION > 0, + "AgentRuntimeView::VERSION must be > 0" + ); + } } } // end dto_extended_tests diff --git a/src-tauri/src/orgtrack/external_cli_detection.rs b/src-tauri/src/orgtrack/external_cli_detection.rs index 38c52a5cfa..3077d020c9 100644 --- a/src-tauri/src/orgtrack/external_cli_detection.rs +++ b/src-tauri/src/orgtrack/external_cli_detection.rs @@ -488,6 +488,9 @@ pub const EXTERNAL_CLI_SOURCES: &[ExternalCliSourceSpec] = &[ ), ]; +#[allow(clippy::too_many_arguments)] +// The const constructor keeps every registry column visible in the static +// source table; a second builder layer would hide omissions at compile time. const fn source( source_id: &'static str, display_name: &'static str, diff --git a/src-tauri/src/orgtrack/file_session_history.rs b/src-tauri/src/orgtrack/file_session_history.rs index 33cbcd6f9d..abc0c9a500 100644 --- a/src-tauri/src/orgtrack/file_session_history.rs +++ b/src-tauri/src/orgtrack/file_session_history.rs @@ -527,11 +527,13 @@ fn interaction_strength( ) } +type ResolvedInteractionActor = (Option, Option, Option); + fn resolve_interaction_actor( store: &dyn RecordStore, session_cache: &mut HashMap>, interaction: &ResourceInteractionRecord, -) -> Result<(Option, Option, Option), String> { +) -> Result { if let Some(actor_id) = interaction.actor_id.as_deref() { let actor_record = match store.get_session_actor( &interaction.source, diff --git a/src-tauri/src/orgtrack/mod.rs b/src-tauri/src/orgtrack/mod.rs index 9ac6e61f7b..fb47d6c30d 100644 --- a/src-tauri/src/orgtrack/mod.rs +++ b/src-tauri/src/orgtrack/mod.rs @@ -164,6 +164,9 @@ pub async fn orgtrack_get_extraction_memory_gate( } #[cfg(test)] +#[allow(clippy::items_after_test_module)] +// Tauri commands must remain grouped above validation helpers; the tests cover +// both sections without changing the production module layout. mod tests { use super::{is_temporary_diff_path, project_file_session_history}; use orgtrack_core::canonical::{ diff --git a/src-tauri/src/orgtrack/session_provenance/historical_backfill.rs b/src-tauri/src/orgtrack/session_provenance/historical_backfill.rs index c38e233e0c..1351c6dc40 100644 --- a/src-tauri/src/orgtrack/session_provenance/historical_backfill.rs +++ b/src-tauri/src/orgtrack/session_provenance/historical_backfill.rs @@ -932,12 +932,11 @@ fn reconcile_recent_codex_sessions( continue; } let is_quiescent = session_is_quiescent(&session, now_ms); - if !is_quiescent { - if !active_codex_recovery_is_quiet_enough(session.source_mtime_ms, now_ms) - || active_reconciliations >= ACTIVE_CODEX_RECONCILIATION_BATCH_PER_PASS - { - continue; - } + if !is_quiescent + && (!active_codex_recovery_is_quiet_enough(session.source_mtime_ms, now_ms) + || active_reconciliations >= ACTIVE_CODEX_RECONCILIATION_BATCH_PER_PASS) + { + continue; } if !throttle.should_attempt(&session.session_id, is_quiescent, now_ms) { continue; diff --git a/src-tauri/src/orgtrack/session_provenance/hook_capture.rs b/src-tauri/src/orgtrack/session_provenance/hook_capture.rs index 75255cf588..4dfc8f8d02 100644 --- a/src-tauri/src/orgtrack/session_provenance/hook_capture.rs +++ b/src-tauri/src/orgtrack/session_provenance/hook_capture.rs @@ -110,10 +110,10 @@ pub fn capture_hook_stdin(source: &str) -> Result { Ok(envelopes.len() + usize::from(lifecycle.is_some())) } -fn codex_session_start_source_session_id<'a>( +fn codex_session_start_source_session_id( source: HookSource, - payload: &'a serde_json::Value, -) -> Option<&'a str> { + payload: &serde_json::Value, +) -> Option<&str> { if source != HookSource::Codex { return None; } @@ -232,10 +232,7 @@ fn spool_has_capacity(inbox: &Path, incoming_bytes: u64) -> Result continue; }; let path = entry.path(); - if !path - .extension() - .is_some_and(|extension| extension == "json") - { + if path.extension().is_none_or(|extension| extension != "json") { continue; } file_count = file_count.saturating_add(1); diff --git a/src-tauri/src/orgtrack/usage_dashboard_commands.rs b/src-tauri/src/orgtrack/usage_dashboard_commands.rs index 258f70f4eb..ff5c6fc791 100644 --- a/src-tauri/src/orgtrack/usage_dashboard_commands.rs +++ b/src-tauri/src/orgtrack/usage_dashboard_commands.rs @@ -137,6 +137,9 @@ pub async fn usage_dashboard_trends( } /// Optional summary/trends and request-log page from one round-store scan. +#[allow(clippy::too_many_arguments)] +// Tauri serializes these parameters as the existing frontend command contract; +// replacing them with a request object would change the wire payload. #[tauri::command] pub async fn usage_dashboard_overview( bucket: Option, From 8493cce94c110d9ea7947bcdec26d27392e0792a Mon Sep 17 00:00:00 2001 From: Harry19081 <20519290+Harry19081@users.noreply.github.com> Date: Sat, 1 Aug 2026 17:46:46 +0800 Subject: [PATCH 2/2] fix(rust): satisfy Rust 1.97 clippy lints --- .../src/core/providers/anthropic_native/request.rs | 5 +---- .../crates/agent-core/src/orchestrator_notify/handlers.rs | 5 ++--- src-tauri/crates/agent-core/src/state/commands/tools.rs | 2 +- src-tauri/crates/browser/src/layering.rs | 2 +- src-tauri/crates/key-vault/src/providers/google/mod.rs | 2 +- src-tauri/crates/key-vault/src/providers/openai/mod.rs | 2 +- src-tauri/crates/lsp/src/workspace_scan/typescript.rs | 5 ++--- .../crates/orgtrack-core/src/sources/codex/app/normalize.rs | 5 ++--- src-tauri/src/agent_sessions/session_directory/display.rs | 5 ++--- 9 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src-tauri/crates/agent-core/src/core/providers/anthropic_native/request.rs b/src-tauri/crates/agent-core/src/core/providers/anthropic_native/request.rs index a22921d539..d83e41f2e8 100644 --- a/src-tauri/crates/agent-core/src/core/providers/anthropic_native/request.rs +++ b/src-tauri/crates/agent-core/src/core/providers/anthropic_native/request.rs @@ -241,10 +241,7 @@ pub(super) fn apply_headers( req } AnthropicAuthMode::AzureBearer => { - let mut req = req.header( - "Authorization", - format!("Bearer {}", &client.config.api_key), - ); + let mut req = req.header("Authorization", format!("Bearer {}", client.config.api_key)); if !beta_overridden { req = req.header( "anthropic-beta", diff --git a/src-tauri/crates/agent-core/src/orchestrator_notify/handlers.rs b/src-tauri/crates/agent-core/src/orchestrator_notify/handlers.rs index b094fcad85..569b01e685 100644 --- a/src-tauri/crates/agent-core/src/orchestrator_notify/handlers.rs +++ b/src-tauri/crates/agent-core/src/orchestrator_notify/handlers.rs @@ -120,10 +120,9 @@ pub(crate) fn parse_issue_line(line: &str) -> Option = Vec::new(); - for (label, _webview) in app.webviews().iter() { + for label in app.webviews().keys() { if !label.starts_with("browser-session-") { continue; } diff --git a/src-tauri/crates/key-vault/src/providers/google/mod.rs b/src-tauri/crates/key-vault/src/providers/google/mod.rs index 0f3a46216b..8ef1447e81 100644 --- a/src-tauri/crates/key-vault/src/providers/google/mod.rs +++ b/src-tauri/crates/key-vault/src/providers/google/mod.rs @@ -157,7 +157,7 @@ impl GoogleValidator { let proxy_url = base_url.unwrap(); info!( "[Google] Proxy mode — verifying auth via completion test with model: {}", - &models[0] + models[0] ); match self.test_completion(api_key, proxy_url, &models[0]).await { Ok(()) => { diff --git a/src-tauri/crates/key-vault/src/providers/openai/mod.rs b/src-tauri/crates/key-vault/src/providers/openai/mod.rs index 83b4117787..d36912abda 100644 --- a/src-tauri/crates/key-vault/src/providers/openai/mod.rs +++ b/src-tauri/crates/key-vault/src/providers/openai/mod.rs @@ -156,7 +156,7 @@ impl OpenAIValidator { // lightweight completion call using the first discovered model. info!( "[OpenAI] Proxy mode — verifying auth via completion test with model: {}", - &models[0] + models[0] ); match self.test_completion(api_key, url, &models[0]).await { Ok(()) => { diff --git a/src-tauri/crates/lsp/src/workspace_scan/typescript.rs b/src-tauri/crates/lsp/src/workspace_scan/typescript.rs index 579fb6dbfc..d665cb8708 100644 --- a/src-tauri/crates/lsp/src/workspace_scan/typescript.rs +++ b/src-tauri/crates/lsp/src/workspace_scan/typescript.rs @@ -85,10 +85,9 @@ fn parse_tsc_line(line: &str, workspace_path: &str) -> Option Option 1 { diff --git a/src-tauri/src/agent_sessions/session_directory/display.rs b/src-tauri/src/agent_sessions/session_directory/display.rs index a7f2877f5b..0557ed2378 100644 --- a/src-tauri/src/agent_sessions/session_directory/display.rs +++ b/src-tauri/src/agent_sessions/session_directory/display.rs @@ -21,11 +21,10 @@ pub fn generate_display_label(name: &str, user_input: Option<&str>) -> Option