@team-agent/installer 0.5.98 → 0.5.100

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.
Files changed (71) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +1 -163
  4. package/crates/team-agent/src/cli/diagnose.rs +3 -19
  5. package/crates/team-agent/src/cli/emit.rs +20 -204
  6. package/crates/team-agent/src/cli/mod.rs +138 -205
  7. package/crates/team-agent/src/cli/send/coordinator.rs +2 -2
  8. package/crates/team-agent/src/cli/spec.rs +41 -67
  9. package/crates/team-agent/src/cli/tests/main_preserved.rs +2 -186
  10. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +9 -10
  11. package/crates/team-agent/src/cli/tests/run_delegation.rs +0 -3
  12. package/crates/team-agent/src/cli/tests/verb_validate.rs +0 -1
  13. package/crates/team-agent/src/cli/triage.rs +1 -1
  14. package/crates/team-agent/src/cli/types.rs +0 -55
  15. package/crates/team-agent/src/compiler/tests.rs +5 -8
  16. package/crates/team-agent/src/compiler.rs +6 -14
  17. package/crates/team-agent/src/leader/lease.rs +1 -1
  18. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +1 -1
  19. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +1 -1
  20. package/crates/team-agent/src/lifecycle/launch/agent_state.rs +5 -25
  21. package/crates/team-agent/src/lifecycle/launch/identity.rs +2 -18
  22. package/crates/team-agent/src/lifecycle/launch/layout.rs +7 -29
  23. package/crates/team-agent/src/lifecycle/launch/leader_context.rs +1 -1
  24. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +1 -1
  25. package/crates/team-agent/src/lifecycle/launch/ownership.rs +1 -1
  26. package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +7 -7
  27. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +12 -49
  28. package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +3 -9
  29. package/crates/team-agent/src/lifecycle/launch/readiness.rs +1 -1
  30. package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -61
  31. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +2 -15
  32. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +3 -7
  33. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +1 -1
  34. package/crates/team-agent/src/lifecycle/launch.rs +3 -4
  35. package/crates/team-agent/src/lifecycle/mod.rs +0 -8
  36. package/crates/team-agent/src/lifecycle/restart/agent.rs +62 -8
  37. package/crates/team-agent/src/lifecycle/restart/common.rs +0 -32
  38. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +6 -15
  39. package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +2 -2
  40. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +1 -1
  41. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +1 -2
  42. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +0 -1
  43. package/crates/team-agent/src/lifecycle/tests/core.rs +0 -213
  44. package/crates/team-agent/src/lifecycle/tests/issue238_codex_effort_contract.rs +96 -0
  45. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +1 -0
  46. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +31 -77
  47. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -2
  48. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +4 -8
  49. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +16 -9
  50. package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +1 -1
  51. package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +0 -60
  52. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +3 -4
  53. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +2 -2
  54. package/crates/team-agent/src/lifecycle/tests.rs +1 -2
  55. package/crates/team-agent/src/lifecycle/types.rs +3 -133
  56. package/crates/team-agent/src/messaging/send.rs +2 -2
  57. package/crates/team-agent/src/model/enums.rs +21 -71
  58. package/crates/team-agent/src/model/spec.rs +5 -20
  59. package/crates/team-agent/src/provider/adapters/codex.rs +2 -2
  60. package/crates/team-agent/src/provider/types.rs +7 -6
  61. package/crates/team-agent/src/state/repository.rs +0 -5
  62. package/examples/team.spec.yaml +0 -1
  63. package/package.json +4 -4
  64. package/schemas/team.schema.json +2 -2
  65. package/skills/team-agent/SKILL.md +1 -1
  66. package/skills/team-agent/references/recovery-runbook.md +2 -2
  67. package/skills/team-agent/references/team-agent-operator.md +3 -10
  68. package/skills/team-agent/references/team-in-team.md +0 -6
  69. package/crates/team-agent/src/lifecycle/display.rs +0 -550
  70. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +0 -884
  71. package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +0 -481
@@ -45,11 +45,11 @@ use serde_json::{json, Map, Value};
45
45
  use thiserror::Error;
46
46
 
47
47
  // REUSE in-tree(只 import,不 redefine):
48
- use crate::messaging::{self, AlertType, MessageTarget, SendOptions, TrustedSender};
48
+ use crate::messaging::{self, MessageTarget, SendOptions, TrustedSender};
49
49
  use crate::model::ids::{TaskId, TeamKey};
