@team-agent/installer 0.5.97 → 0.5.99
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 +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +0 -64
- package/crates/team-agent/src/cli/diagnose.rs +0 -16
- package/crates/team-agent/src/cli/emit.rs +15 -42
- package/crates/team-agent/src/cli/mod.rs +130 -31
- package/crates/team-agent/src/cli/spec.rs +7 -10
- package/crates/team-agent/src/cli/tests/main_preserved.rs +0 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +0 -1
- package/crates/team-agent/src/cli/tests/mod.rs +0 -1
- package/crates/team-agent/src/cli/tests/run_delegation.rs +0 -3
- package/crates/team-agent/src/cli/tests/verb_validate.rs +0 -1
- package/crates/team-agent/src/cli/types.rs +0 -14
- package/crates/team-agent/src/compiler/tests.rs +5 -8
- package/crates/team-agent/src/compiler.rs +6 -14
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +5 -25
- package/crates/team-agent/src/lifecycle/launch/identity.rs +2 -18
- package/crates/team-agent/src/lifecycle/launch/layout.rs +7 -29
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +7 -7
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +12 -49
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +3 -9
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -61
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +2 -15
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +3 -7
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch.rs +3 -4
- package/crates/team-agent/src/lifecycle/mod.rs +0 -8
- package/crates/team-agent/src/lifecycle/restart/agent.rs +62 -8
- package/crates/team-agent/src/lifecycle/restart/common.rs +0 -32
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +0 -9
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +1 -2
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +0 -1
- package/crates/team-agent/src/lifecycle/tests/core.rs +0 -213
- package/crates/team-agent/src/lifecycle/tests/issue238_codex_effort_contract.rs +96 -0
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +1 -0
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +31 -77
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +4 -8
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +7 -7
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +3 -4
- package/crates/team-agent/src/lifecycle/tests.rs +1 -2
- package/crates/team-agent/src/lifecycle/types.rs +3 -133
- package/crates/team-agent/src/model/enums.rs +21 -71
- package/crates/team-agent/src/model/spec.rs +5 -20
- package/crates/team-agent/src/provider/adapters/codex.rs +2 -2
- package/crates/team-agent/src/provider/types.rs +6 -5
- package/examples/team.spec.yaml +0 -1
- package/package.json +4 -4
- package/schemas/team.schema.json +2 -2
- package/skills/team-agent/SKILL.md +1 -1
- package/skills/team-agent/references/team-agent-operator.md +23 -38
- package/crates/team-agent/src/cli/tests/compile.rs +0 -192
- package/crates/team-agent/src/lifecycle/display.rs +0 -550
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +0 -884
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +0 -481
|
@@ -43,7 +43,7 @@ team-agent codex
|
|
|
43
43
|
team-agent claude
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
Pass provider flags after the provider name, for example `team-agent codex --dangerously-bypass-approvals-and-sandbox`.
|
|
46
|
+
Pass provider flags after the provider name, for example `team-agent codex --dangerously-bypass-approvals-and-sandbox`. Run `team-agent quick-start` from the leader's current tmux pane. Do not start a real team from a naked terminal that Team Agent cannot address through tmux.
|
|
47
47
|
|
|
48
48
|
**0.5.66:** leader `--dangerously-*` flags no longer inherit bypass to workers. Per-worker bypass is the role field `dangerously_skip_permissions` (see Permissions).
|
|
49
49
|
|
|
@@ -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
|
|
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
|
|
@@ -98,14 +98,7 @@ team-agent quick-start .team/current
|
|
|
98
98
|
|
|
99
99
|
YAML lists must be block style. Use `tools:\n - fs_read`; do not use `tools: [fs_read, mcp_team]`.
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
- `none` (default): headless / no GUI window manager. The team runs entirely in the per-workspace tmux server; this is what the demo above uses.
|
|
104
|
-
- `adaptive`: framework picks an available GUI layout for the local platform.
|
|
105
|
-
- `ghostty_workspace`: one Ghostty window. Workers are shown in tmux tabs/windows, up to 3 side-by-side panes per tab. Four workers become `3 + 1`; eight become `3 + 3 + 2`.
|
|
106
|
-
- `ghostty_window`: one Ghostty window per worker.
|
|
107
|
-
|
|
108
|
-
**Omitting `display_backend` defaults to `none`** (changed in 0.3.4). Set `display_backend: adaptive` (or one of the explicit ghostty variants) in `TEAM.md` only when the user wants GUI windows.
|
|
101
|
+
Workers always run headlessly in independent windows on the per-workspace tmux server. No GUI display backend is configured in `TEAM.md`.
|
|
109
102
|
|
|
110
103
|
## Private Tmux Socket
|
|
111
104
|
|
|
@@ -179,7 +172,7 @@ codex debug models
|
|
|
179
172
|
|
|
180
173
|
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
174
|
|
|
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`** —
|
|
175
|
+
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
176
|
|
|
184
177
|
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
178
|
Use `provider: claude` or `provider: claude_code` for Claude workers.
|
|
@@ -233,15 +226,17 @@ POST {BASE_URL}/v1/chat/completions
|
|
|
233
226
|
|
|
234
227
|
Fail = report the HTTP/body. Success = leave the id alone. **Do not substitute a different id.**
|
|
235
228
|
|
|
236
|
-
How
|
|
229
|
+
How role `model` and profile `MODEL` are resolved (not a validity list):
|
|
230
|
+
|
|
231
|
+
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.
|
|
232
|
+
|
|
233
|
+
For an existing spec file or team directory at `$d`, run the retained validation:
|
|
237
234
|
|
|
238
235
|
```bash
|
|
239
|
-
team-agent
|
|
236
|
+
team-agent validate "$d" --json
|
|
240
237
|
```
|
|
241
238
|
|
|
242
|
-
|
|
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.
|
|
239
|
+
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
240
|
|
|
246
241
|
How to check `--auth-mode` literals (the CLI does not print an allow-list on this gauge):
|
|
247
242
|
|
|
@@ -265,7 +260,7 @@ Observed (all exit 0):
|
|
|
265
260
|
|
|
266
261
|
```text
|
|
267
262
|
usage: team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--session-converge-deadline SECONDS] [--json]
|
|
268
|
-
usage: team-agent add-agent AGENT --role-file FILE [--force] [--workspace WORKSPACE] [--team TEAM] [--
|
|
263
|
+
usage: team-agent add-agent AGENT --role-file FILE [--force] [--workspace WORKSPACE] [--team TEAM] [--json]
|
|
269
264
|
usage: team-agent shutdown [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]
|
|
270
265
|
```
|
|
271
266
|
|
|
@@ -289,26 +284,19 @@ team-agent permission-modes
|
|
|
289
284
|
|
|
290
285
|
Observed (exit 1): `invalid choice: 'permission-modes'`.
|
|
291
286
|
|
|
292
|
-
`team-agent --help` does **not** list `permission_mode`, `TEAM_AGENT_LEADER_BYPASS`, or `dangerous_auto_approve`.
|
|
287
|
+
`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
288
|
|
|
294
289
|
### Live control: role `dangerously_skip_permissions`
|
|
295
290
|
|
|
296
|
-
Required boolean on every role doc. Missing or non-bool fails
|
|
291
|
+
Required boolean on every role doc. Missing or non-bool fails the internal compiler; this is checked again before lifecycle launch.
|
|
297
292
|
|
|
298
|
-
|
|
293
|
+
For an existing spec file, the retained schema check is:
|
|
299
294
|
|
|
300
295
|
```bash
|
|
301
|
-
|
|
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
|
|
296
|
+
team-agent validate "$d" --json
|
|
305
297
|
```
|
|
306
298
|
|
|
307
|
-
|
|
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.
|
|
299
|
+
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
300
|
|
|
313
301
|
`true` is the per-worker bypass opt-in. `false` is the default you should copy unless the user explicitly wants prompts skipped.
|
|
314
302
|
|
|
@@ -345,7 +333,7 @@ What the sources actually do (reader can re-open these files):
|
|
|
345
333
|
| `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
334
|
| `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
335
|
| `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 消费)
|
|
336
|
+
| 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
337
|
| `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
338
|
| `worker_spawn_env` test | `crates/team-agent/src/layout/worker_env.rs` | **Strips** inherited `TEAM_AGENT_LEADER_BYPASS` from parent env. |
|
|
351
339
|
| `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 +450,7 @@ On success, `send --json` includes `message_id`. The deprecation warning itself
|
|
|
462
450
|
- `team-agent start-agent coder --workspace .` repairs one missing worker window without interrupting other workers.
|
|
463
451
|
- `team-agent doctor` checks local dependencies and provider auth hints.
|
|
464
452
|
- `team-agent results --case CASE_ID` reads reported results for a case.
|
|
465
|
-
- `team-agent
|
|
453
|
+
- `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
454
|
|
|
467
455
|
<!-- command-coverage:normative-start -->
|
|
468
456
|
### Normative command inventory
|
|
@@ -620,16 +608,13 @@ For any non-zero `team-agent` exit, report the command, exit code, last about 20
|
|
|
620
608
|
|
|
621
609
|
**If the error JSON/text includes a structured `action` field, run that `action` first.** This rule does not expire with skill versions.
|
|
622
610
|
|
|
623
|
-
|
|
611
|
+
For an existing spec file or team directory, use the retained validation:
|
|
624
612
|
|
|
625
613
|
```bash
|
|
626
|
-
|
|
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
|
|
614
|
+
team-agent validate "$d" --json
|
|
630
615
|
```
|
|
631
616
|
|
|
632
|
-
|
|
617
|
+
A validation failure may include a structured `action`; prefer that action over guessing flags.
|
|
633
618
|
|
|
634
619
|
`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
620
|
|
|
@@ -637,7 +622,7 @@ Observed (exit 1): JSON includes `"ok": false` and `"action": "run \`team-agent
|
|
|
637
622
|
|
|
638
623
|
Examples of `action` observed on this gauge:
|
|
639
624
|
|
|
640
|
-
-
|
|
625
|
+
- add-agent usage failure: `"action": "run \`team-agent doctor\` or inspect the log path shown here"`
|
|
641
626
|
- 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
627
|
- `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
628
|
|
|
@@ -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
|
-
}
|