feat: phase 2 — am web : dashboard web local + API JSON (contrats --json, 127.0.0.1, tiny_http, frontend embarqué) (closes #54)
release / linux (push) Successful in 14m16s
release / windows (push) Canceled after 0s
release / macos (push) Canceled after 0s

This commit is contained in:
2026-08-18 16:40:15 -04:00
parent 7f4d74f811
commit fa51cdb339
20 changed files with 1392 additions and 40 deletions
+35 -23
View File
@@ -7,19 +7,19 @@ use serde::Serialize;
use std::path::PathBuf;
#[derive(Serialize)]
struct SessionRow {
id: String,
kind: String,
agent: Option<String>,
status: String,
pid: Option<u32>,
cwd: Option<String>,
project: Option<String>,
started_at: String,
ended_at: Option<String>,
duration_s: Option<u64>,
exit_code: Option<i32>,
log: Option<String>,
pub struct SessionRow {
pub id: String,
pub kind: String,
pub agent: Option<String>,
pub status: String,
pub pid: Option<u32>,
pub cwd: Option<String>,
pub project: Option<String>,
pub started_at: String,
pub ended_at: Option<String>,
pub duration_s: Option<u64>,
pub exit_code: Option<i32>,
pub log: Option<String>,
}
fn row_of(r: &SessionRecord) -> SessionRow {
@@ -39,6 +39,27 @@ fn row_of(r: &SessionRecord) -> SessionRow {
}
}
/// Rows for the web API (issue #54): same shape as `am sessions --json`.
/// Unlike `run`, it never reconciles the registry (the web is read-only).
pub fn list_rows(
app: &App,
agent: Option<&str>,
project: Option<&str>,
status: Option<&str>,
) -> Result<Vec<SessionRow>> {
let sf = sessions::load(app)?;
let mut rows: Vec<SessionRow> = sf
.sessions
.values()
.filter(|r| agent.map_or(true, |a| r.agent.as_deref() == Some(a)))
.filter(|r| project.map_or(true, |p| r.project.as_deref() == Some(p)))
.filter(|r| status.map_or(true, |s| r.status == s))
.map(row_of)
.collect();
rows.sort_by(|a, b| b.started_at.cmp(&a.started_at));
Ok(rows)
}
pub fn run(
app: &App,
agent: Option<&str>,
@@ -63,16 +84,7 @@ pub fn run(
return resume_session(app, id);
}
sessions::reconcile(app)?;
let sf = sessions::load(app)?;
let mut rows: Vec<SessionRow> = sf
.sessions
.values()
.filter(|r| agent.map_or(true, |a| r.agent.as_deref() == Some(a)))
.filter(|r| project.map_or(true, |p| r.project.as_deref() == Some(p)))
.filter(|r| status.map_or(true, |s| r.status == s))
.map(row_of)
.collect();
rows.sort_by(|a, b| b.started_at.cmp(&a.started_at));
let rows = list_rows(app, agent, project, status)?;
if app.json() {
print_json(&rows);
return Ok(0);