50
50
 
51
51
  pub(crate) const COMMS_BOUNDARY_TEXT: &str = "validates live pane binding consistency and zero-token comms contracts. Does NOT perform live runtime message round-trip. (zero token, zero pollution)";
52
- pub(crate) const QUICK_START_REMINDER: &str = "Reminder: Do not inspect raw worker terminal output during normal operation. Use team-agent status / inbox / collect instead. Wait for report_result.";
52
+ pub(crate) const QUICK_START_REMINDER: &str = "Reminder: Do not inspect raw worker pane output during normal operation. Use team-agent status / inbox / collect instead. Wait for report_result.";
53
53
  pub(crate) const SEND_REMINDER: &str = "Message delivered. Wait for the worker to report_result. Do not poll the worker terminal with capture-pane.";
54
54
  pub(crate) const STATUS_REMINDER: &str = "Results are finalized automatically; use --watch-result or team-agent inbox AGENT -n 3 for transport fallback. Do not capture-pane worker terminals.";
55
55
 
@@ -119,7 +119,7 @@ mod hermetic_test_support;
119
119
  pub mod status_port;
120
120
 
121
121
  /// PLACEHOLDER → step13 lifecycle(`runtime.{quick_start,start_agent,add_agent,fork_agent,
122
- /// remove_agent,start_agent,stop_agent,reset_agent,restart,shutdown,start_leader,acknowledge_idle}`)。
122
+ /// remove_agent,start_agent,stop_agent,reset_agent,restart,shutdown,start_leader}`)。
123
123
  /// `quick_start.py` 物理在本子系统但实现属 step 13(card)。本层只声明委派面。
124
124
  pub mod lifecycle_port {
125
125
  use super::*;
@@ -133,16 +133,14 @@ pub mod lifecycle_port {
133
133
  name: Option<&str>,
134
134
  team_id: Option<&str>,
135
135
  yes: bool,
136
- open_display: bool,
137
136
  backend: Option<&str>,
138
137
  ) -> Result<Value, CliError> {
139
- match crate::lifecycle::quick_start_in_workspace_with_display_and_backend(
138
+ match crate::lifecycle::quick_start_in_workspace_with_backend(
140
139
  workspace,
141
140
  agents_dir,
142
141
  name,
143
142
  yes,
144
143
  team_id,
145
- open_display,
146
144
  backend,
147
145
  ) {
148
146
  Ok(report) => Ok(quick_start_value(report)),
@@ -1155,10 +1153,7 @@ pub mod lifecycle_port {
1155
1153
  }
1156
1154
  }
1157
1155
  }
1158
- let _ = crate::lifecycle::display::close_team_display_backends(
1159
- &run_workspace,
1160
- session,
1161
- );
1156
+ cleanup_owned_team_windows(&run_workspace, transport, &state, session);
1162
1157
  } else {
1163
1158
  let targets = vec![session.as_str().to_string()];
1164
1159
  let event_log = crate::event_log::EventLog::new(&run_workspace);
@@ -1185,10 +1180,7 @@ pub mod lifecycle_port {
1185
1180
  } else {
1186
1181
  push_unique_session(&mut killed_sessions, session.clone());
1187
1182
  }
1188
- let _ = crate::lifecycle::display::close_team_display_backends(
1189
- &run_workspace,
1190
- session,
1191
- );
1183
+ cleanup_owned_team_windows(&run_workspace, transport, &state, session);
1192
1184
  }
1193
1185
  }
1194
1186
  }
@@ -1473,6 +1465,127 @@ pub mod lifecycle_port {
1473
1465
  Ok(response)
1474
1466
  }
1475
1467
 
