@team-agent/installer 0.5.41 → 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 (152) 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/coordinator/tick.rs +19 -1
  51. package/crates/team-agent/src/db/message_store.rs +138 -30
  52. package/crates/team-agent/src/db/migration.rs +249 -61
  53. package/crates/team-agent/src/db/schema.rs +303 -82
  54. package/crates/team-agent/src/diagnose/comms.rs +9 -2
  55. package/crates/team-agent/src/diagnose/mod.rs +1 -3
  56. package/crates/team-agent/src/diagnose/orphans.rs +79 -61
  57. package/crates/team-agent/src/event_log.rs +70 -16
  58. package/crates/team-agent/src/layout/manager.rs +15 -4
  59. package/crates/team-agent/src/layout/mod.rs +4 -4
  60. package/crates/team-agent/src/layout/overlay.rs +10 -3
  61. package/crates/team-agent/src/layout/placement.rs +5 -1
  62. package/crates/team-agent/src/layout/recovery.rs +4 -2
  63. package/crates/team-agent/src/layout/runtime_sessions.rs +7 -7
  64. package/crates/team-agent/src/layout/sessions.rs +17 -9
  65. package/crates/team-agent/src/layout/tmux_endpoint.rs +1 -1
  66. package/crates/team-agent/src/layout/worker_env.rs +52 -19
  67. package/crates/team-agent/src/leader/helpers.rs +7 -1
  68. package/crates/team-agent/src/leader/lease.rs +195 -82
  69. package/crates/team-agent/src/leader/owner_bind.rs +55 -22
  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/start.rs +75 -54
  73. package/crates/team-agent/src/leader/takeover.rs +46 -11
  74. package/crates/team-agent/src/leader/tests/basics.rs +320 -167
  75. package/crates/team-agent/src/leader/tests/byte_findings.rs +361 -219
  76. package/crates/team-agent/src/leader/tests/identity.rs +428 -356
  77. package/crates/team-agent/src/leader/tests/idle.rs +285 -254
  78. package/crates/team-agent/src/leader/tests/lease_api.rs +338 -274
  79. package/crates/team-agent/src/leader/tests/lease_claim.rs +643 -593
  80. package/crates/team-agent/src/leader/tests/mod.rs +115 -99
  81. package/crates/team-agent/src/leader/tests/rediscover.rs +74 -22
  82. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +237 -211
  83. package/crates/team-agent/src/lib.rs +4 -4
  84. package/crates/team-agent/src/lifecycle/display.rs +7 -3
  85. package/crates/team-agent/src/lifecycle/launch.rs +6 -1
  86. package/crates/team-agent/src/lifecycle/mod.rs +9 -1
  87. package/crates/team-agent/src/lifecycle/profile_launch.rs +77 -34
  88. package/crates/team-agent/src/lifecycle/profile_smoke.rs +3 -1
  89. package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -6
  90. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +1 -4
  91. package/crates/team-agent/src/lifecycle/restart/preflight.rs +6 -5
  92. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -22
  93. package/crates/team-agent/src/lifecycle/restart/remove.rs +45 -35
  94. package/crates/team-agent/src/lifecycle/restart/team_state.rs +63 -17
  95. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +251 -84
  96. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +198 -48
  97. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -1
  98. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +152 -32
  99. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +1 -5
  100. package/crates/team-agent/src/lifecycle/tests.rs +2 -2
  101. package/crates/team-agent/src/main.rs +4 -4
  102. package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +47 -20
  103. package/crates/team-agent/src/mcp_server/mod.rs +11 -2
  104. package/crates/team-agent/src/mcp_server/types.rs +14 -3
  105. package/crates/team-agent/src/mcp_server/wire.rs +230 -68
  106. package/crates/team-agent/src/messaging/delivery.rs +20 -18
  107. package/crates/team-agent/src/messaging/helpers.rs +25 -4
  108. package/crates/team-agent/src/messaging/leader_receiver.rs +4 -5
  109. package/crates/team-agent/src/messaging/mod.rs +2 -3
  110. package/crates/team-agent/src/messaging/selftest.rs +46 -26
  111. package/crates/team-agent/src/messaging/tests/main_preserved.rs +47 -12
  112. package/crates/team-agent/src/messaging/tests/runtime.rs +57 -22
  113. package/crates/team-agent/src/messaging/tests/spine.rs +154 -40
  114. package/crates/team-agent/src/messaging/tests/wave2.rs +31 -32
  115. package/crates/team-agent/src/messaging/trust.rs +25 -2
  116. package/crates/team-agent/src/messaging/watchers.rs +37 -9
  117. package/crates/team-agent/src/model/enums.rs +65 -16
  118. package/crates/team-agent/src/model/ids.rs +12 -3
  119. package/crates/team-agent/src/model/paths.rs +28 -7
  120. package/crates/team-agent/src/model/permissions.rs +176 -33
  121. package/crates/team-agent/src/model/routing.rs +66 -20
  122. package/crates/team-agent/src/model/spec.rs +365 -69
  123. package/crates/team-agent/src/model/task_graph.rs +36 -9
  124. package/crates/team-agent/src/model/yaml/tests.rs +24 -6
  125. package/crates/team-agent/src/model/yaml.rs +7 -6
  126. package/crates/team-agent/src/packaging/install.rs +23 -9
  127. package/crates/team-agent/src/packaging/migrate.rs +5 -7
  128. package/crates/team-agent/src/packaging/mod.rs +9 -1
  129. package/crates/team-agent/src/packaging/repair.rs +13 -6
  130. package/crates/team-agent/src/packaging/tests.rs +63 -16
  131. package/crates/team-agent/src/packaging/types.rs +22 -7
  132. package/crates/team-agent/src/platform/argv.rs +4 -1
  133. package/crates/team-agent/src/platform/file_lock.rs +22 -8
  134. package/crates/team-agent/src/platform/process.rs +21 -22
  135. package/crates/team-agent/src/provider/adapters/claude.rs +1 -3
  136. package/crates/team-agent/src/provider/approvals/parsing.rs +134 -26
  137. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +13 -3
  138. package/crates/team-agent/src/provider/classify.rs +127 -42
  139. package/crates/team-agent/src/provider/faults.rs +17 -5
  140. package/crates/team-agent/src/provider/helpers.rs +6 -5
  141. package/crates/team-agent/src/provider/startup_prompt.rs +75 -27
  142. package/crates/team-agent/src/state/repository.rs +27 -14
  143. package/crates/team-agent/src/tmux_backend/tests.rs +1637 -1398
  144. package/crates/team-agent/src/tmux_backend.rs +80 -44
  145. package/crates/team-agent/src/topology.rs +27 -20
  146. package/crates/team-agent/src/transport/test_support.rs +20 -23
  147. package/crates/team-agent/src/transport/tests/behavior.rs +292 -293
  148. package/crates/team-agent/src/transport/tests/mod.rs +178 -187
  149. package/crates/team-agent/src/transport/tests/wire.rs +561 -525
  150. package/crates/team-agent/src/transport.rs +12 -17
  151. package/crates/team-agent/src/transport_factory.rs +29 -14
  152. package/package.json +4 -4
