revise bulk-clear to explicit ids per mara's feedback, fix clippy line count
This commit is contained in:
parent
eb570c003d
commit
bc69ee3b8f
7 changed files with 228 additions and 181 deletions
|
|
@ -146,11 +146,114 @@ fn msg_id_tag(id: i64) -> String {
|
|||
/// transport to return at all, which is worse than a bug: it's a deadlock
|
||||
/// (the agent can't even see what's pending to start clearing it). Capping
|
||||
/// here guarantees `get_loose_ends` always returns successfully; the
|
||||
/// truncation summary tells the agent how to bulk-clear the rest via
|
||||
/// `ack_todos_until` (see that tool's doc for why it's the intended escape
|
||||
/// hatch, not a per-id triage loop).
|
||||
/// truncation summary tells the agent to review the shown batch, bulk-clear
|
||||
/// the reviewed ids via `mark_todos_done`, then call again for the next
|
||||
/// batch — deliberately NOT a "clear everything below id N" range escape
|
||||
/// hatch (a reviewer's call: a range-based bulk-ack risks silently
|
||||
/// acking something the agent never actually looked at, since todos are
|
||||
/// heterogeneous unrelated items, not a sequentially-read stream the way
|
||||
/// inbox messages are).
|
||||
const MAX_RENDERED_TODOS: usize = 40;
|
||||
|
||||
/// Render one non-`Todo` [`hive_sh4re::LooseEnd`] variant onto `out`. Split
|
||||
/// out of `render_loose_ends` to keep that function under clippy's
|
||||
/// `too_many_lines` limit — `Todo` stays inline there since it also needs
|
||||
/// the shared `shown_todos` counter.
|
||||
fn render_one_loose_end(out: &mut String, t: &hive_sh4re::LooseEnd) {
|
||||
use std::fmt::Write as _;
|
||||
match t {
|
||||
hive_sh4re::LooseEnd::Approval {
|
||||
id,
|
||||
agent,
|
||||
commit_ref,
|
||||
description,
|
||||
age_seconds,
|
||||
} => {
|
||||
let desc = description
|
||||
.as_deref()
|
||||
.map(|d| format!(" — {d}"))
|
||||
.unwrap_or_default();
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- approval #{id} ({agent} @ {commit_ref}, {age_seconds}s old){desc}"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::Question {
|
||||
id,
|
||||
asker,
|
||||
target,
|
||||
question,
|
||||
age_seconds,
|
||||
} => {
|
||||
let to = target.as_deref().unwrap_or("operator");
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- question #{id} ({asker} → {to}, {age_seconds}s old): {question}"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::Reminder {
|
||||
id,
|
||||
owner,
|
||||
message,
|
||||
due_at,
|
||||
age_seconds,
|
||||
} => {
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- reminder #{id} ({owner}, scheduled {age_seconds}s ago, due_at={due_at}): {message}"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::PendingMessages { count } => {
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- {count} pending inbox message(s) — drain with recv (recv(max: {count}) to batch)"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::UnreadMatrix { rooms, summary } => {
|
||||
let _ = write!(out, "- unread matrix messages in {rooms} room(s)");
|
||||
if summary.is_empty() {
|
||||
let _ = writeln!(
|
||||
out,
|
||||
" — use list_rooms + read_room to view, mark_read to clear"
|
||||
);
|
||||
} else {
|
||||
let _ = writeln!(out, ":");
|
||||
for line in summary.lines() {
|
||||
let _ = writeln!(out, " {line}");
|
||||
}
|
||||
let _ = writeln!(
|
||||
out,
|
||||
" use list_rooms + read_room to view, mark_read to clear"
|
||||
);
|
||||
}
|
||||
}
|
||||
hive_sh4re::LooseEnd::Todo { .. } => {
|
||||
// Handled inline by the caller (needs the shared shown-count).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render one `Todo` [`hive_sh4re::LooseEnd`] onto `out`. Split out for the
|
||||
/// same `too_many_lines` reason as [`render_one_loose_end`].
|
||||
fn render_todo_loose_end(
|
||||
out: &mut String,
|
||||
id: i64,
|
||||
subsystem: &str,
|
||||
subsystem_key: Option<&str>,
|
||||
summary: &str,
|
||||
source: Option<&str>,
|
||||
age_seconds: u64,
|
||||
) {
|
||||
use std::fmt::Write as _;
|
||||
let key = subsystem_key.map(|k| format!(" {k}")).unwrap_or_default();
|
||||
let src = source.map(|s| format!(" — {s}")).unwrap_or_default();
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- todo #{id} [{subsystem}{key}, {age_seconds}s old]: {summary}{src} \
|
||||
(cancel_loose_end kind:\"todo\" id:{id} to clear)"
|
||||
);
|
||||
}
|
||||
|
||||
/// Inner renderer for a `Vec<LooseEnd>` already extracted from the socket
|
||||
/// reply. Called by the `get_loose_ends` handler, which injects the
|
||||
/// `UnreadMatrix` entry before formatting.
|
||||
|
|
@ -162,113 +265,41 @@ pub(super) fn render_loose_ends(loose_ends: &[hive_sh4re::LooseEnd]) -> String {
|
|||
let mut out = format!("{} loose end(s):\n", loose_ends.len());
|
||||
let mut shown_todos = 0usize;
|
||||
let mut hidden_todos = 0usize;
|
||||
let mut hidden_min_id: Option<i64> = None;
|
||||
for t in loose_ends {
|
||||
if let hive_sh4re::LooseEnd::Todo { id, .. } = t
|
||||
&& shown_todos >= MAX_RENDERED_TODOS
|
||||
{
|
||||
let hive_sh4re::LooseEnd::Todo {
|
||||
id,
|
||||
subsystem,
|
||||
subsystem_key,
|
||||
summary,
|
||||
source,
|
||||
age_seconds,
|
||||
} = t
|
||||
else {
|
||||
render_one_loose_end(&mut out, t);
|
||||
continue;
|
||||
};
|
||||
if shown_todos >= MAX_RENDERED_TODOS {
|
||||
hidden_todos += 1;
|
||||
hidden_min_id = Some(hidden_min_id.map_or(*id, |m| m.min(*id)));
|
||||
continue;
|
||||
}
|
||||
match t {
|
||||
hive_sh4re::LooseEnd::Approval {
|
||||
id,
|
||||
agent,
|
||||
commit_ref,
|
||||
description,
|
||||
age_seconds,
|
||||
} => {
|
||||
let desc = description
|
||||
.as_deref()
|
||||
.map(|d| format!(" — {d}"))
|
||||
.unwrap_or_default();
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- approval #{id} ({agent} @ {commit_ref}, {age_seconds}s old){desc}"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::Question {
|
||||
id,
|
||||
asker,
|
||||
target,
|
||||
question,
|
||||
age_seconds,
|
||||
} => {
|
||||
let to = target.as_deref().unwrap_or("operator");
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- question #{id} ({asker} → {to}, {age_seconds}s old): {question}"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::Reminder {
|
||||
id,
|
||||
owner,
|
||||
message,
|
||||
due_at,
|
||||
age_seconds,
|
||||
} => {
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- reminder #{id} ({owner}, scheduled {age_seconds}s ago, due_at={due_at}): {message}"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::PendingMessages { count } => {
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- {count} pending inbox message(s) — drain with recv (recv(max: {count}) to batch)"
|
||||
);
|
||||
}
|
||||
hive_sh4re::LooseEnd::UnreadMatrix { rooms, summary } => {
|
||||
let _ = write!(out, "- unread matrix messages in {rooms} room(s)");
|
||||
if summary.is_empty() {
|
||||
let _ = writeln!(
|
||||
out,
|
||||
" — use list_rooms + read_room to view, mark_read to clear"
|
||||
);
|
||||
} else {
|
||||
let _ = writeln!(out, ":");
|
||||
for line in summary.lines() {
|
||||
let _ = writeln!(out, " {line}");
|
||||
}
|
||||
let _ = writeln!(
|
||||
out,
|
||||
" use list_rooms + read_room to view, mark_read to clear"
|
||||
);
|
||||
}
|
||||
}
|
||||
hive_sh4re::LooseEnd::Todo {
|
||||
id,
|
||||
subsystem,
|
||||
subsystem_key,
|
||||
summary,
|
||||
source,
|
||||
age_seconds,
|
||||
} => {
|
||||
let key = subsystem_key
|
||||
.as_deref()
|
||||
.map(|k| format!(" {k}"))
|
||||
.unwrap_or_default();
|
||||
let src = source
|
||||
.as_deref()
|
||||
.map(|s| format!(" — {s}"))
|
||||
.unwrap_or_default();
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- todo #{id} [{subsystem}{key}, {age_seconds}s old]: {summary}{src} \
|
||||
(cancel_loose_end kind:\"todo\" id:{id} to clear)"
|
||||
);
|
||||
shown_todos += 1;
|
||||
}
|
||||
}
|
||||
render_todo_loose_end(
|
||||
&mut out,
|
||||
*id,
|
||||
subsystem,
|
||||
subsystem_key.as_deref(),
|
||||
summary,
|
||||
source.as_deref(),
|
||||
*age_seconds,
|
||||
);
|
||||
shown_todos += 1;
|
||||
}
|
||||
if hidden_todos > 0 {
|
||||
let min_id = hidden_min_id.unwrap_or(0);
|
||||
let _ = writeln!(
|
||||
out,
|
||||
"- {hidden_todos} more todo(s) not shown (oldest not shown: #{min_id}) — \
|
||||
call ack_todos_until(up_to: {min_id}) to bulk-clear the old backlog, or \
|
||||
cancel_loose_end kind:\"todo\" id:<N> to clear individually"
|
||||
"- {hidden_todos} more todo(s) not shown — review the ones above, then clear \
|
||||
the ids you've actually looked at with mark_todos_done(ids: [...]) (or \
|
||||
cancel_loose_end kind:\"todo\" id:<N> for just one) and call get_loose_ends \
|
||||
again to see the next batch; there is no blind bulk-clear-by-range for todos"
|
||||
);
|
||||
}
|
||||
out
|
||||
|
|
@ -385,11 +416,11 @@ pub(super) async fn mark_local_todo_done(id: i64) -> Option<hive_agent_sock::Res
|
|||
dial_agent_socket(&hive_agent_sock::Request::MarkTodoDone { id }).await
|
||||
}
|
||||
|
||||
/// Bulk-ack every un-acked local todo with `id <= up_to`, via the harness's
|
||||
/// in-agent socket — the todo-store analogue of `mark_local_todo_done`, for
|
||||
/// the `ack_todos_until` tool.
|
||||
pub(super) async fn mark_local_todos_done_until(up_to: i64) -> Option<hive_agent_sock::Response> {
|
||||
dial_agent_socket(&hive_agent_sock::Request::MarkTodosDoneUntil { up_to }).await
|
||||
/// Bulk-ack an explicit list of local todo ids, via the harness's in-agent
|
||||
/// socket — the multi-id analogue of `mark_local_todo_done`, for the
|
||||
/// `mark_todos_done` tool.
|
||||
pub(super) async fn mark_local_todos_done(ids: Vec<i64>) -> Option<hive_agent_sock::Response> {
|
||||
dial_agent_socket(&hive_agent_sock::Request::MarkTodosDone { ids }).await
|
||||
}
|
||||
|
||||
/// Format a `Vec<MatrixRoomUnread>` into a per-room summary string.
|
||||
|
|
|
|||
Loading…
Reference in a new issue