@team-agent/installer 0.5.97 → 0.5.98

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.
package/Cargo.lock CHANGED
@@ -581,7 +581,7 @@ dependencies = [
581
581
 
582
582
  [[package]]
583
583
  name = "team-agent"
584
- version = "0.5.97"
584
+ version = "0.5.98"
585
585
  dependencies = [
586
586
  "anyhow",
587
587
  "chrono",
package/Cargo.toml CHANGED
@@ -9,7 +9,7 @@ members = ["crates/team-agent", "crates/win-conpty-phase0", "crates/conpty-trans
9
9
 
10
10
  [workspace.package]
11
11
  edition = "2021"
12
- version = "0.5.97"
12
+ version = "0.5.98"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -269,50 +269,6 @@ fn append_reminder(text: String, reminder: &str) -> String {
269
269
  }
270
270
  }
271
271
 
272
- /// `cmd_compile`(`commands.py:42`)。
273
- pub fn cmd_compile(args: &CompileArgs) -> Result<CmdResult, CliError> {
274
- let spec =
275
- crate::compiler::compile_team(&args.team).map_err(|e| CliError::Runtime(e.to_string()))?;
276
- warn_ignored_owner_team_id(&args.team);
277
- std::fs::write(&args.out, crate::model::yaml::dumps(&spec))?;
278
- Ok(CmdResult::from_json(
279
- json!({
280
- "ok": true,
281
- "team_dir": args.team.to_string_lossy().to_string(),
282
- "out": args.out.to_string_lossy().to_string(),
283
- "agents": compiled_agent_ids_for_cli(&spec),
284
- }),
285
- args.json,
286
- ))
287
- }
288
-
289
- fn warn_ignored_owner_team_id(team_dir: &std::path::Path) {
290
- let Ok(Some(ignored)) = crate::compiler::ignored_owner_team_id_from_team_md(team_dir) else {
291
- return;
292
- };
293
- let workspace = crate::model::paths::team_workspace(team_dir)
294
- .unwrap_or_else(|_| team_dir.parent().unwrap_or(team_dir).to_path_buf());
295
- eprintln!(
296
- "Warning: ignored TEAM.md {}={}",
297
- ignored.field, ignored.value
298
- );
299
- eprintln!("Reason: owner identity is the canonical runtime team key, not TEAM.md front matter");
300
- eprintln!("Action: remove {} from TEAM.md", ignored.field);
301
- let fields = json!({
302
- "field": ignored.field,
303
- "source": team_dir.join("TEAM.md").to_string_lossy().to_string(),
304
- "value": ignored.value,
305
- "warning": "ignored user-set owner_team_id",
306
- "reason": "owner identity is derived from the canonical runtime team key",
307
- "action": "remove owner_team_id from TEAM.md",
308
- });
309
- if let Err(err) =
310
- crate::event_log::EventLog::new(&workspace).write("spec.field_ignored", fields)
311
- {
312
- eprintln!("Warning: spec.field_ignored event write failed: {err}");
313
- }
314
- }
315
-
316
272
  /// `cmd_status`(`commands.py:90`)。CLI status 统一为只读七字段 brief;
317
273
  /// `--json` 与人读路径共享 native tmux/process projection;`--summary`/`--detail` 保留参数兼容性但不暴露诊断。
318
274
  #[cfg(test)]
@@ -968,19 +924,6 @@ fn sessions_overview(state: &Value, spec: Option<&crate::model::yaml::Value>) ->
968
924
  Value::Array(rows)
969
925
  }
970
926
 
971
- fn compiled_agent_ids_for_cli(spec: &crate::model::yaml::Value) -> Vec<String> {
972
- spec.get("agents")
973
- .and_then(crate::model::yaml::Value::as_list)
974
- .map(|agents| {
975
- agents
976
- .iter()
977
- .filter_map(|agent| agent.get("id").and_then(crate::model::yaml::Value::as_str))
978
- .map(str::to_string)
979
- .collect()
980
- })
981
- .unwrap_or_default()
982
- }
983
-
984
927
  fn session_row(
985
928
  state: &Value,
986
929
  spec_agent: &crate::model::yaml::Value,
@@ -174,7 +174,6 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
174
174
  match command {
175
175
  "init" => cmd_init(&init_args(args, cwd)).map(emit_result),
176
176
  "quick-start" => cmd_quick_start(&quick_start_args(args, cwd)?).map(emit_result),
177
- "compile" => cmd_compile(&compile_args(args, cwd)?).map(emit_result),
178
177
  "send" => cmd_send(&send_args(args, cwd)?).map(emit_result),
179
178
  "allow-peer-talk" => {
180
179
  cmd_allow_peer_talk(&allow_peer_talk_args(args, cwd)?).map(emit_result)
@@ -239,7 +238,6 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
239
238
  const DISPATCH_COMMANDS: &[&str] = &[
240
239
  "init",
241
240
  "quick-start",
242
- "compile",
243
241
  "send",
244
242
  "allow-peer-talk",
245
243
  "status",
@@ -401,7 +399,6 @@ fn command_help(command: Option<&str>) -> String {
401
399
  Some("init") => compat_hidden_help("init", "usage: team-agent init [--workspace WORKSPACE] [--force] [--json]"),
402
400
  Some("quick-start") => "usage: team-agent quick-start [TEAMDIR] [--workspace WORKSPACE] [--name NAME] [--team-id TEAM|--team TEAM] [--yes] [--no-display] [--backend tmux|conpty] [--json] [--detail]\n\ndefaults: display_backend=adaptive; set display_backend: none in TEAM.md or pass --no-display to use one worker window per agent.\n\n--backend selects the worker transport (Phase 1d Batch 2): tmux (default on POSIX; unchanged behavior), conpty (Windows-native ConPTY worker transport; requires the shim binary and Windows host).\n\n--detail includes internal receiver/topology diagnostics in JSON output.\n\nAfter a successful start, use the returned `send_commands` (or choose an agent explicitly) with `team-agent send AGENT MESSAGE`.".to_string(),
403
401
  Some("start") => compat_hidden_help("start", "usage: team-agent start [TEAMDIR] [--yes] [--fresh] [--json]"),
404
- Some("compile") => "usage: team-agent compile --team TEAM [--out FILE] [--json]".to_string(),
405
402
  Some("send") => concat!(
406
403
  "usage: team-agent send TO MESSAGE... ",
407
404
  "[--workspace WORKSPACE] [--team TEAM] ",
@@ -853,7 +850,6 @@ struct ParsedArgs {
853
850
  result: Option<String>,
854
851
  real: bool,
855
852
  assignee: Option<String>,
856
- out: Option<PathBuf>,
857
853
  auth_mode: Option<String>,
858
854
  proxy_mode: Option<String>,
859
855
  pane: Option<String>,
@@ -950,7 +946,6 @@ fn parse_args(args: &[String]) -> ParsedArgs {
950
946
  "--result" => parsed.result = next_arg(args, &mut i),
951
947
  "--real" => parsed.real = true,
952
948
  "--assignee" => parsed.assignee = next_arg(args, &mut i),
953
- "--out" => parsed.out = next_arg(args, &mut i).map(PathBuf::from),
954
949
  "--auth-mode" => parsed.auth_mode = next_arg(args, &mut i),
955
950
  "--proxy-mode" => parsed.proxy_mode = next_arg(args, &mut i),
956
951
  "--pane" => parsed.pane = next_arg(args, &mut i),
@@ -1145,23 +1140,6 @@ fn init_args(args: &[String], cwd: &Path) -> InitArgs {
1145
1140
  }
1146
1141
  }
1147
1142
 
1148
- fn compile_args(args: &[String], cwd: &Path) -> Result<CompileArgs, CliError> {
1149
- let parsed = parse_args(args);
1150
- let team = parsed
1151
- .team
1152
- .as_deref()
1153
- .map(PathBuf::from)
1154
- .ok_or_else(|| CliError::Usage("missing --team".to_string()))?;
1155
- let out = parsed
1156
- .out
1157
- .unwrap_or_else(|| PathBuf::from("team.spec.yaml"));
1158
- Ok(CompileArgs {
1159
- team: resolve_cli_path(cwd, &team),
1160
- out: resolve_cli_path(cwd, &out),
1161
- json: parsed.json,
1162
- })
1163
- }
1164
-
1165
1143
  fn resolve_cli_path(cwd: &Path, path: &Path) -> PathBuf {
1166
1144
  if path.is_absolute() {
1167
1145
  path.to_path_buf()
@@ -44,7 +44,6 @@ pub(crate) enum TokenUsage {
44
44
  pub(crate) enum DispatchKind {
45
45
  Init,
46
46
  QuickStart,
47
- Compile,
48
47
  Send,
49
48
  AllowPeerTalk,
50
49
  Status,
@@ -90,7 +89,6 @@ pub(crate) enum DispatchKind {
90
89
  pub(crate) const ALL_DISPATCH_KINDS: &[DispatchKind] = &[
91
90
  DispatchKind::Init,
92
91
  DispatchKind::QuickStart,
93
- DispatchKind::Compile,
94
92
  DispatchKind::Send,
95
93
  DispatchKind::AllowPeerTalk,
96
94
  DispatchKind::Status,
@@ -210,7 +208,6 @@ pub(crate) const COMMAND_SPECS: &[CommandSpec] = &[
210
208
  CommandSpec { name: "identity", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Identity), summary: "inspect identity metadata", usage: "usage: team-agent identity [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
211
209
  CommandSpec { name: "watch", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Watch), summary: "watch event logs", usage: "usage: team-agent watch [--workspace WORKSPACE] [--team TEAM]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
212
210
  CommandSpec { name: "sessions", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Sessions), summary: "inspect session inventory", usage: "usage: team-agent sessions [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
213
- CommandSpec { name: "compile", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Compile), summary: "compile a team spec", usage: "usage: team-agent compile --team TEAM [--out FILE] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
214
211
  CommandSpec { name: "validate", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Validate), summary: "validate a team spec", usage: "usage: team-agent validate [SPEC] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
215
212
  CommandSpec { name: "preflight", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Preflight), summary: "run preflight checks", usage: "usage: team-agent preflight [TEAMDIR] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
216
213
  CommandSpec { name: "wait-ready", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::WaitReady), summary: "wait for runtime readiness", usage: "usage: team-agent wait-ready [--workspace WORKSPACE] [--team TEAM] [--timeout SECONDS] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, alias_of: None, sunset: None, action: None, governance: None },
@@ -123,7 +123,6 @@ fn outcome_text(r: Result<CmdResult, CliError>) -> String {
123
123
  }
124
124
 
125
125
  mod base;
126
- mod compile;
127
126
  mod divergence;
128
127
  mod lane_c;
129
128
  mod leader_watch;
@@ -321,14 +321,6 @@ pub struct InitArgs {
321
321
  pub json: bool,
322
322
  }
323
323
 
324
- /// `compile`(`parser.py:125`)。
325
- #[derive(Debug, Clone, PartialEq, Eq)]
326
- pub struct CompileArgs {
327
- pub team: PathBuf,
328
- pub out: PathBuf,
329
- pub json: bool,
330
- }
331
-
332
324
  /// `send`(`parser.py:262`)。`target` xor `--to`(fanout);`message` 多 token join 空格。
333
325
  #[derive(Debug, Clone, PartialEq)]
334
326
  pub struct SendArgs {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.97",
3
+ "version": "0.5.98",
4
4
  "description": "npx installer for Team Agent",
5
5
  "keywords": [
6
6
  "codex",
@@ -20,9 +20,9 @@
20
20
  "team-agent-installer": "npm/install.mjs"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@team-agent/cli-darwin-arm64": "0.5.97",
24
- "@team-agent/cli-darwin-x64": "0.5.97",
25
- "@team-agent/cli-linux-x64": "0.5.97"
23
+ "@team-agent/cli-darwin-arm64": "0.5.98",
24
+ "@team-agent/cli-darwin-x64": "0.5.98",
25
+ "@team-agent/cli-linux-x64": "0.5.98"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",
@@ -55,7 +55,7 @@ When the user has been communicating in Chinese throughout the conversation, all
55
55
 
56
56
  ## Minimal Copy-Paste Team
57
57
 
58
- `dangerously_skip_permissions` is **required** on every role doc (boolean). `TEAM.md` `dangerous_auto_approve` is **not** the 0.5.66 bypass switch (see Permissions). Values under `provider_models:` below are **fill-ins for omitted role `model`**, not a validity catalog (lookup: `team-agent compile --team <dir> --out /tmp/spec.yaml --json` and read the compiled agent `model`).
58
+ `dangerously_skip_permissions` is **required** on every role doc (boolean). `TEAM.md` `dangerous_auto_approve` is **not** the 0.5.66 bypass switch (see Permissions). Values under `provider_models:` below are **fill-ins for omitted role `model`**, not a validity catalog; the values are configuration fallbacks.
59
59
 
60
60
  ```bash
61
61
  mkdir -p .team/current/agents
@@ -179,7 +179,7 @@ codex debug models
179
179
 
180
180
  That command is the Codex catalog. This skill does **not** keep a model id list. If `codex` is not on PATH, the lookup is unavailable; do not invent slugs.
181
181
 
182
- Role docs may omit `model` for non-grok subscription workers; compile then fills from `TEAM.md` `provider_models` or leaves `null` when a profile is present (see compatible_api). **Do not treat those fill-ins as a validity catalog.** **Grok roles cannot omit `model`** — compile fails closed (same `compile --team` command as below).
182
+ Role docs may omit `model` for non-grok subscription workers; compile then fills from `TEAM.md` `provider_models` or leaves `null` when a profile is present (see compatible_api). **Do not treat those fill-ins as a validity catalog.** **Grok roles cannot omit `model`** — the internal compiler fails closed.
183
183
 
184
184
  Claude: run `claude auth status`; if missing, run `claude auth login`. Team Agent stores Claude worker sessions by passing `--session-id` and resumes with `--resume`.
185
185
  Use `provider: claude` or `provider: claude_code` for Claude workers.
@@ -233,15 +233,17 @@ POST {BASE_URL}/v1/chat/completions
233
233
 
234
234
  Fail = report the HTTP/body. Success = leave the id alone. **Do not substitute a different id.**
235
235
 
236
- How compile currently wires role `model` vs profile `MODEL` (not a validity list):
236
+ How role `model` and profile `MODEL` are resolved (not a validity list):
237
+
238
+ The internal compiler preserves a role `model:` when present. If it is omitted, provider/team defaults may fill it; a profile-deferred role may remain `null`. A profile's `MODEL` does not override an explicit role model, and the compiler does not compare the two. Actual profile/provider readiness is checked during launch and preflight, not by a public export command.
239
+
240
+ For an existing spec file or team directory at `$d`, run the retained validation:
237
241
 
238
242
  ```bash
239
- team-agent compile --help
243
+ team-agent validate "$d" --json
240
244
  ```
241
245
 
242
- Observed (exit 0): `usage: team-agent compile --team TEAM [--out FILE] [--json]`.
243
-
244
- Recreate: `auth_mode: compatible_api` without `profile` → compile exit 1 `profile is required when auth_mode is 'compatible_api'`. Role `model:` set + `profile:` set → compiled agent `model` is the role string; profile `MODEL` is not read at compile. Role omits `model` + `profile:` → compiled `model: null`. Compile does **not** compare the two. Whether launch refuses a mismatch was **not** spawned-verified.
246
+ A file input runs schema structural validation. A team-directory input internally compiles `TEAM.md` and `agents/*.md` and validates role-document completeness. Neither input writes or exports a spec file.
245
247
 
246
248
  How to check `--auth-mode` literals (the CLI does not print an allow-list on this gauge):
247
249
 
@@ -289,26 +291,19 @@ team-agent permission-modes
289
291
 
290
292
  Observed (exit 1): `invalid choice: 'permission-modes'`.
291
293
 
292
- `team-agent --help` does **not** list `permission_mode`, `TEAM_AGENT_LEADER_BYPASS`, or `dangerous_auto_approve`. Lookup is `team-agent compile` / `team-agent validate` on a throwaway team dir, not a flag enum.
294
+ `team-agent --help` does **not** list `permission_mode`, `TEAM_AGENT_LEADER_BYPASS`, or `dangerous_auto_approve`. Use `team-agent validate "$d" --json` with an existing spec file or team directory; it does not enumerate permission modes.
293
295
 
294
296
  ### Live control: role `dangerously_skip_permissions`
295
297
 
296
- Required boolean on every role doc. Missing or non-bool fails compile.
298
+ Required boolean on every role doc. Missing or non-bool fails the internal compiler; this is checked again before lifecycle launch.
297
299
 
298
- Recreate:
300
+ For an existing spec file, the retained schema check is:
299
301
 
300
302
  ```bash
301
- d=$(mktemp -d) && mkdir -p "$d/agents"
302
- printf '%s\n' '---' 'name: t' 'objective: t' 'provider: fake' '---' 'x' > "$d/TEAM.md"
303
- printf '%s\n' '---' 'name: coder' 'role: Worker' 'provider: fake' 'model: fake' 'auth_mode: subscription' 'tools:' ' - mcp_team' '---' 'b' > "$d/agents/coder.md"
304
- team-agent compile --team "$d" --out /tmp/ta-compile-out.yaml --json
303
+ team-agent validate "$d" --json
305
304
  ```
306
305
 
307
- Observed (exit 1): `missing front matter field dangerously_skip_permissions. This field must be declared explicitly; it controls whether the agent launches with permission prompts bypassed.` JSON also includes `"action": "run \`team-agent doctor\` or inspect the log path shown here"`.
308
-
309
- Non-bool (`dangerously_skip_permissions: bypass`) observed (exit 1): `front matter field dangerously_skip_permissions must be a boolean.`
310
-
311
- Legal values reachable from that error: **boolean `true` or `false`**. No other literals are accepted.
306
+ With a team-directory input, `validate` internally compiles `TEAM.md` and `agents/*.md` and validates role-document completeness; with a file input, it runs schema structural validation. Neither input writes or exports a spec file. The internal compiler rejects non-bool (`dangerously_skip_permissions: bypass`) and accepts only boolean **`true`** or **`false`**.
312
307
 
313
308
  `true` is the per-worker bypass opt-in. `false` is the default you should copy unless the user explicitly wants prompts skipped.
314
309
 
@@ -345,7 +340,7 @@ What the sources actually do (reader can re-open these files):
345
340
  | `required_dangerously_skip_permissions` | `crates/team-agent/src/compiler.rs` | Compile **requires** role `dangerously_skip_permissions` bool. This is the 0.5.66 worker bypass source. |
346
341
  | `resolved_tool_strings_for_command` | `crates/team-agent/src/lifecycle/worker_command_context.rs` | `true` appends tool sentinel `dangerous_auto_approve`; comment: no longer consumes team/runtime/leader `DangerousApproval`. |
347
342
  | `provider_bypass_flag` | `crates/team-agent/src/provider/bypass_flags.rs` | **唯一权威**: role `dangerously_skip_permissions: true` decides whether to add a provider bypass argv flag. Maps provider → flag string only. |
348
- | spec allowed key `permission_mode` | `crates/team-agent/src/model/spec.rs` | Historical; **not consumed** by compiler (comment: 0.5.66 起不再被 compiler 消费). CLI compile of `permission_mode: bypass` and `permission_mode: not-a-mode` both `ok: true` with the key absent from spec. |
343
+ | spec allowed key `permission_mode` | `crates/team-agent/src/model/spec.rs` | Historical; **not consumed** by compiler (comment: 0.5.66 起不再被 compiler 消费); the key is absent from the compiled agent spec. |
349
344
  | `apply_mcp_auto_approval_env` | `crates/team-agent/src/lifecycle/launch/worker_env.rs` | Writes `TEAM_AGENT_LEADER_BYPASS` `1`/`0` from `DangerousApproval` when source is `LeaderProcess`. Separate from compile. |
350
345
  | `worker_spawn_env` test | `crates/team-agent/src/layout/worker_env.rs` | **Strips** inherited `TEAM_AGENT_LEADER_BYPASS` from parent env. |
351
346
  | `claude_dangerous_auto_approve` (and siblings) | `crates/team-agent/src/provider/adapters/*.rs` | Adapters look for tool name `dangerous_auto_approve`, not `TEAM.md`. |
@@ -462,7 +457,7 @@ On success, `send --json` includes `message_id`. The deprecation warning itself
462
457
  - `team-agent start-agent coder --workspace .` repairs one missing worker window without interrupting other workers.
463
458
  - `team-agent doctor` checks local dependencies and provider auth hints.
464
459
  - `team-agent results --case CASE_ID` reads reported results for a case.
465
- - `team-agent compile` / `team-agent validate` are hidden from top-level `--help` but `--help` on those verbs works; use them to check role docs without launching.
460
+ - `team-agent validate` is hidden from top-level `--help` but `--help` on the verb works; use it to check an existing spec without launching.
466
461
 
467
462
  <!-- command-coverage:normative-start -->
468
463
  ### Normative command inventory
@@ -620,16 +615,13 @@ For any non-zero `team-agent` exit, report the command, exit code, last about 20
620
615
 
621
616
  **If the error JSON/text includes a structured `action` field, run that `action` first.** This rule does not expire with skill versions.
622
617
 
623
- Reproduce a structured `action` (missing `dangerously_skip_permissions` → compile JSON):
618
+ For an existing spec file or team directory, use the retained validation:
624
619
 
625
620
  ```bash
626
- d=$(mktemp -d) && mkdir -p "$d/agents"
627
- printf '%s\n' '---' 'name: t' 'objective: t' 'provider: fake' '---' 'x' > "$d/TEAM.md"
628
- printf '%s\n' '---' 'name: coder' 'role: Worker' 'provider: fake' 'model: fake' 'auth_mode: subscription' 'tools:' ' - mcp_team' '---' 'b' > "$d/agents/coder.md"
629
- team-agent compile --team "$d" --out /tmp/ta-failure-rules-compile.yaml --json
621
+ team-agent validate "$d" --json
630
622
  ```
631
623
 
632
- Observed (exit 1): JSON includes `"ok": false` and `"action": "run \`team-agent doctor\` or inspect the log path shown here"`, plus `missing front matter field dangerously_skip_permissions`. Prefer the `action` over guessing flags.
624
+ A validation failure may include a structured `action`; prefer that action over guessing flags.
633
625
 
634
626
  `coordinator.session_missing` is a self-healing transient: run `team-agent status --json`, if `ready` is true (or workers show `running`) continue; do not shutdown and wait.
635
627
 
@@ -637,7 +629,7 @@ Observed (exit 1): JSON includes `"ok": false` and `"action": "run \`team-agent
637
629
 
638
630
  Examples of `action` observed on this gauge:
639
631
 
640
- - compile/add-agent usage failure: `"action": "run \`team-agent doctor\` or inspect the log path shown here"`
632
+ - add-agent usage failure: `"action": "run \`team-agent doctor\` or inspect the log path shown here"`
641
633
  - send with no runtime: `"action": "Run team-agent quick-start/restart in the target workspace, or choose a workspace that has .team/runtime/state.json"`
642
634
  - `claim-leader` from a worker pane: `"action": "pane %21 is registered as worker developer-d108; run claim-leader from the leader's own pane, not a worker pane"` (exit 1, `ok: false`, `reason: caller_not_leader_shaped`)
643
635
 
@@ -1,192 +0,0 @@
1
- use super::*;
2
-
3
- fn compile_team_dir(tag: &str) -> std::path::PathBuf {
4
- let team = tmp_workspace().join(tag);
5
- std::fs::create_dir_all(team.join("agents")).unwrap();
6
- std::fs::write(
7
- team.join("TEAM.md"),
8
- "---\nname: compileteam\nobjective: Compile probe.\nprovider: fake\n---\n\nCompile team.\n",
9
- )
10
- .unwrap();
11
- std::fs::write(
12
- team.join("agents").join("worker.md"),
13
- "---\nname: worker\nrole: Worker\nprovider: fake\nmodel: fake\ntools:\n - mcp_team\ndangerously_skip_permissions: false\n---\n\nWorker role.\n",
14
- )
15
- .unwrap();
16
- team
17
- }
18
-
19
- fn compile_team_dir_with_owner_team_id(tag: &str) -> std::path::PathBuf {
20
- let team = compile_team_dir(tag);
21
- std::fs::write(
22
- team.join("TEAM.md"),
23
- "---\nname: compileteam\nobjective: Compile probe.\nprovider: fake\nowner_team_id: user-set-owner\n---\n\nCompile team.\n",
24
- )
25
- .unwrap();
26
- team
27
- }
28
-
29
- #[test]
30
- fn cmd_compile_json_and_human_match_golden_shape_and_writes_out() {
31
- let team = compile_team_dir("compile-ok");
32
- let out = team.parent().unwrap().join("out.yaml");
33
- let args = CompileArgs {
34
- team: team.clone(),
35
- out: out.clone(),
36
- json: true,
37
- };
38
-
39
- let result = cmd_compile(&args).expect("compile");
40
- assert_eq!(result.exit, ExitCode::Ok);
41
- assert!(
42
- out.exists(),
43
- "compile must write the compiled spec to --out"
44
- );
45
- assert!(
46
- std::fs::read_to_string(&out)
47
- .unwrap()
48
- .contains("version: 1"),
49
- "compiled out file must contain the spec YAML"
50
- );
51
-
52
- let json_text = emit(&result.output, true).unwrap();
53
- let expected_json = format!(
54
- "{{\n \"agents\": [\n \"worker\"\n ],\n \"ok\": true,\n \"out\": \"{}\",\n \"team_dir\": \"{}\"\n}}",
55
- out.to_string_lossy(),
56
- team.to_string_lossy()
57
- );
58
- assert_eq!(
59
- json_text, expected_json,
60
- "golden --json is sorted pretty JSON"
61
- );
62
-
63
- let human_text = emit(&result.output, false).unwrap();
64
- let expected_human = format!(
65
- "ok: True\nteam_dir: {}\nout: {}\nagents: [\"worker\"]",
66
- team.to_string_lossy(),
67
- out.to_string_lossy()
68
- );
69
- assert_eq!(
70
- human_text, expected_human,
71
- "golden human output preserves cmd_compile insertion order"
72
- );
73
- }
74
-
75
- #[test]
76
- fn cmd_compile_ignores_user_owner_team_id_and_emits_warning_event() {
77
- let team = compile_team_dir_with_owner_team_id("compile-ignored-owner");
78
- let workspace = team.parent().unwrap().to_path_buf();
79
- let out = workspace.join("ignored-owner-out.yaml");
80
- let args = CompileArgs {
81
- team: team.clone(),
82
- out: out.clone(),
83
- json: true,
84
- };
85
-
86
- let result = cmd_compile(&args).expect("compile");
87
- assert_eq!(result.exit, ExitCode::Ok);
88
- let compiled = std::fs::read_to_string(&out).unwrap();
89
- assert!(
90
- !compiled.contains("owner_team_id"),
91
- "user-set owner_team_id must not be compiled into team.spec.yaml"
92
- );
93
- let events = crate::event_log::EventLog::new(&workspace).tail(0).unwrap();
94
- let event = events
95
- .iter()
96
- .find(|event| {
97
- event.get("event").and_then(serde_json::Value::as_str) == Some("spec.field_ignored")
98
- })
99
- .expect("owner_team_id warning event");
100
- assert_eq!(
101
- event.get("field").and_then(serde_json::Value::as_str),
102
- Some("owner_team_id")
103
- );
104
- assert_eq!(
105
- event.get("value").and_then(serde_json::Value::as_str),
106
- Some("user-set-owner")
107
- );
108
- assert_eq!(
109
- event.get("action").and_then(serde_json::Value::as_str),
110
- Some("remove owner_team_id from TEAM.md")
111
- );
112
- }
113
-
114
- #[test]
115
- fn cmd_compile_without_owner_team_id_emits_no_ignored_field_event() {
116
- let team = compile_team_dir("compile-no-ignored-owner");
117
- let workspace = team.parent().unwrap().to_path_buf();
118
- let out = workspace.join("no-ignored-owner-out.yaml");
119
- let args = CompileArgs {
120
- team: team.clone(),
121
- out,
122
- json: true,
123
- };
124
-
125
- let result = cmd_compile(&args).expect("compile");
126
- assert_eq!(result.exit, ExitCode::Ok);
127
- let events = crate::event_log::EventLog::new(&workspace).tail(0).unwrap();
128
- assert!(
129
- events.iter().all(|event| {
130
- event.get("event").and_then(serde_json::Value::as_str) != Some("spec.field_ignored")
131
- }),
132
- "TEAM.md without owner_team_id must not emit ignored-field warning"
133
- );
134
- }
135
-
136
- #[test]
137
- fn run_dispatches_compile_and_error_path_exits_error() {
138
- let team = compile_team_dir("compile-dispatch");
139
- let out = team.parent().unwrap().join("dispatch.yaml");
140
- let argv = vec![
141
- "compile".to_string(),
142
- "--team".to_string(),
143
- team.to_string_lossy().to_string(),
144
- "--out".to_string(),
145
- out.to_string_lossy().to_string(),
146
- "--json".to_string(),
147
- ];
148
- assert_eq!(run(&argv, team.parent().unwrap()), ExitCode::Ok);
149
- assert!(
150
- out.exists(),
151
- "dispatch compile must route to cmd_compile and write --out"
152
- );
153
-
154
- let bad = tmp_workspace().join("compile-bad");
155
- std::fs::create_dir_all(bad.join("agents")).unwrap();
156
- std::fs::write(
157
- bad.join("TEAM.md"),
158
- "---\nname: badteam\nobjective: Bad.\nprovider: fake\n---\n",
159
- )
160
- .unwrap();
161
- std::fs::write(
162
- bad.join("agents").join("broken.md"),
163
- "---\nname: broken\nrole: Broken\nmodel: fake\n---\n",
164
- )
165
- .unwrap();
166
- let bad_out = bad.parent().unwrap().join("bad.yaml");
167
- let bad_args = CompileArgs {
168
- team: bad.clone(),
169
- out: bad_out.clone(),
170
- json: true,
171
- };
172
- let err = cmd_compile(&bad_args).unwrap_err().to_string();
173
- assert!(
174
- err.contains("missing front matter field provider"),
175
- "got {err}"
176
- );
177
- assert_eq!(
178
- run(
179
- &[
180
- "compile".to_string(),
181
- "--team".to_string(),
182
- bad.to_string_lossy().to_string(),
183
- "--out".to_string(),
184
- bad_out.to_string_lossy().to_string(),
185
- "--json".to_string(),
186
- ],
187
- bad.parent().unwrap(),
188
- ),
189
- ExitCode::Error,
190
- "invalid compile input must exit 1, not fall through as an unknown subcommand"
191
- );
192
- }