From 30d82148e01c2936e98ea202bfd62c9cd20ff70e Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 22 May 2026 17:50:11 +0200 Subject: [PATCH] clippy: apply auto-fixable warnings across workspace (closes #265 partial) --- Cargo.lock | 1 + hive-ag3nt/src/events.rs | 19 +++----- hive-ag3nt/src/forge_notify.rs | 35 +++++++-------- hive-ag3nt/src/mcp.rs | 2 +- hive-ag3nt/src/turn.rs | 68 ++++++++++++++--------------- hive-ag3nt/src/web_ui.rs | 2 +- hive-c0re/src/actions.rs | 15 +++---- hive-c0re/src/broker.rs | 3 +- hive-c0re/src/container_view.rs | 6 +-- hive-c0re/src/crash_watch.rs | 2 +- hive-c0re/src/events_vacuum.rs | 2 +- hive-c0re/src/forge.rs | 9 ++-- hive-c0re/src/main.rs | 4 +- hive-c0re/src/meta.rs | 5 +-- hive-c0re/src/reminder_scheduler.rs | 2 +- hive-c0re/src/stats_vacuum.rs | 2 +- hive-fr0nt/src/lib.rs | 2 +- hive-sh4re/src/lib.rs | 6 +-- 18 files changed, 83 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1558ce3..1da33aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -589,6 +589,7 @@ dependencies = [ "hive-fr0nt", "hive-sh4re", "libc", + "reqwest", "rusqlite", "serde", "serde_json", diff --git a/hive-ag3nt/src/events.rs b/hive-ag3nt/src/events.rs index ec8ca7e..ac40950 100644 --- a/hive-ag3nt/src/events.rs +++ b/hive-ag3nt/src/events.rs @@ -312,24 +312,19 @@ pub fn context_window_tokens(model: &str) -> u64 { let m = model.to_ascii_lowercase(); // Per-model env vars set by `hyperhive.contextWindowTokens` in Nix. for (key, val) in std::env::vars() { - if let Some(suffix) = key.strip_prefix("HIVE_CONTEXT_WINDOW_TOKENS_") { - if !suffix.is_empty() && m.contains(&suffix.to_ascii_lowercase()) { - if let Ok(v) = val.trim().parse::() { - if v > 0 { + if let Some(suffix) = key.strip_prefix("HIVE_CONTEXT_WINDOW_TOKENS_") + && !suffix.is_empty() && m.contains(&suffix.to_ascii_lowercase()) + && let Ok(v) = val.trim().parse::() + && v > 0 { return v; } - } - } - } } // Global override (single value, any model). - if let Ok(s) = std::env::var("HIVE_CONTEXT_WINDOW_TOKENS") { - if let Ok(v) = s.trim().parse::() { - if v > 0 { + if let Ok(s) = std::env::var("HIVE_CONTEXT_WINDOW_TOKENS") + && let Ok(v) = s.trim().parse::() + && v > 0 { return v; } - } - } // Hard fallback for dev/test outside NixOS where env vars aren't set. 200_000 } diff --git a/hive-ag3nt/src/forge_notify.rs b/hive-ag3nt/src/forge_notify.rs index e023c5c..b043424 100644 --- a/hive-ag3nt/src/forge_notify.rs +++ b/hive-ag3nt/src/forge_notify.rs @@ -93,7 +93,7 @@ pub async fn run(socket: PathBuf, is_manager: bool) { let url = format!("{forge_url}/api/v1/user"); fetch_json(&client, &url, &token) .await - .and_then(|v| v["login"].as_str().map(|s| s.to_owned())) + .and_then(|v| v["login"].as_str().map(std::borrow::ToOwned::to_owned)) .unwrap_or_default() }; if own_login.is_empty() { @@ -184,7 +184,7 @@ fn truncate(s: &str, max: usize) -> String { /// Map a Forgejo review state to a readable action label. /// Returns `None` for non-review states (regular comments have no `state` field; /// `PENDING` means the review was saved but not submitted yet). -/// Forgejo review states: "APPROVED", "REQUEST_CHANGES", "COMMENT", "PENDING". +/// Forgejo review states: "APPROVED", "`REQUEST_CHANGES`", "COMMENT", "PENDING". fn review_state_label(state: &str) -> Option<&str> { match state { "APPROVED" => Some("approved"), @@ -204,7 +204,7 @@ fn review_state_label(state: &str) -> Option<&str> { /// - New item: `[new issue #N repo] title\nurl: ...\nassignee: user` /// - State: `[PR merged #N repo] title\nurl: ...\nassignee: user` /// -/// Assignees (and, for PRs, requested_reviewers) are appended unconditionally +/// Assignees (and, for PRs, `requested_reviewers`) are appended unconditionally /// on all issue/PR notifications (closes #256). /// /// Number is extracted from `html_url` last path segment before any `#`. @@ -246,10 +246,10 @@ async fn format_notification( // Always fetch subject detail for assignee/reviewer metadata (#256). // Keeps agents informed of current ownership without a follow-up fetch. - let subject = if !subject_api_url.is_empty() { - fetch_json(client, subject_api_url, token).await - } else { + let subject = if subject_api_url.is_empty() { None + } else { + fetch_json(client, subject_api_url, token).await }; let is_pr = matches!(notif_type, "Pull Request" | "Pull"); @@ -328,10 +328,10 @@ async fn format_notification( // Review submission on a PR. let kind = format!("PR {review_label}{num}{repo}"); let mut out = format!("[{kind}] {title}\nurl: {url}"); - if !body_text.is_empty() { - out.push_str(&format!("\n\n{author}: {}", truncate(body_text, BODY_TRUNCATE))); - } else { + if body_text.is_empty() { out.push_str(&format!("\n\nreviewer: {author}")); + } else { + out.push_str(&format!("\n\n{author}: {}", truncate(body_text, BODY_TRUNCATE))); } out.push_str(&meta_suffix); Some(out) @@ -457,12 +457,9 @@ async fn poll_once( let body_opt = format_notification(client, token, notif, own_login).await; // None means self-echo — mark read silently, no delivery. - let body = match body_opt { - Some(b) => b, - None => { - mark_read(client, forge_url, token, id).await; - continue; - } + let body = if let Some(b) = body_opt { b } else { + mark_read(client, forge_url, token, id).await; + continue; }; let delivered = if is_manager { @@ -501,9 +498,9 @@ async fn poll_once( // when HIVE_FORGE_KEEP_SUBSCRIPTIONS=1 — triage and other firehose // consumers set this to retain broad repo visibility. let reason = notif["reason"].as_str().unwrap_or(""); - if !keep_subscriptions && reason == "subscribed" { - if let Some(repo) = notif["repository"]["full_name"].as_str() { - if !unsubbed_repos.contains(repo) { + if !keep_subscriptions && reason == "subscribed" + && let Some(repo) = notif["repository"]["full_name"].as_str() + && !unsubbed_repos.contains(repo) { let unsub_url = format!("{forge_url}/api/v1/repos/{repo}/subscription"); match client .delete(&unsub_url) @@ -523,8 +520,6 @@ async fn poll_once( } } } - } - } } } diff --git a/hive-ag3nt/src/mcp.rs b/hive-ag3nt/src/mcp.rs index eb41797..1bd52d5 100644 --- a/hive-ag3nt/src/mcp.rs +++ b/hive-ag3nt/src/mcp.rs @@ -681,7 +681,7 @@ pub async fn serve_manager_stdio(socket: PathBuf) -> Result<()> { #[derive(Debug, serde::Deserialize, schemars::JsonSchema)] pub struct RequestInitConfigArgs { - /// New sub-agent name (≤9 chars). Queues an InitConfig approval; on + /// New sub-agent name (≤9 chars). Queues an `InitConfig` approval; on /// approval hive-c0re seeds the proposed config repo at /// `/agents//config/agent.nix` with the default template. /// After the approval the manager can edit and commit the config before diff --git a/hive-ag3nt/src/turn.rs b/hive-ag3nt/src/turn.rs index 69843e7..db5a69c 100644 --- a/hive-ag3nt/src/turn.rs +++ b/hive-ag3nt/src/turn.rs @@ -272,11 +272,10 @@ pub async fn drive_turn(prompt: &str, files: &TurnFiles, bus: &Bus) -> TurnOutco // turn overflows into the reactive path. Best-effort — never changes // the outcome of the turn that already succeeded, but records it as // `Compacted` so turn stats can distinguish it from a plain `Ok`. - if matches!(outcome, TurnOutcome::Ok) { - if maybe_checkpoint_and_compact(files, bus).await { + if matches!(outcome, TurnOutcome::Ok) + && maybe_checkpoint_and_compact(files, bus).await { return TurnOutcome::Compacted; } - } outcome } @@ -528,42 +527,39 @@ async fn run_claude(prompt: &str, files: &TurnFiles, bus: &Bus) -> Result<(bool, if line.contains(PROMPT_TOO_LONG_MARKER) { flag_out.store(true, Ordering::Relaxed); } - match serde_json::from_str::(&line) { - Ok(v) => { - // Rate-limit detection: only fire on JSON `error` events, - // not on arbitrary text content. An agent discussing a past - // rate limit in its response would otherwise trigger a false - // positive (the full conversation flows through stdout as - // stream-json, so any text the model outputs is visible here). - if v.get("type").and_then(|t| t.as_str()) == Some("error") { - let raw = v.to_string(); - if RATE_LIMIT_MARKERS.iter().any(|m| raw.contains(m)) { - rate_out.store(true, Ordering::Relaxed); - } - } - if let Some(u) = crate::events::TokenUsage::from_assistant_event(&v) { - last_inference = Some(u); - } - if let Some(cost) = crate::events::TokenUsage::from_stream_event(&v) { - // Fallback to `cost` if the turn somehow produced - // a result without any assistant event — keeps the - // ctx badge from going stale on a degenerate turn. - let ctx = last_inference.unwrap_or(cost); - bus_out.record_turn_usage(ctx, cost); - } - bus_out.observe_stream(&v); - bus_out.emit(LiveEvent::Stream(v)); - } - Err(_) => { - // Non-JSON stdout: raw text check is fine here since these - // are claude CLI messages, not conversation content. - if RATE_LIMIT_MARKERS.iter().any(|m| line.contains(m)) { + if let Ok(v) = serde_json::from_str::(&line) { + // Rate-limit detection: only fire on JSON `error` events, + // not on arbitrary text content. An agent discussing a past + // rate limit in its response would otherwise trigger a false + // positive (the full conversation flows through stdout as + // stream-json, so any text the model outputs is visible here). + if v.get("type").and_then(|t| t.as_str()) == Some("error") { + let raw = v.to_string(); + if RATE_LIMIT_MARKERS.iter().any(|m| raw.contains(m)) { rate_out.store(true, Ordering::Relaxed); } - bus_out.emit(LiveEvent::Note { - text: format!("(non-json) {line}"), - }); } + if let Some(u) = crate::events::TokenUsage::from_assistant_event(&v) { + last_inference = Some(u); + } + if let Some(cost) = crate::events::TokenUsage::from_stream_event(&v) { + // Fallback to `cost` if the turn somehow produced + // a result without any assistant event — keeps the + // ctx badge from going stale on a degenerate turn. + let ctx = last_inference.unwrap_or(cost); + bus_out.record_turn_usage(ctx, cost); + } + bus_out.observe_stream(&v); + bus_out.emit(LiveEvent::Stream(v)); + } else { + // Non-JSON stdout: raw text check is fine here since these + // are claude CLI messages, not conversation content. + if RATE_LIMIT_MARKERS.iter().any(|m| line.contains(m)) { + rate_out.store(true, Ordering::Relaxed); + } + bus_out.emit(LiveEvent::Note { + text: format!("(non-json) {line}"), + }); } } }); diff --git a/hive-ag3nt/src/web_ui.rs b/hive-ag3nt/src/web_ui.rs index 53e3148..a0d2b0b 100644 --- a/hive-ag3nt/src/web_ui.rs +++ b/hive-ag3nt/src/web_ui.rs @@ -265,7 +265,7 @@ async fn screen_ws( } /// Pure byte pump: forwards raw bytes between the WebSocket client and -/// the VNC TCP stream. Transparent to any RFB variant (plain, VeNCrypt). +/// the VNC TCP stream. Transparent to any RFB variant (plain, `VeNCrypt`). async fn relay_ws_vnc(socket: axum::extract::ws::WebSocket, vnc_port: u16) { // Import futures traits locally so they don't conflict with // tokio_stream::StreamExt used at module scope. diff --git a/hive-c0re/src/actions.rs b/hive-c0re/src/actions.rs index 5fcb768..977b9f2 100644 --- a/hive-c0re/src/actions.rs +++ b/hive-c0re/src/actions.rs @@ -65,11 +65,10 @@ pub async fn approve(coord: Arc, id: i64) -> Result<()> { if let Err(e) = crate::forge::ensure_config_repo(&approval.agent).await { tracing::warn!(agent = %approval.agent, error = ?e, "forge: ensure_config_repo after first spawn failed"); } - if let Some(core_token) = crate::forge::core_token() { - if let Err(e) = crate::forge::meta_read_access(&approval.agent, &core_token).await { + if let Some(core_token) = crate::forge::core_token() + && let Err(e) = crate::forge::meta_read_access(&approval.agent, &core_token).await { tracing::warn!(agent = %approval.agent, error = ?e, "forge: meta_read_access after first spawn failed"); } - } if let Err(e) = crate::forge::ensure_meta_remote(&approval.agent).await { tracing::warn!(agent = %approval.agent, error = ?e, "forge: ensure_meta_remote after first spawn failed"); } @@ -91,11 +90,10 @@ pub async fn approve(coord: Arc, id: i64) -> Result<()> { } .await; // Wire the meta remote now that the proposed repo exists. - if result.is_ok() { - if let Err(e) = crate::forge::ensure_meta_remote(&approval.agent).await { + if result.is_ok() + && let Err(e) = crate::forge::ensure_meta_remote(&approval.agent).await { tracing::warn!(agent = %approval.agent, error = ?e, "forge: ensure_meta_remote after init_config failed"); } - } finish_approval(&coord, &approval, result, None, false) } ApprovalKind::UpdateMetaInputs => { @@ -145,11 +143,10 @@ pub async fn approve(coord: Arc, id: i64) -> Result<()> { if let Err(e) = crate::forge::push_config(&agent_bg).await { tracing::warn!(agent = %agent_bg, error = ?e, "forge: push_config after spawn failed"); } - if let Some(core_token) = crate::forge::core_token() { - if let Err(e) = crate::forge::meta_read_access(&agent_bg, &core_token).await { + if let Some(core_token) = crate::forge::core_token() + && let Err(e) = crate::forge::meta_read_access(&agent_bg, &core_token).await { tracing::warn!(agent = %agent_bg, error = ?e, "forge: meta_read_access after spawn failed"); } - } if let Err(e) = crate::forge::ensure_meta_remote(&agent_bg).await { tracing::warn!(agent = %agent_bg, error = ?e, "forge: ensure_meta_remote after spawn failed"); } diff --git a/hive-c0re/src/broker.rs b/hive-c0re/src/broker.rs index 34a20ef..f2e1698 100644 --- a/hive-c0re/src/broker.rs +++ b/hive-c0re/src/broker.rs @@ -613,8 +613,7 @@ impl Broker { let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .ok() - .map(|d| d.as_secs() as i64) - .unwrap_or(0); + .map_or(0, |d| d.as_secs() as i64); now - since_secs as i64 } else { i64::MIN diff --git a/hive-c0re/src/container_view.rs b/hive-c0re/src/container_view.rs index 2524892..ffbf5b9 100644 --- a/hive-c0re/src/container_view.rs +++ b/hive-c0re/src/container_view.rs @@ -49,7 +49,7 @@ pub struct ContainerView { #[serde(default)] pub pending_reminders: u64, /// Context-window size (prompt tokens) from the agent's most recent - /// completed turn, read directly from the turn-stats SQLite. + /// completed turn, read directly from the turn-stats `SQLite`. /// `None` when the file is absent or the agent has no turns yet. /// Stale by up to one crash-watch cycle (~10s); good enough for /// the "which agent is close to the window?" dashboard glance. @@ -84,7 +84,7 @@ pub async fn build_all(coord: &Coordinator) -> Vec { } else { continue; }; - let deployed_full = locked.get(&format!("agent-{logical}")).map(|s| s.as_str()); + let deployed_full = locked.get(&format!("agent-{logical}")).map(std::string::String::as_str); let needs_update = crate::auto_update::agent_config_pending(&logical, deployed_full); let needs_login = !is_manager && !claude_has_session(&Coordinator::agent_claude_dir(&logical)); @@ -159,7 +159,7 @@ fn is_rate_limited(name: &str) -> bool { } /// Read the most recent completed turn's context-window size (prompt -/// tokens) from the agent's turn-stats SQLite. Returns `None` when +/// tokens) from the agent's turn-stats `SQLite`. Returns `None` when /// the file is absent or has no rows. Best-effort — any DB error /// silently yields `None` so a missing/corrupt file never blocks /// `build_all`. diff --git a/hive-c0re/src/crash_watch.rs b/hive-c0re/src/crash_watch.rs index 99bd3b0..e00a420 100644 --- a/hive-c0re/src/crash_watch.rs +++ b/hive-c0re/src/crash_watch.rs @@ -80,7 +80,7 @@ pub fn spawn(coord: Arc) { seeded = true; tokio::select! { - _ = tokio::time::sleep(POLL_INTERVAL) => {} + () = tokio::time::sleep(POLL_INTERVAL) => {} _ = shutdown.changed() => { tracing::info!("crash watcher: shutdown signal received"); break; diff --git a/hive-c0re/src/events_vacuum.rs b/hive-c0re/src/events_vacuum.rs index 2c99fed..b545f22 100644 --- a/hive-c0re/src/events_vacuum.rs +++ b/hive-c0re/src/events_vacuum.rs @@ -29,7 +29,7 @@ pub fn spawn(coord: Arc) { loop { sweep_once(); tokio::select! { - _ = tokio::time::sleep(VACUUM_INTERVAL) => {} + () = tokio::time::sleep(VACUUM_INTERVAL) => {} _ = shutdown.changed() => { tracing::info!("events vacuum: shutdown signal received"); break; diff --git a/hive-c0re/src/forge.rs b/hive-c0re/src/forge.rs index 100ea9b..49d6e93 100644 --- a/hive-c0re/src/forge.rs +++ b/hive-c0re/src/forge.rs @@ -54,9 +54,9 @@ const SEEDED_ORGS: &[&str] = &[CONFIG_ORG]; /// a forge namespace). /// - `read:user` — token-owner endpoint clients call to introspect. /// - `write:misc` — hooks, attachments, the rest of the long tail. -/// - `read:notification` — required by forge_notify to poll +/// - `read:notification` — required by `forge_notify` to poll /// `GET /notifications` for unread PR/review events. -/// - `write:notification` — required by forge_notify to mark +/// - `write:notification` — required by `forge_notify` to mark /// notifications as read via `PATCH /notifications/threads/{id}`. const TOKEN_SCOPES: &str = "read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc"; @@ -583,11 +583,10 @@ pub async fn ensure_all() { } // Grant read-only access to core/meta and wire the `meta` remote // into the proposed repo so agents can fetch their deployment context. - if let Some(token) = core_token.as_deref() { - if let Err(e) = meta_read_access(&name, token).await { + if let Some(token) = core_token.as_deref() + && let Err(e) = meta_read_access(&name, token).await { tracing::warn!(%name, error = ?e, "forge: ensure_meta_read_access failed"); } - } if let Err(e) = ensure_meta_remote(&name).await { tracing::warn!(%name, error = ?e, "forge: ensure_meta_remote failed"); } diff --git a/hive-c0re/src/main.rs b/hive-c0re/src/main.rs index 21c0769..70f9409 100644 --- a/hive-c0re/src/main.rs +++ b/hive-c0re/src/main.rs @@ -176,7 +176,7 @@ async fn main() -> Result<()> { Err(e) => tracing::warn!(error = ?e, "broker vacuum failed"), } tokio::select! { - _ = tokio::time::sleep(interval) => {} + () = tokio::time::sleep(interval) => {} _ = vacuum_shutdown.changed() => { tracing::info!("broker vacuum: shutdown signal received"); break; @@ -219,7 +219,7 @@ async fn main() -> Result<()> { tracing::info!("SIGINT received — requesting shutdown"); coord_sig.request_shutdown(); } - _ = async { + () = async { let mut sig = tokio::signal::unix::signal( tokio::signal::unix::SignalKind::terminate() ).expect("failed to install SIGTERM handler"); diff --git a/hive-c0re/src/meta.rs b/hive-c0re/src/meta.rs index c5899be..980a749 100644 --- a/hive-c0re/src/meta.rs +++ b/hive-c0re/src/meta.rs @@ -299,12 +299,11 @@ fn render_flake( // Forge URL — injected when hive-c0re itself has HIVE_FORGE_URL set // (the NixOS module derives it from hyperhive.forge.{domain,httpPort}). // Agents use it in forge_notify to poll Forgejo for PR/review events. - if let Ok(forge_url) = std::env::var("HIVE_FORGE_URL") { - if !forge_url.is_empty() { + if let Ok(forge_url) = std::env::var("HIVE_FORGE_URL") + && !forge_url.is_empty() { let escaped = forge_url.replace('\\', "\\\\").replace('"', "\\\""); let _ = writeln!(out, " HIVE_FORGE_URL = \"{escaped}\";"); } - } out.push_str( r#" HYPERHIVE_STATE_DIR = "/agents/${name}/state"; }; diff --git a/hive-c0re/src/reminder_scheduler.rs b/hive-c0re/src/reminder_scheduler.rs index 6cc64db..92d16e8 100644 --- a/hive-c0re/src/reminder_scheduler.rs +++ b/hive-c0re/src/reminder_scheduler.rs @@ -57,7 +57,7 @@ pub fn spawn(coord: Arc) { loop { tick(&coord); tokio::select! { - _ = tokio::time::sleep(POLL_INTERVAL) => {} + () = tokio::time::sleep(POLL_INTERVAL) => {} _ = shutdown.changed() => { tracing::info!("reminder scheduler: shutdown signal received"); break; diff --git a/hive-c0re/src/stats_vacuum.rs b/hive-c0re/src/stats_vacuum.rs index ab252bd..4f92160 100644 --- a/hive-c0re/src/stats_vacuum.rs +++ b/hive-c0re/src/stats_vacuum.rs @@ -27,7 +27,7 @@ pub fn spawn(coord: Arc) { loop { sweep_once(); tokio::select! { - _ = tokio::time::sleep(VACUUM_INTERVAL) => {} + () = tokio::time::sleep(VACUUM_INTERVAL) => {} _ = shutdown.changed() => { tracing::info!("stats vacuum: shutdown signal received"); break; diff --git a/hive-fr0nt/src/lib.rs b/hive-fr0nt/src/lib.rs index ee38281..e791dee 100644 --- a/hive-fr0nt/src/lib.rs +++ b/hive-fr0nt/src/lib.rs @@ -41,7 +41,7 @@ pub const TERMINAL_JS: &str = include_str!("../assets/terminal.js"); /// without internet egress (the container itself never fetches it). /// /// NB: must be the **UMD** build, not `marked.min.js` / `lib/marked.cjs` — -/// those are CommonJS (`exports.parse = …`, no wrapper) and throw +/// those are `CommonJS` (`exports.parse = …`, no wrapper) and throw /// `exports is not defined` in a `