@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
@@ -38,7 +38,9 @@ pub(crate) fn claude_explicit_error_fact(record: &serde_json::Value) -> Option<F
38
38
  FactKind::Error,
39
39
  )
40
40
  .with_api_error_details(
41
- record.get("apiErrorStatus").and_then(serde_json::Value::as_i64),
41
+ record
42
+ .get("apiErrorStatus")
43
+ .and_then(serde_json::Value::as_i64),
42
44
  non_empty_string_field(record, "error"),
43
45
  non_empty_string_field(record, "requestId"),
44
46
  non_empty_string_field(record, "uuid"),
@@ -58,7 +60,9 @@ fn codex_explicit_error_fact(record: &serde_json::Value) -> Option<FaultFact> {
58
60
  }
59
61
  Some(FaultFact::new(
60
62
  Signature::new("turn_failed"),
61
- turn.get("id").and_then(serde_json::Value::as_str).map(TurnId::new),
63
+ turn.get("id")
64
+ .and_then(serde_json::Value::as_str)
65
+ .map(TurnId::new),
62
66
  FactKind::Failed,
63
67
  ))
64
68
  }
@@ -126,8 +130,14 @@ fn claude_record_is_assistant_api_error(record: &serde_json::Value) -> bool {
126
130
  .and_then(|message| message.get("role"))
127
131
  .and_then(serde_json::Value::as_str)
128
132
  == Some("assistant")
129
- && record.get("isApiErrorMessage").and_then(serde_json::Value::as_bool) == Some(true)
130
- && (record.get("apiErrorStatus").and_then(serde_json::Value::as_i64).is_some()
133
+ && record
134
+ .get("isApiErrorMessage")
135
+ .and_then(serde_json::Value::as_bool)
136
+ == Some(true)
137
+ && (record
138
+ .get("apiErrorStatus")
139
+ .and_then(serde_json::Value::as_i64)
140
+ .is_some()
131
141
  || non_empty_string_field(record, "error").is_some()
132
142
  || non_empty_string_field(record, "requestId").is_some())
133
143
  }
@@ -156,7 +166,9 @@ fn codex_fault_fact(record: &serde_json::Value) -> Option<FaultFact> {
156
166
  if turn.get("status").and_then(serde_json::Value::as_str) == Some("failed") {
157
167
  return Some(FaultFact::new(
158
168
  Signature::new("turn_failed"),
159
- turn.get("id").and_then(serde_json::Value::as_str).map(TurnId::new),
169
+ turn.get("id")
170
+ .and_then(serde_json::Value::as_str)
171
+ .map(TurnId::new),
160
172
  FactKind::Failed,
161
173
  ));
162
174
  }
@@ -22,10 +22,7 @@ pub(crate) fn find_session_id(record: &serde_json::Value) -> Option<String> {
22
22
  if let Some(s) = record.get("sessionId").and_then(serde_json::Value::as_str) {
23
23
  return Some(s.to_string());
24
24
  }
25
- if let Some(s) = record
26
- .get("session_id")
27
- .and_then(serde_json::Value::as_str)
28
- {
25
+ if let Some(s) = record.get("session_id").and_then(serde_json::Value::as_str) {
29
26
  return Some(s.to_string());
30
27
  }
31
28
  record
@@ -37,7 +34,11 @@ pub(crate) fn find_session_id(record: &serde_json::Value) -> Option<String> {
37
34
  .map(ToString::to_string)
38
35
  }
39
36
 
40
- pub(crate) fn patterns(idle: &str, processing: &str, error: &str) -> Result<StatusPatterns, ProviderError> {
37
+ pub(crate) fn patterns(
38
+ idle: &str,
39
+ processing: &str,
40
+ error: &str,
41
+ ) -> Result<StatusPatterns, ProviderError> {
41
42
  Ok(StatusPatterns {
42
43
  idle: compile_regex(idle)?,
43
44
  processing: compile_regex(processing)?,
@@ -28,10 +28,8 @@ const CLAUDE_TRUST_MARKERS: &[&str] = &[
28
28
  "Enter to confirm",
29
29
  ];
30
30
  const CLAUDE_READY_MARKERS: &[&str] = &["Claude Code"];
31
- pub const COPILOT_TRUST_PROMPT_MARKER: &str =
32
- include_str!("testdata/copilot-trust-prompt.txt");
33
- pub const COPILOT_READY_MARKER: &str =
34
- include_str!("testdata/copilot-ready-marker.txt");
31
+ pub const COPILOT_TRUST_PROMPT_MARKER: &str = include_str!("testdata/copilot-trust-prompt.txt");
32
+ pub const COPILOT_READY_MARKER: &str = include_str!("testdata/copilot-ready-marker.txt");
35
33
  const COPILOT_TRUST_MARKERS: &[&str] = &[COPILOT_TRUST_PROMPT_MARKER];
36
34
  const COPILOT_READY_MARKERS: &[&str] = &[COPILOT_READY_MARKER];
37
35
  const COPILOT_TRUST_TITLE: &str = "Confirm folder trust";
@@ -173,13 +171,9 @@ fn has_active_claude_yes_trust_shape(output: &str) -> bool {
173
171
  {
174
172
  return false;
175
173
  }
176
- output
177
- .lines()
178
- .map(str::trim_start)
179
- .any(|line| {
180
- line == "❯ 1. Yes, I trust this folder"
181
- || line == "> 1. Yes, I trust this folder"
182
- })
174
+ output.lines().map(str::trim_start).any(|line| {
175
+ line == "❯ 1. Yes, I trust this folder" || line == "> 1. Yes, I trust this folder"
176
+ })
183
177
  }
184
178
 
185
179
  fn has_claude_ready_shape(output: &str) -> bool {
@@ -352,7 +346,10 @@ pub fn codex_handle_startup_prompts(
352
346
  StartupScreenDecision::KeepPolling => sleep_between_polls(sleep_s),
353
347
  }
354
348
  }
355
- StartupPromptOutcome { handled, capture_error }
349
+ StartupPromptOutcome {
350
+ handled,
351
+ capture_error,
352
+ }
356
353
  }
357
354
 
358
355
  pub fn claude_handle_startup_prompts(
@@ -386,7 +383,10 @@ pub fn claude_handle_startup_prompts(
386
383
  }
387
384
  }
388
385
  }
389
- StartupPromptOutcome { handled, capture_error }
386
+ StartupPromptOutcome {
387
+ handled,
388
+ capture_error,
389
+ }
390
390
  }
391
391
 
392
392
  pub fn copilot_handle_startup_prompts(
@@ -420,11 +420,17 @@ pub fn copilot_handle_startup_prompts(
420
420
  }
421
421
  }
422
422
  }
423
- StartupPromptOutcome { handled, capture_error }
423
+ StartupPromptOutcome {
424
+ handled,
425
+ capture_error,
426
+ }
424
427
  }
425
428
 
426
429
  fn max_rfind(output: &str, needles: &[&str]) -> Option<usize> {
427
- needles.iter().filter_map(|needle| output.rfind(needle)).max()
430
+ needles
431
+ .iter()
432
+ .filter_map(|needle| output.rfind(needle))
433
+ .max()
428
434
  }
429
435
 
430
436
  fn is_more_recent(prompt_pos: Option<usize>, ready_pos: Option<usize>) -> bool {
@@ -449,8 +455,8 @@ mod tests {
449
455
  use crate::model::enums::PaneLiveness;
450
456
  use crate::transport::{
451
457
  AttachOutcome, BackendKind, CaptureRange, CapturedText, InjectPayload, InjectReport, Key,
452
- PaneField, PaneId, PaneInfo, SessionName, SetEnvOutcome, SpawnResult, Target, TransportError,
453
- WindowName,
458
+ PaneField, PaneId, PaneInfo, SessionName, SetEnvOutcome, SpawnResult, Target,
459
+ TransportError, WindowName,
454
460
  };
455
461
  use std::collections::BTreeMap;
456
462
  use std::path::Path;
@@ -483,7 +489,8 @@ mod tests {
483
489
  fn stale_trust_above_ready_is_not_answered_ready_wins() {
484
490
  // trust prompt FIRST, then a ready marker LATER => trust_pos < ready_pos => do NOT answer.
485
491
  // This is the positional-recency命门 a naive substring port gets wrong (would re-send Enter).
486
- let screen = format!("{TRUST_DIR}\n[trusted earlier]\n{READY_BANNER} ready\n{READY_PROMPT} ");
492
+ let screen =
493
+ format!("{TRUST_DIR}\n[trusted earlier]\n{READY_BANNER} ready\n{READY_PROMPT} ");
487
494
  assert_eq!(
488
495
  classify_codex_startup_screen(&screen),
489
496
  StartupScreenDecision::Ready,
@@ -519,7 +526,10 @@ mod tests {
519
526
  #[test]
520
527
  fn stale_update_above_ready_is_not_skipped_ready_wins() {
521
528
  let screen = format!("{UPDATE_AVAIL}\n{READY_BANNER}\n{READY_PROMPT} ");
522
- assert_eq!(classify_codex_startup_screen(&screen), StartupScreenDecision::Ready);
529
+ assert_eq!(
530
+ classify_codex_startup_screen(&screen),
531
+ StartupScreenDecision::Ready
532
+ );
523
533
  }
524
534
 
525
535
  // ── golden ORDER — update is checked BEFORE trust (both more recent) -> SkipUpdatePrompt wins ─────
@@ -528,7 +538,10 @@ mod tests {
528
538
  // both update + trust appear after the ready marker; golden runs maybe_skip_update_prompt
529
539
  // FIRST each iteration -> the screen resolves to SkipUpdatePrompt, not AnswerWorkspaceTrust.
530
540
  let screen = format!("{READY_BANNER}\n{TRUST_DIR}\n{UPDATE_AVAIL}\n");
531
- assert_eq!(classify_codex_startup_screen(&screen), StartupScreenDecision::SkipUpdatePrompt);
541
+ assert_eq!(
542
+ classify_codex_startup_screen(&screen),
543
+ StartupScreenDecision::SkipUpdatePrompt
544
+ );
532
545
  }
533
546
 
534
547
  // ── ready-only / neither ─────────────────────────────────────────────────────────────────────────
@@ -601,22 +614,50 @@ mod tests {
601
614
  fn kind(&self) -> BackendKind {
602
615
  BackendKind::Tmux
603
616
  }
604
- fn spawn_first(&self, _s: &SessionName, _w: &WindowName, _a: &[String], _c: &Path, _e: &BTreeMap<String, String>) -> Result<SpawnResult, TransportError> {
617
+ fn spawn_first(
618
+ &self,
619
+ _s: &SessionName,
620
+ _w: &WindowName,
621
+ _a: &[String],
622
+ _c: &Path,
623
+ _e: &BTreeMap<String, String>,
624
+ ) -> Result<SpawnResult, TransportError> {
605
625
  unimplemented!("not reached by startup-prompt loop")
606
626
  }
607
- fn spawn_into(&self, _s: &SessionName, _w: &WindowName, _a: &[String], _c: &Path, _e: &BTreeMap<String, String>) -> Result<SpawnResult, TransportError> {
627
+ fn spawn_into(
628
+ &self,
629
+ _s: &SessionName,
630
+ _w: &WindowName,
631
+ _a: &[String],
632
+ _c: &Path,
633
+ _e: &BTreeMap<String, String>,
634
+ ) -> Result<SpawnResult, TransportError> {
608
635
  unimplemented!("not reached by startup-prompt loop")
609
636
  }
610
- fn inject(&self, _t: &Target, _p: &InjectPayload, _submit: Key, _b: bool) -> Result<InjectReport, TransportError> {
637
+ fn inject(
638
+ &self,
639
+ _t: &Target,
640
+ _p: &InjectPayload,
641
+ _submit: Key,
642
+ _b: bool,
643
+ ) -> Result<InjectReport, TransportError> {
611
644
  unimplemented!("not reached")
612
645
  }
613
646
  fn send_keys(&self, _t: &Target, keys: &[Key]) -> Result<(), TransportError> {
614
647
  self.sent.lock().unwrap().push(keys.to_vec());
615
648
  Ok(())
616
649
  }
617
- fn capture(&self, _t: &Target, range: CaptureRange) -> Result<CapturedText, TransportError> {
650
+ fn capture(
651
+ &self,
652
+ _t: &Target,
653
+ range: CaptureRange,
654
+ ) -> Result<CapturedText, TransportError> {
618
655
  let mut q = self.screens.lock().unwrap();
619
- let text = if q.is_empty() { String::new() } else { q.remove(0) };
656
+ let text = if q.is_empty() {
657
+ String::new()
658
+ } else {
659
+ q.remove(0)
660
+ };
620
661
  Ok(CapturedText { text, range })
621
662
  }
622
663
  fn query(&self, _t: &Target, _f: PaneField) -> Result<Option<String>, TransportError> {
@@ -634,7 +675,12 @@ mod tests {
634
675
  fn list_windows(&self, _s: &SessionName) -> Result<Vec<WindowName>, TransportError> {
635
676
  unimplemented!("not reached")
636
677
  }
637
- fn set_session_env(&self, _s: &SessionName, _k: &str, _v: &str) -> Result<SetEnvOutcome, TransportError> {
678
+ fn set_session_env(
679
+ &self,
680
+ _s: &SessionName,
681
+ _k: &str,
682
+ _v: &str,
683
+ ) -> Result<SetEnvOutcome, TransportError> {
638
684
  unimplemented!("not reached")
639
685
  }
640
686
  fn kill_session(&self, _s: &SessionName) -> Result<(), TransportError> {
@@ -700,7 +746,9 @@ mod tests {
700
746
  );
701
747
  let sent = t.sent.lock().unwrap();
702
748
  assert_eq!(
703
- sent.iter().filter(|keys| keys.as_slice() == [Key::Enter]).count(),
749
+ sent.iter()
750
+ .filter(|keys| keys.as_slice() == [Key::Enter])
751
+ .count(),
704
752
  1,
705
753
  "copilot trust prompt must choose option 1 with one Enter; got {sent:?}"
706
754
  );
@@ -1,17 +1,32 @@
1
- //! S1a StateRepository facade.
1
+ //! StateRepository facade.
2
2
  //!
3
- //! Ref: `.team/artifacts/s1a-state-repository-design.md`
3
+ //! Ref:
4
+ //! - `.team/artifacts/s1a-state-repository-design.md` (skeleton)
5
+ //! - `.team/artifacts/s1b-writer-cluster-locate.md` (0.5.42 first
6
+ //! writer-cluster migration: `CoordinatorTick` + `ClaimLeader`)
4
7
  //!
5
- //! S1a is a **skeleton + governance** slice. `StateRepository` is a thin write
6
- //! facade that dispatches every write to the existing helper family without
7
- //! changing helper behavior, merge policy, or on-disk layout. The value it adds
8
- //! is that every write now carries a `StateWriteIntent`, so S1b can migrate
9
- //! writer clusters one semantic at a time.
8
+ //! `StateRepository` is a thin write facade that dispatches every write
9
+ //! to the existing helper family without changing helper behavior,
10
+ //! merge policy, or on-disk layout. The value it adds is that every
11
+ //! write now carries a `StateWriteIntent`, so writer clusters migrate
12
+ //! one semantic at a time.
10
13
  //!
11
- //! Non-goals in S1a (see design section 11): no schema rewrite, no path
12
- //! layout change, no writer migration, no helper deletion. Every existing
13
- //! caller keeps calling the raw helpers behind the S1a allowlist; only new
14
- //! direct callsites are governed.
14
+ //! 0.5.42 status: first real consumers are the daemon `Coordinator::
15
+ //! tick` production save (`CoordinatorTick`) and the lease/claim
16
+ //! writer cluster's two terminal saves (`ClaimLeader`)
17
+ //! `write_lease_dual_state` + `save_claim_team_scoped_state`.
18
+ //! Post-S1b, the direct-save allowlist drops from 73 to 70; the three
19
+ //! migrated sites have no allowlist row and every future direct save
20
+ //! must either enter through `StateRepository` or claim an explicit
21
+ //! new allowlist row (fail-closed).
22
+ //!
23
+ //! Non-goals kept from S1a (design §11) + reasserted by
24
+ //! s1b-writer-cluster-locate.md §7: no schema rewrite, no path layout
25
+ //! change, no helper deletion, no epoch computation in the repository,
26
+ //! no retry / reload / event emission, no reinterpretation of
27
+ //! `owner_epoch` / `topology_convergence` / readback proof — the
28
+ //! caller still owns the whole `Value`, and repository dispatches to
29
+ //! the same existing persist helper the direct edge used to hit.
15
30
 
16
31
  #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
17
32
 
@@ -323,9 +338,7 @@ fn route_direct(
323
338
  // intent lives under `coordinator.abnormal_api_error_recovery`, a
324
339
  // root-scoped bookkeeping namespace that must survive across team
325
340
  // boundaries; use the same helper family as CoordinatorConptyShim.
326
- StateWriteIntent::CoordinatorApiErrorRecovery { .. } => {
327
- helper_write_root(workspace, state)
328
- }
341
+ StateWriteIntent::CoordinatorApiErrorRecovery { .. } => helper_write_root(workspace, state),
329
342
  // McpAssignTask uses the reapply variant today; direct save routes
330
343
  // to the root helper for parity.
331
344
  StateWriteIntent::McpAssignTask { .. } => helper_write_root(workspace, state),