use crate::harness::*;
#[test]
fn agents_kind_filter_json_and_tree_json_and_multi_node_text() {
let h = populated_home();
let bt = h.run(&[
"agents",
at(SESS).as_str(),
"--shape",
"builtin-task",
"--format",
"json",
]);
assert!(bt.success, "stderr: {}", bt.stderr);
assert!(
bt.stdout.contains("\"builtin-task\""),
"builtin-task JSON label missing: {}",
bt.stdout
);
let flat = h.run(&["agents", at(SESS).as_str(), "--format", "json"]);
assert!(flat.success, "stderr: {}", flat.stderr);
assert!(
!flat.stdout.contains("\"children\""),
"v0.5 flat rows must not nest children[]: {}",
flat.stdout
);
assert!(
!json_rows(&flat.stdout, "agent").is_empty(),
"kind:agent rows present: {}",
flat.stdout
);
let text = h.run(&["agents", at(SESS).as_str()]);
assert!(text.success && text.stdout.matches("triggered").count() >= 2);
}
#[test]
fn agents_single_agent_grab_text() {
let h = populated_home();
let out = h.run(&["agents", at(SESS).as_str(), "--agent", "aaa111"]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(
out.stdout.contains("aaa111"),
"node not grabbed: {}",
out.stdout
);
}
#[test]
fn agents_agent_grab_bypasses_time_and_kind_filters() {
let h = populated_home();
let out = h.run(&[
"agents",
at(SESS).as_str(),
"--agent",
"aaa111",
"--since",
"2026-06-08T00:00:00Z",
"--shape",
"workflow",
]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(
out.stdout.contains("aaa111"),
"direct --agent lookup must bypass time/kind filters: {}",
out.stdout
);
}
#[test]
fn agents_agent_grab_renders_single_node_not_whole_workflow() {
let h = populated_home();
let out = h.run(&["agents", at(SESS).as_str(), "--agent", "bbb222"]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(
out.stdout.contains("bbb222"),
"node grabbed: {}",
out.stdout
);
assert!(
!out.stdout.contains("WORKFLOW"),
"--agent must suppress the whole-workflow tree: {}",
out.stdout
);
}
#[test]
fn agents_kind_filter_workflow_only() {
let h = populated_home();
let out = h.run(&["agents", at(SESS).as_str(), "--shape", "workflow"]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(out.stdout.contains("workflow"));
assert!(!out.stdout.contains("builtin-task"));
assert!(out.stdout.contains("kind=workflow"));
}
#[test]
fn agents_by_completion_axis_and_window() {
let h = populated_home();
let out = h.run(&[
"agents",
at(SESS).as_str(),
"--since",
"2026-06-07T06:00:30Z",
"--order-by",
"completion",
]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(out.stdout.contains("window-axis=completion"));
assert!(out.stdout.contains("workflow"));
assert!(!out.stdout.contains("builtin-task"));
}
#[test]
fn agents_single_agent_grab_includes_returned_and_files() {
let h = topology_home();
let out = h.run(&[
"agents",
at(SESS).as_str(),
"--agent",
"topo11",
"--with-files",
"--format",
"json",
]);
assert!(out.success, "stderr: {}", out.stderr);
let lines: Vec<&str> = out
.stdout
.lines()
.filter(|l| !l.trim().is_empty())
.collect();
assert_eq!(
lines.len(),
4,
"header + session + agent + summary: {:?}",
lines
);
let agents = json_rows(&out.stdout, "agent");
assert_eq!(agents.len(), 1, "exactly the one selected node");
let v = &agents[0];
assert_eq!(v["agent_id"], "topo11");
assert_eq!(
v["returned_message"],
"SYNC-RETURN: the built-in carry answer"
);
let files = v["files_changed"].as_array().expect("files_changed array");
assert_eq!(files.len(), 1);
assert_eq!(files[0]["path"], "/repo/src/parse.rs");
assert_eq!(files[0]["op"], "edit");
}
#[test]
fn agents_fork_provenance_and_agent_type_filter() {
let h = Home::new();
h.write(
&format!("{ENC}/{SESS}.jsonl"),
concat!(
r#"{"type":"user","uuid":"u0","timestamp":"2026-06-07T05:00:00.000Z","message":{"role":"user","content":"work"}}"#, "\n",
),
);
h.write(
&format!("{ENC}/{SESS}/subagents/agent-f0f0f0f0f0f0.jsonl"),
concat!(
r#"{"type":"fork-context-ref","agentId":"f0f0f0f0f0f0","parentSessionId":"0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d","parentLastUuid":"aaaa1111-2222-4333-8444-555566667777","contextLength":2513}"#, "\n",
r#"{"type":"user","isSidechain":true,"agentId":"f0f0f0f0f0f0","timestamp":"2026-06-07T05:01:00.000Z","message":{"role":"user","content":"forked work"}}"#, "\n",
r#"{"type":"assistant","isSidechain":true,"agentId":"f0f0f0f0f0f0","timestamp":"2026-06-07T05:01:05.000Z","message":{"role":"assistant","content":[{"type":"text","text":"continuing from the fork"}]}}"#, "\n",
),
);
h.write(
&format!("{ENC}/{SESS}/subagents/agent-f0f0f0f0f0f0.meta.json"),
r#"{"agentType":"fork","isFork":true}"#,
);
h.write(
&format!("{ENC}/{SESS}/subagents/agent-abcd9999ee00.jsonl"),
concat!(
r#"{"type":"user","isSidechain":true,"agentId":"abcd9999ee00","timestamp":"2026-06-07T05:02:00.000Z","message":{"role":"user","content":"plain work"}}"#, "\n",
r#"{"type":"assistant","isSidechain":true,"agentId":"abcd9999ee00","timestamp":"2026-06-07T05:02:05.000Z","message":{"role":"assistant","content":[{"type":"text","text":"done"}]}}"#, "\n",
),
);
h.write(
&format!("{ENC}/{SESS}/subagents/agent-abcd9999ee00.meta.json"),
r#"{"agentType":"general-purpose","description":"worker","toolUseId":"t1"}"#,
);
let out = h.run(&["agents", at(SESS).as_str()]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(
out.stdout
.contains("forked-at aaaa1111-2222-4333-8444-555566667777 (context 2513)"),
"fork point named: {}",
out.stdout
);
let json = h.run(&["agents", at(SESS).as_str(), "--format", "json"]);
let fork_row: serde_json::Value = json
.stdout
.lines()
.map(|l| serde_json::from_str(l).unwrap())
.find(|o: &serde_json::Value| o["kind"] == "agent" && o["agent_type"] == "fork")
.expect("fork agent row");
assert_eq!(
fork_row["fork_parent_last_uuid"],
"aaaa1111-2222-4333-8444-555566667777"
);
assert_eq!(fork_row["fork_context_length"], 2513);
let plain_row: serde_json::Value = json
.stdout
.lines()
.map(|l| serde_json::from_str(l).unwrap())
.find(|o: &serde_json::Value| o["kind"] == "agent" && o["agent_type"] == "general-purpose")
.expect("plain agent row");
assert_eq!(plain_row["fork_parent_last_uuid"], serde_json::Value::Null);
let only_fork = h.run(&["agents", at(SESS).as_str(), "--agent-type", "fork"]);
assert!(
only_fork.stdout.contains("f0f0f0f0f0f0"),
"{}",
only_fork.stdout
);
assert!(
!only_fork.stdout.contains("abcd9999ee00"),
"filter excludes the other type: {}",
only_fork.stdout
);
let both = h.run(&[
"agents",
at(SESS).as_str(),
"--agent-type",
"fork",
"--agent-type",
"general-purpose",
]);
assert!(both.stdout.contains("f0f0f0f0f0f0") && both.stdout.contains("abcd9999ee00"));
}