@team-agent/installer 0.5.42 → 0.5.43

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 (151) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +129 -54
  4. package/crates/team-agent/src/cli/diagnose.rs +1 -2
  5. package/crates/team-agent/src/cli/emit.rs +1 -7
  6. package/crates/team-agent/src/cli/helpers.rs +3 -1
  7. package/crates/team-agent/src/cli/leader.rs +2 -1
  8. package/crates/team-agent/src/cli/mod.rs +27 -7
  9. package/crates/team-agent/src/cli/named_address.rs +14 -5
  10. package/crates/team-agent/src/cli/profile.rs +19 -7
  11. package/crates/team-agent/src/cli/send.rs +9 -3
  12. package/crates/team-agent/src/cli/status.rs +8 -30
  13. package/crates/team-agent/src/cli/status_port.rs +1341 -1272
  14. package/crates/team-agent/src/cli/tests/base.rs +738 -660
  15. package/crates/team-agent/src/cli/tests/compile.rs +45 -18
  16. package/crates/team-agent/src/cli/tests/divergence.rs +462 -444
  17. package/crates/team-agent/src/cli/tests/lane_c.rs +365 -282
  18. package/crates/team-agent/src/cli/tests/leader_watch.rs +356 -329
  19. package/crates/team-agent/src/cli/tests/main_preserved.rs +672 -564
  20. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +284 -224
  21. package/crates/team-agent/src/cli/tests/mod.rs +17 -7
  22. package/crates/team-agent/src/cli/tests/named_address.rs +8 -2
  23. package/crates/team-agent/src/cli/tests/peer_allow.rs +10 -2
  24. package/crates/team-agent/src/cli/tests/run_delegation.rs +314 -273
  25. package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +26 -15
  26. package/crates/team-agent/src/cli/tests/status_send.rs +707 -629
  27. package/crates/team-agent/src/cli/tests/verb_install_skill.rs +20 -4
  28. package/crates/team-agent/src/cli/tests/verb_profile.rs +46 -17
  29. package/crates/team-agent/src/cli/tests/verb_validate.rs +15 -3
  30. package/crates/team-agent/src/codex_app_server.rs +2 -5
  31. package/crates/team-agent/src/compiler/tests.rs +139 -33
  32. package/crates/team-agent/src/compiler.rs +55 -22
  33. package/crates/team-agent/src/conpty/backend.rs +23 -33
  34. package/crates/team-agent/src/coordinator/backoff.rs +2 -7
  35. package/crates/team-agent/src/coordinator/conpty_shim.rs +55 -67
  36. package/crates/team-agent/src/coordinator/health.rs +46 -31
  37. package/crates/team-agent/src/coordinator/mod.rs +3 -3
  38. package/crates/team-agent/src/coordinator/orphan.rs +22 -10
  39. package/crates/team-agent/src/coordinator/steps/abnormal.rs +47 -52
  40. package/crates/team-agent/src/coordinator/tests/abnormal.rs +55 -19
  41. package/crates/team-agent/src/coordinator/tests/basics.rs +179 -41
  42. package/crates/team-agent/src/coordinator/tests/daemon.rs +53 -13
  43. package/crates/team-agent/src/coordinator/tests/health_sync.rs +78 -19
  44. package/crates/team-agent/src/coordinator/tests/main_preserved.rs +61 -11
  45. package/crates/team-agent/src/coordinator/tests/mod.rs +33 -39
  46. package/crates/team-agent/src/coordinator/tests/spine.rs +52 -12
  47. package/crates/team-agent/src/coordinator/tests/takeover.rs +73 -15
  48. package/crates/team-agent/src/coordinator/tests/tick_core.rs +50 -15
  49. package/crates/team-agent/src/coordinator/tests/watch.rs +74 -20
  50. package/crates/team-agent/src/db/message_store.rs +138 -30
  51. package/crates/team-agent/src/db/migration.rs +249 -61
  52. package/crates/team-agent/src/db/schema.rs +303 -82
  53. package/crates/team-agent/src/diagnose/comms.rs +9 -2
  54. package/crates/team-agent/src/diagnose/mod.rs +1 -3
  55. package/crates/team-agent/src/diagnose/orphans.rs +79 -61
  56. package/crates/team-agent/src/event_log.rs +70 -16
  57. package/crates/team-agent/src/layout/manager.rs +15 -4
  58. package/crates/team-agent/src/layout/mod.rs +4 -4
  59. package/crates/team-agent/src/layout/overlay.rs +10 -3
  60. package/crates/team-agent/src/layout/placement.rs +5 -1
  61. package/crates/team-agent/src/layout/recovery.rs +4 -2
  62. package/crates/team-agent/src/layout/runtime_sessions.rs +7 -7
  63. package/crates/team-agent/src/layout/sessions.rs +17 -9
  64. package/crates/team-agent/src/layout/tmux_endpoint.rs +1 -1
  65. package/crates/team-agent/src/layout/worker_env.rs +52 -19
  66. package/crates/team-agent/src/leader/helpers.rs +7 -1
  67. package/crates/team-agent/src/leader/lease.rs +166 -80
  68. package/crates/team-agent/src/leader/owner_bind.rs +55 -22
  69. package/crates/team-agent/src/leader/rediscover/tests.rs +88 -24
  70. package/crates/team-agent/src/leader/rediscover.rs +74 -25
  71. package/crates/team-agent/src/leader/start.rs +75 -54
  72. package/crates/team-agent/src/leader/takeover.rs +46 -11
  73. package/crates/team-agent/src/leader/tests/basics.rs +320 -167
  74. package/crates/team-agent/src/leader/tests/byte_findings.rs +361 -219
  75. package/crates/team-agent/src/leader/tests/identity.rs +428 -356
  76. package/crates/team-agent/src/leader/tests/idle.rs +285 -254
  77. package/crates/team-agent/src/leader/tests/lease_api.rs +338 -274
  78. package/crates/team-agent/src/leader/tests/lease_claim.rs +643 -593
  79. package/crates/team-agent/src/leader/tests/mod.rs +115 -99
  80. package/crates/team-agent/src/leader/tests/rediscover.rs +74 -22
  81. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +237 -211
  82. package/crates/team-agent/src/lib.rs +4 -4
  83. package/crates/team-agent/src/lifecycle/display.rs +7 -3
  84. package/crates/team-agent/src/lifecycle/launch.rs +6 -1
  85. package/crates/team-agent/src/lifecycle/mod.rs +9 -1
  86. package/crates/team-agent/src/lifecycle/profile_launch.rs +77 -34
  87. package/crates/team-agent/src/lifecycle/profile_smoke.rs +3 -1
  88. package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -6
  89. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +1 -4
  90. package/crates/team-agent/src/lifecycle/restart/preflight.rs +6 -5
  91. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -22
  92. package/crates/team-agent/src/lifecycle/restart/remove.rs +45 -35
  93. package/crates/team-agent/src/lifecycle/restart/team_state.rs +63 -17
  94. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +251 -84
  95. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +198 -48
  96. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -1
  97. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +152 -32
  98. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +1 -5
  99. package/crates/team-agent/src/lifecycle/tests.rs +2 -2
  100. package/crates/team-agent/src/main.rs +4 -4
  101. package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +47 -20
  102. package/crates/team-agent/src/mcp_server/mod.rs +11 -2
  103. package/crates/team-agent/src/mcp_server/types.rs +14 -3
  104. package/crates/team-agent/src/mcp_server/wire.rs +230 -68
  105. package/crates/team-agent/src/messaging/delivery.rs +20 -18
  106. package/crates/team-agent/src/messaging/helpers.rs +25 -4
  107. package/crates/team-agent/src/messaging/leader_receiver.rs +4 -5
  108. package/crates/team-agent/src/messaging/mod.rs +2 -3
  109. package/crates/team-agent/src/messaging/selftest.rs +46 -26
  110. package/crates/team-agent/src/messaging/tests/main_preserved.rs +47 -12
  111. package/crates/team-agent/src/messaging/tests/runtime.rs +57 -22
  112. package/crates/team-agent/src/messaging/tests/spine.rs +154 -40
  113. package/crates/team-agent/src/messaging/tests/wave2.rs +31 -32
  114. package/crates/team-agent/src/messaging/trust.rs +25 -2
  115. package/crates/team-agent/src/messaging/watchers.rs +37 -9
  116. package/crates/team-agent/src/model/enums.rs +65 -16
  117. package/crates/team-agent/src/model/ids.rs +12 -3
  118. package/crates/team-agent/src/model/paths.rs +28 -7
  119. package/crates/team-agent/src/model/permissions.rs +176 -33
  120. package/crates/team-agent/src/model/routing.rs +66 -20
  121. package/crates/team-agent/src/model/spec.rs +365 -69
  122. package/crates/team-agent/src/model/task_graph.rs +36 -9
  123. package/crates/team-agent/src/model/yaml/tests.rs +24 -6
  124. package/crates/team-agent/src/model/yaml.rs +7 -6
  125. package/crates/team-agent/src/packaging/install.rs +23 -9
  126. package/crates/team-agent/src/packaging/migrate.rs +5 -7
  127. package/crates/team-agent/src/packaging/mod.rs +9 -1
  128. package/crates/team-agent/src/packaging/repair.rs +13 -6
  129. package/crates/team-agent/src/packaging/tests.rs +63 -16
  130. package/crates/team-agent/src/packaging/types.rs +22 -7
  131. package/crates/team-agent/src/platform/argv.rs +4 -1
  132. package/crates/team-agent/src/platform/file_lock.rs +22 -8
  133. package/crates/team-agent/src/platform/process.rs +21 -22
  134. package/crates/team-agent/src/provider/adapters/claude.rs +1 -3
  135. package/crates/team-agent/src/provider/approvals/parsing.rs +134 -26
  136. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +13 -3
  137. package/crates/team-agent/src/provider/classify.rs +127 -42
  138. package/crates/team-agent/src/provider/faults.rs +17 -5
  139. package/crates/team-agent/src/provider/helpers.rs +6 -5
  140. package/crates/team-agent/src/provider/startup_prompt.rs +75 -27
  141. package/crates/team-agent/src/state/repository.rs +1 -3
  142. package/crates/team-agent/src/tmux_backend/tests.rs +1637 -1398
  143. package/crates/team-agent/src/tmux_backend.rs +80 -44
  144. package/crates/team-agent/src/topology.rs +27 -20
  145. package/crates/team-agent/src/transport/test_support.rs +20 -23
  146. package/crates/team-agent/src/transport/tests/behavior.rs +292 -293
  147. package/crates/team-agent/src/transport/tests/mod.rs +178 -187
  148. package/crates/team-agent/src/transport/tests/wire.rs +561 -525
  149. package/crates/team-agent/src/transport.rs +12 -17
  150. package/crates/team-agent/src/transport_factory.rs +29 -14
  151. package/package.json +4 -4