@@ -1,5 +1,5 @@
1
- use super::*;
2
1
  use super::spine::{message_status, DeliveringTransport};
2
+ use super::*;
3
3
 
4
4
  // ═════════════════════════════════════════════════════════════════════════
5
5
  // P0 REGRESSION (root cause pinned) — a per-agent capture/health-check FAILURE must not abort the
@@ -31,20 +31,42 @@ struct CaptureFailsDeliverTransport {
31
31
  }
32
32
  impl CaptureFailsDeliverTransport {
33
33
  fn new() -> Self {
34
- Self { inner: DeliveringTransport::new() }
34
+ Self {
35
+ inner: DeliveringTransport::new(),
36
+ }
35
37
  }
36
38
  }
37
39
  impl Transport for CaptureFailsDeliverTransport {
38
40
  fn kind(&self) -> BackendKind {
39
41
  self.inner.kind()
40
42
  }
41
- fn spawn_first(&self, s: &SessionName, w: &WindowName, a: &[String], c: &std::path::Path, e: &std::collections::BTreeMap<String, String>) -> Result<SpawnResult, TransportError> {
43
+ fn spawn_first(
44
+ &self,
45
+ s: &SessionName,
46
+ w: &WindowName,
47
+ a: &[String],
48
+ c: &std::path::Path,
49
+ e: &std::collections::BTreeMap<String, String>,
50
+ ) -> Result<SpawnResult, TransportError> {
42
51
  self.inner.spawn_first(s, w, a, c, e)
43
52
  }
44
- fn spawn_into(&self, s: &SessionName, w: &WindowName, a: &[String], c: &std::path::Path, e: &std::collections::BTreeMap<String, String>) -> Result<SpawnResult, TransportError> {
53
+ fn spawn_into(
54
+ &self,
55
+ s: &SessionName,
56
+ w: &WindowName,
57
+ a: &[String],
58
+ c: &std::path::Path,
59
+ e: &std::collections::BTreeMap<String, String>,
60
+ ) -> Result<SpawnResult, TransportError> {
45
61
  self.inner.spawn_into(s, w, a, c, e)
46
62
  }
47
- fn inject(&self, t: &Target, p: &InjectPayload, submit: Key, bracketed: bool) -> Result<InjectReport, TransportError> {
63
+ fn inject(
64
+ &self,
65
+ t: &Target,
66
+ p: &InjectPayload,
67
+ submit: Key,
68
+ bracketed: bool,
69
+ ) -> Result<InjectReport, TransportError> {
48
70
  self.inner.inject(t, p, submit, bracketed)
49
71
  }
50
72
  fn send_keys(&self, t: &Target, k: &[Key]) -> Result<(), TransportError> {
@@ -52,7 +74,9 @@ impl Transport for CaptureFailsDeliverTransport {
52
74
  }
53
75
  fn capture(&self, _t: &Target, _r: CaptureRange) -> Result<CapturedText, TransportError> {
54
76
  // the agent's window is gone — capture fails (tmux can't find the target).
55
- Err(TransportError::TargetNotFound { target: "window gone (stopped agent)".to_string() })
77
+ Err(TransportError::TargetNotFound {
78
+ target: "window gone (stopped agent)".to_string(),
79
+ })
56
80
  }
57
81
  fn query(&self, t: &Target, f: PaneField) -> Result<Option<String>, TransportError> {
58
82
  self.inner.query(t, f)
@@ -69,7 +93,12 @@ impl Transport for CaptureFailsDeliverTransport {
69
93
  fn list_windows(&self, s: &SessionName) -> Result<Vec<WindowName>, TransportError> {
70
94
  self.inner.list_windows(s)
71
95
  }
72
- fn set_session_env(&self, s: &SessionName, k: &str, v: &str) -> Result<SetEnvOutcome, TransportError> {
96
+ fn set_session_env(
97
+ &self,
98
+ s: &SessionName,
99
+ k: &str,
100
+ v: &str,
101
+ ) -> Result<SetEnvOutcome, TransportError> {
73
102
  self.inner.set_session_env(s, k, v)
74
103
  }
75
104
  fn kill_session(&self, s: &SessionName) -> Result<(), TransportError> {
@@ -87,7 +116,10 @@ fn tick_swallows_capture_failure_and_still_delivers_to_other_agent() {
87
116
  let dir = std::env::temp_dir().join(format!(
88
117
  "team-agent-coord-stopreg-{}-{}",
89
118
  std::process::id(),
90
- std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
119
+ std::time::SystemTime::now()
120
+ .duration_since(std::time::UNIX_EPOCH)
121
+ .unwrap()
122
+ .as_nanos()
91
123
  ));
92
124
  std::fs::create_dir_all(&dir).unwrap();
93
125
  // w1 STOPPED (window gone -> capture fails), w2 ACTIVE — w2 keeps the tmux session alive.
@@ -104,14 +136,32 @@ fn tick_swallows_capture_failure_and_still_delivers_to_other_agent() {
104
136
  .unwrap();
105
137
  let store = MessageStore::open(&dir).unwrap();
106
138
  let mid = store
107
- .create_message(Some("task-1"), "leader", "w2", "after stop", None, true, None)
139
+ .create_message(
140
+ Some("task-1"),
141
+ "leader",
142
+ "w2",
143
+ "after stop",
144
+ None,
145
+ true,
146
+ None,
147
+ )
108
148
  .unwrap();
109
149
  drop(store);
110
- assert_eq!(message_status(&dir, &mid), "accepted", "precondition: a fresh message is 'accepted'");
150
+ assert_eq!(
151
+ message_status(&dir, &mid),
152
+ "accepted",
153
+ "precondition: a fresh message is 'accepted'"
154
+ );
111
155
  let ws = WorkspacePath::new(dir.clone());
112
156
  let reg: Box<dyn ProviderRegistry> = Box::new(MockRegistry::new(&[], &[]));
113
157
  // capture() ERRORS (window gone) but inject delivers + session present.
114
- let coord = Coordinator::for_test(ws, reg, Box::new(CaptureFailsDeliverTransport::new()), None, None);
158
+ let coord = Coordinator::for_test(
159
+ ws,
160
+ reg,
161
+ Box::new(CaptureFailsDeliverTransport::new()),
162
+ None,
163
+ None,
164
+ );
115
165
  let result = coord.tick();
116
166
  // (a) a per-agent capture failure must NOT abort the whole tick.
117
167
  assert!(
@@ -68,10 +68,16 @@ struct MapMarkerStore {
68
68
  }
69
69
  impl MapMarkerStore {
70
70
  fn ok() -> Self {
71
- Self { markers: Default::default(), fail: false }
71
+ Self {
72
+ markers: Default::default(),
73
+ fail: false,
74
+ }
72
75
  }
73
76
  fn failing() -> Self {
74
- Self { markers: Default::default(), fail: true }
77
+ Self {
78
+ markers: Default::default(),
79
+ fail: true,
80
+ }
75
81
  }
76
82
  }
77
83
  impl MarkerStore for MapMarkerStore {
@@ -159,19 +165,11 @@ impl Transport for MockTransport {
159
165
  self.record("send_keys");
160
166
  self.inner.send_keys(t, keys)
161
167
  }
162
- fn capture(
163
- &self,
164
- t: &Target,
165
- range: CaptureRange,
166
- ) -> Result<CapturedText, TransportError> {
168
+ fn capture(&self, t: &Target, range: CaptureRange) -> Result<CapturedText, TransportError> {
167
169
  self.record("capture");
168
170
  self.inner.capture(t, range)
169
171
  }
170
- fn query(
171
- &self,
172
- t: &Target,
173
- f: PaneField,
174
- ) -> Result<Option<String>, TransportError> {
172
+ fn query(&self, t: &Target, f: PaneField) -> Result<Option<String>, TransportError> {
175
173
  self.record("query");
176
174
  self.inner.query(t, f)
177
175
  }
@@ -187,10 +185,7 @@ impl Transport for MockTransport {
187
185
  self.record("has_session");
188
186
  self.inner.has_session(s)
189
187
  }
190
- fn list_windows(
191
- &self,
192
- s: &SessionName,
193
- ) -> Result<Vec<WindowName>, TransportError> {
188
+ fn list_windows(&self, s: &SessionName) -> Result<Vec<WindowName>, TransportError> {
194
189
  self.record("list_windows");
195
190
  self.inner.list_windows(s)
196
191
  }
@@ -211,10 +206,7 @@ impl Transport for MockTransport {
211
206
  self.record("kill_window");
212
207
  self.inner.kill_window(t)
213
208
  }
214
- fn attach_session(
215
- &self,
216
- s: &SessionName,
217
- ) -> Result<AttachOutcome, TransportError> {
209
+ fn attach_session(&self, s: &SessionName) -> Result<AttachOutcome, TransportError> {
218
210
  self.record("attach_session");
219
211
  self.inner.attach_session(s)
220
212
  }
@@ -229,7 +221,10 @@ fn coord_for_test(
229
221
  session_present: bool,
230
222
  save_hook: Option<SaveHook>,
231
223
  recorder: Option<OrderRecorder>,
232
- ) -> (Coordinator, std::sync::Arc<std::sync::Mutex<Vec<&'static str>>>) {
224
+ ) -> (
225
+ Coordinator,
226
+ std::sync::Arc<std::sync::Mutex<Vec<&'static str>>>,
227
+ ) {
233
228
  let dir = std::env::temp_dir().join(format!(
234
229
  "team-agent-coord-tick-{}-{}",
235
230
  std::process::id(),
@@ -243,13 +238,7 @@ fn coord_for_test(
243
238
  let reg: Box<dyn ProviderRegistry> = Box::new(MockRegistry::new(&[], &[]));
244
239
  let transport = MockTransport::new(session_present);
245
240
  let calls = std::sync::Arc::clone(&transport.calls);
246
- let coord = Coordinator::for_test(
247
- ws,
248
- reg,
249
- Box::new(transport),
250
- save_hook,
251
- recorder,
252
- );
241
+ let coord = Coordinator::for_test(ws, reg, Box::new(transport), save_hook, recorder);
253
242
  (coord, calls)
254
243
  }
255
244
 
@@ -261,7 +250,10 @@ fn coord_for_test(
261
250
  fn coord_for_test_with_session(
262
251
  session_present: bool,
263
252
  session_name: &str,
264
- ) -> (Coordinator, std::sync::Arc<std::sync::Mutex<Vec<&'static str>>>) {
253
+ ) -> (
254
+ Coordinator,
255
+ std::sync::Arc<std::sync::Mutex<Vec<&'static str>>>,
256
+ ) {
265
257
  let dir = std::env::temp_dir().join(format!(
266
258
  "team-agent-coord-tick-sess-{}-{}",
267
259
  std::process::id(),
@@ -296,21 +288,23 @@ fn failing_save_hook() -> SaveHook {
296
288
  fn read_event_log_dir(dir: &std::path::Path) -> Vec<serde_json::Value> {
297
289
  let path = crate::model::paths::logs_dir(dir).join("events.jsonl");
298
290
  match std::fs::read_to_string(&path) {
299
- Ok(text) => text.lines().filter_map(|l| serde_json::from_str(l).ok()).collect(),
291
+ Ok(text) => text
292
+ .lines()
293
+ .filter_map(|l| serde_json::from_str(l).ok())
294
+ .collect(),
300
295
  Err(_) => Vec::new(),
301
296
  }
302
297
  }
303
298
 
304
-
305
- mod basics;
299
+ mod a0_lostupdate;
306
300
  mod abnormal;
307
- mod watch;
308
- mod tick_core;
309
- mod spine;
310
- mod health_sync;
311
- mod takeover;
301
+ mod api_error_recovery;
302
+ mod basics;
312
303
  mod daemon;
313
304
  mod energy;
305
+ mod health_sync;
314
306
  mod main_preserved;
315
- mod a0_lostupdate;
316
- mod api_error_recovery;
307
+ mod spine;
308
+ mod takeover;
309
+ mod tick_core;
310
+ mod watch;
@@ -18,7 +18,9 @@ pub(super) struct DeliveringTransport {
18
18
  }
19
19
  impl DeliveringTransport {
20
20
  pub(super) fn new() -> Self {
21
- Self { inner: MockTransport::new(true) }
21
+ Self {
22
+ inner: MockTransport::new(true),
23
+ }
22
24
  }
23
25
  }
24
26
  impl Transport for DeliveringTransport {
@@ -56,7 +58,8 @@ impl Transport for DeliveringTransport {
56
58
  Ok(InjectReport {
57
59
  stage_reached: crate::transport::InjectStage::Submit,
58
60
  inject_verification: crate::transport::InjectVerification::CaptureContainsToken,
59
- submit_verification: crate::transport::SubmitVerification::EnterSentWithoutPlaceholderCheck,
61
+ submit_verification:
62
+ crate::transport::SubmitVerification::EnterSentWithoutPlaceholderCheck,
60
63
  turn_verification: crate::transport::TurnVerification::NotYetObserved,
61
64
  attempts: 1,
62
65
  submit_diagnostics: None,
@@ -83,7 +86,12 @@ impl Transport for DeliveringTransport {
83
86
  fn list_windows(&self, s: &SessionName) -> Result<Vec<WindowName>, TransportError> {
84
87
  self.inner.list_windows(s)
85
88
  }
86
- fn set_session_env(&self, s: &SessionName, k: &str, v: &str) -> Result<SetEnvOutcome, TransportError> {
89
+ fn set_session_env(
90
+ &self,
91
+ s: &SessionName,
92
+ k: &str,
93
+ v: &str,
94
+ ) -> Result<SetEnvOutcome, TransportError> {
87
95
  self.inner.set_session_env(s, k, v)
88
96
  }
89
97
  fn kill_session(&self, s: &SessionName) -> Result<(), TransportError> {
@@ -146,8 +154,12 @@ fn seed_due_health_ping(dir: &std::path::Path) -> i64 {
146
154
  fn scheduled_status(dir: &std::path::Path, id: i64) -> String {
147
155
  let store = MessageStore::open(dir).unwrap();
148
156
  let conn = crate::db::schema::open_db(store.db_path()).unwrap();
149
- conn.query_row("select status from scheduled_events where id = ?1", [id], |r| r.get::<_, String>(0))
150
- .unwrap()
157
+ conn.query_row(
158
+ "select status from scheduled_events where id = ?1",
159
+ [id],
160
+ |r| r.get::<_, String>(0),
161
+ )
162
+ .unwrap()
151
163
  }
152
164
 
153
165
  pub(super) fn message_status(dir: &std::path::Path, message_id: &str) -> String {
@@ -167,7 +179,11 @@ pub(super) fn message_status(dir: &std::path::Path, message_id: &str) -> String
167
179
  fn spine_tick_fires_due_scheduled_event_and_marks_db_done() {
168
180
  let (coord, dir) = seeded_spine_coord(Box::new(MockTransport::new(true)), None);
169
181
  let id = seed_due_health_ping(&dir);
170
- assert_eq!(scheduled_status(&dir, id), "pending", "precondition: the seeded row starts pending");
182
+ assert_eq!(
183
+ scheduled_status(&dir, id),
184
+ "pending",
185
+ "precondition: the seeded row starts pending"
186
+ );
171
187
 
172
188
  let report = coord.tick().expect("tick returns a typed report");
173
189
 
@@ -189,14 +205,23 @@ fn spine_tick_fires_due_scheduled_event_and_marks_db_done() {
189
205
  // mutation — AFTER the real obligation side-effects, not after no-op probes.
190
206
  #[test]
191
207
  fn spine_tick_save_failure_still_persists_real_scheduled_mutation() {
192
- let (coord, dir) = seeded_spine_coord(Box::new(MockTransport::new(true)), Some(failing_save_hook()));
208
+ let (coord, dir) = seeded_spine_coord(
209
+ Box::new(MockTransport::new(true)),
210
+ Some(failing_save_hook()),
211
+ );
193
212
  let id = seed_due_health_ping(&dir);
194
213
 
195
- let report = coord.tick().expect("a degraded tick is Ok(TickReport), not Err");
214
+ let report = coord
215
+ .tick()
216
+ .expect("a degraded tick is Ok(TickReport), not Err");
196
217
 
197
218
  // degraded report shape (bug-084: save failure → ok=false / persisted=false, NOT Err).
198
219
  assert!(!report.ok, "save failure → ok=false");
199
- assert_eq!(report.persisted, Some(false), "save failure → persisted=Some(false)");
220
+ assert_eq!(
221
+ report.persisted,
222
+ Some(false),
223
+ "save failure → persisted=Some(false)"
224
+ );
200
225
  assert_eq!(report.reason, Some(TickStopReason::PersistenceDegraded));
201
226
  // the REAL db side-effect happened BEFORE the (failed) save.
202
227
  assert_eq!(
@@ -221,10 +246,22 @@ fn spine_tick_delivers_pending_message_drives_real_db_or_report() {
221
246
  let (coord, dir) = seeded_spine_coord(Box::new(DeliveringTransport::new()), None);
222
247
  let store = MessageStore::open(&dir).unwrap();
223
248
  let mid = store
224
- .create_message(Some("task-1"), "leader", "w1", "do the thing", None, true, None)
249
+ .create_message(
250
+ Some("task-1"),
251
+ "leader",
252
+ "w1",
253
+ "do the thing",
254
+ None,
255
+ true,
256
+ None,
257
+ )
225
258
  .unwrap();
226
259
  drop(store);
227
- assert_eq!(message_status(&dir, &mid), "accepted", "precondition: a fresh message is 'accepted'");
260
+ assert_eq!(
261
+ message_status(&dir, &mid),
262
+ "accepted",
263
+ "precondition: a fresh message is 'accepted'"
264
+ );
228
265
 
229
266
  let report = coord.tick().expect("tick returns a typed report");
230
267
 
@@ -251,7 +288,10 @@ fn spine_tick_session_missing_emits_event() {
251
288
  // tmux gate fire → the tick stops. The gate must ALSO emit coordinator.session_missing.
252
289
  let (coord, dir) = seeded_spine_coord(Box::new(MockTransport::new(false)), None);
253
290
  let report = coord.tick().expect("tick returns a typed report");
254
- assert!(report.stop, "precondition: a missing session stops the tick");
291
+ assert!(
292
+ report.stop,
293
+ "precondition: a missing session stops the tick"
294
+ );
255
295
  let events = read_event_log_dir(&dir);
256
296
  assert!(
257
297
  events
@@ -21,18 +21,40 @@ impl Transport for CountingCaptureTransport {
21
21
  fn kind(&self) -> BackendKind {
22
22
  BackendKind::Tmux
23
23
  }
24
- fn spawn_first(&self, _s: &SessionName, _w: &WindowName, _a: &[String], _c: &std::path::Path, _e: &std::collections::BTreeMap<String, String>) -> Result<SpawnResult, TransportError> {
24
+ fn spawn_first(
25
+ &self,
26
+ _s: &SessionName,
27
+ _w: &WindowName,
28
+ _a: &[String],
29
+ _c: &std::path::Path,
30
+ _e: &std::collections::BTreeMap<String, String>,
31
+ ) -> Result<SpawnResult, TransportError> {
25
32
  unimplemented!("not reached")
26
33
  }
27
- fn spawn_into(&self, _s: &SessionName, _w: &WindowName, _a: &[String], _c: &std::path::Path, _e: &std::collections::BTreeMap<String, String>) -> Result<SpawnResult, TransportError> {
34
+ fn spawn_into(
35
+ &self,
36
+ _s: &SessionName,
37
+ _w: &WindowName,
38
+ _a: &[String],
39
+ _c: &std::path::Path,
40
+ _e: &std::collections::BTreeMap<String, String>,
41
+ ) -> Result<SpawnResult, TransportError> {
28
42
  unimplemented!("not reached")
29
43
  }
30
- fn inject(&self, _t: &Target, _p: &InjectPayload, _s: Key, _b: bool) -> Result<InjectReport, TransportError> {
31
- self.injects.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
44
+ fn inject(
45
+ &self,
46
+ _t: &Target,
47
+ _p: &InjectPayload,
48
+ _s: Key,
49
+ _b: bool,
50
+ ) -> Result<InjectReport, TransportError> {
51
+ self.injects
52
+ .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
32
53
  Ok(InjectReport {
33
54
  stage_reached: crate::transport::InjectStage::Submit,
34
55
  inject_verification: crate::transport::InjectVerification::CaptureContainsToken,
35
- submit_verification: crate::transport::SubmitVerification::EnterSentWithoutPlaceholderCheck,
56
+ submit_verification:
57
+ crate::transport::SubmitVerification::EnterSentWithoutPlaceholderCheck,
36
58
  turn_verification: crate::transport::TurnVerification::NotYetObserved,
37
59
  attempts: 1,
38
60
  submit_diagnostics: None,
@@ -42,7 +64,10 @@ impl Transport for CountingCaptureTransport {
42
64
  Ok(())
43
65
  }
44
66
  fn capture(&self, _t: &Target, range: CaptureRange) -> Result<CapturedText, TransportError> {
45
- Ok(CapturedText { text: self.scrollback.clone(), range })
67
+ Ok(CapturedText {
68
+ text: self.scrollback.clone(),
69
+ range,
70
+ })
46
71
  }
47
72
  fn query(&self, _t: &Target, _f: PaneField) -> Result<Option<String>, TransportError> {
48
73
  Ok(None)
@@ -59,7 +84,12 @@ impl Transport for CountingCaptureTransport {
59
84
  fn list_windows(&self, _s: &SessionName) -> Result<Vec<WindowName>, TransportError> {
60
85
  Ok(Vec::new())
61
86
  }
62
- fn set_session_env(&self, _s: &SessionName, _k: &str, _v: &str) -> Result<SetEnvOutcome, TransportError> {
87
+ fn set_session_env(
88
+ &self,
89
+ _s: &SessionName,
90
+ _k: &str,
91
+ _v: &str,
92
+ ) -> Result<SetEnvOutcome, TransportError> {
63
93
  Ok(SetEnvOutcome::Applied)
64
94
  }
65
95
  fn kill_session(&self, _s: &SessionName) -> Result<(), TransportError> {
@@ -76,17 +106,30 @@ impl Transport for CountingCaptureTransport {
76
106
  fn slice2b_dir() -> std::path::PathBuf {
77
107
  use std::sync::atomic::{AtomicU64, Ordering};
78
108
  static N: AtomicU64 = AtomicU64::new(0);
79
- let dir = std::env::temp_dir().join(format!("ta-rs-2b-{}-{}", std::process::id(), N.fetch_add(1, Ordering::Relaxed)));
109
+ let dir = std::env::temp_dir().join(format!(
110
+ "ta-rs-2b-{}-{}",
111
+ std::process::id(),
112
+ N.fetch_add(1, Ordering::Relaxed)
113
+ ));
80
114
  std::fs::create_dir_all(&dir).unwrap();
81
115
  dir
82
116
  }
83
117
 
84
118
  /// Build a coordinator over a workspace seeded with `state` (verbatim) + a counting transport.
85
- fn takeover_coord(state: serde_json::Value) -> (Coordinator, std::path::PathBuf, std::sync::Arc<std::sync::atomic::AtomicUsize>) {
119
+ fn takeover_coord(
120
+ state: serde_json::Value,
121
+ ) -> (
122
+ Coordinator,
123
+ std::path::PathBuf,
124
+ std::sync::Arc<std::sync::atomic::AtomicUsize>,
125
+ ) {
86
126
  let dir = slice2b_dir();
87
127
  crate::state::persist::save_runtime_state(&dir, &state).unwrap();
88
128
  let injects = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0));
89
- let transport = CountingCaptureTransport { scrollback: String::new(), injects: std::sync::Arc::clone(&injects) };
129
+ let transport = CountingCaptureTransport {
130
+ scrollback: String::new(),
131
+ injects: std::sync::Arc::clone(&injects),
132
+ };
90
133
  let ws = WorkspacePath::new(dir.clone());
91
134
  let reg: Box<dyn ProviderRegistry> = Box::new(MockRegistry::new(&[], &[]));
92
135
  let coord = Coordinator::for_test(ws, reg, Box::new(transport), None, None);
@@ -94,7 +137,13 @@ fn takeover_coord(state: serde_json::Value) -> (Coordinator, std::path::PathBuf,
94
137
  }
95
138
 
96
139
  /// Seed an agent_health row (real DB) — what sync_health writes and detect_stuck/detect_deadlocks read.
97
- fn seed_agent_health(dir: &std::path::Path, agent_id: &str, status: &str, last_output_at: &str, owner_team_id: Option<&str>) {
140
+ fn seed_agent_health(
141
+ dir: &std::path::Path,
142
+ agent_id: &str,
143
+ status: &str,
144
+ last_output_at: &str,
145
+ owner_team_id: Option<&str>,
146
+ ) {
98
147
  let store = MessageStore::open(dir).unwrap();
99
148
  let conn = crate::db::schema::open_db(store.db_path()).unwrap();
100
149
  conn.execute(
@@ -106,7 +155,9 @@ fn seed_agent_health(dir: &std::path::Path, agent_id: &str, status: &str, last_o
106
155
  }
107
156
 
108
157
  fn has_event(dir: &std::path::Path, name: &str) -> bool {
109
- read_event_log_dir(dir).iter().any(|e| e.get("event").and_then(|v| v.as_str()) == Some(name))
158
+ read_event_log_dir(dir)
159
+ .iter()
160
+ .any(|e| e.get("event").and_then(|v| v.as_str()) == Some(name))
110
161
  }
111
162
 
112
163
  // #236 nag_removal (N35) — detect_stuck no longer synthesized in coordinator tick.
@@ -123,7 +174,9 @@ fn slice2b_detect_stuck_no_longer_synthesized_by_framework_n35() {
123
174
  }));
124
175
  seed_agent_health(&dir, "w1", "RUNNING", &stale, Some("team-h"));
125
176
  let store = MessageStore::open(&dir).unwrap();
126
- let _ = store.create_message(Some("t"), "leader", "w1", "do work", None, true, None).unwrap();
177
+ let _ = store
178
+ .create_message(Some("t"), "leader", "w1", "do work", None, true, None)
179
+ .unwrap();
127
180
  drop(store);
128
181
 
129
182
  let report = coord.tick().expect("tick");
@@ -148,7 +201,9 @@ fn slice2b_detect_deadlocks_no_longer_synthesized_by_framework_n35() {
148
201
  }));
149
202
  seed_agent_health(&dir, "w1", "IDLE", &now, Some("team-h"));
150
203
  let store = MessageStore::open(&dir).unwrap();
151
- let _ = store.create_message(Some("t"), "w2", "w1", "are you done?", None, true, None).unwrap();
204
+ let _ = store
205
+ .create_message(Some("t"), "w2", "w1", "are you done?", None, true, None)
206
+ .unwrap();
152
207
  drop(store);
153
208
 
154
209
  let report = coord.tick().expect("tick");
@@ -199,7 +254,10 @@ fn slice2b_takeover_unarmed_idle_worker_is_never_pinged() {
199
254
  // NO coordinator.idle_takeover_monitor → not armed → reason not_armed_no_worker_turn.
200
255
  }));
201
256
  coord.tick().expect("tick");
202
- assert!(!has_event(&dir, "idle_takeover.reminder"), "a NOT-armed worker must never be pinged (§121)");
257
+ assert!(
258
+ !has_event(&dir, "idle_takeover.reminder"),
259
+ "a NOT-armed worker must never be pinged (§121)"
260
+ );
203
261
  assert_eq!(
204
262
  injects.load(std::sync::atomic::Ordering::Relaxed),
205
263
  0,