feat(#2632): switch agent page loose-ends pill to todos; remove bash-tasks pill
- Add GET /api/todos backend endpoint (connects to HIVE_AGENT_SOCKET,
calls ListTodos, returns { todos: [...] } — LooseEnd::Todo items).
- Register route in web_ui/mod.rs.
- index.html: replace loose-ends pill (🪢) + bash-tasks pill (⚙)
with a single todos pill (📋, id=todos-pill).
- agent.css: add .header-pill-todos count colour (green, same as old tasks).
- app.js:
- refreshTodos() fetches /api/todos, drives renderTodos/buildTodosList.
- refreshLooseEnds() becomes background-only (no pill); still drives
reconcileAskBinds for inline ask-form wiring.
- Remove refreshBashTasks / buildBashTasksList / renderBashTasks.
- Cold-load and turn_end both call refreshTodos; 4s interval replaces
the old bash-tasks interval.
This commit is contained in:
parent
b68d91269f
commit
4905b688be
5 changed files with 107 additions and 97 deletions
|
|
@ -117,6 +117,7 @@ pub async fn serve(
|
|||
.route("/api/logout", post(auth::post_logout))
|
||||
.route("/api/loose-ends", get(stats::api_loose_ends))
|
||||
.route("/api/bash-tasks", get(stats::api_bash_tasks))
|
||||
.route("/api/todos", get(stats::api_todos))
|
||||
.route("/api/stats", get(stats::api_stats))
|
||||
.route("/screen/ws", get(screen::screen_ws))
|
||||
.route("/icon", get(screen::serve_icon));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//! Stats + loose-ends + bash-tasks read endpoints.
|
||||
//! Stats + loose-ends + bash-tasks + todos read endpoints.
|
||||
|
||||
use axum::extract::State;
|
||||
use axum::http::StatusCode;
|
||||
|
|
@ -130,3 +130,45 @@ pub(super) async fn api_bash_tasks() -> Response {
|
|||
.unwrap_or_default();
|
||||
axum::Json(serde_json::json!({ "tasks": tasks })).into_response()
|
||||
}
|
||||
|
||||
/// `GET /api/todos` — snapshot of this agent's local todos (loose-ends v2).
|
||||
///
|
||||
/// Connects to the in-agent harness socket (`HIVE_AGENT_SOCKET`) and calls
|
||||
/// `ListTodos`. Returns `{ "todos": [...] }` where each entry is a
|
||||
/// `LooseEnd::Todo` (subsystem, key, summary, source, `age_seconds`). Returns
|
||||
/// an empty array when the socket is unavailable — best-effort, same
|
||||
/// silent-failure contract as `/api/bash-tasks`.
|
||||
pub(super) async fn api_todos() -> Response {
|
||||
use tokio::io::{AsyncBufReadExt as _, AsyncWriteExt as _, BufReader};
|
||||
use tokio::net::UnixStream;
|
||||
|
||||
let socket_path = match std::env::var_os("HIVE_AGENT_SOCKET") {
|
||||
Some(p) => std::path::PathBuf::from(p),
|
||||
None => return axum::Json(serde_json::json!({ "todos": [] })).into_response(),
|
||||
};
|
||||
if !socket_path.exists() {
|
||||
return axum::Json(serde_json::json!({ "todos": [] })).into_response();
|
||||
}
|
||||
let todos = tokio::time::timeout(std::time::Duration::from_secs(3), async move {
|
||||
let mut stream = UnixStream::connect(&socket_path).await?;
|
||||
let req = hive_agent_sock::Request::ListTodos { subsystem: None };
|
||||
let mut line = serde_json::to_string(&req)?;
|
||||
line.push('\n');
|
||||
stream.write_all(line.as_bytes()).await?;
|
||||
stream.flush().await?;
|
||||
let mut lines = BufReader::new(stream).lines();
|
||||
let resp_line = lines
|
||||
.next_line()
|
||||
.await?
|
||||
.ok_or_else(|| anyhow::anyhow!("agent socket closed without response"))?;
|
||||
let resp: hive_agent_sock::Response = serde_json::from_str(&resp_line)?;
|
||||
anyhow::Ok(match resp {
|
||||
hive_agent_sock::Response::LooseEnds { loose_ends } => loose_ends,
|
||||
_ => Vec::new(),
|
||||
})
|
||||
})
|
||||
.await
|
||||
.unwrap_or_else(|_| Err(anyhow::anyhow!("timeout")))
|
||||
.unwrap_or_default();
|
||||
axum::Json(serde_json::json!({ "todos": todos })).into_response()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue