@team-agent/installer 0.5.92 → 0.5.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +381 -157
- package/crates/team-agent/src/cli/diagnose.rs +40 -10
- package/crates/team-agent/src/cli/emit.rs +6 -4
- package/crates/team-agent/src/cli/mod.rs +483 -470
- package/crates/team-agent/src/cli/models.rs +1 -0
- package/crates/team-agent/src/cli/spec.rs +2 -2
- package/crates/team-agent/src/cli/tests/base.rs +20 -10
- package/crates/team-agent/src/cli/tests/divergence.rs +12 -21
- package/crates/team-agent/src/cli/tests/main_preserved.rs +6 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +20 -11
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +197 -30
- package/crates/team-agent/src/cli/triage.rs +31 -31
- package/crates/team-agent/src/cli/types.rs +3 -1
- package/crates/team-agent/src/coordinator/health.rs +92 -30
- package/crates/team-agent/src/coordinator/tick.rs +62 -8
- package/crates/team-agent/src/coordinator/types.rs +2 -0
- package/crates/team-agent/src/kill_audit.rs +41 -2
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +48 -14
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +4 -8
- package/crates/team-agent/src/lifecycle/launch.rs +17 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -0
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +10 -4
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +10 -7
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +91 -4
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +128 -11
- package/crates/team-agent/src/platform/process.rs +4 -45
- package/crates/team-agent/src/tmux_backend.rs +113 -3
- package/crates/team-agent/src/transport/test_support.rs +30 -0
- package/crates/team-agent/src/transport.rs +41 -0
- package/package.json +4 -4
|
@@ -161,6 +161,19 @@ pub(crate) fn diagnose_runtime(state: &Value, backend: &dyn Transport) -> (Value
|
|
|
161
161
|
}
|
|
162
162
|
issues.push(issue);
|
|
163
163
|
}
|
|
164
|
+
// Preserve distinct worker failures even when the shared session probe
|
|
165
|
+
// short-circuits pane enumeration. This keeps scope evidence without
|
|
166
|
+
// issuing another transport probe per worker.
|
|
167
|
+
if let Some(agents) = state.get("agents").and_then(Value::as_object) {
|
|
168
|
+
for agent_id in agents.keys() {
|
|
169
|
+
let issue = format!("worker_window_missing:{agent_id}");
|
|
170
|
+
issues.push(json!(issue.clone()));
|
|
171
|
+
repairs.push(json!({
|
|
172
|
+
"issue": issue,
|
|
173
|
+
"action": "team-agent restart",
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
164
177
|
return (Value::Array(issues), Value::Array(repairs));
|
|
165
178
|
}
|
|
166
179
|
|
|
@@ -289,6 +302,7 @@ pub(crate) fn diagnose_runtime_for_workspace(
|
|
|
289
302
|
state: &Value,
|
|
290
303
|
backend: &dyn Transport,
|
|
291
304
|
selected_team_key: Option<&str>,
|
|
305
|
+
coordinator_health: &crate::coordinator::HealthReport,
|
|
292
306
|
) -> (Value, Value) {
|
|
293
307
|
let (mut issues, mut repairs) = diagnose_runtime(state, backend);
|
|
294
308
|
append_live_leader_workspace_mismatch_issue(
|
|
@@ -306,7 +320,7 @@ pub(crate) fn diagnose_runtime_for_workspace(
|
|
|
306
320
|
&mut repairs,
|
|
307
321
|
);
|
|
308
322
|
append_legacy_snapshot_issue(workspace, state, &mut issues);
|
|
309
|
-
append_coordinator_health_issue(workspace, state, &mut issues, &mut repairs);
|
|
323
|
+
append_coordinator_health_issue(workspace, state, coordinator_health, &mut issues, &mut repairs);
|
|
310
324
|
append_runtime_bindings_stale_after_boot_issue(workspace, state, &mut issues, &mut repairs);
|
|
311
325
|
(issues, repairs)
|
|
312
326
|
}
|
|
@@ -322,8 +336,27 @@ pub(crate) fn workspace_has_existing_team_runtime(
|
|
|
322
336
|
workspace: &std::path::Path,
|
|
323
337
|
team_key: &str,
|
|
324
338
|
) -> bool {
|
|
325
|
-
|
|
326
|
-
|
|
339
|
+
// A source TEAM.md/team.spec.yaml is install/configuration context, not a
|
|
340
|
+
// live runtime. Only persisted runtime state/specs make topology checks
|
|
341
|
+
// applicable; an empty workspace therefore remains a healthy no-runtime
|
|
342
|
+
// report instead of a fabricated missing-session issue.
|
|
343
|
+
if let Ok(state) = crate::state::persist::load_runtime_state_without_migrations(workspace) {
|
|
344
|
+
// The workspace's top-level view may describe a stopped sibling.
|
|
345
|
+
// Preserve the top-level fallback for legacy single-team state only
|
|
346
|
+
// when there is no selected team entry.
|
|
347
|
+
let team_state = state
|
|
348
|
+
.get("teams")
|
|
349
|
+
.and_then(|teams| teams.get(team_key))
|
|
350
|
+
.unwrap_or(&state);
|
|
351
|
+
let terminal = team_state
|
|
352
|
+
.get("status")
|
|
353
|
+
.and_then(Value::as_str)
|
|
354
|
+
.is_some_and(|status| matches!(status, "stopped" | "shutdown" | "archived" | "terminal"));
|
|
355
|
+
if terminal {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
crate::model::paths::runtime_spec_path(workspace, team_key).is_file()
|
|
327
360
|
|| crate::state::persist::runtime_state_path(workspace).is_file()
|
|
328
361
|
}
|
|
329
362
|
|
|
@@ -790,21 +823,18 @@ fn append_legacy_snapshot_issue(workspace: &std::path::Path, state: &Value, issu
|
|
|
790
823
|
fn append_coordinator_health_issue(
|
|
791
824
|
workspace: &std::path::Path,
|
|
792
825
|
state: &Value,
|
|
826
|
+
health: &crate::coordinator::HealthReport,
|
|
793
827
|
issues: &mut Value,
|
|
794
828
|
repairs: &mut Value,
|
|
795
829
|
) {
|
|
796
|
-
|
|
797
|
-
// `.team/runtime/team.db`, including when the file is missing or empty.
|
|
798
|
-
let workspace = crate::coordinator::WorkspacePath::new(workspace.to_path_buf());
|
|
799
|
-
let health = crate::coordinator::coordinator_health_read_only(&workspace);
|
|
800
|
-
let Some(id) = coordinator_issue_id(state, &health) else {
|
|
830
|
+
let Some(id) = coordinator_issue_id(state, health) else {
|
|
801
831
|
return;
|
|
802
832
|
};
|
|
803
833
|
if let Some(items) = issues.as_array_mut() {
|
|
804
|
-
items.push(coordinator_issue_value(id,
|
|
834
|
+
items.push(coordinator_issue_value(id, health, workspace));
|
|
805
835
|
}
|
|
806
836
|
if let Some(items) = repairs.as_array_mut() {
|
|
807
|
-
items.push(coordinator_repair_hint(id,
|
|
837
|
+
items.push(coordinator_repair_hint(id, health));
|
|
808
838
|
}
|
|
809
839
|
}
|
|
810
840
|
|
|
@@ -225,7 +225,8 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
225
225
|
"profile" => cmd_profile(&profile_args(args, cwd)?).map(emit_result),
|
|
226
226
|
"results" => cmd_results(&results_args(args, cwd)?).map(emit_result),
|
|
227
227
|
"wait" => cmd_wait(&wait_args(args, cwd)?).map(emit_result),
|
|
228
|
-
|
|
228
|
+
// Compatibility spelling: parse and execute the exact doctor contract.
|
|
229
|
+
"diagnose" => cmd_doctor(&doctor_args(args, cwd)).map(emit_result),
|
|
229
230
|
"preflight" => cmd_preflight(&preflight_args(args, cwd)).map(emit_result),
|
|
230
231
|
"wait-ready" => cmd_wait_ready(&wait_ready_args(args, cwd)).map(emit_result),
|
|
231
232
|
"e2e" => cmd_e2e(&e2e_args(args, cwd)).map(emit_result),
|
|
@@ -340,7 +341,7 @@ pub(crate) fn default_help() -> String {
|
|
|
340
341
|
"reset-agent",
|
|
341
342
|
],
|
|
342
343
|
);
|
|
343
|
-
append_help_section(&mut out, "Diagnose", &["
|
|
344
|
+
append_help_section(&mut out, "Diagnose", &["doctor"]);
|
|
344
345
|
append_help_section(
|
|
345
346
|
&mut out,
|
|
346
347
|
"Guided recovery",
|
|
@@ -444,7 +445,7 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
444
445
|
Some("profile") => "usage: team-agent profile COMMAND NAME [--workspace WORKSPACE] [--team TEAM] [--auth-mode MODE] [--proxy-mode direct|inherit] [--json]".to_string(),
|
|
445
446
|
Some("results") => "usage: team-agent results --case CASE_ID [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
446
447
|
Some("wait") => "usage: team-agent wait --task TASK [--workspace WORKSPACE] [--json]".to_string(),
|
|
447
|
-
Some("diagnose") => "usage: team-agent
|
|
448
|
+
Some("diagnose") => "usage: team-agent doctor [SPEC] [--workspace WORKSPACE] [--team TEAM] [--gate orphans|comms] [--comms] [--fix] [--fix-schema] [--cleanup-orphans] [--confirm] [--json]".to_string(),
|
|
448
449
|
Some("preflight") => "usage: team-agent preflight [TEAMDIR] [--json]".to_string(),
|
|
449
450
|
Some("wait-ready") => "usage: team-agent wait-ready [--workspace WORKSPACE] [--team TEAM] [--timeout SECONDS] [--json]".to_string(),
|
|
450
451
|
Some("e2e") => "usage: team-agent e2e [--workspace WORKSPACE] [--providers LIST] [--real] [--json]".to_string(),
|
|
@@ -2172,7 +2173,8 @@ mod tests {
|
|
|
2172
2173
|
fn hidden_commands_not_in_default_help() {
|
|
2173
2174
|
let top_help = command_help(None);
|
|
2174
2175
|
let visible = visible_help_commands(&top_help);
|
|
2175
|
-
|
|
2176
|
+
assert!(visible.iter().any(|command| command == "doctor"));
|
|
2177
|
+
for command in ["leaders", "diagnose", "e2e", "peek", "coordinator"] {
|
|
2176
2178
|
assert!(
|
|
2177
2179
|
!visible.iter().any(|visible| visible == command),
|
|
2178
2180
|
"`{command}` must stay hidden from default help"
|