@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 +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +0 -57
- package/crates/team-agent/src/cli/emit.rs +0 -22
- package/crates/team-agent/src/cli/spec.rs +0 -3
- package/crates/team-agent/src/cli/tests/mod.rs +0 -1
- package/crates/team-agent/src/cli/types.rs +0 -8
- package/package.json +4 -4
- package/skills/team-agent/references/team-agent-operator.md +20 -28
- package/crates/team-agent/src/cli/tests/compile.rs +0 -192
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
|
@@ -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 },
|
|
@@ -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.
|
|
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.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.5.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.5.
|
|
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
|
|
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`** —
|
|
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
|
|
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
|
|
243
|
+
team-agent validate "$d" --json
|
|
240
244
|
```
|
|
241
245
|
|
|
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.
|
|
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`.
|
|
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
|
|
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
|
-
|
|
300
|
+
For an existing spec file, the retained schema check is:
|
|
299
301
|
|
|
300
302
|
```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
|
|
303
|
+
team-agent validate "$d" --json
|
|
305
304
|
```
|
|
306
305
|
|
|
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.
|
|
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 消费)
|
|
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
|
|
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
|
-
|
|
618
|
+
For an existing spec file or team directory, use the retained validation:
|
|
624
619
|
|
|
625
620
|
```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
|
|
621
|
+
team-agent validate "$d" --json
|
|
630
622
|
```
|
|
631
623
|
|
|
632
|
-
|
|
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
|
-
-
|
|
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
|
-
}
|