1468
+ /// Remove legacy adaptive display windows without reopening a display backend.
1469
+ /// Every target is scoped to the selected transport and passes the same
1470
+ /// ownership/protection audit as the rest of shutdown. Unknown or protected
1471
+ /// targets are intentionally left in place.
1472
+ fn cleanup_owned_team_windows(
1473
+ workspace: &Path,
1474
+ transport: &dyn crate::transport::Transport,
1475
+ state: &Value,
1476
+ session: &crate::transport::SessionName,
1477
+ ) {
1478
+ let Some(agents) = state.get("agents").and_then(Value::as_object) else {
1479
+ return;
1480
+ };
1481
+ let leader_session = state
1482
+ .get("leader_receiver")
1483
+ .and_then(|receiver| receiver.get("session_name"))
1484
+ .and_then(Value::as_str)
1485
+ .filter(|value| !value.is_empty())
1486
+ .unwrap_or_else(|| session.as_str());
1487
+ let leader_panes = collect_state_leader_anchor_pane_ids(
1488
+ state,
1489
+ transport.tmux_endpoint().as_deref(),
1490
+ );
1491
+ let event_log = crate::event_log::EventLog::new(workspace);
1492
+ let team_key = state.get("team_key").and_then(Value::as_str);
1493
+ let generation = state_generation(state);
1494
+ let overview_prefix = format!("team-agent:{}:overview", session.as_str());
1495
+ let mut windows = std::collections::BTreeSet::new();
1496
+ let mut panes = std::collections::BTreeSet::new();
1497
+ for (_agent_id, agent) in agents {
1498
+ let Some(display) = agent.get("display").and_then(Value::as_object) else {
1499
+ continue;
1500
+ };
1501
+ if display.get("backend").and_then(Value::as_str) != Some("adaptive") {
1502
+ continue;
1503
+ }
1504
+ if display.get("status").and_then(Value::as_str) == Some("stopped") {
1505
+ continue;
1506
+ }
1507
+ if let Some(window) = display
1508
+ .get("workspace_window")
1509
+ .or_else(|| display.get("window"))
1510
+ .or_else(|| agent.get("window"))
1511
+ .and_then(Value::as_str)
1512
+ .filter(|value| !value.is_empty())
1513
+ {
1514
+ if window == overview_prefix || window.starts_with(&format!("{overview_prefix}-")) {
1515
+ windows.insert(format!("{leader_session}:{window}"));
1516
+ }
1517
+ }
1518
+ if let Some(pane) = display.get("pane_id").and_then(Value::as_str) {
1519
+ if pane.starts_with('%') && !leader_panes.contains(pane) {
1520
+ panes.insert(pane.to_string());
1521
+ }
1522
+ }
1523
+ }
1524
+ if let Ok(live_windows) = transport.list_windows(&crate::transport::SessionName::new(
1525
+ leader_session.to_string(),
1526
+ )) {
1527
+ for window in live_windows {
1528
+ let name = window.as_str();
1529
+ if name == overview_prefix || name.starts_with(&format!("{overview_prefix}-")) {
1530
+ windows.insert(format!("{leader_session}:{name}"));
1531
+ }
1532
+ }
1533
+ }
1534
+ let live_targets = transport.list_targets().unwrap_or_default();
1535
+ for target in &live_targets {
1536
+ if leader_panes.contains(target.pane_id.as_str()) {
1537
+ continue;
1538
+ }
1539
+ if let Some(window) = target.window_name.as_ref() {
1540
+ if windows.contains(&format!("{}:{}", target.session.as_str(), window.as_str())) {
1541
+ panes.remove(target.pane_id.as_str());
1542
+ }
1543
+ }
1544
+ }
1545
+ for target in windows {
1546
+ let Some((target_session, target_window)) = target.split_once(':') else {
1547
+ continue;
1548
+ };
1549
+ let target = crate::transport::Target::SessionWindow {
1550
+ session: crate::transport::SessionName::new(target_session.to_string()),
1551
+ window: crate::transport::WindowName::new(target_window.to_string()),
1552
+ };
1553
+ let target_text = format!("{target_session}:{target_window}");
1554
+ let audit = crate::kill_audit::pre_kill_audit_scoped(
1555
+ &event_log,
1556
+ transport,
1557
+ "shutdown.legacy_display_window",
1558
+ "kill-window",
1559
+ std::slice::from_ref(&target_text),
1560
+ workspace,
1561
+ team_key,
1562
+ generation,
1563
+ "session_marker+state_display_window+team_tag",
1564
+ "positive workspace/team ownership",
1565
+ );
1566
+ if audit.is_ok() {
1567
+ let _ = transport.kill_window(&target);
1568
+ }
1569
+ }
1570
+ for pane in panes {
1571
+ let audit = crate::kill_audit::pre_kill_audit_scoped(
1572
+ &event_log,
1573
+ transport,
1574
+ "shutdown.legacy_display_pane",
1575
+ "kill-pane",
1576
+ std::slice::from_ref(&pane),
1577
+ workspace,
1578
+ team_key,
1579
+ generation,
1580
+ "state_display_pane+team_session",
1581
+ "positive workspace/team ownership",
1582
+ );
1583
+ if audit.is_ok() {
1584
+ let _ = transport.kill_pane(&crate::transport::PaneId::new(pane));
1585
+ }
1586
+ }
1587
+ }
1588
+
1476
1589
  /// 0.5.x Windows portability Batch 6 Option A: locate and
