fix(clippy): fix all clippy warnings in hive-ag3nt, hive-forge, hive-matrix-mcp, hive-sh4re
Fixes all clippy -D warnings errors in the crates iris owns: hive-sh4re: - doc_lazy_continuation: add blank /// separator in priv_proto.rs - doc_markdown: backtick PRIVATE_NETWORK=0 / PRIVATE_NETWORK=1 hive-matrix-mcp: - map_unwrap_or: map().unwrap_or_else() -> map_or_else() in paths.rs - collapsible_if: if-let chains in wake.rs - doc_markdown: backtick M_UNKNOWN_TOKEN in main.rs - cast_possible_truncation: usize/u64 -> u32::try_from in handlers.rs - map_unwrap_or: map_or_else() in handlers.rs - manual_let_else: match Ok(r) => r, Err => return -> let Ok in handlers.rs - unused_async: remove async from list_invites; update socket.rs call site hive-forge: - doc_markdown: backtick REQUEST_CHANGES / APPROVED / COMMENT in pr_reviews.rs - unnecessary_wraps: list_reviews_text returns () not Result<()> - doc_markdown: backtick start_page / last_page in comments.rs - cast_possible_truncation: PAGE_SIZE u64 -> usize; remove as usize casts hive-ag3nt: - collapsible_if: if-let chains in events.rs and mcp.rs - single_match_else: match -> if let in events.rs and mcp.rs - items_after_statements: hoist STATUS_MAX_CHARS const in mcp.rs - map_unwrap_or: map_or_else() in mcp.rs and mcp_loose_ends.rs - cast_possible_truncation: usize -> u32::try_from in mcp.rs - doc_markdown: backtick snake_case in mcp.rs, needs_update/deployed_sha in web_ui.rs, HISTORY_CAPACITY in web_ui.rs - identical_match_arms: combine manage_root_agent | query_agent_state - redundant_closure: |s| s.to_string() -> ToString::to_string in web_ui.rs - duration_suboptimal_units: from_secs(3600) -> from_hours(1) in turn.rs Remaining failures in hive-c0re (39), hive-priv (8), hive-bash-mcp (11) are owned by damocles.
This commit is contained in:
parent
6a35f48458
commit
92b32d06fb
13 changed files with 128 additions and 133 deletions
|
|
@ -80,18 +80,18 @@ fn harness_json_path() -> PathBuf {
|
|||
|
||||
fn read_harness_state() -> (bool, bool) {
|
||||
// Try the new consolidated file first.
|
||||
if let Ok(raw) = std::fs::read_to_string(harness_json_path()) {
|
||||
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&raw) {
|
||||
let rate_limited = v
|
||||
.get("rate_limited")
|
||||
.and_then(|x| x.as_bool())
|
||||
.unwrap_or(false);
|
||||
let needs_login = v
|
||||
.get("needs_login")
|
||||
.and_then(|x| x.as_bool())
|
||||
.unwrap_or(false);
|
||||
return (rate_limited, needs_login);
|
||||
}
|
||||
if let Ok(raw) = std::fs::read_to_string(harness_json_path())
|
||||
&& let Ok(v) = serde_json::from_str::<serde_json::Value>(&raw)
|
||||
{
|
||||
let rate_limited = v
|
||||
.get("rate_limited")
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
let needs_login = v
|
||||
.get("needs_login")
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
return (rate_limited, needs_login);
|
||||
}
|
||||
// Fall back to legacy sentinel files written by older harness builds.
|
||||
let state_dir = crate::paths::state_dir();
|
||||
|
|
@ -265,38 +265,35 @@ impl EventStore {
|
|||
let conn = self.conn.lock().unwrap();
|
||||
// Fetch one extra row so we can tell whether more exist.
|
||||
let fetch = limit_i.saturating_add(1);
|
||||
let rows: Vec<(i64, LiveEvent)> = match before_id {
|
||||
Some(bid) => {
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, payload_json FROM events
|
||||
WHERE id < ?1
|
||||
ORDER BY id DESC
|
||||
LIMIT ?2",
|
||||
)?;
|
||||
stmt.query_map(params![bid, fetch], |row| {
|
||||
let id: i64 = row.get(0)?;
|
||||
let s: String = row.get(1)?;
|
||||
Ok(serde_json::from_str::<LiveEvent>(&s).ok().map(|e| (id, e)))
|
||||
})?
|
||||
.flatten()
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
None => {
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, payload_json FROM events
|
||||
ORDER BY id DESC
|
||||
LIMIT ?1",
|
||||
)?;
|
||||
stmt.query_map(params![fetch], |row| {
|
||||
let id: i64 = row.get(0)?;
|
||||
let s: String = row.get(1)?;
|
||||
Ok(serde_json::from_str::<LiveEvent>(&s).ok().map(|e| (id, e)))
|
||||
})?
|
||||
.flatten()
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
let rows: Vec<(i64, LiveEvent)> = if let Some(bid) = before_id {
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, payload_json FROM events
|
||||
WHERE id < ?1
|
||||
ORDER BY id DESC
|
||||
LIMIT ?2",
|
||||
)?;
|
||||
stmt.query_map(params![bid, fetch], |row| {
|
||||
let id: i64 = row.get(0)?;
|
||||
let s: String = row.get(1)?;
|
||||
Ok(serde_json::from_str::<LiveEvent>(&s).ok().map(|e| (id, e)))
|
||||
})?
|
||||
.flatten()
|
||||
.flatten()
|
||||
.collect()
|
||||
} else {
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, payload_json FROM events
|
||||
ORDER BY id DESC
|
||||
LIMIT ?1",
|
||||
)?;
|
||||
stmt.query_map(params![fetch], |row| {
|
||||
let id: i64 = row.get(0)?;
|
||||
let s: String = row.get(1)?;
|
||||
Ok(serde_json::from_str::<LiveEvent>(&s).ok().map(|e| (id, e)))
|
||||
})?
|
||||
.flatten()
|
||||
.flatten()
|
||||
.collect()
|
||||
};
|
||||
let has_more = rows.len() > limit;
|
||||
let mut rows: Vec<(i64, LiveEvent)> = rows.into_iter().take(limit).collect();
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@ impl From<hive_sh4re::Response> for SocketReply {
|
|||
/// the file is never written with text the server would later reject (which
|
||||
/// would leave a stale invalid entry on disk).
|
||||
fn write_status_file(text: &str) -> Result<(), String> {
|
||||
// 200 chars mirrors STATUS_MAX_CHARS in hive-c0re/src/limits.rs.
|
||||
// Keep in sync if that constant changes.
|
||||
const STATUS_MAX_CHARS: usize = 200;
|
||||
let trimmed = text.trim();
|
||||
if !trimmed.is_empty() {
|
||||
if trimmed.contains('\n') || trimmed.contains('\r') {
|
||||
|
|
@ -120,9 +123,6 @@ fn write_status_file(text: &str) -> Result<(), String> {
|
|||
.to_owned(),
|
||||
);
|
||||
}
|
||||
// 200 chars mirrors STATUS_MAX_CHARS in hive-c0re/src/limits.rs.
|
||||
// Keep in sync if that constant changes.
|
||||
const STATUS_MAX_CHARS: usize = 200;
|
||||
let len = trimmed.chars().count();
|
||||
if len > STATUS_MAX_CHARS {
|
||||
return Err(format!(
|
||||
|
|
@ -310,9 +310,10 @@ struct MatrixRoomUnread {
|
|||
async fn matrix_unread_summary() -> Option<Vec<MatrixRoomUnread>> {
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::net::UnixStream;
|
||||
let socket = std::env::var_os("HIVE_MATRIX_SOCKET")
|
||||
.map(std::path::PathBuf::from)
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("/run/hive-matrix/socket"));
|
||||
let socket = std::env::var_os("HIVE_MATRIX_SOCKET").map_or_else(
|
||||
|| std::path::PathBuf::from("/run/hive-matrix/socket"),
|
||||
std::path::PathBuf::from,
|
||||
);
|
||||
if !socket.exists() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -339,11 +340,11 @@ fn format_matrix_summary(rooms: &[MatrixRoomUnread]) -> String {
|
|||
}
|
||||
let mut out = String::new();
|
||||
for r in rooms {
|
||||
if r.count == 1 {
|
||||
if let (Some(body), Some(sender)) = (&r.last_body, &r.last_sender) {
|
||||
let _ = writeln!(out, "- {}: {sender}: {body}", r.label);
|
||||
continue;
|
||||
}
|
||||
if r.count == 1
|
||||
&& let (Some(body), Some(sender)) = (&r.last_body, &r.last_sender)
|
||||
{
|
||||
let _ = writeln!(out, "- {}: {sender}: {body}", r.label);
|
||||
continue;
|
||||
}
|
||||
let _ = writeln!(out, "- {}: {} unread", r.label, r.count);
|
||||
}
|
||||
|
|
@ -775,19 +776,19 @@ impl AgentServer {
|
|||
};
|
||||
// Prepend matrix unread entry for self-queries only (can't
|
||||
// reach another agent's matrix daemon from here).
|
||||
if is_self_query {
|
||||
if let Some(unread_rooms) = matrix_unread_summary().await {
|
||||
let total = unread_rooms.len() as u32;
|
||||
if total > 0 {
|
||||
let summary = format_matrix_summary(&unread_rooms);
|
||||
loose_ends.insert(
|
||||
0,
|
||||
hive_sh4re::LooseEnd::UnreadMatrix {
|
||||
rooms: total,
|
||||
summary,
|
||||
},
|
||||
);
|
||||
}
|
||||
if is_self_query
|
||||
&& let Some(unread_rooms) = matrix_unread_summary().await
|
||||
{
|
||||
let total = u32::try_from(unread_rooms.len()).unwrap_or(u32::MAX);
|
||||
if total > 0 {
|
||||
let summary = format_matrix_summary(&unread_rooms);
|
||||
loose_ends.insert(
|
||||
0,
|
||||
hive_sh4re::LooseEnd::UnreadMatrix {
|
||||
rooms: total,
|
||||
summary,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
let mut out = annotate_retries(render_loose_ends(&loose_ends), retries);
|
||||
|
|
@ -1754,14 +1755,14 @@ pub const SERVER_NAME: &str = "hyperhive";
|
|||
pub const ALLOWED_BUILTIN_TOOLS: &[&str] = &["Edit", "Glob", "Grep", "Read", "Write"];
|
||||
|
||||
/// Env var written by the meta renderer with a comma-separated list of
|
||||
/// `hive_sh4re::ToolGroup` snake_case names (e.g. `"messaging,inbox,meta"`).
|
||||
/// `hive_sh4re::ToolGroup` `snake_case` names (e.g. `"messaging,inbox,meta"`).
|
||||
/// When present, the harness expands the groups into per-tool allow entries
|
||||
/// instead of using the hardcoded flavor default. See `docs/conventions.md::Tool groups`.
|
||||
const TOOL_GROUPS_ENV: &str = "HIVE_TOOL_GROUPS";
|
||||
|
||||
/// `HIVE_CAPABILITIES` env var injected by `meta::render_flake` when the
|
||||
/// operator grants capabilities to this agent. Comma-separated
|
||||
/// `hive_sh4re::Capability` snake_case names. Absent = no extra capabilities.
|
||||
/// `hive_sh4re::Capability` `snake_case` names. Absent = no extra capabilities.
|
||||
const CAPABILITIES_ENV: &str = "HIVE_CAPABILITIES";
|
||||
|
||||
/// Returns the MCP tool names (without `mcp__hyperhive__` prefix) that are
|
||||
|
|
@ -1778,14 +1779,12 @@ fn allowed_capability_tools() -> Vec<String> {
|
|||
let t = token.trim().to_ascii_lowercase();
|
||||
match t.as_str() {
|
||||
"read_host_journal" => tools.push("get_host_journal".to_owned()),
|
||||
// manage_root_agent doesn't expose new MCP tools (it gates
|
||||
// existing lifecycle tools via the topology enforcement).
|
||||
"manage_root_agent" => {}
|
||||
// query_agent_state doesn't expose new MCP tools; it unlocks
|
||||
// the `agent` field in get_loose_ends / count_pending_reminders
|
||||
// / reminder_rollup on the agent socket (c0re enforces the cap
|
||||
// server-side; the harness honours it by passing the field).
|
||||
"query_agent_state" => {}
|
||||
// manage_root_agent / query_agent_state don't expose new MCP
|
||||
// tools: manage_root_agent gates existing lifecycle tools via
|
||||
// topology enforcement; query_agent_state unlocks the `agent`
|
||||
// field in get_loose_ends / count_pending_reminders /
|
||||
// reminder_rollup (c0re enforces the cap server-side).
|
||||
"manage_root_agent" | "query_agent_state" => {}
|
||||
unknown => {
|
||||
tracing::warn!(capability = %unknown, "unrecognised capability in HIVE_CAPABILITIES — skipped");
|
||||
}
|
||||
|
|
@ -1810,13 +1809,12 @@ fn effective_tool_groups() -> Vec<hive_sh4re::ToolGroup> {
|
|||
for token in raw.split(',') {
|
||||
let t = token.trim().to_ascii_lowercase();
|
||||
// Parse via serde_json (the canonical deserialization path).
|
||||
match serde_json::from_value::<hive_sh4re::ToolGroup>(serde_json::Value::String(t.clone()))
|
||||
if let Ok(g) =
|
||||
serde_json::from_value::<hive_sh4re::ToolGroup>(serde_json::Value::String(t.clone()))
|
||||
{
|
||||
Ok(g) => groups.push(g),
|
||||
Err(_) => tracing::warn!(
|
||||
token = %t,
|
||||
"{TOOL_GROUPS_ENV}: unknown tool group, skipping"
|
||||
),
|
||||
groups.push(g);
|
||||
} else {
|
||||
tracing::warn!(token = %t, "{TOOL_GROUPS_ENV}: unknown tool group, skipping");
|
||||
}
|
||||
}
|
||||
if groups.is_empty() {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ fn loose_ends_dir() -> PathBuf {
|
|||
let state_path = PathBuf::from(&state);
|
||||
state_path
|
||||
.parent()
|
||||
.map(|p| p.join("harness"))
|
||||
.unwrap_or_else(|| PathBuf::from(state))
|
||||
.map_or_else(|| PathBuf::from(state), |p| p.join("harness"))
|
||||
};
|
||||
base.join("mcp-loose-ends")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -905,7 +905,7 @@ mod tests {
|
|||
fs::write(dir.path().join("credentials.json"), b"{}").unwrap();
|
||||
let snapshot = DirSnapshot {
|
||||
file_count: 1,
|
||||
newest_mtime: Some(SystemTime::now() + Duration::from_secs(3600)),
|
||||
newest_mtime: Some(SystemTime::now() + Duration::from_hours(1)),
|
||||
};
|
||||
assert!(!session_refreshed(snapshot, snapshot_dir(dir.path())));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -579,7 +579,7 @@ async fn api_state(State(state): State<AppState>) -> axum::Json<StateSnapshot> {
|
|||
/// fetches this once per running agent to get fresh, agent-authoritative
|
||||
/// values instead of relying on hive-c0re's periodic file-reads.
|
||||
///
|
||||
/// Structural fields (running, needs_update, deployed_sha, parent, …)
|
||||
/// Structural fields (running, `needs_update`, `deployed_sha`, parent, …)
|
||||
/// continue to come from hive-c0re's `/api/state`; this endpoint covers
|
||||
/// only the fields the agent itself is the source of truth for.
|
||||
#[derive(serde::Serialize)]
|
||||
|
|
@ -808,7 +808,7 @@ struct HistoryParams {
|
|||
/// Cursor: only return events with sqlite row id < `before`.
|
||||
/// Omit for the initial (most-recent) page.
|
||||
before: Option<i64>,
|
||||
/// Page size (default 100, capped at HISTORY_CAPACITY).
|
||||
/// Page size (default 100, capped at `HISTORY_CAPACITY`).
|
||||
limit: Option<usize>,
|
||||
}
|
||||
|
||||
|
|
@ -1094,7 +1094,7 @@ fn available_models() -> Vec<String> {
|
|||
const DEFAULT: &[&str] = &["haiku", "sonnet", "opus"];
|
||||
let raw = match std::env::var("HIVE_AVAILABLE_MODELS") {
|
||||
Ok(v) if !v.trim().is_empty() => v,
|
||||
_ => return DEFAULT.iter().map(|s| s.to_string()).collect(),
|
||||
_ => return DEFAULT.iter().map(ToString::to_string).collect(),
|
||||
};
|
||||
let models: Vec<String> = raw
|
||||
.split(',')
|
||||
|
|
@ -1102,7 +1102,7 @@ fn available_models() -> Vec<String> {
|
|||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
if models.is_empty() {
|
||||
DEFAULT.iter().map(|s| s.to_string()).collect()
|
||||
DEFAULT.iter().map(ToString::to_string).collect()
|
||||
} else {
|
||||
models
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use crate::verbs::print_json;
|
|||
/// Forgejo's per-page comment cap. The API caps `limit` at 50 even
|
||||
/// if a higher value is requested; pin it explicitly so the math
|
||||
/// downstream doesn't depend on a hidden default.
|
||||
const PAGE_SIZE: u64 = 50;
|
||||
const PAGE_SIZE: usize = 50;
|
||||
|
||||
#[derive(ClapArgs)]
|
||||
pub struct Args {
|
||||
|
|
@ -112,7 +112,7 @@ fn fetch_tail(client: &Client, repo: &str, number: u64, n: usize) -> Result<Vec<
|
|||
// Cap `n` at the actual total so the math below stays in range
|
||||
// when the caller asks for more comments than exist.
|
||||
let n = n.min(total);
|
||||
let page_size = PAGE_SIZE as usize;
|
||||
let page_size = PAGE_SIZE;
|
||||
// 0-based index of the first comment we want; integer-divide to
|
||||
// get the 1-based page that contains it.
|
||||
let start_idx = total - n;
|
||||
|
|
@ -145,12 +145,12 @@ mod tests {
|
|||
|
||||
/// Pure helper mirroring the page-arithmetic in `fetch_tail`:
|
||||
/// given a total comment count + requested tail size, return
|
||||
/// the (start_page, last_page) pair the network loop would
|
||||
/// the (`start_page`, `last_page`) pair the network loop would
|
||||
/// walk. Lets us pin the pagination plan — the part that's
|
||||
/// easy to off-by-one — without touching the network.
|
||||
fn tail_plan(total: usize, n: usize) -> (usize, usize) {
|
||||
let n = n.min(total);
|
||||
let page_size = PAGE_SIZE as usize;
|
||||
let page_size = PAGE_SIZE;
|
||||
let start_idx = total - n;
|
||||
let start_page = (start_idx / page_size) + 1;
|
||||
let last_page = (total - 1) / page_size + 1;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub struct Args {
|
|||
#[arg(long, conflicts_with_all = ["request_changes", "comment"])]
|
||||
approve: bool,
|
||||
|
||||
/// Request changes on the PR (submit a REQUEST_CHANGES review).
|
||||
/// Request changes on the PR (submit a `REQUEST_CHANGES` review).
|
||||
#[arg(long, conflicts_with_all = ["approve", "comment"])]
|
||||
request_changes: bool,
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ pub fn run(client: &Client, args: Args) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Submit a review event (APPROVED / REQUEST_CHANGES / COMMENT) and print
|
||||
/// Submit a review event (`APPROVED` / `REQUEST_CHANGES` / `COMMENT`) and print
|
||||
/// a compact summary of the created review.
|
||||
fn submit_review(client: &Client, number: u64, event: &str, body: Option<String>) -> Result<()> {
|
||||
let repo = client.repo();
|
||||
|
|
@ -89,7 +89,8 @@ fn list_reviews(client: &Client, number: u64) -> Result<()> {
|
|||
if client.json_mode() {
|
||||
list_reviews_json(client, repo, number, &reviews)
|
||||
} else {
|
||||
list_reviews_text(client, repo, number, &reviews)
|
||||
list_reviews_text(client, repo, number, &reviews);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,10 +130,10 @@ fn list_reviews_json(client: &Client, repo: &str, number: u64, reviews: &[Value]
|
|||
|
||||
/// Human-readable output: Markdown-style heading per review, inline
|
||||
/// comments as `[path:line] body` (line omitted for PR-level comments).
|
||||
fn list_reviews_text(client: &Client, repo: &str, number: u64, reviews: &[Value]) -> Result<()> {
|
||||
fn list_reviews_text(client: &Client, repo: &str, number: u64, reviews: &[Value]) {
|
||||
if reviews.is_empty() {
|
||||
println!("(no reviews)");
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
for r in reviews {
|
||||
let id = r.get("id").and_then(Value::as_u64).unwrap_or(0);
|
||||
|
|
@ -160,5 +161,4 @@ fn list_reviews_text(client: &Client, repo: &str, number: u64, reviews: &[Value]
|
|||
}
|
||||
println!();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ pub async fn list_room_members(client: &Client, room_ref: &str) -> DaemonRespons
|
|||
DaemonResponse::ok(&list)
|
||||
}
|
||||
|
||||
pub async fn list_invites(client: &Client) -> DaemonResponse {
|
||||
pub fn list_invites(client: &Client) -> DaemonResponse {
|
||||
let invites: Vec<InviteInfo> = client
|
||||
.invited_rooms()
|
||||
.into_iter()
|
||||
|
|
@ -422,11 +422,14 @@ pub async fn read_room(client: &Client, room_ref: &str, limit: Option<usize>) ->
|
|||
/// [`collect_unread`] issues for count==1 rooms.
|
||||
#[must_use]
|
||||
pub fn unread_count(client: &Client) -> DaemonResponse {
|
||||
let rooms = client
|
||||
.joined_rooms()
|
||||
.into_iter()
|
||||
.filter(|r| r.unread_notification_counts().notification_count > 0)
|
||||
.count() as u32;
|
||||
let rooms = u32::try_from(
|
||||
client
|
||||
.joined_rooms()
|
||||
.into_iter()
|
||||
.filter(|r| r.unread_notification_counts().notification_count > 0)
|
||||
.count(),
|
||||
)
|
||||
.unwrap_or(u32::MAX);
|
||||
DaemonResponse::ok(&serde_json::json!({ "rooms": rooms }))
|
||||
}
|
||||
|
||||
|
|
@ -447,14 +450,14 @@ pub async fn collect_unread(client: &Client) -> Vec<crate::protocol::RoomUnread>
|
|||
use crate::protocol::RoomUnread;
|
||||
let mut result = Vec::new();
|
||||
for room in client.joined_rooms() {
|
||||
let count = room.unread_notification_counts().notification_count as u32;
|
||||
let count = u32::try_from(room.unread_notification_counts().notification_count)
|
||||
.unwrap_or(u32::MAX);
|
||||
if count == 0 {
|
||||
continue;
|
||||
}
|
||||
let label = room
|
||||
.canonical_alias()
|
||||
.map(|a| a.to_string())
|
||||
.unwrap_or_else(|| room.room_id().to_string());
|
||||
.map_or_else(|| room.room_id().to_string(), |a| a.to_string());
|
||||
let (last_body, last_sender) = if count == 1 {
|
||||
fetch_last_message(client, &room).await
|
||||
} else {
|
||||
|
|
@ -482,9 +485,8 @@ async fn fetch_last_message(
|
|||
let mut req =
|
||||
get_message_events::v3::Request::new(room.room_id().to_owned(), Direction::Backward);
|
||||
req.limit = matrix_sdk::ruma::UInt::from(1u32);
|
||||
let resp = match client.send(req).await {
|
||||
Ok(r) => r,
|
||||
Err(_) => return (None, None),
|
||||
let Ok(resp) = client.send(req).await else {
|
||||
return (None, None);
|
||||
};
|
||||
for raw in &resp.chunk {
|
||||
if let Ok(ev) = raw.deserialize() {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
//! synced with hive-c0re's token-provisioning timing.
|
||||
//!
|
||||
//! Stale-token recovery: handled in `client::build_and_restore` — see
|
||||
//! that module for the M_UNKNOWN_TOKEN detection + cleanup flow.
|
||||
//! that module for the `M_UNKNOWN_TOKEN` detection + cleanup flow.
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use matrix_sdk::config::SyncSettings;
|
||||
|
|
|
|||
|
|
@ -83,8 +83,7 @@ pub fn mcp_loose_ends_dir() -> PathBuf {
|
|||
let state_path = PathBuf::from(&state);
|
||||
state_path
|
||||
.parent()
|
||||
.map(|p| p.join("harness"))
|
||||
.unwrap_or_else(|| PathBuf::from(state))
|
||||
.map_or_else(|| PathBuf::from(state), |p| p.join("harness"))
|
||||
};
|
||||
base.join("mcp-loose-ends")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ async fn dispatch(req: DaemonRequest, client: &Client) -> DaemonResponse {
|
|||
handlers::mark_read(client, &room, &event_id).await
|
||||
}
|
||||
DaemonRequest::ListRooms => handlers::list_rooms(client).await,
|
||||
DaemonRequest::ListInvites => handlers::list_invites(client).await,
|
||||
DaemonRequest::ListInvites => handlers::list_invites(client),
|
||||
DaemonRequest::JoinRoom { room } => handlers::join_room(client, &room).await,
|
||||
DaemonRequest::InviteUser { room, user_id } => {
|
||||
handlers::invite_user(client, &room, &user_id).await
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ pub async fn send_wake(socket: &Path, body: impl AsRef<str>) -> Result<()> {
|
|||
// Drain the response line so the server doesn't get ECONNRESET on
|
||||
// its write-back. We don't act on the response — best-effort wake.
|
||||
let mut reader = tokio::io::BufReader::new(read);
|
||||
let mut _resp = String::new();
|
||||
let _ = reader.read_line(&mut _resp).await;
|
||||
let mut resp = String::new();
|
||||
let _ = reader.read_line(&mut resp).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -86,13 +86,13 @@ pub fn format_unread_summary(rooms: &[crate::protocol::RoomUnread]) -> String {
|
|||
// Terse path: exactly one room, exactly one unread with body.
|
||||
if rooms.len() == 1 {
|
||||
let r = &rooms[0];
|
||||
if r.count == 1 {
|
||||
if let (Some(body), Some(sender)) = (&r.last_body, &r.last_sender) {
|
||||
return format!(
|
||||
"[matrix] {sender} in {label}: {body} — use read_room to view, mark_read to clear",
|
||||
label = r.label
|
||||
);
|
||||
}
|
||||
if r.count == 1
|
||||
&& let (Some(body), Some(sender)) = (&r.last_body, &r.last_sender)
|
||||
{
|
||||
return format!(
|
||||
"[matrix] {sender} in {label}: {body} — use read_room to view, mark_read to clear",
|
||||
label = r.label
|
||||
);
|
||||
}
|
||||
return format!(
|
||||
"[matrix] {} unread in {} — use read_room to view, mark_read to clear",
|
||||
|
|
@ -102,11 +102,11 @@ pub fn format_unread_summary(rooms: &[crate::protocol::RoomUnread]) -> String {
|
|||
// Multi-room path.
|
||||
let mut out = String::from("[matrix] unread messages:");
|
||||
for r in rooms {
|
||||
if r.count == 1 {
|
||||
if let (Some(body), Some(sender)) = (&r.last_body, &r.last_sender) {
|
||||
let _ = write!(out, "\n- {}: {sender}: {body}", r.label);
|
||||
continue;
|
||||
}
|
||||
if r.count == 1
|
||||
&& let (Some(body), Some(sender)) = (&r.last_body, &r.last_sender)
|
||||
{
|
||||
let _ = write!(out, "\n- {}: {sender}: {body}", r.label);
|
||||
continue;
|
||||
}
|
||||
let _ = write!(out, "\n- {}: {} unread", r.label, r.count);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ pub enum PrivRequest {
|
|||
WriteNspawnFlags {
|
||||
container: String,
|
||||
binds: Vec<BindMount>,
|
||||
/// `None` = host netns (PRIVATE_NETWORK=0). `Some` = private netns with
|
||||
/// veth on the specified bridge (PRIVATE_NETWORK=1).
|
||||
/// `None` = host netns (`PRIVATE_NETWORK=0`). `Some` = private netns with
|
||||
/// veth on the specified bridge (`PRIVATE_NETWORK=1`).
|
||||
#[serde(default)]
|
||||
isolation: Option<NetworkIsolation>,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue