@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
@@ -13,7 +13,11 @@ fn skill_source() -> PathBuf {
13
13
  CTR.fetch_add(1, Ordering::Relaxed)
14
14
  ));
15
15
  std::fs::create_dir_all(dir.join("team-agent")).unwrap();
16
- std::fs::write(dir.join("team-agent").join("SKILL.md"), b"---\nname: team-agent\n---\nbody\n").unwrap();
16
+ std::fs::write(
17
+ dir.join("team-agent").join("SKILL.md"),
18
+ b"---\nname: team-agent\n---\nbody\n",
19
+ )
20
+ .unwrap();
17
21
  dir.join("team-agent")
18
22
  }
19
23
 
@@ -34,7 +38,11 @@ fn dispatch_routes_install_skill_dry_run_all() {
34
38
  ],
35
39
  &ws,
36
40
  );
37
- assert_eq!(code, ExitCode::Ok, "`install-skill --target all --source <dir> --dry-run` must route + exit 0");
41
+ assert_eq!(
42
+ code,
43
+ ExitCode::Ok,
44
+ "`install-skill --target all --source <dir> --dry-run` must route + exit 0"
45
+ );
38
46
  let _ = std::fs::remove_dir_all(&ws);
39
47
  let _ = std::fs::remove_dir_all(source.parent().unwrap());
40
48
  }
@@ -52,7 +60,11 @@ fn install_skill_missing_source_is_usage_error() {
52
60
  ],
53
61
  &ws,
54
62
  );
55
- assert_eq!(code, ExitCode::Error, "install-skill without --source must error (CliError::Usage -> emit_cli_error exit 1)");
63
+ assert_eq!(
64
+ code,
65
+ ExitCode::Error,
66
+ "install-skill without --source must error (CliError::Usage -> emit_cli_error exit 1)"
67
+ );
56
68
  let _ = std::fs::remove_dir_all(&ws);
57
69
  }
58
70
 
@@ -70,7 +82,11 @@ fn install_skill_invalid_target_is_usage_error() {
70
82
  ],
71
83
  &ws,
72
84
  );
73
- assert_eq!(code, ExitCode::Error, "install-skill --target bogus must error (CliError::Usage -> emit_cli_error exit 1)");
85
+ assert_eq!(
86
+ code,
87
+ ExitCode::Error,
88
+ "install-skill --target bogus must error (CliError::Usage -> emit_cli_error exit 1)"
89
+ );
74
90
  let _ = std::fs::remove_dir_all(&ws);
75
91
  let _ = std::fs::remove_dir_all(source.parent().unwrap());
76
92
  }
@@ -11,8 +11,16 @@ fn profiles_dir(ws: &std::path::Path) -> std::path::PathBuf {
11
11
  fn seed_official_api_profile(ws: &std::path::Path) {
12
12
  let dir = profiles_dir(ws);
13
13
  std::fs::create_dir_all(&dir).unwrap();
14
- std::fs::write(dir.join("AGENTS.md"), "# Team Agent Profile Secret Boundary\n").unwrap();
15
- std::fs::write(dir.join("CLAUDE.md"), "# Team Agent Profile Secret Boundary\n").unwrap();
14
+ std::fs::write(
15
+ dir.join("AGENTS.md"),
16
+ "# Team Agent Profile Secret Boundary\n",
17
+ )
18
+ .unwrap();
19
+ std::fs::write(
20
+ dir.join("CLAUDE.md"),
21
+ "# Team Agent Profile Secret Boundary\n",
22
+ )
23
+ .unwrap();
16
24
  std::fs::write(
17
25
  dir.join("api_prof.env"),
18
26
  "AUTH_MODE=official_api\nPROFILE_NAME=api_prof\nAPI_KEY=sk-test-secret\nMODEL=gpt-test\n",
@@ -62,7 +70,11 @@ fn profile_init_routes_and_creates_secret_boundary_files() {
62
70
  ]),
63
71
  &ws,
64
72
  );
65
- assert_eq!(code, ExitCode::Ok, "`profile init ... --json` must route and exit 0");
73
+ assert_eq!(
74
+ code,
75
+ ExitCode::Ok,
76
+ "`profile init ... --json` must route and exit 0"
77
+ );
66
78
 
67
79
  let dir = profiles_dir(&ws);
68
80
  assert!(
@@ -97,7 +109,11 @@ fn profile_init_routes_and_creates_secret_boundary_files() {
97
109
  ]),
98
110
  &ws,
99
111
  );