1477
1590
  /// terminate the ConPTY shim if `state.transport.shim.pid` is
1478
1591
  /// recorded. Returns a JSON blob for the shutdown response so
@@ -2635,7 +2748,6 @@ pub mod lifecycle_port {
2635
2748
  workspace: &Path,
2636
2749
  agent: &str,
2637
2750
  force: bool,
2638
- open_display: bool,
2639
2751
  allow_fresh: bool,
2640
2752
  team: Option<&str>,
2641
2753
  ) -> Result<Value, CliError> {
@@ -2644,7 +2756,7 @@ pub mod lifecycle_port {
2644
2756
  workspace,
2645
2757
  &agent_id,
2646
2758
  force,
2647
- open_display,
2759
+ true,
2648
2760
  allow_fresh,
2649
2761
  team,
2650
2762
  ) {
@@ -2712,7 +2824,6 @@ pub mod lifecycle_port {
2712
2824
  workspace: &Path,
2713
2825
  agent: &str,
2714
2826
  discard_session: bool,
2715
- open_display: bool,
2716
2827
  team: Option<&str>,
2717
2828
  ) -> Result<Value, CliError> {
2718
2829
  let agent_id = crate::model::ids::AgentId::new(agent);
@@ -2720,7 +2831,7 @@ pub mod lifecycle_port {
2720
2831
  workspace,
2721
2832
  &agent_id,
2722
2833
  discard_session,
2723
- open_display,
2834
+ true,
2724
2835
  team,
2725
2836
  ) {
2726
2837
  Ok(crate::lifecycle::ResetAgentOutcome::Reset {
@@ -2763,7 +2874,6 @@ pub mod lifecycle_port {
2763
2874
  workspace: &Path,
2764
2875
  agent: &str,
2765
2876
  role_file: &str,
2766
- open_display: bool,
2767
2877
  team: Option<&str>,
2768
2878
  force: bool,
2769
2879
  ) -> Result<Value, CliError> {
@@ -2772,7 +2882,7 @@ pub mod lifecycle_port {
2772
2882
  workspace,
2773
2883
  &agent_id,
2774
2884
  Path::new(role_file),
2775
- open_display,
2885
+ true,
2776
2886
  team,
2777
2887
  force,
2778
2888
  ) {
@@ -2811,12 +2921,11 @@ pub mod lifecycle_port {
2811
2921
  source_agent: &str,
2812
2922
  as_agent_id: &str,
2813
2923
  label: Option<&str>,
2814
- open_display: bool,
2815
2924
  team: Option<&str>,
2816
2925
  ) -> Result<Value, CliError> {
2817
2926
  let source = crate::model::ids::AgentId::new(source_agent);
2818
2927
  let dest = crate::model::ids::AgentId::new(as_agent_id);
2819
- match crate::lifecycle::fork_agent(workspace, &source, &dest, label, open_display, team) {
2928
+ match crate::lifecycle::fork_agent(workspace, &source, &dest, label, true, team) {
2820
2929
  Ok(report) => Ok(json!({
2821
2930
  "ok": true,
2822
2931
  "source_agent_id": report.source_agent_id.as_str(),
@@ -2833,12 +2942,11 @@ pub mod lifecycle_port {
2833
2942
  source_agent: &str,
2834
2943
  as_agent_id: &str,
2835
2944
  label: Option<&str>,
2836
- open_display: bool,
2837
2945
  team: Option<&str>,
2838
2946
  ) -> Result<Value, CliError> {
2839
2947
  let source = crate::model::ids::AgentId::new(source_agent);
2840
2948
  let dest = crate::model::ids::AgentId::new(as_agent_id);
2841
- match crate::lifecycle::clone_agent(workspace, &source, &dest, label, open_display, team) {
2949
+ match crate::lifecycle::clone_agent(workspace, &source, &dest, label, true, team) {
2842
2950
  Ok(report) => Ok(json!({
2843
2951
  "ok": true,
2844
2952
  "status": "cloned",
@@ -3024,60 +3132,6 @@ pub mod lifecycle_port {
3024
3132
  format!("'{}'", raw.replace('\'', "'\\''"))
3025
3133
  }
3026
3134
  }
3027
- ///
3028
- /// `runtime.acknowledge_idle`(`cmd_acknowledge_idle`)。
3029
- pub fn acknowledge_idle(workspace: &Path, team: Option<&str>) -> Result<Value, CliError> {
3030
- let mut state = crate::state::persist::load_runtime_state(workspace)
3031
- .map_err(|e| CliError::Runtime(e.to_string()))?;
3032
- let team = team
3033
- .map(ToString::to_string)
3034
- .or_else(|| {
3035
- state
3036
- .get("active_team_key")
3037
- .and_then(Value::as_str)
3038
- .map(ToString::to_string)
3039
- })
3040
- .filter(|s| !s.is_empty())
3041
- .or_else(|| {
3042
- workspace
3043
- .file_name()
3044
- .map(|name| name.to_string_lossy().to_string())
3045
- })
3046
- .unwrap_or_else(|| "current".to_string());
3047
- let now = chrono::Utc::now().to_rfc3339();
3048
- let ttl_seconds = 1800;
3049
- let expires_at = (chrono::Utc::now() + chrono::Duration::seconds(ttl_seconds)).to_rfc3339();
3050
- record_idle_acknowledged(&mut state, &team, &now, &expires_at, ttl_seconds);
3051
- suppress_team_idle_fallbacks(&mut state, &team, &now, &expires_at, ttl_seconds);
3052
- let agent_id = state
3053
- .get("agents")
3054
- .and_then(Value::as_object)
3055
- .and_then(|agents| agents.keys().next().cloned())
3056
- .map(Value::String)
3057
- .unwrap_or(Value::Null);
3058
- crate::state::repository::StateRepository::new(workspace)
3059
- .save(
3060
- crate::state::repository::StateWriteIntent::IdleAck {
3061
- team_key: Some(&team),
3062
- },
3063
- &state,
3064
- )
3065
- .map_err(|e| CliError::Runtime(e.to_string()))?;
3066
- crate::event_log::EventLog::new(workspace)
3067
- .write(
3068
- "coordinator.idle_acknowledged",
3069
- json!({"team": team, "ttl_seconds": ttl_seconds}),
3070
- )
3071
- .map_err(|e| CliError::Runtime(e.to_string()))?;
3072
- Ok(json!({
3073
- "ok": true,
3074
- "team": team,
3075
- "agent_id": agent_id,
3076
- "acknowledged_at": now,
3077
- "expires_at": expires_at,
3078
- "ttl_seconds": ttl_seconds,
3079
- }))
3080
- }
3081
3135
 
3082
3136
  fn error_value(error: crate::lifecycle::LifecycleError) -> Value {
3083
3137
  let message = error.to_string();
@@ -3132,118 +3186,6 @@ pub mod lifecycle_port {
3132
3186
  None
3133
3187
  }
3134
3188
 
3135
- fn record_idle_acknowledged(
3136
- state: &mut Value,
3137
- team: &str,
3138
- acknowledged_at: &str,
3139
- expires_at: &str,
3140
- ttl_seconds: i64,
3141
- ) {
3142
- let Some(root) = state.as_object_mut() else {
3143
- return;
3144
- };
3145
- let coordinator = root
3146
- .entry("coordinator")
3147
- .or_insert_with(|| json!({}))
3148
- .as_object_mut();
3149
- let Some(coordinator) = coordinator else {
3150
- return;
3151
- };
3152
- let idle = coordinator
3153
- .entry("idle_acknowledged")
3154
- .or_insert_with(|| json!({}))
3155
- .as_object_mut();
3156
- let Some(idle) = idle else {
3157
- return;
3158
- };
3159
- idle.insert(
3160
- team.to_string(),
3161
- json!({"acknowledged_at": acknowledged_at, "expires_at": expires_at, "ttl_seconds": ttl_seconds}),
3162
- );
3163
- }
3164
-
3165
- fn suppress_team_idle_fallbacks(
3166
- state: &mut Value,
3167
- team: &str,
3168
- suppressed_at: &str,
3169
- expires_at: &str,
3170
- ttl_seconds: i64,
3171
- ) {
3172
- let agents = state
3173
- .get("agents")
3174
- .and_then(Value::as_object)
3175
- .map(|obj| obj.keys().cloned().collect::<Vec<_>>())
3176
- .unwrap_or_default();
3177
- for agent in agents {
3178
- upsert_suppression(
3179
- state,
3180
- SuppressionRecord {
3181
- team,
3182
- agent_id: &agent,
3183
- alert_type: "idle_fallback",
3184
- suppressed_by: "manual_acknowledge",
3185
- suppressed_at,
3186
- expires_at,
3187
- ttl_seconds,
3188
- },
3189
- );
3190
- }
3191
- }
3192
-
3193
- struct SuppressionRecord<'a> {
3194
- team: &'a str,
3195
- agent_id: &'a str,
3196
- alert_type: &'a str,
3197
- suppressed_by: &'a str,
3198
- suppressed_at: &'a str,
3199
- expires_at: &'a str,
3200
- ttl_seconds: i64,
3201
- }
3202
-
3203
- fn upsert_suppression(state: &mut Value, record: SuppressionRecord<'_>) {
3204
- let Some(root) = state.as_object_mut() else {
3205
- return;
3206
- };
3207
- let Some(coordinator) = root
3208
- .entry("coordinator")
3209
- .or_insert_with(|| json!({}))
3210
- .as_object_mut()
3211
- else {
3212
- return;
3213
- };
3214
- let Some(all) = coordinator
3215
- .entry("suppressed_idle_alerts")
3216
- .or_insert_with(|| json!({}))
3217
- .as_object_mut()
3218
- else {
3219
- return;
3220
- };
3221
- let Some(team_map) = all
3222
- .entry(record.team.to_string())
3223
- .or_insert_with(|| json!({}))
3224
- .as_object_mut()
3225
- else {
3226
- return;
3227
- };
3228
- let Some(agent_map) = team_map
3229
- .entry(record.agent_id.to_string())
3230
- .or_insert_with(|| json!({}))
3231
- .as_object_mut()
3232
- else {
3233
- return;
3234
- };
3235
- agent_map.insert(
3236
- record.alert_type.to_string(),
3237
- json!({
3238
- "suppressed_at": record.suppressed_at,
3239
- "suppressed_by": record.suppressed_by,
3240
- "manual_acknowledge": true,
3241
- "expires_at": record.expires_at,
3242
- "ttl_seconds": record.ttl_seconds,
3243
- }),
3244
- );
3245
- }
3246
-
3247
3189
  const COMPACT_READINESS_KEYS: [&str; 6] = [
3248
3190
  "all_workers_spawned",
3249
3191
  "state",
@@ -3340,10 +3282,10 @@ pub mod lifecycle_port {
3340
3282
  {
3341
3283
  return vec![
3342
3284
  "repair state.session_name to the worker session; it currently names the leader launcher session".to_string(),
3343
- format!("team-agent diagnose --team {team} --json"),
3285
+ format!("team-agent doctor --team {team} --json"),
3344
3286
  ];
3345
3287
  }
3346
- let mut actions = vec![format!("team-agent diagnose --team {team} --json")];
3288
+ let mut actions = vec![format!("team-agent doctor --team {team} --json")];
3347
3289
  if issue_ids
3348
3290
  .iter()
3349
3291
  .any(|id| id.contains("socket") || id.contains("endpoint"))
@@ -3362,7 +3304,6 @@ pub mod lifecycle_port {
3362
3304
  launch,
3363
3305
  next_actions,
3364
3306
  attach_commands,
3365
- display_backend,
3366
3307
  worker_readiness,
3367
3308
  team,
3368
3309
  } => {
@@ -3502,7 +3443,6 @@ pub mod lifecycle_port {
3502
3443
  "team": team,
3503
3444
  "agent_ids": launch.started.iter().map(|agent| agent.agent_id.as_str()).collect::<Vec<_>>(),
3504
3445
  "dry_run": launch.dry_run,
3505
- "display_backend": display_backend,
3506
3446
  "next_actions": next_actions,
3507
3447
  "attach_commands": attach_commands,
3508
3448
  "reminder": crate::cli::QUICK_START_REMINDER,
@@ -3638,12 +3578,6 @@ pub mod lifecycle_port {
3638
3578
  claude_config_dir: None,
3639
3579
  provider_projects_root: None,
3640
3580
  managed_mcp_config: false,
3641
- layout_window: None,
3642
- layout_index: None,
3643
- pane_index: None,
3644
- display: crate::lifecycle::WorkerDisplay::Blocked {
3645
- reason: crate::lifecycle::AdaptiveBlockReason::AggregatorRebuildFailed,
3646
- },
3647
3581
  }],
3648
3582
  dry_run: false,
3649
3583
  tmux_endpoint: None,
@@ -3655,7 +3589,6 @@ pub mod lifecycle_port {
3655
3589
  }),
3656
3590
  next_actions: Vec::new(),
3657
3591
  attach_commands: Vec::new(),
3658
- display_backend: "none".to_string(),
3659
3592
  worker_readiness: crate::lifecycle::QuickStartReadiness::PendingToolLoad,
3660
3593
  team: "team-demo".to_string(),
3661
3594
  });
@@ -3773,7 +3706,7 @@ pub mod lifecycle_port {
3773
3706
  "status": "partial",
3774
3707
  "reason": "restart_agent_failed",
3775
3708
  "failed_agents": [{"agent_id": "worker", "error": "spawn failed"}],
3776
- "next_actions": ["restart-agent worker"],
3709
+ "next_actions": ["reset-agent worker --discard-session"],
3777
3710
  "attach_commands": [],
3778
3711
  "coordinator": {"status": "running", "transport": "default"}
3779
3712
  });
@@ -3781,7 +3714,7 @@ pub mod lifecycle_port {
3781
3714
  compact_restart_value(&mut default);
3782
3715
  assert_eq!(default["status"], json!("partial"));
3783
3716
  assert_eq!(default["reason"], json!("restart_agent_failed"));
3784
- assert_eq!(default["next_actions"], json!(["restart-agent worker"]));
3717
+ assert_eq!(default["next_actions"], json!(["reset-agent worker --discard-session"]));
3785
3718
  assert!(default.get("coordinator").is_none());
3786
3719
  assert!(detail.get("coordinator").is_some());
3787
3720
  }
@@ -4063,7 +3996,7 @@ pub mod lifecycle_port {
4063
3996
  "phase": failure.phase,
4064
3997
  "error": failure.error,
4065
3998
  "action": format!(
4066
- "inspect worker {} output, then restart that worker with `team-agent restart-agent {}` or rerun `team-agent restart --allow-fresh`",
3999
+ "inspect worker {} output, then reset that worker with `team-agent reset-agent {} --discard-session` or rerun `team-agent restart --allow-fresh`",
4067
4000
  failure.agent_id,
4068
4001
  failure.agent_id
4069
4002
  ),
@@ -4109,7 +4042,7 @@ pub mod lifecycle_port {
4109
4042
  "phase": failure.phase,
4110
4043
  "error": failure.error,
4111
4044
  "action": format!(
4112
- "inspect worker {} output, then restart that worker with `team-agent restart-agent {}` or rerun `team-agent restart --allow-fresh`",
4045
+ "inspect worker {} output, then reset that worker with `team-agent reset-agent {} --discard-session` or rerun `team-agent restart --allow-fresh`",
4113
4046
  failure.agent_id,
4114
4047
  failure.agent_id
4115
4048
  ),
@@ -27,13 +27,13 @@ pub(super) fn dirty_topology_refusal_value(
27
27
  "status": "refused_dirty_topology",
28
28
  "reason": reason,
29
29
  "session_name": session_name,
30
- "error": "send refused: tmux endpoint/socket topology is inconsistent; run diagnose from the intended leader socket before sending",
30
+ "error": "send refused: tmux endpoint/socket topology is inconsistent; run doctor from the intended leader socket before sending",
31
31
  "issues": issue_ids
32
32
  .iter()
33
33
  .map(|id| json!({"id": id}))
34
34
  .collect::<Vec<_>>(),
35
35
  "next_actions": [
36
- "team-agent diagnose --json",
36
+ "team-agent doctor --json",
37
37
  format!("team-agent claim-leader --team {repair_team} --confirm --json"),
38
38
  format!("team-agent takeover --team {repair_team} --confirm --json")
39
39
  ],