mod common;
use common::*;
#[test]
fn lifecycle_new_start_complete() {
ensure_built();
let ws = TempWorkspace::new();
let out = ws.run_ok(&["new", "my-session", "-g", "test goal"]);
assert!(out.contains("created"), "new: {}", out);
let out = ws.run_ok(&["start", "my-session"]);
assert!(out.contains("start"), "start: {}", out);
let out = ws.run_ok(&["list", "--active"]);
assert!(out.contains("my-session"), "active list: {}", out);
assert!(out.contains("in_progress"), "active list: {}", out);
ws.write_detail("my-session", "\
## Scope / Plan
Test scope — verify lifecycle.
## Tags
test, lifecycle
## Live Session Data
session_id: auto
started: day20622T10:00Z
pids: none
## Progress Log
- [2026-06-18 10:00Z] Session created
");
let out = ws.run_ok(&["note", "my-session", "implemented the thing"]);
assert!(out.contains("noted"), "note: {}", out);
let out = ws.run_ok(&["complete", "my-session"]);
assert!(out.contains("complete"), "complete: {}", out);
let out = ws.run_ok(&["list", "--status", "completed"]);
assert!(out.contains("my-session"), "completed list: {}", out);
let out = ws.run_ok(&["show", "my-session"]);
assert!(out.contains("completed"), "show status: {}", out);
assert!(out.contains("test goal"), "show goal: {}", out);
}
#[test]
fn lifecycle_start_block_abandon() {
ensure_built();
let ws = TempWorkspace::new();
ws.run_ok(&["new", "blocked-session", "-g", "blocked test"]);
ws.run_ok(&["start", "blocked-session"]);
ws.run_ok(&["block", "blocked-session"]);
let out = ws.run_ok(&["list", "--status", "blocked"]);
assert!(out.contains("blocked-session"), "blocked list: {}", out);
ws.run_ok(&["abandon", "blocked-session"]);
let out = ws.run_ok(&["list", "--status", "abandoned"]);
assert!(out.contains("blocked-session"), "abandoned list: {}", out);
}
#[test]
fn lifecycle_trash_recover() {
ensure_built();
let ws = TempWorkspace::new();
ws.run_ok(&["new", "trash-me", "-g", "trash test"]);
ws.run_ok(&["start", "trash-me"]);
let out = ws.run_ok(&["trash", "trash-me"]);
assert!(out.contains("trashed"), "trash: {}", out);
let out = ws.run_ok(&["list", "--status", "trashed"]);
assert!(out.contains("trash-me"), "trashed list: {}", out);
let out = ws.run_ok(&["recover", "trash-me"]);
assert!(out.contains("recovered"), "recover: {}", out);
let out = ws.run_ok(&["list", "--active"]);
assert!(out.contains("trash-me"), "recovered active: {}", out);
}
#[test]
fn lifecycle_pending_clears_identity() {
ensure_built();
let ws = TempWorkspace::new();
ws.run_ok(&["new", "reset-me", "-g", "reset test"]);
ws.run_ok(&["start", "reset-me"]);
ws.run_ok(&["attach", "reset-me", "f493397b-456a-426d-92e1-4d5f15da0311"]);
let out = ws.run_ok(&["pending", "reset-me"]);
assert!(out.contains("reset"), "pending: {}", out);
let reg = ws.read_registry();
let entry = reg["sessions"]
.as_array()
.unwrap()
.iter()
.find(|s| s["name"] == "reset-me")
.unwrap();
assert_eq!(entry["session_id"], "", "session_id should be cleared");
assert!(entry["pids"].as_array().unwrap().is_empty(), "pids should be cleared");
assert_eq!(entry["status"], "pending");
}
#[test]
fn new_rejects_duplicate() {
ensure_built();
let ws = TempWorkspace::new();
ws.run_ok(&["new", "unique-session", "-g", "first"]);
let err = ws.run_err(&["new", "unique-session", "-g", "second"]);
assert!(err.contains("already exists"), "duplicate error: {}", err);
}
#[test]
fn new_force_skips_fuzzy_duplicate() {
ensure_built();
let ws = TempWorkspace::new();
ws.run_ok(&["new", "test", "-g", "original"]);
let err = ws.run_err(&["new", "test2", "-g", "similar"]);
assert!(err.contains("looks similar"), "fuzzy error: {}", err);
let out = ws.run_ok(&["new", "test2", "-g", "similar", "--force"]);
assert!(out.contains("created"), "force create: {}", out);
}
#[test]
fn list_summary_and_status_filter() {
ensure_built();
let ws = TempWorkspace::new();
ws.run_ok(&["new", "session-a", "-g", "one"]);
ws.run_ok(&["new", "session-b", "-g", "two", "--force"]);
ws.run_ok(&["start", "session-a"]);
let out = ws.run_ok(&["list", "--summary"]);
assert!(out.contains("1 active"), "summary active: {}", out);
assert!(out.contains("2 total"), "summary total: {}", out);
let out = ws.run(&["list", "--status", "bogus"]);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(stderr.contains("unknown status"), "invalid status: {}", stderr);
let out = ws.run(&["list", "--status", "help"]);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(stderr.contains("pending"), "status help: {}", stderr);
}