100
- assert_eq!(second, ExitCode::Ok, "profile init is idempotent and still exits 0");
112
+ assert_eq!(
113
+ second,
114
+ ExitCode::Ok,
115
+ "profile init is idempotent and still exits 0"
116
+ );
101
117
  assert_eq!(
102
118
  std::fs::read_to_string(dir.join("codex_sub.env")).unwrap(),
103
119
  "AUTH_MODE=subscription\nPROFILE_NAME=codex_sub\n",
@@ -131,20 +147,21 @@ fn profile_doctor_routes_existing_ok_and_missing_error() {
131
147
  ]),
132
148
  &ws,
133
149
  );
134
- assert_eq!(existing, ExitCode::Ok, "profile doctor existing profile must exit 0");
150
+ assert_eq!(
151
+ existing,
152
+ ExitCode::Ok,
153
+ "profile doctor existing profile must exit 0"
154
+ );
135
155
 
136
156
  let missing = run(
137
- &profile_argv(&[
138
- "profile",
139
- "doctor",
140
- "missing",
141
- "--workspace",
142
- ".",
143
- "--json",
144
- ]),
157
+ &profile_argv(&["profile", "doctor", "missing", "--workspace", ".", "--json"]),
145
158
  &ws,
146
159
  );
147
- assert_eq!(missing, ExitCode::Error, "profile doctor missing profile must exit 1");
160
+ assert_eq!(
161
+ missing,
162
+ ExitCode::Error,
163
+ "profile doctor missing profile must exit 1"
164
+ );
148
165
  let _ = std::fs::remove_dir_all(&ws);
149
166
  }
150
167
 
@@ -165,18 +182,30 @@ fn profile_show_routes_and_preserves_redacted_secret_contract() {
165
182
  &profile_argv(&["profile", "show", "api_prof", "--workspace", ".", "--json"]),
166
183
  &ws,
167
184
  );
168
- assert_eq!(code, ExitCode::Ok, "profile show existing profile must exit 0");
185
+ assert_eq!(
186
+ code,
187
+ ExitCode::Ok,
188
+ "profile show existing profile must exit 0"
189
+ );
169
190
 
170
191
  let missing = run(
171
192
  &profile_argv(&["profile", "show", "missing", "--workspace", ".", "--json"]),
172
193
  &ws,
173
194
  );
174
- assert_eq!(missing, ExitCode::Error, "profile show missing profile must exit 1");
195
+ assert_eq!(
196
+ missing,
197
+ ExitCode::Error,
198
+ "profile show missing profile must exit 1"
199
+ );
175
200
 
176
201
  let code_human = run(
177
202
  &profile_argv(&["profile", "show", "api_prof", "--workspace", "."]),
178
203
  &ws,
179
204
  );
180
- assert_eq!(code_human, ExitCode::Ok, "profile show human output path must route");
205
+ assert_eq!(
206
+ code_human,
207
+ ExitCode::Ok,
208
+ "profile show human output path must route"
209
+ );
181
210
  let _ = std::fs::remove_dir_all(&ws);
182
211
  }
@@ -92,10 +92,18 @@ tasks:
92
92
  status: "pending"
93
93
  "#;
94
94
 
