@team-agent/installer 0.5.42 → 0.5.44

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 (156) 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 +126 -16
  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 +51 -56
  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 +87 -19
  66. package/crates/team-agent/src/leader/helpers.rs +7 -1
  67. package/crates/team-agent/src/leader/lease.rs +199 -89
  68. package/crates/team-agent/src/leader/owner_bind.rs +55 -22
  69. package/crates/team-agent/src/leader/provider_attribution.rs +25 -6
  70. package/crates/team-agent/src/leader/rediscover/tests.rs +88 -24
  71. package/crates/team-agent/src/leader/rediscover.rs +74 -25
  72. package/crates/team-agent/src/leader/registry.rs +1 -1
  73. package/crates/team-agent/src/leader/start.rs +75 -54
  74. package/crates/team-agent/src/leader/takeover.rs +46 -11
  75. package/crates/team-agent/src/leader/tests/basics.rs +320 -167
  76. package/crates/team-agent/src/leader/tests/byte_findings.rs +361 -219
  77. package/crates/team-agent/src/leader/tests/identity.rs +428 -356
  78. package/crates/team-agent/src/leader/tests/idle.rs +285 -254
  79. package/crates/team-agent/src/leader/tests/lease_api.rs +338 -274
  80. package/crates/team-agent/src/leader/tests/lease_claim.rs +643 -593
  81. package/crates/team-agent/src/leader/tests/mod.rs +115 -99
  82. package/crates/team-agent/src/leader/tests/rediscover.rs +74 -22
  83. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +237 -211
  84. package/crates/team-agent/src/lib.rs +4 -4
  85. package/crates/team-agent/src/lifecycle/display.rs +7 -3
  86. package/crates/team-agent/src/lifecycle/launch.rs +55 -15
  87. package/crates/team-agent/src/lifecycle/mod.rs +9 -1
  88. package/crates/team-agent/src/lifecycle/profile_launch.rs +77 -34
  89. package/crates/team-agent/src/lifecycle/profile_smoke.rs +3 -1
  90. package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -6
  91. package/crates/team-agent/src/lifecycle/restart/common.rs +6 -2
  92. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +1 -4
  93. package/crates/team-agent/src/lifecycle/restart/preflight.rs +6 -5
  94. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -22
  95. package/crates/team-agent/src/lifecycle/restart/remove.rs +45 -35
  96. package/crates/team-agent/src/lifecycle/restart/team_state.rs +63 -17
  97. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +251 -84
  98. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +198 -48
  99. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -1
  100. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +152 -32
  101. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +1 -5
  102. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +3 -0
  103. package/crates/team-agent/src/lifecycle/tests.rs +2 -2
  104. package/crates/team-agent/src/main.rs +4 -4
  105. package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +47 -20
  106. package/crates/team-agent/src/mcp_server/mod.rs +11 -2
  107. package/crates/team-agent/src/mcp_server/types.rs +14 -3
  108. package/crates/team-agent/src/mcp_server/wire.rs +230 -68
  109. package/crates/team-agent/src/messaging/delivery.rs +20 -18
  110. package/crates/team-agent/src/messaging/helpers.rs +25 -4
  111. package/crates/team-agent/src/messaging/leader_receiver.rs +4 -5
  112. package/crates/team-agent/src/messaging/mod.rs +2 -3
  113. package/crates/team-agent/src/messaging/selftest.rs +46 -26
  114. package/crates/team-agent/src/messaging/tests/main_preserved.rs +47 -12
  115. package/crates/team-agent/src/messaging/tests/runtime.rs +57 -22
  116. package/crates/team-agent/src/messaging/tests/spine.rs +154 -40
  117. package/crates/team-agent/src/messaging/tests/wave2.rs +31 -32
  118. package/crates/team-agent/src/messaging/trust.rs +25 -2
  119. package/crates/team-agent/src/messaging/watchers.rs +37 -9
  120. package/crates/team-agent/src/model/enums.rs +65 -16
  121. package/crates/team-agent/src/model/ids.rs +12 -3
  122. package/crates/team-agent/src/model/paths.rs +28 -7
  123. package/crates/team-agent/src/model/permissions.rs +176 -33
  124. package/crates/team-agent/src/model/routing.rs +66 -20
  125. package/crates/team-agent/src/model/spec.rs +365 -69
  126. package/crates/team-agent/src/model/task_graph.rs +36 -9
  127. package/crates/team-agent/src/model/yaml/tests.rs +24 -6
  128. package/crates/team-agent/src/model/yaml.rs +7 -6
  129. package/crates/team-agent/src/packaging/install.rs +23 -9
  130. package/crates/team-agent/src/packaging/migrate.rs +5 -7
  131. package/crates/team-agent/src/packaging/mod.rs +9 -1
  132. package/crates/team-agent/src/packaging/repair.rs +13 -6
  133. package/crates/team-agent/src/packaging/tests.rs +63 -16
  134. package/crates/team-agent/src/packaging/types.rs +22 -7
  135. package/crates/team-agent/src/platform/argv.rs +4 -1
  136. package/crates/team-agent/src/platform/file_lock.rs +22 -8
  137. package/crates/team-agent/src/platform/process.rs +54 -24
  138. package/crates/team-agent/src/provider/adapters/claude.rs +1 -3
  139. package/crates/team-agent/src/provider/approvals/parsing.rs +134 -26
  140. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +13 -3
  141. package/crates/team-agent/src/provider/classify.rs +127 -42
  142. package/crates/team-agent/src/provider/faults.rs +17 -5
  143. package/crates/team-agent/src/provider/helpers.rs +6 -5
  144. package/crates/team-agent/src/provider/startup_prompt.rs +75 -27
  145. package/crates/team-agent/src/state/persist.rs +28 -0
  146. package/crates/team-agent/src/state/repository.rs +8 -3
  147. package/crates/team-agent/src/tmux_backend/tests.rs +1637 -1398
  148. package/crates/team-agent/src/tmux_backend.rs +80 -44
  149. package/crates/team-agent/src/topology.rs +40 -20
  150. package/crates/team-agent/src/transport/test_support.rs +20 -23
  151. package/crates/team-agent/src/transport/tests/behavior.rs +292 -293
  152. package/crates/team-agent/src/transport/tests/mod.rs +178 -187
  153. package/crates/team-agent/src/transport/tests/wire.rs +561 -525
  154. package/crates/team-agent/src/transport.rs +12 -17
  155. package/crates/team-agent/src/transport_factory.rs +29 -14
  156. package/package.json +4 -4