package/Cargo.lock CHANGED
@@ -575,7 +575,7 @@ dependencies = [
575
575
 
576
576
  [[package]]
577
577
  name = "team-agent"
578
- version = "0.5.42"
578
+ version = "0.5.43"
579
579
  dependencies = [
580
580
  "anyhow",
581
581
  "chrono",
package/Cargo.toml CHANGED
@@ -9,7 +9,7 @@ members = ["crates/team-agent", "crates/win-conpty-phase0", "crates/conpty-trans
9
9
 
10
10
  [workspace.package]
11
11
  edition = "2021"
12
- version = "0.5.42"
12
+ version = "0.5.43"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -80,14 +80,15 @@ pub fn cmd_init(args: &InitArgs) -> Result<CmdResult, CliError> {
80
80
  if args.force || !state_path.exists() {
81
81
  std::fs::write(&state_path, INIT_STATE_TEMPLATE)?;
82
82
  }
83
- crate::event_log::EventLog::new(&args.workspace).write(
84
- "init",
85
- json!({
86
- "spec_path": spec_path.to_string_lossy().to_string(),
87
- "state_path": state_path.to_string_lossy().to_string(),
88
- }),
89
- )
90
- .map_err(|e| CliError::Runtime(e.to_string()))?;
83
+ crate::event_log::EventLog::new(&args.workspace)
84
+ .write(
85
+ "init",
86
+ json!({
87
+ "spec_path": spec_path.to_string_lossy().to_string(),
88
+ "state_path": state_path.to_string_lossy().to_string(),
89
+ }),
90
+ )
91
+ .map_err(|e| CliError::Runtime(e.to_string()))?;
91
92
  Ok(CmdResult::from_json(
92
93
  json!({
93
94
  "ok": true,
@@ -122,7 +123,10 @@ pub fn cmd_quick_start(args: &QuickStartArgs) -> Result<CmdResult, CliError> {
122
123
  .and_then(|readiness| readiness.get("ready"))
123
124
  .and_then(Value::as_bool)
124
125
  .unwrap_or(true);
125
- let status = value.get("status").and_then(Value::as_str).map(str::to_string);
126
+ let status = value
127
+ .get("status")
128
+ .and_then(Value::as_str)
129
+ .map(str::to_string);
126
130
  if args.json
127
131
  || value.get("ok").and_then(Value::as_bool) == Some(false)
128
132
  || session_capture_incomplete
@@ -173,8 +177,8 @@ fn append_reminder(text: String, reminder: &str) -> String {
173
177
 
174
178
  /// `cmd_compile`(`commands.py:42`)。
175
179
  pub fn cmd_compile(args: &CompileArgs) -> Result<CmdResult, CliError> {
176
- let spec = crate::compiler::compile_team(&args.team)
177
- .map_err(|e| CliError::Runtime(e.to_string()))?;
180
+ let spec =
181
+ crate::compiler::compile_team(&args.team).map_err(|e| CliError::Runtime(e.to_string()))?;
178
182
  warn_ignored_owner_team_id(&args.team);
179
183
  std::fs::write(&args.out, crate::model::yaml::dumps(&spec))?;
180
184
  Ok(CmdResult::from_json(
@@ -194,7 +198,10 @@ fn warn_ignored_owner_team_id(team_dir: &std::path::Path) {
194
198
  };
195
199
  let workspace = crate::model::paths::team_workspace(team_dir)
196
200
  .unwrap_or_else(|_| team_dir.parent().unwrap_or(team_dir).to_path_buf());
197
- eprintln!("Warning: ignored TEAM.md {}={}", ignored.field, ignored.value);
201
+ eprintln!(
202
+ "Warning: ignored TEAM.md {}={}",
203
+ ignored.field, ignored.value
204
+ );
198
205
  eprintln!("Reason: owner identity is the canonical runtime team key, not TEAM.md front matter");
199
206
  eprintln!("Action: remove {} from TEAM.md", ignored.field);
200
207
  let fields = json!({
@@ -205,7 +212,9 @@ fn warn_ignored_owner_team_id(team_dir: &std::path::Path) {
205
212
  "reason": "owner identity is derived from the canonical runtime team key",
206
213
  "action": "remove owner_team_id from TEAM.md",
207
214
  });
208
- if let Err(err) = crate::event_log::EventLog::new(&workspace).write("spec.field_ignored", fields) {
215
+ if let Err(err) =
216
+ crate::event_log::EventLog::new(&workspace).write("spec.field_ignored", fields)
217
+ {
209
218
  eprintln!("Warning: spec.field_ignored event write failed: {err}");
210
219
  }
211
220
  }
@@ -362,17 +371,17 @@ pub fn cmd_watch(args: &WatchArgs) -> Result<CmdResult, CliError> {
362
371
  }
363
372
  #[cfg(test)]
364
373
  {
365
- let store = crate::message_store::MessageStore::open(&args.workspace)
374
+ let store = crate::message_store::MessageStore::open(&args.workspace)
375
+ .map_err(|e| CliError::Runtime(e.to_string()))?;
376
+ let mut cursor = crate::coordinator::WatchCursor::default();
377
+ let lines = crate::coordinator::collect_watch_lines(
378
+ &workspace,
379
+ &mut cursor,
380
+ &store,
381
+ args.team.as_deref(),
382
+ )
366
383
  .map_err(|e| CliError::Runtime(e.to_string()))?;
367
- let mut cursor = crate::coordinator::WatchCursor::default();
368
- let lines = crate::coordinator::collect_watch_lines(
369
- &workspace,
370
- &mut cursor,
371
- &store,
372
- args.team.as_deref(),
373
- )
374
- .map_err(|e| CliError::Runtime(e.to_string()))?;
375
- Ok(CmdResult::human(lines.join("\n")))
384
+ Ok(CmdResult::human(lines.join("\n")))
376
385
  }
377
386
  }
378
387
 
@@ -494,7 +503,11 @@ pub fn cmd_diagnose(args: &DiagnoseArgs) -> Result<CmdResult, CliError> {
494
503
  )
495
504
  .map_err(|e| CliError::Runtime(e.to_string()))?;
496
505
  let state = selected.state;
497
- let event_log = selected.run_workspace.join(".team").join("logs").join("events.jsonl");
506
+ let event_log = selected
507
+ .run_workspace
508
+ .join(".team")
509
+ .join("logs")
510
+ .join("events.jsonl");
498
511
  // 0.5.x Phase 1d Batch 3: factory-routed diagnose backend so
499
512
  // conpty teams get accurate `has_session` / capture from the shim
500
513
  // rather than a workspace tmux fallback (which would always miss
@@ -537,19 +550,13 @@ pub fn cmd_diagnose(args: &DiagnoseArgs) -> Result<CmdResult, CliError> {
537
550
  /// `cmd_preflight`(`parser.py:160`)。
538
551
  pub fn cmd_preflight(args: &PreflightArgs) -> Result<CmdResult, CliError> {
539
552
  let report = build_preflight_report(&args.team)?;
540
- Ok(CmdResult::from_json(
541
- report,
542
- args.json,
543
- ))
553
+ Ok(CmdResult::from_json(report, args.json))
544
554
  }
545
555
 
546
556
  /// `cmd_wait_ready`(`parser.py:171`)。
547
557
  pub fn cmd_wait_ready(args: &WaitReadyArgs) -> Result<CmdResult, CliError> {
548
558
  let report = build_wait_ready_report(&args.workspace, args.timeout, args.team.as_deref())?;
549
- Ok(CmdResult::from_json(
550
- report,
551
- args.json,
552
- ))
559
+ Ok(CmdResult::from_json(report, args.json))
553
560
  }
554
561
 
555
562
  /// `cmd_e2e`(`parser.py:449`)。
@@ -579,10 +586,15 @@ pub fn cmd_e2e(args: &E2eArgs) -> Result<CmdResult, CliError> {
579
586
  /// `cmd_peek`(`commands.py:118`)。
580
587
  pub fn cmd_peek(args: &PeekArgs) -> Result<CmdResult, CliError> {
581
588
  if !args.allow_raw_screen {
582
- return Err(CliError::Usage("peek requires --allow-raw-screen".to_string()));
589
+ return Err(CliError::Usage(
590
+ "peek requires --allow-raw-screen".to_string(),
591
+ ));
583
592
  }
584
593
  let state = crate::state::persist::load_runtime_state(&args.workspace)?;
585
- let Some(agent_state) = state.get("agents").and_then(|agents| agents.get(&args.agent)) else {
594
+ let Some(agent_state) = state
595
+ .get("agents")
596
+ .and_then(|agents| agents.get(&args.agent))
597
+ else {
586
598
  return Ok(CmdResult::from_json(
587
599
  json!({
588
600
  "ok": false,
@@ -661,13 +673,29 @@ fn peek_unavailable(agent: &str, json: bool) -> CmdResult {
661
673
  )
662
674
  }
663
675
 
664
- fn agent_pane_id(state: &Value, agent: &str, agent_state: &Value) -> Option<(String, String, String)> {
665
- let session = state.get("session_name").and_then(Value::as_str).filter(|s| !s.is_empty())?;
676
+ fn agent_pane_id(
677
+ state: &Value,
678
+ agent: &str,
679
+ agent_state: &Value,
680
+ ) -> Option<(String, String, String)> {
681
+ let session = state
682
+ .get("session_name")
683
+ .and_then(Value::as_str)
684
+ .filter(|s| !s.is_empty())?;
666
685
  let window = ["window", "window_name"]
667
686
  .iter()
668
- .find_map(|key| agent_state.get(*key).and_then(Value::as_str).filter(|s| !s.is_empty()))
687
+ .find_map(|key| {
688
+ agent_state
689
+ .get(*key)
690
+ .and_then(Value::as_str)
691
+ .filter(|s| !s.is_empty())
692
+ })
669
693
  .unwrap_or(agent);
670
- Some((session.to_string(), window.to_string(), format!("{session}:{window}")))
694
+ Some((
695
+ session.to_string(),
696
+ window.to_string(),
697
+ format!("{session}:{window}"),
698
+ ))
671
699
  }
672
700
 
673
701
  fn run_fake_e2e(workspace: &Path) -> Result<Value, CliError> {
@@ -787,7 +815,10 @@ fn command_on_path(command: &str) -> bool {
787
815
  }
788
816
 
789
817
  fn command_version(command: &str) -> Value {
790
- match std::process::Command::new(command).arg("--version").output() {
818
+ match std::process::Command::new(command)
819
+ .arg("--version")
820
+ .output()
821
+ {
791
822
  Ok(output) if output.status.success() => {
792
823
  let text = String::from_utf8_lossy(&output.stdout).trim().to_string();
793
824
  if text.is_empty() {
@@ -959,7 +990,10 @@ tasks:
959
990
 
960
991
  fn sessions_overview(state: &Value, spec: Option<&crate::model::yaml::Value>) -> Value {
961
992
  let mut rows = Vec::new();
962
- if let Some(agents) = spec.and_then(|v| v.get("agents")).and_then(crate::model::yaml::Value::as_list) {
993
+ if let Some(agents) = spec
994
+ .and_then(|v| v.get("agents"))
995
+ .and_then(crate::model::yaml::Value::as_list)
996
+ {
963
997
  for agent in agents {
964
998
  let Some(agent_id) = agent.get("id").and_then(crate::model::yaml::Value::as_str) else {
965
999
  continue;
@@ -1015,7 +1049,10 @@ fn session_row(
1015
1049
  }
1016
1050
 
1017
1051
  fn yaml_str(value: &crate::model::yaml::Value, key: &str) -> Option<String> {
1018
- value.get(key).and_then(crate::model::yaml::Value::as_str).map(ToString::to_string)
1052
+ value
1053
+ .get(key)
1054
+ .and_then(crate::model::yaml::Value::as_str)
1055
+ .map(ToString::to_string)
1019
1056
  }
1020
1057
 
1021
1058
  fn field_or_null(value: &Value, keys: &[&str]) -> Value {
@@ -1041,7 +1078,11 @@ fn last_task_for_agent(state: &Value, agent_id: &str) -> Value {
1041
1078
  .rev()
1042
1079
  .find(|task| task.get("assignee").and_then(Value::as_str) == Some(agent_id))
1043
1080
  })
1044
- .and_then(|task| task.get("id").and_then(Value::as_str).map(ToString::to_string))
1081
+ .and_then(|task| {
1082
+ task.get("id")
1083
+ .and_then(Value::as_str)
1084
+ .map(ToString::to_string)
1085
+ })
1045
1086
  .map(Value::String)
1046
1087
  .unwrap_or(Value::Null)
1047
1088
  }
@@ -1067,8 +1108,10 @@ fn window_target(agent_state: &Value, agent_id: &str) -> Value {
1067
1108
  }
1068
1109
  }
1069
1110
 
1070
-
1071
- fn load_team_spec_optional(workspace: &Path, state: &Value) -> Result<Option<crate::model::yaml::Value>, CliError> {
1111
+ fn load_team_spec_optional(
1112
+ workspace: &Path,
1113
+ state: &Value,
1114
+ ) -> Result<Option<crate::model::yaml::Value>, CliError> {
1072
1115
  let spec_path = state
1073
1116
  .get("spec_path")
1074
1117
  .and_then(Value::as_str)
@@ -1196,7 +1239,10 @@ fn format_inbox_human(
1196
1239
  Ok(lines.join("\n"))
1197
1240
  }
1198
1241
 
1199
- fn uncollected_result_count(workspace: &Path, owner_team_id: Option<&str>) -> Result<i64, CliError> {
1242
+ fn uncollected_result_count(
1243
+ workspace: &Path,
1244
+ owner_team_id: Option<&str>,
1245
+ ) -> Result<i64, CliError> {
1200
1246
  let store = crate::message_store::MessageStore::open(workspace)
1201
1247
  .map_err(|e| CliError::Runtime(e.to_string()))?;
1202
1248
  let conn = crate::db::schema::open_db(store.db_path())
@@ -1401,10 +1447,16 @@ pub fn cmd_doctor(args: &DoctorArgs) -> Result<CmdResult, CliError> {
1401
1447
  ));
1402
1448
  }
1403
1449
  if args.comms || matches!(args.gate, Some(DoctorGate::Comms)) {
1404
- let value = crate::diagnose::comms::doctor_comms_json(&args.workspace, args.team.as_deref(), Some("comms"))?;
1450
+ let value = crate::diagnose::comms::doctor_comms_json(
1451
+ &args.workspace,
1452
+ args.team.as_deref(),
1453
+ Some("comms"),
1454
+ )?;
1405
1455
  if !args.json {
1406
1456
  let json_tail = serde_json::to_string_pretty(&sort_json(&value))?;
1407
- return Ok(CmdResult::human(format!("{COMMS_BOUNDARY_TEXT}\n{json_tail}")));
1457
+ return Ok(CmdResult::human(format!(
1458
+ "{COMMS_BOUNDARY_TEXT}\n{json_tail}"
1459
+ )));
1408
1460
  }
1409
1461
  return Ok(CmdResult::from_json(value, true));
1410
1462
  }
@@ -1439,9 +1491,18 @@ mod tests {
1439
1491
  });
1440
1492
  let out = quickstart_human(&value);
1441
1493
  assert!(out.contains("team started"), "must keep summary; got {out}");
1442
- assert!(out.contains("attach:"), "must render attach block; got {out}");
1443
- assert!(out.contains("team-y:w1") && out.contains("team-y:w2"), "must list each attach cmd; got {out}");
1444
- assert!(out.ends_with(crate::cli::QUICK_START_REMINDER), "must append harness reminder; got {out}");
1494
+ assert!(
1495
+ out.contains("attach:"),
1496
+ "must render attach block; got {out}"
1497
+ );
1498
+ assert!(
1499
+ out.contains("team-y:w1") && out.contains("team-y:w2"),
1500
+ "must list each attach cmd; got {out}"
1501
+ );
1502
+ assert!(
1503
+ out.ends_with(crate::cli::QUICK_START_REMINDER),
1504
+ "must append harness reminder; got {out}"
1505
+ );
1445
1506
  }
1446
1507
 
1447
1508
  #[test]
@@ -1467,11 +1528,18 @@ mod tests {
1467
1528
  "w1": {"pane_id": "%7", "window": "w1"}
1468
1529
  }
1469
1530
  });
1470
- let agent = state.get("agents").and_then(|agents| agents.get("w1")).unwrap();
1531
+ let agent = state
1532
+ .get("agents")
1533
+ .and_then(|agents| agents.get("w1"))
1534
+ .unwrap();
1471
1535
 
1472
1536
  assert_eq!(
1473
1537
  agent_pane_id(&state, "w1", agent).unwrap(),
1474
- ("team-x".to_string(), "w1".to_string(), "team-x:w1".to_string())
1538
+ (
1539
+ "team-x".to_string(),
1540
+ "w1".to_string(),
1541
+ "team-x:w1".to_string()
1542
+ )
1475
1543
  );
1476
1544
  }
1477
1545
 
@@ -1483,11 +1551,18 @@ mod tests {
1483
1551
  "w1": {"window": "worker-one"}
1484
1552
  }
1485
1553
  });
1486
- let agent = state.get("agents").and_then(|agents| agents.get("w1")).unwrap();
1554
+ let agent = state
1555
+ .get("agents")
1556
+ .and_then(|agents| agents.get("w1"))
1557
+ .unwrap();
1487
1558
 
1488
1559
  assert_eq!(
1489
1560
  agent_pane_id(&state, "w1", agent).unwrap(),
1490
- ("team-x".to_string(), "worker-one".to_string(), "team-x:worker-one".to_string())
1561
+ (
1562
+ "team-x".to_string(),
1563
+ "worker-one".to_string(),
1564
+ "team-x:worker-one".to_string()
1565
+ )
1491
1566
  );
1492
1567
  }
1493
1568
  }
@@ -57,8 +57,7 @@ pub(crate) fn diagnose_runtime(state: &Value, backend: &dyn Transport) -> (Value
57
57
  let error_str = error.to_string();
58
58
  let issue_id = classify_tmux_server_error(&error_str);
59
59
  issues.push(json!(issue_id));
60
- let mut hint =
61
- recovery_hint(session_name, issue_id, "team-agent diagnose");
60
+ let mut hint = recovery_hint(session_name, issue_id, "team-agent diagnose");
62
61
  if let Some(obj) = hint.as_object_mut() {
63
62
  obj.insert("reason".to_string(), Value::String(error_str));
64
63
  }
@@ -1673,13 +1673,7 @@ mod tests {
1673
1673
  fn hidden_commands_not_in_default_help() {
1674
1674
  let top_help = command_help(None);
1675
1675
  let visible = visible_help_commands(&top_help);
1676
- for command in [
1677
- "leaders",
1678
- "doctor",
1679
- "e2e",
1680
- "peek",
1681
- "coordinator",
1682
- ] {
1676
+ for command in ["leaders", "doctor", "e2e", "peek", "coordinator"] {
1683
1677
  assert!(
1684
1678
  !visible.iter().any(|visible| visible == command),
1685
1679
  "`{command}` must stay hidden from default help"
@@ -30,7 +30,9 @@ pub(crate) fn python_truthy(value: &Value) -> bool {
30
30
  match value {
31
31
  Value::Null => false,
32
32
  Value::Bool(b) => *b,
33
- Value::Number(n) => n.as_i64().map(|v| v != 0)
33
+ Value::Number(n) => n
34
+ .as_i64()
35
+ .map(|v| v != 0)
34
36
  .or_else(|| n.as_u64().map(|v| v != 0))
35
37
  .or_else(|| n.as_f64().map(|v| v != 0.0))
36
38
  .unwrap_or(false),
@@ -30,7 +30,8 @@ pub fn leader_launcher_args(values: &[String]) -> Result<LeaderLauncherArgs, Cli
30
30
  )));
31
31
  }
32
32
  }
33
- out.provider_args.extend(values.iter().skip(idx + 1).cloned());
33
+ out.provider_args
34
+ .extend(values.iter().skip(idx + 1).cloned());
34
35
  break;
35
36
  } else if token == "--attach" || token == "--attach-existing" {
36
37
  out.attach_existing = true;
@@ -3347,8 +3347,7 @@ pub mod lifecycle_port {
3347
3347
  let repair_team = team
3348
3348
  .filter(|team| !team.is_empty())
3349
3349
  .unwrap_or(session_name.as_str());
3350
- let shutdown_scoped =
3351
- format!("team-agent shutdown --team {repair_team}");
3350
+ let shutdown_scoped = format!("team-agent shutdown --team {repair_team}");
3352
3351
  json!({
3353
3352
  "ok": false,
3354
3353
  "status": "refused_build_before_destroy",
@@ -4126,8 +4125,18 @@ pub mod leader_port {
4126
4125
  let mut value = lease_value(result);
4127
4126
  insert_resolved_team(&mut value, requested_team, resolved_team.as_deref());
4128
4127
  if value.get("ok").and_then(Value::as_bool) == Some(true) {
4129
- emit_topology_convergence_event(workspace, resolved_team.as_deref(), "takeover", &value);
4130
- register_after_binding_success(workspace, resolved_team.as_deref(), "takeover", &mut value);
4128
+ emit_topology_convergence_event(
4129
+ workspace,
4130
+ resolved_team.as_deref(),
4131
+ "takeover",
4132
+ &value,
4133
+ );
4134
+ register_after_binding_success(
4135
+ workspace,
4136
+ resolved_team.as_deref(),
4137
+ "takeover",
4138
+ &mut value,
4139
+ );
4131
4140
  }
4132
4141
  Ok(value)
4133
4142
  }
@@ -4163,8 +4172,18 @@ pub mod leader_port {
4163
4172
  let mut value = lease_value(result);
4164
4173
  insert_resolved_team(&mut value, team, resolved_team.as_deref());
4165
4174
  if value.get("ok").and_then(Value::as_bool) == Some(true) {
4166
- emit_topology_convergence_event(workspace, resolved_team.as_deref(), "claim-leader", &value);
4167
- register_after_binding_success(workspace, resolved_team.as_deref(), "claim-leader", &mut value);
4175
+ emit_topology_convergence_event(
4176
+ workspace,
4177
+ resolved_team.as_deref(),
4178
+ "claim-leader",
4179
+ &value,
4180
+ );
4181
+ register_after_binding_success(
4182
+ workspace,
4183
+ resolved_team.as_deref(),
4184
+ "claim-leader",
4185
+ &mut value,
4186
+ );
4168
4187
  }
4169
4188
  Ok(value)
4170
4189
  }
@@ -4332,7 +4351,8 @@ pub mod leader_port {
4332
4351
  }
4333
4352
 
4334
4353
  fn insert_resolved_team(value: &mut Value, requested: Option<&str>, resolved: Option<&str>) {
4335
- let (Some(requested), Some(resolved)) = (requested.filter(|team| !team.is_empty()), resolved)
4354
+ let (Some(requested), Some(resolved)) =
4355
+ (requested.filter(|team| !team.is_empty()), resolved)
4336
4356
  else {
4337
4357
  return;
4338
4358
  };
@@ -97,9 +97,15 @@ impl NamedAddressError {
97
97
  obj.insert("error".to_string(), Value::String(self.message.clone()));
98
98
  obj.insert("action".to_string(), Value::String(self.action.clone()));
99
99
  obj.insert("log".to_string(), Value::String(self.log.clone()));
100
- obj.insert("candidates".to_string(), Value::Array(self.candidates.clone()));
100
+ obj.insert(
101
+ "candidates".to_string(),
102
+ Value::Array(self.candidates.clone()),
103
+ );
101
104
  if let Some(requested) = self.requested_team.as_deref() {
102
- obj.insert("requested_team".to_string(), Value::String(requested.to_string()));
105
+ obj.insert(
106
+ "requested_team".to_string(),
107
+ Value::String(requested.to_string()),
108
+ );
103
109
  }
104
110
  if !self.available_team_keys.is_empty() {
105
111
  obj.insert(
@@ -113,7 +119,10 @@ impl NamedAddressError {
113
119
  );
114
120
  }
115
121
  if let Some(suggested) = self.suggested_name.as_deref() {
116
- obj.insert("suggested_name".to_string(), Value::String(suggested.to_string()));
122
+ obj.insert(
123
+ "suggested_name".to_string(),
124
+ Value::String(suggested.to_string()),
125
+ );
117
126
  }
118
127
  Value::Object(obj)
119
128
  }
@@ -662,8 +671,8 @@ fn resolve_leader(
662
671
  // silently reused the `current` team's receiver and reported a stale
663
672
  // pane_id). Legacy single-team compat is preserved only when the state
664
673
  // has no `teams` map yet and the requested key equals `active_team_key`.
665
- let receiver = resolve_team_scoped_leader_receiver(state, team, target_workspace)?
666
- .ok_or_else(|| {
674
+ let receiver =
675
+ resolve_team_scoped_leader_receiver(state, team, target_workspace)?.ok_or_else(|| {
667
676
  let mut err = leader_not_attached_third_party(
668
677
  target_workspace,
669
678
  team,
@@ -34,11 +34,17 @@ fn init_profile(args: &ProfileArgs) -> Result<Value, CliError> {
34
34
  let mut obj = Map::new();
35
35
  obj.insert("ok".to_string(), Value::Bool(true));
36
36
  obj.insert("profile".to_string(), Value::String(args.name.clone()));
37
- obj.insert("auth_mode".to_string(), Value::String(auth_mode.to_string()));
37
+ obj.insert(
38
+ "auth_mode".to_string(),
39
+ Value::String(auth_mode.to_string()),
40
+ );
38
41
  obj.insert("path".to_string(), path_value(&path));
39
42
  obj.insert("template_path".to_string(), path_value(&template_path));
40
43
  obj.insert("created_profile".to_string(), Value::Bool(created_profile));
41
- obj.insert("created_template".to_string(), Value::Bool(created_template));
44
+ obj.insert(
45
+ "created_template".to_string(),
46
+ Value::Bool(created_template),
47
+ );
42
48
  obj.insert("secret_written".to_string(), Value::Bool(created_profile));
43
49
  obj.insert(
44
50
  "safe_inspection_command".to_string(),
@@ -116,7 +122,10 @@ fn show_profile(args: &ProfileArgs) -> Result<Value, CliError> {
116
122
  );
117
123
  obj.insert("auth_mode".to_string(), Value::String(auth_mode));
118
124
  obj.insert("values".to_string(), redacted_values(&values));
119
- obj.insert("keys_present".to_string(), string_array(sorted_keys(&values)));
125
+ obj.insert(
126
+ "keys_present".to_string(),
127
+ string_array(sorted_keys(&values)),
128
+ );
120
129
  obj.insert("secret_keys_present".to_string(), string_array(secret_keys));
121
130
  obj.insert("missing_common".to_string(), string_array(missing_common));
122
131
  obj.insert("safe_for_agent_context".to_string(), Value::Bool(true));
@@ -134,7 +143,10 @@ fn show_profile(args: &ProfileArgs) -> Result<Value, CliError> {
134
143
 
135
144
  fn profile_dir(args: &ProfileArgs) -> PathBuf {
136
145
  let _ = &args.team;
137
- args.workspace.join(".team").join("current").join("profiles")
146
+ args.workspace
147
+ .join(".team")
148
+ .join("current")
149
+ .join("profiles")
138
150
  }
139
151
 
140
152
  fn validate_auth_mode(auth_mode: &str) -> Result<(), CliError> {
@@ -274,9 +286,9 @@ fn secret_keys_present(values: &Map<String, Value>) -> Vec<String> {
274
286
  }
275
287
 
276
288
  fn credential_present(values: &Map<String, Value>) -> bool {
277
- values.iter().any(|(key, value)| {
278
- is_secret_key(key) && value.as_str().is_some_and(|raw| !raw.is_empty())
279
- })
289
+ values
290
+ .iter()
291
+ .any(|(key, value)| is_secret_key(key) && value.as_str().is_some_and(|raw| !raw.is_empty()))
280
292
  }
281
293
 
282
294
  fn missing_common_keys(values: &Map<String, Value>, auth_mode: &str) -> Vec<String> {
@@ -375,9 +375,15 @@ fn coordinator_health_status_wire(
375
375
  /// F1 (0.3.26): direct pane-id send — bypasses agent-name routing + team
376
376
  /// membership check. Constructs `Target::Pane`, renders the message with
377
377
  /// the standard protocol block (Team Agent message from sender + token),
378
- /// injects via the default tmux backend, and surfaces the inject report as
379
- /// a JSON result. Cross-team capable: no restriction on which tmux session
380
- /// or socket the pane belongs to.
378
+ /// injects via the selected team's endpoint-local tmux transport, and
379
+ /// surfaces the inject report as a JSON result.
380
+ ///
381
+ /// 0.5.43 debt-sweep (§6.2): the pre-0.5.43 comment overstated the
382
+ /// scope. pane_id is inherently endpoint-local —
383
+ /// `lifecycle_worker_tmux_backend_for_selected_state` below builds the
384
+ /// transport from the SELECTED team's persisted endpoint. For cross-
385
+ /// workspace delivery, use `--to-name` / `--to-leader` instead; there
386
+ /// is intentionally no `--socket` flag.
381
387
  fn send_to_pane_direct(
382
388
  workspace: &Path,
383
389
  pane_id: &str,
@@ -9,8 +9,7 @@ use super::*;
9
9
  pub fn classify_agent_bucket(raw_status: &str, health_status: &str) -> SummaryBucket {
10
10
  let raw = raw_status.to_ascii_lowercase();
11
11
  let health = health_status.to_ascii_lowercase();
12
- if matches!(raw.as_str(), "failed" | "error") || matches!(health.as_str(), "failed" | "error")
13
- {
12
+ if matches!(raw.as_str(), "failed" | "error") || matches!(health.as_str(), "failed" | "error") {
14
13
  SummaryBucket::Failed
15
14
  } else if matches!(raw.as_str(), "stopped" | "done") || health == "done" {
16
15
  SummaryBucket::Stopped
@@ -43,10 +42,7 @@ pub fn agent_summary_counts(agents: &Value, health: &Value) -> SummaryCounts {
43
42
  }
44
43
  continue;
45
44
  }
46
- let raw = agent
47
- .get("status")
48
- .and_then(Value::as_str)
49
- .unwrap_or("");
45
+ let raw = agent.get("status").and_then(Value::as_str).unwrap_or("");
50
46
  let hstatus = health
51
47
  .get(agent_id)
52
48
  .and_then(|v| v.get("status"))
@@ -136,17 +132,13 @@ pub fn format_status_summary(data: &Value) -> String {
136
132
  "stopped",
137
133
  );
138
134
  let schema_ok = python_truthy(
139
- data
140
- .get("coordinator")
141
- .and_then(|v| v.get("schema_ok"))
135
+ data.get("coordinator")
136
+ .and_then(|v| v.get("schema_ok"))
142
137
  .unwrap_or(&Value::Null),
143
138
  );
144
139
  let tmux = python_truthy(data.get("tmux_session_present").unwrap_or(&Value::Null));
145
140
  let receiver = data.get("leader_receiver").unwrap_or(&Value::Null);
146
- let pane = non_empty_str(
147
- receiver.get("pane_id").and_then(Value::as_str),
148
- "-",
149
- );
141
+ let pane = non_empty_str(receiver.get("pane_id").and_then(Value::as_str), "-");
150
142
  let cmd = first_non_empty_str(
151
143
  &[
152
144
  receiver.get("pane_current_command").and_then(Value::as_str),
@@ -266,17 +258,8 @@ fn csv_agent_status(
266
258
  /// `_latest_result_line`(`commands.py:333-337`):agent_id/summary/created_at 渲染单行。
267
259
  /// summary `\n`→` ` 后 [:80] 截断、空 → `-`;agent_id 空 → `-`;created_at 经 age_text。
268
260
  pub(crate) fn format_latest_result(value: &Value) -> String {
269
- let agent = non_empty_str(
270
- value
271
- .get("agent_id")
272
- .and_then(Value::as_str)
273
- ,
274
- "-",
275
- );
276
- let raw_summary = value
277
- .get("summary")
278
- .and_then(Value::as_str)
279
- .unwrap_or("");
261
+ let agent = non_empty_str(value.get("agent_id").and_then(Value::as_str), "-");
262
+ let raw_summary = value.get("summary").and_then(Value::as_str).unwrap_or("");
280
263
  let summary_flat = raw_summary.replace('\n', " ");
281
264
  let summary = prefix_chars(&summary_flat, 80);
282
265
  let summary = if summary.is_empty() {
@@ -284,12 +267,7 @@ pub(crate) fn format_latest_result(value: &Value) -> String {
284
267
  } else {
285
268
  summary
286
269
  };
287
- let created = age_text(
288
- value
289
- .get("created_at")
290
- .and_then(Value::as_str)
291
- ,
292
- );
270
+ let created = age_text(value.get("created_at").and_then(Value::as_str));
293
271
  format!("{agent} -> {summary} @ {created}")
294
272
  }
295
273