clippy: apply auto-fixable warnings across workspace (closes #265 partial)

This commit is contained in:
damocles 2026-05-22 17:50:11 +02:00 committed by Mara
parent 56d0b02c2f
commit 30d82148e0
18 changed files with 83 additions and 102 deletions

1
Cargo.lock generated
View file

@ -589,6 +589,7 @@ dependencies = [
"hive-fr0nt",
"hive-sh4re",
"libc",
"reqwest",
"rusqlite",
"serde",
"serde_json",

View file

@ -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::<u64>() {
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::<u64>()
&& 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::<u64>() {
if v > 0 {
if let Ok(s) = std::env::var("HIVE_CONTEXT_WINDOW_TOKENS")
&& let Ok(v) = s.trim().parse::<u64>()
&& v > 0 {
return v;
}
}
}
// Hard fallback for dev/test outside NixOS where env vars aren't set.
200_000
}

View file

@ -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 => {
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)
@ -525,8 +522,6 @@ async fn poll_once(
}
}
}
}
}
/// Mark a notification thread as read. Best-effort — logs on failure but
/// does not abort the poll loop. A notification left unread will resurface

View file

@ -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/<name>/config/agent.nix` with the default template.
/// After the approval the manager can edit and commit the config before

View file

@ -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,8 +527,7 @@ 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::<serde_json::Value>(&line) {
Ok(v) => {
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&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
@ -553,8 +551,7 @@ async fn run_claude(prompt: &str, files: &TurnFiles, bus: &Bus) -> Result<(bool,
}
bus_out.observe_stream(&v);
bus_out.emit(LiveEvent::Stream(v));
}
Err(_) => {
} 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)) {
@ -565,7 +562,6 @@ async fn run_claude(prompt: &str, files: &TurnFiles, bus: &Bus) -> Result<(bool,
});
}
}
}
});
let stderr_tail: Arc<Mutex<VecDeque<String>>> =
Arc::new(Mutex::new(VecDeque::with_capacity(STDERR_TAIL_LINES)));

View file

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

View file

@ -65,11 +65,10 @@ pub async fn approve(coord: Arc<Coordinator>, 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<Coordinator>, 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<Coordinator>, 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");
}

View file

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

View file

@ -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<ContainerView> {
} 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`.

View file

@ -80,7 +80,7 @@ pub fn spawn(coord: Arc<Coordinator>) {
seeded = true;
tokio::select! {
_ = tokio::time::sleep(POLL_INTERVAL) => {}
() = tokio::time::sleep(POLL_INTERVAL) => {}
_ = shutdown.changed() => {
tracing::info!("crash watcher: shutdown signal received");
break;

View file

@ -29,7 +29,7 @@ pub fn spawn(coord: Arc<Coordinator>) {
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;

View file

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

View file

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

View file

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

View file

@ -57,7 +57,7 @@ pub fn spawn(coord: Arc<Coordinator>) {
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;

View file

@ -27,7 +27,7 @@ pub fn spawn(coord: Arc<Coordinator>) {
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;

View file

@ -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 `<script>` tag, leaving `window.marked`
/// undefined and markdown silently falling back to raw text (issue #244).
pub const MARKED_JS: &str = include_str!("../assets/marked.umd.js");

View file

@ -124,11 +124,11 @@ pub enum ApprovalStatus {
/// Reminder activity statistics for an agent over a time window.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReminderStats {
/// Total reminders scheduled in the window (created_at >= cutoff).
/// Total reminders scheduled in the window (`created_at` >= cutoff).
pub scheduled: u64,
/// Reminders that have been delivered in the window (sent_at IS NOT NULL).
/// Reminders that have been delivered in the window (`sent_at` IS NOT NULL).
pub delivered: u64,
/// Reminders still pending in the window (sent_at IS NULL).
/// Reminders still pending in the window (`sent_at` IS NULL).
pub pending: u64,
}