From f3258ee2b57dfe745e268bb004beff427d968965 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Sun, 29 Mar 2026 22:05:36 -0700 Subject: [PATCH] fix(output): emit array-of-objects for JSON output sessions list/dump and agents list/dump were passing Vec> directly to render_json, producing unlabeled arrays. Now each row is mapped to a serde_json object with named keys before serializing. Closes claudbg-pfa5 Co-Authored-By: Claude Sonnet 4.6 --- ...-is-array-of-arrays-instead-of-array-of.md | 8 +++-- src/commands/agents.rs | 31 +++++++++++++++-- src/commands/sessions.rs | 33 +++++++++++++++++-- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/.beans/claudbg-pfa5--json-output-is-array-of-arrays-instead-of-array-of.md b/.beans/claudbg-pfa5--json-output-is-array-of-arrays-instead-of-array-of.md index 10bfdb8..6cf51ab 100644 --- a/.beans/claudbg-pfa5--json-output-is-array-of-arrays-instead-of-array-of.md +++ b/.beans/claudbg-pfa5--json-output-is-array-of-arrays-instead-of-array-of.md @@ -1,11 +1,11 @@ --- # claudbg-pfa5 title: JSON output is array-of-arrays instead of array-of-objects -status: todo +status: completed type: bug priority: normal created_at: 2026-03-30T04:37:05Z -updated_at: 2026-03-30T04:41:14Z +updated_at: 2026-03-30T05:05:12Z parent: claudbg-tci9 --- @@ -38,3 +38,7 @@ Output should be an array of objects with named keys: - `src/commands/sessions.rs` — `list()` and `dump()` JSON output branches - `src/output/json.rs` — generic `render_json` + +## Summary of Changes + +Fixed JSON output in both sessions.rs and agents.rs to produce array-of-objects instead of array-of-arrays. Each row is now mapped to a serde_json object with named keys before serializing. Keys: sessions list (id, date, project, model, messages, subagents), sessions dump (seq, timestamp, type, role, content), agents list (id, type, file, modified), agents dump (seq, timestamp, type, role, content). diff --git a/src/commands/agents.rs b/src/commands/agents.rs index bc456da..8ee4889 100644 --- a/src/commands/agents.rs +++ b/src/commands/agents.rs @@ -185,7 +185,20 @@ pub async fn list(session_id: &str, opts: &crate::cli::GlobalOpts) -> Result<()> crate::cli::OutputFormat::Table => { crate::output::render_table(&["Agent ID", "Type", "File", "Modified"], &rows)? } - crate::cli::OutputFormat::Json => crate::output::render_json(&rows)?, + crate::cli::OutputFormat::Json => { + let objects: Vec = rows + .iter() + .map(|r| { + serde_json::json!({ + "id": r[0], + "type": r[1], + "file": r[2], + "modified": r[3], + }) + }) + .collect(); + crate::output::render_json(&objects)? + } crate::cli::OutputFormat::Xml => { crate::output::render_xml_rows(&["agent_id", "type", "file", "modified"], &rows)? } @@ -239,7 +252,21 @@ pub async fn dump( crate::cli::OutputFormat::Table => { crate::output::render_table(&["#", "Timestamp", "Type", "Role", "Content"], &rows)? } - crate::cli::OutputFormat::Json => crate::output::render_json(&rows)?, + crate::cli::OutputFormat::Json => { + let objects: Vec = rows + .iter() + .map(|r| { + serde_json::json!({ + "seq": r[0], + "timestamp": r[1], + "type": r[2], + "role": r[3], + "content": r[4], + }) + }) + .collect(); + crate::output::render_json(&objects)? + } crate::cli::OutputFormat::Xml => { crate::output::render_xml_rows(&["seq", "timestamp", "type", "role", "content"], &rows)? } diff --git a/src/commands/sessions.rs b/src/commands/sessions.rs index 4955a76..722eda3 100644 --- a/src/commands/sessions.rs +++ b/src/commands/sessions.rs @@ -202,7 +202,22 @@ pub async fn list(opts: &crate::cli::GlobalOpts) -> Result<()> { crate::cli::OutputFormat::Table => { crate::output::render_table(&["ID", "Date", "Project", "Model", "Messages"], &rows)? } - crate::cli::OutputFormat::Json => crate::output::render_json(&rows)?, + crate::cli::OutputFormat::Json => { + let objects: Vec = rows + .iter() + .map(|r| { + serde_json::json!({ + "id": r[0], + "date": r[1], + "project": r[2], + "model": r[3], + "messages": r[4], + "subagents": 0, + }) + }) + .collect(); + crate::output::render_json(&objects)? + } crate::cli::OutputFormat::Xml => crate::output::render_xml_rows( &["session_id", "date", "project", "model", "messages"], &rows, @@ -293,7 +308,21 @@ pub async fn dump(id: &str, follow: bool, opts: &crate::cli::GlobalOpts) -> Resu crate::cli::OutputFormat::Table => { crate::output::render_table(&["#", "Timestamp", "Type", "Role", "Content"], &rows)? } - crate::cli::OutputFormat::Json => crate::output::render_json(&rows)?, + crate::cli::OutputFormat::Json => { + let objects: Vec = rows + .iter() + .map(|r| { + serde_json::json!({ + "seq": r[0], + "timestamp": r[1], + "type": r[2], + "role": r[3], + "content": r[4], + }) + }) + .collect(); + crate::output::render_json(&objects)? + } crate::cli::OutputFormat::Xml => { crate::output::render_xml_rows(&["seq", "timestamp", "type", "role", "content"], &rows)? }