@@ -1,5 +1,5 @@
1
- use super::*;
2
1
  use super::launch_spawn::{seed_healthy_coordinator, DELEG_ROLE_ALPHA, DELEG_ROLE_BRAVO};
2
+ use super::*;
3
3
 
4
4
  // ═════════════════════════════════════════════════════════════════════════
5
5
 
@@ -38,30 +38,86 @@ impl crate::transport::Transport for LaneTransport {
38
38
  fn kind(&self) -> crate::transport::BackendKind {
39
39
  crate::transport::BackendKind::Tmux
40
40
  }
41
- fn spawn_first(&self, session: &crate::transport::SessionName, window: &crate::transport::WindowName, argv: &[String], _c: &std::path::Path, _e: &std::collections::BTreeMap<String, String>) -> Result<crate::transport::SpawnResult, crate::transport::TransportError> {
42
- self.spawns.lock().unwrap().push(("spawn_first".to_string(), argv.to_vec()));
43
- Ok(crate::transport::SpawnResult { pane_id: crate::transport::PaneId::new(format!("%{}", window.as_str())), session: session.clone(), window: window.clone(), child_pid: None })
41
+ fn spawn_first(
42
+ &self,
43
+ session: &crate::transport::SessionName,
44
+ window: &crate::transport::WindowName,
45
+ argv: &[String],
46
+ _c: &std::path::Path,
47
+ _e: &std::collections::BTreeMap<String, String>,
48
+ ) -> Result<crate::transport::SpawnResult, crate::transport::TransportError> {
49
+ self.spawns
50
+ .lock()
51
+ .unwrap()
52
+ .push(("spawn_first".to_string(), argv.to_vec()));
53
+ Ok(crate::transport::SpawnResult {
54
+ pane_id: crate::transport::PaneId::new(format!("%{}", window.as_str())),
55
+ session: session.clone(),
56
+ window: window.clone(),
57
+ child_pid: None,
58
+ })
44
59
  }
45
- fn spawn_into(&self, session: &crate::transport::SessionName, window: &crate::transport::WindowName, argv: &[String], _c: &std::path::Path, _e: &std::collections::BTreeMap<String, String>) -> Result<crate::transport::SpawnResult, crate::transport::TransportError> {
46
- self.spawns.lock().unwrap().push(("spawn_into".to_string(), argv.to_vec()));
47
- Ok(crate::transport::SpawnResult { pane_id: crate::transport::PaneId::new(format!("%{}", window.as_str())), session: session.clone(), window: window.clone(), child_pid: None })
60
+ fn spawn_into(
61
+ &self,
62
+ session: &crate::transport::SessionName,
63
+ window: &crate::transport::WindowName,
64
+ argv: &[String],
65
+ _c: &std::path::Path,
66
+ _e: &std::collections::BTreeMap<String, String>,
67
+ ) -> Result<crate::transport::SpawnResult, crate::transport::TransportError> {
68
+ self.spawns
69
+ .lock()
70
+ .unwrap()
71
+ .push(("spawn_into".to_string(), argv.to_vec()));
72
+ Ok(crate::transport::SpawnResult {
73
+ pane_id: crate::transport::PaneId::new(format!("%{}", window.as_str())),
74
+ session: session.clone(),
75
+ window: window.clone(),
76
+ child_pid: None,
77
+ })
48
78
  }
49
- fn inject(&self, _t: &crate::transport::Target, _p: &crate::transport::InjectPayload, _s: crate::transport::Key, _b: bool) -> Result<crate::transport::InjectReport, crate::transport::TransportError> {
79
+ fn inject(
80
+ &self,
81
+ _t: &crate::transport::Target,
82
+ _p: &crate::transport::InjectPayload,
83
+ _s: crate::transport::Key,
84
+ _b: bool,
85
+ ) -> Result<crate::transport::InjectReport, crate::transport::TransportError> {
50
86
  unimplemented!("LaneTransport::inject not reached by stop/reset/remove/fork")
51
87
  }
52
- fn send_keys(&self, _t: &crate::transport::Target, _k: &[crate::transport::Key]) -> Result<(), crate::transport::TransportError> {
88
+ fn send_keys(
89
+ &self,
90
+ _t: &crate::transport::Target,
91
+ _k: &[crate::transport::Key],
92
+ ) -> Result<(), crate::transport::TransportError> {
53
93
  Ok(())
54
94
  }
55
- fn capture(&self, _t: &crate::transport::Target, r: crate::transport::CaptureRange) -> Result<crate::transport::CapturedText, crate::transport::TransportError> {
56
- Ok(crate::transport::CapturedText { text: String::new(), range: r })
95
+ fn capture(
96
+ &self,
97
+ _t: &crate::transport::Target,
98
+ r: crate::transport::CaptureRange,
99
+ ) -> Result<crate::transport::CapturedText, crate::transport::TransportError> {
100
+ Ok(crate::transport::CapturedText {
101
+ text: String::new(),
102
+ range: r,
103
+ })
57
104
  }
58
- fn query(&self, _t: &crate::transport::Target, _f: crate::transport::PaneField) -> Result<Option<String>, crate::transport::TransportError> {
105
+ fn query(
106
+ &self,
107
+ _t: &crate::transport::Target,
108
+ _f: crate::transport::PaneField,
109
+ ) -> Result<Option<String>, crate::transport::TransportError> {
59
110
  Ok(None)
60
111
  }
61
- fn liveness(&self, _p: &crate::transport::PaneId) -> Result<crate::model::enums::PaneLiveness, crate::transport::TransportError> {
112
+ fn liveness(
113
+ &self,
114
+ _p: &crate::transport::PaneId,
115
+ ) -> Result<crate::model::enums::PaneLiveness, crate::transport::TransportError> {
62
116
  Ok(crate::model::enums::PaneLiveness::Unknown)
63
117
  }
64
- fn list_targets(&self) -> Result<Vec<crate::transport::PaneInfo>, crate::transport::TransportError> {
118
+ fn list_targets(
119
+ &self,
120
+ ) -> Result<Vec<crate::transport::PaneInfo>, crate::transport::TransportError> {
65
121
  Ok(self
66
122
  .windows
67
123
  .iter()
@@ -80,31 +136,57 @@ impl crate::transport::Transport for LaneTransport {
80
136
  })
81
137
  .collect())
82
138
  }
83
- fn has_session(&self, _s: &crate::transport::SessionName) -> Result<bool, crate::transport::TransportError> {
139
+ fn has_session(
140
+ &self,
141
+ _s: &crate::transport::SessionName,
142
+ ) -> Result<bool, crate::transport::TransportError> {
84
143
  Ok(true)
85
144
  }
86
- fn list_windows(&self, s: &crate::transport::SessionName) -> Result<Vec<crate::transport::WindowName>, crate::transport::TransportError> {
145
+ fn list_windows(
146
+ &self,
147
+ s: &crate::transport::SessionName,
148
+ ) -> Result<Vec<crate::transport::WindowName>, crate::transport::TransportError> {
87
149
  if s.as_str() == self.session {
88
- Ok(self.windows.iter().map(|w| crate::transport::WindowName::new(w.as_str())).collect())
150
+ Ok(self
151
+ .windows
152
+ .iter()
153
+ .map(|w| crate::transport::WindowName::new(w.as_str()))
154
+ .collect())
89
155
  } else {
90
156
  Ok(Vec::new())
91
157
  }
92
158
  }
93
- fn set_session_env(&self, _s: &crate::transport::SessionName, _k: &str, _v: &str) -> Result<crate::transport::SetEnvOutcome, crate::transport::TransportError> {
159
+ fn set_session_env(
160
+ &self,
161
+ _s: &crate::transport::SessionName,
162
+ _k: &str,
163
+ _v: &str,
164
+ ) -> Result<crate::transport::SetEnvOutcome, crate::transport::TransportError> {
94
165
  Ok(crate::transport::SetEnvOutcome::Applied)
95
166
  }
96
- fn kill_session(&self, _s: &crate::transport::SessionName) -> Result<(), crate::transport::TransportError> {
167
+ fn kill_session(
168
+ &self,
169
+ _s: &crate::transport::SessionName,
170
+ ) -> Result<(), crate::transport::TransportError> {
97
171
  Ok(())
98
172
  }
99
- fn kill_window(&self, t: &crate::transport::Target) -> Result<(), crate::transport::TransportError> {
173
+ fn kill_window(
174
+ &self,
175
+ t: &crate::transport::Target,
176
+ ) -> Result<(), crate::transport::TransportError> {
100
177
  let name = match t {
101
178
  crate::transport::Target::Pane(p) => p.as_str().to_string(),
102
- crate::transport::Target::SessionWindow { session, window } => format!("{}:{}", session.as_str(), window.as_str()),
179
+ crate::transport::Target::SessionWindow { session, window } => {
180
+ format!("{}:{}", session.as_str(), window.as_str())
181
+ }
103
182
  };
104
183
  self.killed.lock().unwrap().push(name);
105
184
  Ok(())
106
185
  }
107
- fn attach_session(&self, _s: &crate::transport::SessionName) -> Result<crate::transport::AttachOutcome, crate::transport::TransportError> {
186
+ fn attach_session(
187
+ &self,
188
+ _s: &crate::transport::SessionName,
189
+ ) -> Result<crate::transport::AttachOutcome, crate::transport::TransportError> {
108
190
  Ok(crate::transport::AttachOutcome::Attached)
109
191
  }
110
192
  }
@@ -114,7 +196,11 @@ impl crate::transport::Transport for LaneTransport {
114
196
  fn lanea_ws_agents(agents: serde_json::Value) -> PathBuf {
115
197
  let ws = temp_ws().join("laneav2");
116
198
  std::fs::create_dir_all(ws.join("agents")).unwrap();
117
- std::fs::write(ws.join("TEAM.md"), "---\nname: laneateam\nobjective: Lane A v2 probe.\nprovider: codex\n---\n\nteam.\n").unwrap();
199
+ std::fs::write(
200
+ ws.join("TEAM.md"),
201
+ "---\nname: laneateam\nobjective: Lane A v2 probe.\nprovider: codex\n---\n\nteam.\n",
202
+ )
203
+ .unwrap();
118
204
  std::fs::write(ws.join("agents").join("alpha.md"), DELEG_ROLE_ALPHA).unwrap();
119
205
  std::fs::write(ws.join("agents").join("bravo.md"), DELEG_ROLE_BRAVO).unwrap();
120
206
  let spec = crate::compiler::compile_team(&ws).expect("compile lane-A v2 team");
@@ -128,11 +214,24 @@ fn lanea_ws_agents(agents: serde_json::Value) -> PathBuf {
128
214
  .replace("default_assignee: \"alpha\"", "default_assignee: \"bravo\"")
129
215
  .replace("assign_to: \"alpha\"", "assign_to: \"bravo\"")
130
216
  .replace("assignee: \"alpha\"", "assignee: \"bravo\"");
131
- assert!(!yaml.contains("default_assignee: \"alpha\""), "fixture unroute: default_assignee still alpha");
132
- assert!(!yaml.contains("assign_to: \"alpha\""), "fixture unroute: a routing rule still assign_to alpha");
133
- assert!(!yaml.contains("assignee: \"alpha\""), "fixture unroute: task still assignee alpha");
217
+ assert!(
218
+ !yaml.contains("default_assignee: \"alpha\""),
219
+ "fixture unroute: default_assignee still alpha"
220
+ );
221
+ assert!(
222
+ !yaml.contains("assign_to: \"alpha\""),
223
+ "fixture unroute: a routing rule still assign_to alpha"
224
+ );
225
+ assert!(
226
+ !yaml.contains("assignee: \"alpha\""),
227
+ "fixture unroute: task still assignee alpha"
228
+ );
134
229
  std::fs::write(ws.join("team.spec.yaml"), yaml).unwrap();
135
- crate::state::persist::save_runtime_state(&ws, &json!({ "session_name": "team-laneateam", "agents": agents })).unwrap();
230
+ crate::state::persist::save_runtime_state(
231
+ &ws,
232
+ &json!({ "session_name": "team-laneateam", "agents": agents }),
233
+ )
234
+ .unwrap();
136
235
  ws
137
236
  }
138
237
 
@@ -142,7 +241,11 @@ fn lanea_ws_agents(agents: serde_json::Value) -> PathBuf {
142
241
  fn lanea_one_agent_ws(alpha_status: &str) -> PathBuf {
143
242
  let ws = temp_ws().join("lanea1");
144
243
  std::fs::create_dir_all(ws.join("agents")).unwrap();
145
- std::fs::write(ws.join("TEAM.md"), "---\nname: laneateam\nobjective: Lane A one-agent probe.\nprovider: codex\n---\n\nteam.\n").unwrap();
244
+ std::fs::write(
245
+ ws.join("TEAM.md"),
246
+ "---\nname: laneateam\nobjective: Lane A one-agent probe.\nprovider: codex\n---\n\nteam.\n",
247
+ )
248
+ .unwrap();
146
249
  std::fs::write(ws.join("agents").join("alpha.md"), DELEG_ROLE_ALPHA).unwrap();
147
250
  let spec = crate::compiler::compile_team(&ws).expect("compile 1-agent team");
148
251
  std::fs::write(ws.join("team.spec.yaml"), crate::model::yaml::dumps(&spec)).unwrap();
@@ -156,8 +259,14 @@ fn lanea_one_agent_ws(alpha_status: &str) -> PathBuf {
156
259
  fn set_context_state_file(ws: &std::path::Path, name: &str) {
157
260
  let p = ws.join("team.spec.yaml");
158
261
  let text = std::fs::read_to_string(&p).unwrap();
159
- let replaced = text.replace("state_file: \"team_state.md\"", &format!("state_file: \"{name}\""));
160
- assert_ne!(replaced, text, "expected to rewrite context.state_file in the compiled spec; got:\n{text}");
262
+ let replaced = text.replace(
263
+ "state_file: \"team_state.md\"",
264
+ &format!("state_file: \"{name}\""),
265
+ );
266
+ assert_ne!(
267
+ replaced, text,
268
+ "expected to rewrite context.state_file in the compiled spec; got:\n{text}"
269
+ );
161
270
  std::fs::write(&p, replaced).unwrap();
162
271
  }
163
272
 
@@ -167,7 +276,11 @@ fn set_context_state_file(ws: &std::path::Path, name: &str) {
167
276
  pub(super) fn fork_ws(alpha_role: &str) -> PathBuf {
168
277
  let ws = temp_ws().join("forkv2");
169
278
  std::fs::create_dir_all(ws.join("agents")).unwrap();
170
- std::fs::write(ws.join("TEAM.md"), "---\nname: laneateam\nobjective: Fork v2 probe.\nprovider: codex\n---\n\nteam.\n").unwrap();
279
+ std::fs::write(
280
+ ws.join("TEAM.md"),
281
+ "---\nname: laneateam\nobjective: Fork v2 probe.\nprovider: codex\n---\n\nteam.\n",
282
+ )
283
+ .unwrap();
171
284
  std::fs::write(ws.join("agents").join("alpha.md"), alpha_role).unwrap();
172
285
  std::fs::write(ws.join("agents").join("bravo.md"), DELEG_ROLE_BRAVO).unwrap();
173
286
  let spec = crate::compiler::compile_team(&ws).expect("compile fork team");
@@ -217,9 +330,12 @@ pub(super) fn fork_ws(alpha_role: &str) -> PathBuf {
217
330
  // must skip the kill (killed empty) and set stopped=false; today kill_window IS called + stopped=true.
218
331
  #[test]
219
332
  fn lanea_stop_window_absent_returns_stopped_false_no_kill() {
220
- let ws = lanea_ws_agents(json!({ "alpha": { "status": "running", "provider": "codex", "window": "alpha" } }));
333
+ let ws = lanea_ws_agents(
334
+ json!({ "alpha": { "status": "running", "provider": "codex", "window": "alpha" } }),
335
+ );
221
336
  let tx = LaneTransport::new("team-laneateam", &[]); // alpha's window is ABSENT
222
- let report = stop_agent_with_transport(&ws, &aid("alpha"), None, &tx).expect("window-absent stop is a clean Ok, not an Err (golden returns stopped:false)");
337
+ let report = stop_agent_with_transport(&ws, &aid("alpha"), None, &tx)
338
+ .expect("window-absent stop is a clean Ok, not an Err (golden returns stopped:false)");
223
339
  assert!(
224
340
  !report.stopped,
225
341
  "golden operations.py:81-99: an ABSENT tmux window => stopped=FALSE (kill skipped); Rust hardcodes stopped:true"
@@ -237,10 +353,16 @@ fn lanea_stop_window_absent_returns_stopped_false_no_kill() {
237
353
  // window-gate fix regressing it.
238
354
  #[test]
239
355
  fn lanea_stop_window_present_kills_and_stopped_true() {
240
- let ws = lanea_ws_agents(json!({ "alpha": { "status": "running", "provider": "codex", "window": "alpha" } }));
356
+ let ws = lanea_ws_agents(
357
+ json!({ "alpha": { "status": "running", "provider": "codex", "window": "alpha" } }),
358
+ );
241
359
  let tx = LaneTransport::new("team-laneateam", &["alpha"]); // window present
242
- let report = stop_agent_with_transport(&ws, &aid("alpha"), None, &tx).expect("present-window stop ok");
243
- assert!(report.stopped, "a present window must be killed => stopped=true");
360
+ let report =
361
+ stop_agent_with_transport(&ws, &aid("alpha"), None, &tx).expect("present-window stop ok");
362
+ assert!(
363
+ report.stopped,
364
+ "a present window must be killed => stopped=true"
365
+ );
244
366
  assert_eq!(
245
367
  tx.killed(),
246
368
  vec!["team-laneateam:alpha".to_string()],
@@ -325,7 +447,10 @@ fn lanea_remove_dynamic_agent_removable_without_from_spec() {
325
447
  );
326
448
  let state = crate::state::persist::load_runtime_state(&ws).expect("load state");
327
449
  assert!(
328
- state.get("agents").and_then(serde_json::Value::as_object).is_some_and(|a| !a.contains_key("alpha")),
450
+ state
451
+ .get("agents")
452
+ .and_then(serde_json::Value::as_object)
453
+ .is_some_and(|a| !a.contains_key("alpha")),
329
454
  "the dynamic agent must actually be removed from state.agents; got {result:?}"
330
455
  );
331
456
  }
@@ -337,9 +462,14 @@ fn lanea_remove_dynamic_agent_removable_without_from_spec() {
337
462
  // a from_spec refusal. RED: an unknown agent with from_spec=false must surface "unknown worker".
338
463
  #[test]
339
464
  fn lanea_remove_unknown_agent_precedes_from_spec_refusal() {
340
- let ws = lanea_ws_agents(json!({ "alpha": { "status": "stopped", "provider": "codex", "window": "alpha" } }));
465
+ let ws = lanea_ws_agents(
466
+ json!({ "alpha": { "status": "stopped", "provider": "codex", "window": "alpha" } }),
467
+ );
341
468
  let tx = LaneTransport::new("team-laneateam", &[]);
342
- let text = format!("{:?}", remove_agent_with_transport(&ws, &aid("ghost"), false, false, None, &tx));
469
+ let text = format!(
470
+ "{:?}",
471
+ remove_agent_with_transport(&ws, &aid("ghost"), false, false, None, &tx)
472
+ );
343
473
  assert!(
344
474
  text.contains("unknown worker"),
345
475
  "golden agents.py:41-54: the unknown-worker check precedes the from_spec refusal; an unknown agent must \
@@ -360,8 +490,10 @@ fn lanea_remove_writes_markdown_team_state_not_json() {
360
490
  "bravo": { "status": "running", "provider": "codex", "window": "bravo" }
361
491
  }));
362
492
  let tx = LaneTransport::new("team-laneateam", &[]);
363
- let _ = remove_agent_with_transport(&ws, &aid("alpha"), true, true, None, &tx).expect("remove ok");
364
- let team_state = std::fs::read_to_string(ws.join("team_state.md")).expect("team_state.md written");
493
+ let _ =
494
+ remove_agent_with_transport(&ws, &aid("alpha"), true, true, None, &tx).expect("remove ok");
495
+ let team_state =
496
+ std::fs::read_to_string(ws.join("team_state.md")).expect("team_state.md written");
365
497
  assert!(
366
498
  team_state.starts_with("# Team State"),
367
499
  "golden write_team_state emits a Markdown document starting '# Team State'; Rust dumps JSON; got:\n{team_state}"
@@ -370,7 +502,10 @@ fn lanea_remove_writes_markdown_team_state_not_json() {
370
502
  !team_state.trim_start().starts_with('{'),
371
503
  "team_state.md must NOT be a JSON dump of runtime state; got:\n{team_state}"
372
504
  );
373
- assert!(team_state.contains("## Agents"), "golden has a '## Agents' section; got:\n{team_state}");
505
+ assert!(
506
+ team_state.contains("## Agents"),
507
+ "golden has a '## Agents' section; got:\n{team_state}"
508
+ );
374
509
  assert!(
375
510
  team_state.contains("bravo: Bravo Worker on codex"),
376
511
  "the '## Agents' section must list the remaining agent bravo (golden '- {{id}}: {{role}} on {{provider}} ({{status}})'); got:\n{team_state}"
@@ -446,7 +581,10 @@ fn lanea_remove_dynamic_role_file_missing_raises() {
446
581
  "bravo": { "status": "stopped", "provider": "codex", "window": "bravo" }
447
582
  }));
448
583
  let tx = LaneTransport::new("team-laneateam", &[]);
449
- let text = format!("{:?}", remove_agent_with_transport(&ws, &aid("alpha"), true, true, None, &tx));
584
+ let text = format!(
585
+ "{:?}",
586
+ remove_agent_with_transport(&ws, &aid("alpha"), true, true, None, &tx)
587
+ );
450
588
  assert!(
451
589
  text.contains("dynamic role file missing"),
452
590
  "golden agents.py:259-260: a state-recorded dynamic_role_file that is MISSING must RAISE 'dynamic role \
@@ -468,7 +606,10 @@ fn lanea_remove_rollback_restores_via_spec_state_file_path() {
468
606
  std::fs::write(ws.join("custom_state.md"), "ORIGINAL CUSTOM TEAM STATE\n").unwrap(); // capture reads this
469
607
  let tx = LaneTransport::new("team-laneateam", &[]);
470
608
  let result = remove_agent_with_transport(&ws, &aid("alpha"), true, true, None, &tx);
471
- assert!(result.is_err(), "precondition: 1-worker removal -> validate_spec fails -> rollback runs; got {result:?}");
609
+ assert!(
610
+ result.is_err(),
611
+ "precondition: 1-worker removal -> validate_spec fails -> rollback runs; got {result:?}"
612
+ );
472
613
  assert!(
473
614
  !ws.join("team_state.md").exists(),
474
615
  "golden agents.py:200-204: rollback restores the spec-derived state_file (custom_state.md), it must NOT \
@@ -486,7 +627,10 @@ fn lanea_remove_rollback_restores_via_spec_state_file_path() {
486
627
  fn lanea_fork_dup_target_leader_id_is_already_exists() {
487
628
  let ws = fork_ws(DELEG_ROLE_ALPHA);
488
629
  let tx = LaneTransport::new("team-laneateam", &[]);
489
- let text = format!("{:?}", fork_agent_with_transport(&ws, &aid("alpha"), &aid("leader"), None, false, None, &tx));
630
+ let text = format!(
631
+ "{:?}",
632
+ fork_agent_with_transport(&ws, &aid("alpha"), &aid("leader"), None, false, None, &tx)
633
+ );
490
634
  assert!(
491
635
  text.contains("already exists"),
492
636
  "golden operations.py:301-302 (_find_agent matches the leader): forking ONTO the leader id must raise \
@@ -503,7 +647,10 @@ fn lanea_fork_dup_target_leader_id_is_already_exists() {
503
647
  fn lanea_fork_window_already_exists_guard_before_spec_mutation() {
504
648
  let ws = fork_ws(DELEG_ROLE_ALPHA);
505
649
  let tx = LaneTransport::new("team-laneateam", &["newfork"]); // the target window already exists
506
- let text = format!("{:?}", fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx));
650
+ let text = format!(
651
+ "{:?}",
652
+ fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx)
653
+ );
507
654
  assert!(
508
655
  text.contains("tmux window already exists for fork target: team-laneateam:newfork"),
509
656
  "golden operations.py:310-312: a pre-existing target window must raise 'tmux window already exists for \
@@ -527,7 +674,8 @@ fn lanea_fork_window_already_exists_guard_before_spec_mutation() {
527
674
  fn lanea_fork_gate_error_text_and_spec_rollback_on_adapter_arm() {
528
675
  let ws = fork_ws(DELEG_ROLE_ALPHA_COMPAT); // source alpha auth_mode=compatible_api -> native fork unsupported
529
676
  let tx = LaneTransport::new("team-laneateam", &[]);
530
- let result = fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx);
677
+ let result =
678
+ fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx);
531
679
  let text = format!("{result:?}");
532
680
  assert!(
533
681
  text.contains("codex does not support native session fork"),
@@ -552,7 +700,9 @@ fn lanea_fork_gate_error_text_and_spec_rollback_on_adapter_arm() {
552
700
  fn lanea_fork_report_session_id_is_not_pane_id() {
553
701
  let ws = fork_ws(DELEG_ROLE_ALPHA); // codex+subscription -> native fork supported -> full success path
554
702
  let tx = LaneTransport::new("team-laneateam", &[]);
555
- let report = fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx).expect("fork ok (codex subscription supports fork)");
703
+ let report =
704
+ fork_agent_with_transport(&ws, &aid("alpha"), &aid("newfork"), None, false, None, &tx)
705
+ .expect("fork ok (codex subscription supports fork)");
556
706
  assert_ne!(
557
707
  report.session_id,
558
708
  Some(crate::provider::SessionId::new("%newfork")),
@@ -884,7 +884,8 @@ fn e5_restart_missing_role_docs_refuses_and_preserves_old_spec() {
884
884
 
885
885
  #[test]
886
886
  fn e5_restart_missing_role_docs_refuses_even_after_endpoint_convergence_marker() {
887
- let _harness_gate = EnvVarGuard::unset("TEAM_AGENT_TEST_ENDPOINT_CONVERGENCE_HARNESS_SPEC_FALLBACK");
887
+ let _harness_gate =
888
+ EnvVarGuard::unset("TEAM_AGENT_TEST_ENDPOINT_CONVERGENCE_HARNESS_SPEC_FALLBACK");
888
889
  let ws = restart_ws_two_resumable_workers();
889
890
  let prev_spec = crate::model::paths::runtime_spec_path(&ws, "restartteam");
890
891
  std::fs::create_dir_all(prev_spec.parent().unwrap()).unwrap();