mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-09 19:03:28 +08:00
feat: add ecc2 global worktree status
This commit is contained in:
205
ecc2/src/main.rs
205
ecc2/src/main.rs
@@ -190,6 +190,9 @@ enum Commands {
|
||||
WorktreeStatus {
|
||||
/// Session ID or alias
|
||||
session_id: Option<String>,
|
||||
/// Show worktree status for all sessions
|
||||
#[arg(long)]
|
||||
all: bool,
|
||||
/// Emit machine-readable JSON instead of the human summary
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
@@ -645,23 +648,40 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
Some(Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
json,
|
||||
patch,
|
||||
check,
|
||||
}) => {
|
||||
let id = session_id.unwrap_or_else(|| "latest".to_string());
|
||||
let resolved_id = resolve_session_id(&db, &id)?;
|
||||
let session = db
|
||||
.get_session(&resolved_id)?
|
||||
.ok_or_else(|| anyhow::anyhow!("Session not found: {resolved_id}"))?;
|
||||
let report = build_worktree_status_report(&session, patch)?;
|
||||
if json {
|
||||
println!("{}", serde_json::to_string_pretty(&report)?);
|
||||
if all && session_id.is_some() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"worktree-status does not accept a session ID when --all is set"
|
||||
));
|
||||
}
|
||||
let reports = if all {
|
||||
session::manager::list_sessions(&db)?
|
||||
.into_iter()
|
||||
.map(|session| build_worktree_status_report(&session, patch))
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
} else {
|
||||
println!("{}", format_worktree_status_human(&report));
|
||||
let id = session_id.unwrap_or_else(|| "latest".to_string());
|
||||
let resolved_id = resolve_session_id(&db, &id)?;
|
||||
let session = db
|
||||
.get_session(&resolved_id)?
|
||||
.ok_or_else(|| anyhow::anyhow!("Session not found: {resolved_id}"))?;
|
||||
vec![build_worktree_status_report(&session, patch)?]
|
||||
};
|
||||
if json {
|
||||
if all {
|
||||
println!("{}", serde_json::to_string_pretty(&reports)?);
|
||||
} else {
|
||||
println!("{}", serde_json::to_string_pretty(&reports[0])?);
|
||||
}
|
||||
} else {
|
||||
println!("{}", format_worktree_status_reports_human(&reports));
|
||||
}
|
||||
if check {
|
||||
std::process::exit(worktree_status_exit_code(&report));
|
||||
std::process::exit(worktree_status_reports_exit_code(&reports));
|
||||
}
|
||||
}
|
||||
Some(Commands::Stop { session_id }) => {
|
||||
@@ -1011,10 +1031,26 @@ fn format_worktree_status_human(report: &WorktreeStatusReport) -> String {
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
fn format_worktree_status_reports_human(reports: &[WorktreeStatusReport]) -> String {
|
||||
reports
|
||||
.iter()
|
||||
.map(format_worktree_status_human)
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n")
|
||||
}
|
||||
|
||||
fn worktree_status_exit_code(report: &WorktreeStatusReport) -> i32 {
|
||||
report.check_exit_code
|
||||
}
|
||||
|
||||
fn worktree_status_reports_exit_code(reports: &[WorktreeStatusReport]) -> i32 {
|
||||
reports
|
||||
.iter()
|
||||
.map(worktree_status_exit_code)
|
||||
.max()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn summarize_coordinate_backlog(
|
||||
outcome: &session::manager::CoordinateBacklogOutcome,
|
||||
) -> CoordinateBacklogPassSummary {
|
||||
@@ -1250,11 +1286,13 @@ mod tests {
|
||||
match cli.command {
|
||||
Some(Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
json,
|
||||
patch,
|
||||
check,
|
||||
}) => {
|
||||
assert_eq!(session_id.as_deref(), Some("planner"));
|
||||
assert!(!all);
|
||||
assert!(!json);
|
||||
assert!(!patch);
|
||||
assert!(!check);
|
||||
@@ -1271,11 +1309,13 @@ mod tests {
|
||||
match cli.command {
|
||||
Some(Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
json,
|
||||
patch,
|
||||
check,
|
||||
}) => {
|
||||
assert_eq!(session_id, None);
|
||||
assert!(!all);
|
||||
assert!(json);
|
||||
assert!(!patch);
|
||||
assert!(!check);
|
||||
@@ -1284,6 +1324,91 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_parses_worktree_status_all_flag() {
|
||||
let cli = Cli::try_parse_from(["ecc", "worktree-status", "--all"])
|
||||
.expect("worktree-status --all should parse");
|
||||
|
||||
match cli.command {
|
||||
Some(Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
json,
|
||||
patch,
|
||||
check,
|
||||
}) => {
|
||||
assert_eq!(session_id, None);
|
||||
assert!(all);
|
||||
assert!(!json);
|
||||
assert!(!patch);
|
||||
assert!(!check);
|
||||
}
|
||||
_ => panic!("expected worktree-status subcommand"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_parses_worktree_status_session_id_with_all_flag() {
|
||||
let err = Cli::try_parse_from(["ecc", "worktree-status", "planner", "--all"])
|
||||
.expect("worktree-status planner --all should parse");
|
||||
|
||||
let command = err.command.expect("expected command");
|
||||
let Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
..
|
||||
} = command
|
||||
else {
|
||||
panic!("expected worktree-status subcommand");
|
||||
};
|
||||
|
||||
assert_eq!(session_id.as_deref(), Some("planner"));
|
||||
assert!(all);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_worktree_status_reports_human_joins_multiple_reports() {
|
||||
let reports = vec![
|
||||
WorktreeStatusReport {
|
||||
session_id: "sess-a".to_string(),
|
||||
task: "first".to_string(),
|
||||
session_state: "running".to_string(),
|
||||
health: "in_progress".to_string(),
|
||||
check_exit_code: 1,
|
||||
patch_included: false,
|
||||
attached: false,
|
||||
path: None,
|
||||
branch: None,
|
||||
base_branch: None,
|
||||
diff_summary: None,
|
||||
file_preview: Vec::new(),
|
||||
patch_preview: None,
|
||||
merge_readiness: None,
|
||||
},
|
||||
WorktreeStatusReport {
|
||||
session_id: "sess-b".to_string(),
|
||||
task: "second".to_string(),
|
||||
session_state: "stopped".to_string(),
|
||||
health: "clear".to_string(),
|
||||
check_exit_code: 0,
|
||||
patch_included: false,
|
||||
attached: false,
|
||||
path: None,
|
||||
branch: None,
|
||||
base_branch: None,
|
||||
diff_summary: None,
|
||||
file_preview: Vec::new(),
|
||||
patch_preview: None,
|
||||
merge_readiness: None,
|
||||
},
|
||||
];
|
||||
|
||||
let text = format_worktree_status_reports_human(&reports);
|
||||
assert!(text.contains("Worktree status for sess-a [running]"));
|
||||
assert!(text.contains("Worktree status for sess-b [stopped]"));
|
||||
assert!(text.contains("\n\nWorktree status for sess-b [stopped]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_parses_worktree_status_patch_flag() {
|
||||
let cli = Cli::try_parse_from(["ecc", "worktree-status", "--patch"])
|
||||
@@ -1292,11 +1417,13 @@ mod tests {
|
||||
match cli.command {
|
||||
Some(Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
json,
|
||||
patch,
|
||||
check,
|
||||
}) => {
|
||||
assert_eq!(session_id, None);
|
||||
assert!(!all);
|
||||
assert!(!json);
|
||||
assert!(patch);
|
||||
assert!(!check);
|
||||
@@ -1313,11 +1440,13 @@ mod tests {
|
||||
match cli.command {
|
||||
Some(Commands::WorktreeStatus {
|
||||
session_id,
|
||||
all,
|
||||
json,
|
||||
patch,
|
||||
check,
|
||||
}) => {
|
||||
assert_eq!(session_id, None);
|
||||
assert!(!all);
|
||||
assert!(!json);
|
||||
assert!(!patch);
|
||||
assert!(check);
|
||||
@@ -1450,6 +1579,62 @@ mod tests {
|
||||
assert_eq!(worktree_status_exit_code(&conflicted), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn worktree_status_reports_exit_code_uses_highest_severity() {
|
||||
let reports = vec![
|
||||
WorktreeStatusReport {
|
||||
session_id: "sess-a".to_string(),
|
||||
task: "first".to_string(),
|
||||
session_state: "running".to_string(),
|
||||
health: "clear".to_string(),
|
||||
check_exit_code: 0,
|
||||
patch_included: false,
|
||||
attached: false,
|
||||
path: None,
|
||||
branch: None,
|
||||
base_branch: None,
|
||||
diff_summary: None,
|
||||
file_preview: Vec::new(),
|
||||
patch_preview: None,
|
||||
merge_readiness: None,
|
||||
},
|
||||
WorktreeStatusReport {
|
||||
session_id: "sess-b".to_string(),
|
||||
task: "second".to_string(),
|
||||
session_state: "running".to_string(),
|
||||
health: "in_progress".to_string(),
|
||||
check_exit_code: 1,
|
||||
patch_included: false,
|
||||
attached: false,
|
||||
path: None,
|
||||
branch: None,
|
||||
base_branch: None,
|
||||
diff_summary: None,
|
||||
file_preview: Vec::new(),
|
||||
patch_preview: None,
|
||||
merge_readiness: None,
|
||||
},
|
||||
WorktreeStatusReport {
|
||||
session_id: "sess-c".to_string(),
|
||||
task: "third".to_string(),
|
||||
session_state: "running".to_string(),
|
||||
health: "conflicted".to_string(),
|
||||
check_exit_code: 2,
|
||||
patch_included: false,
|
||||
attached: false,
|
||||
path: None,
|
||||
branch: None,
|
||||
base_branch: None,
|
||||
diff_summary: None,
|
||||
file_preview: Vec::new(),
|
||||
patch_preview: None,
|
||||
merge_readiness: None,
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(worktree_status_reports_exit_code(&reports), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_parses_assign_command() {
|
||||
let cli = Cli::try_parse_from([
|
||||
|
||||
Reference in New Issue
Block a user