95
- fn write_validate_spec(ws: &std::path::Path, file_name: &str, provider: &str) -> std::path::PathBuf {
95
+ fn write_validate_spec(
96
+ ws: &std::path::Path,
97
+ file_name: &str,
98
+ provider: &str,
99
+ ) -> std::path::PathBuf {
96
100
  let spec = VALIDATE_SPEC_TEMPLATE
97
101
  .replace("__WS__", &ws.to_string_lossy())
98
- .replacen("provider: \"fake\"", &format!("provider: \"{provider}\""), 1);
102
+ .replacen(
103
+ "provider: \"fake\"",
104
+ &format!("provider: \"{provider}\""),
105
+ 1,
106
+ );
99
107
  let path = ws.join(file_name);
100
108
  std::fs::write(&path, spec).unwrap();
101
109
  path
@@ -179,6 +187,10 @@ fn dispatch_routes_validate_default_spec() {
179
187
  let ws = tmp_workspace();
180
188
  let _spec_path = write_validate_spec(&ws, "team.spec.yaml", "fake");
181
189
  let code = run(&["validate".to_string(), "--json".to_string()], &ws);
182
- assert_eq!(code, ExitCode::Ok, "`validate --json` must route and exit 0 for default team.spec.yaml");
190
+ assert_eq!(
191
+ code,
192
+ ExitCode::Ok,
193
+ "`validate --json` must route and exit 0 for default team.spec.yaml"
194
+ );
183
195
  let _ = std::fs::remove_dir_all(&ws);
184
196
  }
@@ -120,10 +120,7 @@ pub fn attach_probe(endpoint: &str, thread_id: &str) -> Result<AppServerBinding,
120
120
  /// Batch 1 Windows N38 typed-unsupported stub. Callers see the same
121
121
  /// `AppServerError` shape as Unix — no silent success, no panic.
122
122
  #[cfg(not(unix))]
123
- pub fn attach_probe(
124
- _endpoint: &str,
125
- _thread_id: &str,
126
- ) -> Result<AppServerBinding, AppServerError> {
123
+ pub fn attach_probe(_endpoint: &str, _thread_id: &str) -> Result<AppServerBinding, AppServerError> {
127
124
  Err(AppServerError::SocketUnreachable(
128
125
  "codex_app_server unix-socket client not supported on this platform \
129
126
  (Windows); use codex CLI stdio or ConPTY worker delivery instead"
@@ -432,7 +429,7 @@ impl AppServerClient {
432
429
  _ => Err(AppServerError::ProtocolMismatch(format!(
433
430
  "{method} failed: {message}"
434
431
  ))),
435
- }
432
+ };
436
433
  }
437
434
  return value
438
435
  .get("result")
@@ -53,7 +53,13 @@ fn compact_json(v: &Value) -> String {
53
53
  Value::Map(pairs) => {
54
54
  let inner: Vec<String> = pairs
55
55
  .iter()
56
- .map(|(k, val)| format!("{}:{}", serde_json::to_string(k).unwrap(), compact_json(val)))
56
+ .map(|(k, val)| {
57
+ format!(
58
+ "{}:{}",
59
+ serde_json::to_string(k).unwrap(),
60
+ compact_json(val)
61
+ )
62
+ })
57
63
  .collect();
58
64
  format!("{{{}}}", inner.join(","))
59
65
  }
@@ -148,7 +154,10 @@ fn front_matter_body_lstrip_strips_only_newlines() {
148
154
  // body.lstrip("\n") removes leading NEWLINES but keeps the 2-space indent.
149
155
  let p = write_tmp("lstrip.md", "---\nname: x\n---\n\n\n indented body\n");
150
156
  let (meta, body) = read_front_matter(&p).unwrap();
151
- assert_eq!(meta, Value::Map(vec![("name".to_string(), Value::Str("x".to_string()))]));
157
+ assert_eq!(
158
+ meta,
159
+ Value::Map(vec![("name".to_string(), Value::Str("x".to_string()))])
160
+ );
152
161
  assert_eq!(body, " indented body\n");
153
162
  }
154
163
 
@@ -168,7 +177,8 @@ fn front_matter_non_object_errors() {
168
177
  let p = write_tmp("list.md", "---\n- a\n- b\n---\nbody\n");
169
178
  let err = read_front_matter(&p).unwrap_err();
170
179
  assert!(
171
- err.to_string().contains("front matter must be a YAML object"),
180
+ err.to_string()
181
+ .contains("front matter must be a YAML object"),
172
182
  "got: {err}"
173
183
  );
174
184
  }
@@ -203,9 +213,15 @@ fn compile_subscription_without_profile_is_thin_manifest() {
203
213
  let team = build_team(TEAM_BASE, &[("implementer.md", ROLE_NOPROFILE)], &[]);
204
214
  let spec = compile_team(&team).unwrap();
205
215
  let agent = &spec.get("agents").and_then(Value::as_list).unwrap()[0];
206
- assert_eq!(agent.get("auth_mode").and_then(Value::as_str), Some("subscription"));
216
+ assert_eq!(
217
+ agent.get("auth_mode").and_then(Value::as_str),
218
+ Some("subscription")
219
+ );
207
220
  assert!(agent.get("profile").is_none(), "profile key must be absent");
208
- assert!(agent.get("credential_ref").is_none(), "credential_ref key must be absent");
221
+ assert!(
222
+ agent.get("credential_ref").is_none(),
223
+ "credential_ref key must be absent"
224
+ );
209
225
  }
210
226
 
211
227
  // Runtime front-matter defaults: every knob from TEAM.md flows through without
@@ -247,7 +263,11 @@ const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","m
247
263
 
248
264
  #[test]
249
265
  fn compile_runtime_front_matter_defaults_match_python() {
250
- let team = build_team(RUNTIME_DEFAULTS_TEAM, &[("implementer.md", RUNTIME_DEFAULTS_ROLE)], &[]);
266
+ let team = build_team(
267
+ RUNTIME_DEFAULTS_TEAM,
268
+ &[("implementer.md", RUNTIME_DEFAULTS_ROLE)],
269
+ &[],
270
+ );
251
271
  let spec = compile_team(&team).unwrap();
252
272
  assert_eq!(templated_compact_json(&spec), RUNTIME_DEFAULTS_JSON);
253
273
  }
@@ -357,7 +377,11 @@ const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"
357
377
  #[test]
358
378
  fn compile_two_agents_sorted_by_filename_with_routing_and_startup_order() {
359
379
  // filenames intentionally out of name order to prove sorted(glob) is by filename.
360
- let team = build_team(TEAM_BASE, &[("02-bravo.md", TWO_ROLE_B), ("01-alpha.md", TWO_ROLE_A)], &[]);
380
+ let team = build_team(
381
+ TEAM_BASE,
382
+ &[("02-bravo.md", TWO_ROLE_B), ("01-alpha.md", TWO_ROLE_A)],
383
+ &[],
384
+ );
361
385
  let spec = compile_team(&team).unwrap();
362
386
  assert_eq!(templated_compact_json(&spec), TWO_AGENTS_JSON);
363
387
  }
@@ -382,7 +406,8 @@ fn compile_missing_required_provider_field_errors() {
382
406
  let team = build_team(TEAM_BASE, &[("implementer.md", ROLE_MISSING_PROVIDER)], &[]);
383
407
  let err = compile_team(&team).unwrap_err();
384
408
  assert!(
385
- err.to_string().contains("missing front matter field provider"),
409
+ err.to_string()
410
+ .contains("missing front matter field provider"),
386
411
  "got: {err}"
387
412
  );
388
413
  }
@@ -403,9 +428,16 @@ Implement bounded tasks.
403
428
 
404
429
  #[test]
405
430
  fn compile_compatible_api_without_profile_errors() {
406
- let team = build_team(TEAM_BASE, &[("implementer.md", ROLE_COMPATIBLE_NO_PROFILE)], &[]);
431
+ let team = build_team(
432
+ TEAM_BASE,
433
+ &[("implementer.md", ROLE_COMPATIBLE_NO_PROFILE)],
434
+ &[],
435
+ );
407
436
  let err = compile_team(&team).unwrap_err();
408
- assert!(err.to_string().contains("profile is required"), "got: {err}");
437
+ assert!(
438
+ err.to_string().contains("profile is required"),
439
+ "got: {err}"
440
+ );
409
441
  }
410
442
 
411
443
  // ════════════════════════ FIX-LOOP (wave-1) RED tests ════════════════════════
@@ -475,7 +507,10 @@ fn fix_a1_provider_models_precede_default_model() {
475
507
  let tm = "---\nname: T\nprovider: codex\ndefault_model: team-y\nprovider_models:\n codex: pm-z\n---\nx\n";
476
508
  let team = build_team(tm, &[("w.md", &role_nomodel("codex"))], &[]);
477
509
  let spec = compile_team(&team).unwrap();
478
- assert_eq!(agent0(&spec).get("model").and_then(Value::as_str), Some("pm-z"));
510
+ assert_eq!(
511
+ agent0(&spec).get("model").and_then(Value::as_str),
512
+ Some("pm-z")
513
+ );
479
514
  }
480
515
 
481
516
  #[test]
@@ -484,7 +519,10 @@ fn fix_a1_claude_aliases_to_claude_code_provider_models() {
484
519
  let tm = "---\nname: T\nprovider: codex\nprovider_models:\n claude_code: cc-v\n---\nx\n";
485
520
  let team = build_team(tm, &[("w.md", &role_nomodel("claude"))], &[]);
486
521
  let spec = compile_team(&team).unwrap();
487
- assert_eq!(agent0(&spec).get("model").and_then(Value::as_str), Some("cc-v"));
522
+ assert_eq!(
523
+ agent0(&spec).get("model").and_then(Value::as_str),
524
+ Some("cc-v")
525
+ );
488
526
  }
489
527
 
490
528
  #[test]
@@ -507,7 +545,11 @@ fn fix_a1_model_null_when_provider_absent_from_table() {
507
545
  for prov in ["gemini_cli", "fake"] {
508
546
  let team = build_team(TM_CODEX, &[("w.md", &role_nomodel(prov))], &[]);
509
547
  let spec = compile_team(&team).unwrap();
510
- assert_eq!(agent0(&spec).get("model"), Some(&Value::Null), "provider {prov} → null");
548
+ assert_eq!(
549
+ agent0(&spec).get("model"),
550
+ Some(&Value::Null),
551
+ "provider {prov} → null"
552
+ );
511
553
  }
512
554
  }
513
555
 
@@ -526,7 +568,10 @@ fn fix_a2_objective_default_when_no_objective_and_no_body() {
526
568
  let tm = "---\nname: T\nprovider: codex\n---\n";
527
569
  let team = build_team(tm, &[("w.md", &role_nomodel("codex"))], &[]);
528
570
  let spec = compile_team(&team).unwrap();
529
- assert_eq!(str_path(&spec, &["team", "objective"]), "Team Agent document-driven team.");
571
+ assert_eq!(
572
+ str_path(&spec, &["team", "objective"]),
573
+ "Team Agent document-driven team."
574
+ );
530
575
  }
531
576
 
532
577
  // ── A3 name ──
@@ -535,7 +580,12 @@ fn fix_a2_objective_default_when_no_objective_and_no_body() {
535
580
  fn fix_a3_name_falls_back_to_parent_dir_name() {
536
581
  // no `name` → team_dir.parent.name (NOT a hardcoded "team").
537
582
  let tm = "---\nprovider: codex\n---\nx\n";
538
- let team = build_layout("my-parent-dir", "leafteam", Some(tm), AgentsDir::WithRole(&role_nomodel("codex")));
583
+ let team = build_layout(
584
+ "my-parent-dir",
585
+ "leafteam",
586
+ Some(tm),
587
+ AgentsDir::WithRole(&role_nomodel("codex")),
588
+ );
539
589
  let spec = compile_team(&team).unwrap();
540
590
  assert_eq!(str_path(&spec, &["team", "name"]), "my-parent-dir");
541
591
  }
@@ -558,7 +608,10 @@ fn fix_a5_session_name_slugifies_team_name() {
558
608
  let tm = "---\nname: My Team!\nprovider: codex\n---\nx\n";
559
609
  let team = build_team(tm, &[("w.md", &role_nomodel("codex"))], &[]);
560
610
  let spec = compile_team(&team).unwrap();
561
- assert_eq!(str_path(&spec, &["runtime", "session_name"]), "team-My-Team");
611
+ assert_eq!(
612
+ str_path(&spec, &["runtime", "session_name"]),
613
+ "team-My-Team"
614
+ );
562
615
  }
563
616
 
564
617
  #[test]
@@ -576,7 +629,10 @@ fn fix_a6_tools_shell_maps_to_execute_bash() {
576
629
  let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ntools:\n - shell\n - mcp_team\n---\nb\n";
577
630
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
578
631
  let spec = compile_team(&team).expect("shell must normalize to execute_bash and compile");
579
- assert_eq!(agent0(&spec).get("tools"), Some(&list_str(vec!["execute_bash", "mcp_team"])));
632
+ assert_eq!(
633
+ agent0(&spec).get("tools"),
634
+ Some(&list_str(vec!["execute_bash", "mcp_team"]))
635
+ );
580
636
  }
581
637
 
582
638
  #[test]
@@ -584,7 +640,10 @@ fn fix_a6_missing_tools_errors() {
584
640
  let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\n---\nb\n";
585
641
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
586
642
  let err = compile_team(&team).unwrap_err();
587
- assert!(err.to_string().contains("missing front matter field tools"), "got: {err}");
643
+ assert!(
644
+ err.to_string().contains("missing front matter field tools"),
645
+ "got: {err}"
646
+ );
588
647
  }
589
648
 
590
649
  #[test]
@@ -592,7 +651,10 @@ fn fix_a6_tools_not_a_list_errors() {
592
651
  let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ntools: justastring\n---\nb\n";
593
652
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
594
653
  let err = compile_team(&team).unwrap_err();
595
- assert!(err.to_string().contains("tools must be a list"), "got: {err}");
654
+ assert!(
655
+ err.to_string().contains("tools must be a list"),
656
+ "got: {err}"
657
+ );
596
658
  }
597
659
 
598
660
  // ── A7 system_prompt inline ──
@@ -602,7 +664,10 @@ fn fix_a7_empty_body_inline_falls_back_to_role() {
602
664
  let role = "---\nname: w\nrole: Reviewer Role\nprovider: codex\nauth_mode: subscription\ntools:\n - mcp_team\n---\n";
603
665
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
604
666
  let spec = compile_team(&team).unwrap();
605
- assert_eq!(str_path(agent0(&spec), &["system_prompt", "inline"]), "Reviewer Role");
667
+ assert_eq!(
668
+ str_path(agent0(&spec), &["system_prompt", "inline"]),
669
+ "Reviewer Role"
670
+ );
606
671
  }
607
672
 
608
673
  // ── A8 auth_mode ──
@@ -614,7 +679,8 @@ fn fix_a8_official_api_without_profile_errors() {
614
679
  let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
615
680
  let err = compile_team(&team).unwrap_err();
616
681
  assert!(
617
- err.to_string().contains("profile is required when auth_mode is 'official_api'"),
682
+ err.to_string()
683
+ .contains("profile is required when auth_mode is 'official_api'"),
618
684
  "got: {err}"
619
685
  );
620
686
  }
@@ -622,10 +688,15 @@ fn fix_a8_official_api_without_profile_errors() {
622
688
  #[test]
623
689
  fn fix_a8_compatible_api_error_names_the_auth_mode() {
624
690
  // Full message form (the old test only checked the "profile is required" prefix).
625
- let team = build_team(TEAM_BASE, &[("implementer.md", ROLE_COMPATIBLE_NO_PROFILE)], &[]);
691
+ let team = build_team(
692
+ TEAM_BASE,
693
+ &[("implementer.md", ROLE_COMPATIBLE_NO_PROFILE)],
694
+ &[],
695
+ );
626
696
  let err = compile_team(&team).unwrap_err();
627
697
  assert!(
628
- err.to_string().contains("profile is required when auth_mode is 'compatible_api'"),
698
+ err.to_string()
699
+ .contains("profile is required when auth_mode is 'compatible_api'"),
629
700
  "got: {err}"
630
701
  );
631
702
  }
@@ -638,8 +709,16 @@ fn fix_a9_bool_coercion_yes_and_one_are_true() {
638
709
  let tm = format!("---\nname: T\nprovider: codex\ndangerous_auto_approve: {v}\nworker_to_worker: {v}\n---\nx\n");
639
710
  let team = build_team(&tm, &[("w.md", &role_nomodel("codex"))], &[]);
640
711
  let spec = compile_team(&team).unwrap();
641
- assert_eq!(get_path(&spec, &["runtime", "dangerous_auto_approve"]), Some(&Value::Bool(true)), "value {v}");
642
- assert_eq!(get_path(&spec, &["communication", "worker_to_worker"]), Some(&Value::Bool(true)), "value {v}");
712
+ assert_eq!(
713
+ get_path(&spec, &["runtime", "dangerous_auto_approve"]),
714
+ Some(&Value::Bool(true)),
715
+ "value {v}"
716
+ );
717
+ assert_eq!(
718
+ get_path(&spec, &["communication", "worker_to_worker"]),
719
+ Some(&Value::Bool(true)),
720
+ "value {v}"
721
+ );
643
722
  }
644
723
  }
645
724
 
@@ -650,7 +729,10 @@ fn fix_a9_bool_coercion_no_is_python_truthy() {
650
729
  let tm = "---\nname: T\nprovider: codex\ndangerous_auto_approve: no\n---\nx\n";
651
730
  let team = build_team(tm, &[("w.md", &role_nomodel("codex"))], &[]);
652
731
  let spec = compile_team(&team).unwrap();
653
- assert_eq!(get_path(&spec, &["runtime", "dangerous_auto_approve"]), Some(&Value::Bool(true)));
732
+ assert_eq!(
733
+ get_path(&spec, &["runtime", "dangerous_auto_approve"]),
734
+ Some(&Value::Bool(true))
735
+ );
654
736
  }
655
737
 
656
738
  #[test]
@@ -659,7 +741,10 @@ fn fix_a9_int_coercion_of_quoted_string() {
659
741
  let tm = "---\nname: T\nprovider: codex\ntick_interval_sec: \"5\"\n---\nx\n";
660
742
  let team = build_team(tm, &[("w.md", &role_nomodel("codex"))], &[]);
661
743
  let spec = compile_team(&team).unwrap();
662
- assert_eq!(get_path(&spec, &["runtime", "tick_interval_sec"]), Some(&Value::Int(5)));
744
+ assert_eq!(
745
+ get_path(&spec, &["runtime", "tick_interval_sec"]),
746
+ Some(&Value::Int(5))
747
+ );
663
748
  }
664
749
 
665
750
  // ── A10 CRLF normalization ──
@@ -671,24 +756,42 @@ fn fix_a10_crlf_role_doc_front_matter_is_parsed() {
671
756
  let crlf_role = "---\r\nname: crlfworker\r\nrole: R\r\nprovider: codex\r\nauth_mode: subscription\r\ntools:\r\n - mcp_team\r\n---\r\n\r\nbody\r\n";
672
757
  let team = build_team(TM_CODEX, &[("w.md", crlf_role)], &[]);
673
758
  let spec = compile_team(&team).expect("CRLF role doc must parse its front matter");
674
- assert_eq!(agent0(&spec).get("id").and_then(Value::as_str), Some("crlfworker"));
675
- assert_eq!(str_path(agent0(&spec), &["system_prompt", "inline"]), "body");
759
+ assert_eq!(
760
+ agent0(&spec).get("id").and_then(Value::as_str),
761
+ Some("crlfworker")
762
+ );
763
+ assert_eq!(
764
+ str_path(agent0(&spec), &["system_prompt", "inline"]),
765
+ "body"
766
+ );
676
767
  }
677
768
 
678
769
  // ── A11 error-message paths ──
679
770
 
680
771
  #[test]
681
772
  fn fix_a11_missing_team_md_message_includes_team_md_path() {
682
- let team = build_layout("p", "teamdir", None, AgentsDir::WithRole(&role_nomodel("codex")));
773
+ let team = build_layout(
774
+ "p",
775
+ "teamdir",
776
+ None,
777
+ AgentsDir::WithRole(&role_nomodel("codex")),
778
+ );
683
779
  let err = compile_team(&team).unwrap_err();
684
- assert!(err.to_string().contains("/TEAM.md: missing TEAM.md"), "got: {err}");
780
+ assert!(
781
+ err.to_string().contains("/TEAM.md: missing TEAM.md"),
782
+ "got: {err}"
783
+ );
685
784
  }
686
785
 
687
786
  #[test]
688
787
  fn fix_a11_missing_agents_dir_message_includes_agents_path() {
689
788
  let team = build_layout("p", "teamdir", Some(TM_CODEX), AgentsDir::Missing);
690
789
  let err = compile_team(&team).unwrap_err();
691
- assert!(err.to_string().contains("/agents: missing agents directory"), "got: {err}");
790
+ assert!(
791
+ err.to_string()
792
+ .contains("/agents: missing agents directory"),
793
+ "got: {err}"
794
+ );
692
795
  }
693
796
 
694
797
  #[test]
@@ -697,5 +800,8 @@ fn fix_a11_agents_is_a_file_reports_no_role_docs() {
697
800
  // gate, then the empty glob → "no role docs found" (path = agents dir).
698
801
  let team = build_layout("p", "teamdir", Some(TM_CODEX), AgentsDir::File);
699
802
  let err = compile_team(&team).unwrap_err();
700
- assert!(err.to_string().contains("/agents: no role docs found"), "got: {err}");
803
+ assert!(
804
+ err.to_string().contains("/agents: no role docs found"),
805
+ "got: {err}"
806
+ );
701
807
  }