@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
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
|
@@ -108,7 +108,6 @@ pub fn cmd_quick_start(args: &QuickStartArgs) -> Result<CmdResult, CliError> {
|
|
|
108
108
|
args.name.as_deref(),
|
|
109
109
|
args.team_id.as_deref(),
|
|
110
110
|
args.yes,
|
|
111
|
-
!args.no_display,
|
|
112
111
|
args.backend.as_deref(),
|
|
113
112
|
)?;
|
|
114
113
|
append_send_guidance(&mut value, &args.workspace, args.team_id.as_deref());
|
|
@@ -269,50 +268,6 @@ fn append_reminder(text: String, reminder: &str) -> String {
|
|
|
269
268
|
}
|
|
270
269
|
}
|
|
271
270
|
|
|
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
271
|
/// `cmd_status`(`commands.py:90`)。CLI status 统一为只读七字段 brief;
|
|
317
272
|
/// `--json` 与人读路径共享 native tmux/process projection;`--summary`/`--detail` 保留参数兼容性但不暴露诊断。
|
|
318
273
|
#[cfg(test)]
|
|
@@ -915,7 +870,6 @@ communication:
|
|
|
915
870
|
mirror_files: ".team/messages"
|
|
916
871
|
runtime:
|
|
917
872
|
backend: "tmux"
|
|
918
|
-
display_backend: "none"
|
|
919
873
|
session_name: "team-agent-fake-e2e"
|
|
920
874
|
auto_launch: true
|
|
921
875
|
require_user_approval_before_launch: false
|
|
@@ -968,19 +922,6 @@ fn sessions_overview(state: &Value, spec: Option<&crate::model::yaml::Value>) ->
|
|
|
968
922
|
Value::Array(rows)
|
|
969
923
|
}
|
|
970
924
|
|
|
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
925
|
fn session_row(
|
|
985
926
|
state: &Value,
|
|
986
927
|
spec_agent: &crate::model::yaml::Value,
|
|
@@ -1269,7 +1210,6 @@ pub fn cmd_start_agent(args: &StartAgentArgs) -> Result<CmdResult, CliError> {
|
|
|
1269
1210
|
&args.workspace,
|
|
1270
1211
|
&args.agent,
|
|
1271
1212
|
args.force,
|
|
1272
|
-
!args.no_display,
|
|
1273
1213
|
args.allow_fresh,
|
|
1274
1214
|
args.team.as_deref(),
|
|
1275
1215
|
)?;
|
|
@@ -1300,7 +1240,6 @@ pub fn cmd_reset_agent(args: &ResetAgentArgs) -> Result<CmdResult, CliError> {
|
|
|
1300
1240
|
&args.workspace,
|
|
1301
1241
|
&args.agent,
|
|
1302
1242
|
args.discard_session,
|
|
1303
|
-
!args.no_display,
|
|
1304
1243
|
args.team.as_deref(),
|
|
1305
1244
|
)?,
|
|
1306
1245
|
args.json,
|
|
@@ -1313,7 +1252,6 @@ pub fn cmd_add_agent(args: &AddAgentArgs) -> Result<CmdResult, CliError> {
|
|
|
1313
1252
|
&args.workspace,
|
|
1314
1253
|
&args.agent,
|
|
1315
1254
|
&args.role_file,
|
|
1316
|
-
!args.no_display,
|
|
1317
1255
|
args.team.as_deref(),
|
|
1318
1256
|
args.force,
|
|
1319
1257
|
)?;
|
|
@@ -1337,7 +1275,6 @@ pub fn cmd_fork_agent(args: &ForkAgentArgs) -> Result<CmdResult, CliError> {
|
|
|
1337
1275
|
&args.source_agent,
|
|
1338
1276
|
&args.as_agent,
|
|
1339
1277
|
args.label.as_deref(),
|
|
1340
|
-
!args.no_display,
|
|
1341
1278
|
args.team.as_deref(),
|
|
1342
1279
|
)?,
|
|
1343
1280
|
args.json,
|
|
@@ -1351,7 +1288,6 @@ pub fn cmd_clone_agent(args: &CloneAgentArgs) -> Result<CmdResult, CliError> {
|
|
|
1351
1288
|
&args.source_agent,
|
|
1352
1289
|
&args.as_agent,
|
|
1353
1290
|
args.label.as_deref(),
|
|
1354
|
-
!args.no_display,
|
|
1355
1291
|
args.team.as_deref(),
|
|
1356
1292
|
)?,
|
|
1357
1293
|
args.json,
|
|
@@ -1319,22 +1319,6 @@ pub(crate) fn build_preflight_report(team: &std::path::Path) -> Result<Value, Cl
|
|
|
1319
1319
|
next_actions.push(json!("install tmux or add it to PATH"));
|
|
1320
1320
|
}
|
|
1321
1321
|
|
|
1322
|
-
let display_backend = compiled
|
|
1323
|
-
.as_ref()
|
|
1324
|
-
.and_then(|spec| yaml_path_str(spec, &["runtime", "display_backend"]))
|
|
1325
|
-
.unwrap_or("none");
|
|
1326
|
-
let ghostty_required = display_backend == "ghostty_window" || display_backend == "ghostty";
|
|
1327
|
-
let ghostty_path = command_path("ghostty");
|
|
1328
|
-
checks.push(json!({
|
|
1329
|
-
"name": "ghostty",
|
|
1330
|
-
"ok": !ghostty_required || ghostty_path.is_some(),
|
|
1331
|
-
"path": ghostty_path,
|
|
1332
|
-
"required": ghostty_required,
|
|
1333
|
-
}));
|
|
1334
|
-
if ghostty_required && ghostty_path.is_none() {
|
|
1335
|
-
next_actions.push(json!("install Ghostty or choose another display_backend"));
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
1322
|
let workspace = crate::model::paths::team_workspace(team)
|
|
1339
1323
|
.map_err(|error| CliError::Runtime(error.to_string()))?;
|
|
1340
1324
|
let profile_dir_exists = workspace
|
|
@@ -158,6 +158,14 @@ pub(crate) fn __test_dispatch(
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliError> {
|
|
161
|
+
// Keep the removed flag harmless for older scripts and persisted command
|
|
162
|
+
// lines; the default tmux backend is already the only runtime path.
|
|
163
|
+
let filtered_args: Vec<String> = args
|
|
164
|
+
.iter()
|
|
165
|
+
.filter(|arg| arg.as_str() != "--no-display")
|
|
166
|
+
.cloned()
|
|
167
|
+
.collect();
|
|
168
|
+
let args = filtered_args.as_slice();
|
|
161
169
|
let Some(spec) = command_spec(command) else {
|
|
162
170
|
return Ok(emit_unknown_subcommand_usage(command));
|
|
163
171
|
};
|
|
@@ -174,7 +182,6 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
174
182
|
match command {
|
|
175
183
|
"init" => cmd_init(&init_args(args, cwd)).map(emit_result),
|
|
176
184
|
"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
185
|
"send" => cmd_send(&send_args(args, cwd)?).map(emit_result),
|
|
179
186
|
"allow-peer-talk" => {
|
|
180
187
|
cmd_allow_peer_talk(&allow_peer_talk_args(args, cwd)?).map(emit_result)
|
|
@@ -239,7 +246,6 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
239
246
|
const DISPATCH_COMMANDS: &[&str] = &[
|
|
240
247
|
"init",
|
|
241
248
|
"quick-start",
|
|
242
|
-
"compile",
|
|
243
249
|
"send",
|
|
244
250
|
"allow-peer-talk",
|
|
245
251
|
"status",
|
|
@@ -399,9 +405,8 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
399
405
|
match command {
|
|
400
406
|
None => default_help(),
|
|
401
407
|
Some("init") => compat_hidden_help("init", "usage: team-agent init [--workspace WORKSPACE] [--force] [--json]"),
|
|
402
|
-
Some("quick-start") => "usage: team-agent quick-start [TEAMDIR] [--workspace WORKSPACE] [--name NAME] [--team-id TEAM|--team TEAM] [--yes] [--
|
|
408
|
+
Some("quick-start") => "usage: team-agent quick-start [TEAMDIR] [--workspace WORKSPACE] [--name NAME] [--team-id TEAM|--team TEAM] [--yes] [--backend tmux|conpty] [--json] [--detail]\n\n--backend selects the worker transport: tmux (default on POSIX) or 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
409
|
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
410
|
Some("send") => concat!(
|
|
406
411
|
"usage: team-agent send TO MESSAGE... ",
|
|
407
412
|
"[--workspace WORKSPACE] [--team TEAM] ",
|
|
@@ -418,13 +423,13 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
418
423
|
Some("stop") => compat_hidden_help("stop", "usage: team-agent stop [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]"),
|
|
419
424
|
Some("shutdown") => "usage: team-agent shutdown [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]".to_string(),
|
|
420
425
|
Some("restart") => "usage: team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--session-converge-deadline SECONDS] [--json] [--detail]".to_string(),
|
|
421
|
-
Some("restart-agent") => compat_hidden_help("restart-agent", "usage: team-agent restart-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--
|
|
422
|
-
Some("reset-agent") => "usage: team-agent reset-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--
|
|
423
|
-
Some("start-agent") => "usage: team-agent start-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--force] [--allow-fresh] [--
|
|
426
|
+
Some("restart-agent") => compat_hidden_help("restart-agent", "usage: team-agent restart-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--json]"),
|
|
427
|
+
Some("reset-agent") => "usage: team-agent reset-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--json]".to_string(),
|
|
428
|
+
Some("start-agent") => "usage: team-agent start-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--force] [--allow-fresh] [--json]\n\nAfter a successful start, use the returned `send_commands` with `team-agent send AGENT MESSAGE`.".to_string(),
|
|
424
429
|
Some("stop-agent") => "usage: team-agent stop-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
425
|
-
Some("add-agent") => "usage: team-agent add-agent AGENT --role-file FILE [--force] [--workspace WORKSPACE] [--team TEAM] [--
|
|
426
|
-
Some("clone-agent") => "usage: team-agent clone-agent SOURCE_AGENT --as AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--
|
|
427
|
-
Some("fork-agent") => "usage: team-agent fork-agent SOURCE_AGENT --as AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--
|
|
430
|
+
Some("add-agent") => "usage: team-agent add-agent AGENT --role-file FILE [--force] [--workspace WORKSPACE] [--team TEAM] [--json]\n\nAfter a successful add, use the returned `send_commands` with `team-agent send AGENT MESSAGE`.".to_string(),
|
|
431
|
+
Some("clone-agent") => "usage: team-agent clone-agent SOURCE_AGENT --as AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
432
|
+
Some("fork-agent") => "usage: team-agent fork-agent SOURCE_AGENT --as AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
428
433
|
Some("remove-agent") => "usage: team-agent remove-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--from-spec] [--confirm] [--force] [--json]".to_string(),
|
|
429
434
|
// 0.5.26 (§7.6): removed from help; dispatch was never wired.
|
|
430
435
|
Some("stuck-list") => "usage: team-agent stuck-list [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
@@ -827,7 +832,6 @@ struct ParsedArgs {
|
|
|
827
832
|
allow_fresh: bool,
|
|
828
833
|
session_converge_deadline_ms: Option<u64>,
|
|
829
834
|
force: bool,
|
|
830
|
-
no_display: bool,
|
|
831
835
|
discard_session: bool,
|
|
832
836
|
role_file: Option<String>,
|
|
833
837
|
as_agent: Option<String>,
|
|
@@ -853,7 +857,6 @@ struct ParsedArgs {
|
|
|
853
857
|
result: Option<String>,
|
|
854
858
|
real: bool,
|
|
855
859
|
assignee: Option<String>,
|
|
856
|
-
out: Option<PathBuf>,
|
|
857
860
|
auth_mode: Option<String>,
|
|
858
861
|
proxy_mode: Option<String>,
|
|
859
862
|
pane: Option<String>,
|
|
@@ -919,7 +922,6 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
919
922
|
next_arg(args, &mut i).and_then(|v| parse_seconds_ms(&v));
|
|
920
923
|
}
|
|
921
924
|
"--force" => parsed.force = true,
|
|
922
|
-
"--no-display" => parsed.no_display = true,
|
|
923
925
|
"--backend" => parsed.backend = next_arg(args, &mut i),
|
|
924
926
|
"--discard-session" => parsed.discard_session = true,
|
|
925
927
|
"--role-file" => parsed.role_file = next_arg(args, &mut i),
|
|
@@ -950,7 +952,6 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
950
952
|
"--result" => parsed.result = next_arg(args, &mut i),
|
|
951
953
|
"--real" => parsed.real = true,
|
|
952
954
|
"--assignee" => parsed.assignee = next_arg(args, &mut i),
|
|
953
|
-
"--out" => parsed.out = next_arg(args, &mut i).map(PathBuf::from),
|
|
954
955
|
"--auth-mode" => parsed.auth_mode = next_arg(args, &mut i),
|
|
955
956
|
"--proxy-mode" => parsed.proxy_mode = next_arg(args, &mut i),
|
|
956
957
|
"--pane" => parsed.pane = next_arg(args, &mut i),
|
|
@@ -1110,7 +1111,6 @@ fn quick_start_args(args: &[String], cwd: &Path) -> Result<QuickStartArgs, CliEr
|
|
|
1110
1111
|
name: parsed.name,
|
|
1111
1112
|
team_id: parsed.team_id.or(parsed.team),
|
|
1112
1113
|
yes: parsed.yes,
|
|
1113
|
-
no_display: parsed.no_display,
|
|
1114
1114
|
json: parsed.json,
|
|
1115
1115
|
detail: parsed.detail,
|
|
1116
1116
|
backend: parsed.backend,
|
|
@@ -1145,23 +1145,6 @@ fn init_args(args: &[String], cwd: &Path) -> InitArgs {
|
|
|
1145
1145
|
}
|
|
1146
1146
|
}
|
|
1147
1147
|
|
|
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
1148
|
fn resolve_cli_path(cwd: &Path, path: &Path) -> PathBuf {
|
|
1166
1149
|
if path.is_absolute() {
|
|
1167
1150
|
path.to_path_buf()
|
|
@@ -1549,7 +1532,6 @@ fn start_agent_args(args: &[String], cwd: &Path) -> Result<StartAgentArgs, CliEr
|
|
|
1549
1532
|
team: parsed.team,
|
|
1550
1533
|
force: parsed.force,
|
|
1551
1534
|
allow_fresh: parsed.allow_fresh,
|
|
1552
|
-
no_display: parsed.no_display,
|
|
1553
1535
|
json: parsed.json,
|
|
1554
1536
|
})
|
|
1555
1537
|
}
|
|
@@ -1573,7 +1555,6 @@ fn reset_agent_args(args: &[String], cwd: &Path) -> Result<ResetAgentArgs, CliEr
|
|
|
1573
1555
|
workspace,
|
|
1574
1556
|
team: parsed.team,
|
|
1575
1557
|
discard_session: parsed.discard_session,
|
|
1576
|
-
no_display: parsed.no_display,
|
|
1577
1558
|
json: parsed.json,
|
|
1578
1559
|
})
|
|
1579
1560
|
}
|
|
@@ -1588,7 +1569,6 @@ fn add_agent_args(args: &[String], cwd: &Path) -> Result<AddAgentArgs, CliError>
|
|
|
1588
1569
|
.role_file
|
|
1589
1570
|
.ok_or_else(|| CliError::Usage("missing --role-file".to_string()))?,
|
|
1590
1571
|
force: parsed.force,
|
|
1591
|
-
no_display: parsed.no_display,
|
|
1592
1572
|
json: parsed.json,
|
|
1593
1573
|
})
|
|
1594
1574
|
}
|
|
@@ -1603,7 +1583,6 @@ fn fork_agent_args(args: &[String], cwd: &Path) -> Result<ForkAgentArgs, CliErro
|
|
|
1603
1583
|
.as_agent
|
|
1604
1584
|
.ok_or_else(|| CliError::Usage("missing --as".to_string()))?,
|
|
1605
1585
|
label: parsed.label,
|
|
1606
|
-
no_display: parsed.no_display,
|
|
1607
1586
|
json: parsed.json,
|
|
1608
1587
|
})
|
|
1609
1588
|
}
|
|
@@ -1618,7 +1597,6 @@ fn clone_agent_args(args: &[String], cwd: &Path) -> Result<CloneAgentArgs, CliEr
|
|
|
1618
1597
|
.as_agent
|
|
1619
1598
|
.ok_or_else(|| CliError::Usage("missing --as".to_string()))?,
|
|
1620
1599
|
label: parsed.label,
|
|
1621
|
-
no_display: parsed.no_display,
|
|
1622
1600
|
json: parsed.json,
|
|
1623
1601
|
})
|
|
1624
1602
|
}
|
|
@@ -2267,7 +2245,6 @@ mod tests {
|
|
|
2267
2245
|
"--team",
|
|
2268
2246
|
"--force",
|
|
2269
2247
|
"--allow-fresh",
|
|
2270
|
-
"--no-display",
|
|
2271
2248
|
"--json",
|
|
2272
2249
|
][..],
|
|
2273
2250
|
),
|
|
@@ -2277,7 +2254,6 @@ mod tests {
|
|
|
2277
2254
|
"--workspace",
|
|
2278
2255
|
"--team",
|
|
2279
2256
|
"--discard-session",
|
|
2280
|
-
"--no-display",
|
|
2281
2257
|
"--json",
|
|
2282
2258
|
][..],
|
|
2283
2259
|
),
|
|
@@ -2287,7 +2263,6 @@ mod tests {
|
|
|
2287
2263
|
"--role-file",
|
|
2288
2264
|
"--workspace",
|
|
2289
2265
|
"--team",
|
|
2290
|
-
"--no-display",
|
|
2291
2266
|
"--json",
|
|
2292
2267
|
][..],
|
|
2293
2268
|
),
|
|
@@ -2298,7 +2273,6 @@ mod tests {
|
|
|
2298
2273
|
"--label",
|
|
2299
2274
|
"--workspace",
|
|
2300
2275
|
"--team",
|
|
2301
|
-
"--no-display",
|
|
2302
2276
|
"--json",
|
|
2303
2277
|
][..],
|
|
2304
2278
|
),
|
|
@@ -2738,6 +2712,5 @@ mod tests {
|
|
|
2738
2712
|
assert_eq!(args.workspace, ws);
|
|
2739
2713
|
// No `fresh` field anymore — the struct must compile and round-trip
|
|
2740
2714
|
// without it.
|
|
2741
|
-
let _ = args.no_display;
|
|
2742
2715
|
}
|
|
2743
2716
|
}
|
|
@@ -49,7 +49,7 @@ use crate::messaging::{self, AlertType, MessageTarget, SendOptions, TrustedSende
|
|
|
49
49
|
use crate::model::ids::{TaskId, TeamKey};
|
|
50
50
|
|
|
51
51
|
pub(crate) const COMMS_BOUNDARY_TEXT: &str = "validates live pane binding consistency and zero-token comms contracts. Does NOT perform live runtime message round-trip. (zero token, zero pollution)";
|
|
52
|
-
pub(crate) const QUICK_START_REMINDER: &str = "Reminder: Do not inspect raw worker
|
|
52
|
+
pub(crate) const QUICK_START_REMINDER: &str = "Reminder: Do not inspect raw worker pane output during normal operation. Use team-agent status / inbox / collect instead. Wait for report_result.";
|
|
53
53
|
pub(crate) const SEND_REMINDER: &str = "Message delivered. Wait for the worker to report_result. Do not poll the worker terminal with capture-pane.";
|
|
54
54
|
pub(crate) const STATUS_REMINDER: &str = "Results are finalized automatically; use --watch-result or team-agent inbox AGENT -n 3 for transport fallback. Do not capture-pane worker terminals.";
|
|
55
55
|
|
|
@@ -133,16 +133,14 @@ pub mod lifecycle_port {
|
|
|
133
133
|
name: Option<&str>,
|
|
134
134
|
team_id: Option<&str>,
|
|
135
135
|
yes: bool,
|
|
136
|
-
open_display: bool,
|
|
137
136
|
backend: Option<&str>,
|
|
138
137
|
) -> Result<Value, CliError> {
|
|
139
|
-
match crate::lifecycle::
|
|
138
|
+
match crate::lifecycle::quick_start_in_workspace_with_backend(
|
|
140
139
|
workspace,
|
|
141
140
|
agents_dir,
|
|
142
141
|
name,
|
|
143
142
|
yes,
|
|
144
143
|
team_id,
|
|
145
|
-
open_display,
|
|
146
144
|
backend,
|
|
147
145
|
) {
|
|
148
146
|
Ok(report) => Ok(quick_start_value(report)),
|
|
@@ -1155,10 +1153,7 @@ pub mod lifecycle_port {
|
|
|
1155
1153
|
}
|
|
1156
1154
|
}
|
|
1157
1155
|
}
|
|
1158
|
-
|
|
1159
|
-
&run_workspace,
|
|
1160
|
-
session,
|
|
1161
|
-
);
|
|
1156
|
+
cleanup_owned_team_windows(&run_workspace, transport, &state, session);
|
|
1162
1157
|
} else {
|
|
1163
1158
|
let targets = vec![session.as_str().to_string()];
|
|
1164
1159
|
let event_log = crate::event_log::EventLog::new(&run_workspace);
|
|
@@ -1185,10 +1180,7 @@ pub mod lifecycle_port {
|
|
|
1185
1180
|
} else {
|
|
1186
1181
|
push_unique_session(&mut killed_sessions, session.clone());
|
|
1187
1182
|
}
|
|
1188
|
-
|
|
1189
|
-
&run_workspace,
|
|
1190
|
-
session,
|
|
1191
|
-
);
|
|
1183
|
+
cleanup_owned_team_windows(&run_workspace, transport, &state, session);
|
|
1192
1184
|
}
|
|
1193
1185
|
}
|
|
1194
1186
|
}
|
|
@@ -1473,6 +1465,127 @@ pub mod lifecycle_port {
|
|
|
1473
1465
|
Ok(response)
|
|
1474
1466
|
}
|
|
1475
1467
|
|
|
1468
|
+
/// Remove legacy adaptive display windows without reopening a display backend.
|
|
1469
|
+
/// Every target is scoped to the selected transport and passes the same
|
|
1470
|
+
/// ownership/protection audit as the rest of shutdown. Unknown or protected
|
|
1471
|
+
/// targets are intentionally left in place.
|
|
1472
|
+
fn cleanup_owned_team_windows(
|
|
1473
|
+
workspace: &Path,
|
|
1474
|
+
transport: &dyn crate::transport::Transport,
|
|
1475
|
+
state: &Value,
|
|
1476
|
+
session: &crate::transport::SessionName,
|
|
1477
|
+
) {
|
|
1478
|
+
let Some(agents) = state.get("agents").and_then(Value::as_object) else {
|
|
1479
|
+
return;
|
|
1480
|
+
};
|
|
1481
|
+
let leader_session = state
|
|
1482
|
+
.get("leader_receiver")
|
|
1483
|
+
.and_then(|receiver| receiver.get("session_name"))
|
|
1484
|
+
.and_then(Value::as_str)
|
|
1485
|
+
.filter(|value| !value.is_empty())
|
|
1486
|
+
.unwrap_or_else(|| session.as_str());
|
|
1487
|
+
let leader_panes = collect_state_leader_anchor_pane_ids(
|
|
1488
|
+
state,
|
|
1489
|
+
transport.tmux_endpoint().as_deref(),
|
|
1490
|
+
);
|
|
1491
|
+
let event_log = crate::event_log::EventLog::new(workspace);
|
|
1492
|
+
let team_key = state.get("team_key").and_then(Value::as_str);
|
|
1493
|
+
let generation = state_generation(state);
|
|
1494
|
+
let overview_prefix = format!("team-agent:{}:overview", session.as_str());
|
|
1495
|
+
let mut windows = std::collections::BTreeSet::new();
|
|
1496
|
+
let mut panes = std::collections::BTreeSet::new();
|
|
1497
|
+
for (_agent_id, agent) in agents {
|
|
1498
|
+
let Some(display) = agent.get("display").and_then(Value::as_object) else {
|
|
1499
|
+
continue;
|
|
1500
|
+
};
|
|
1501
|
+
if display.get("backend").and_then(Value::as_str) != Some("adaptive") {
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
if display.get("status").and_then(Value::as_str) == Some("stopped") {
|
|
1505
|
+
continue;
|
|
1506
|
+
}
|
|
1507
|
+
if let Some(window) = display
|
|
1508
|
+
.get("workspace_window")
|
|
1509
|
+
.or_else(|| display.get("window"))
|
|
1510
|
+
.or_else(|| agent.get("window"))
|
|
1511
|
+
.and_then(Value::as_str)
|
|
1512
|
+
.filter(|value| !value.is_empty())
|
|
1513
|
+
{
|
|
1514
|
+
if window == overview_prefix || window.starts_with(&format!("{overview_prefix}-")) {
|
|
1515
|
+
windows.insert(format!("{leader_session}:{window}"));
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
if let Some(pane) = display.get("pane_id").and_then(Value::as_str) {
|
|
1519
|
+
if pane.starts_with('%') && !leader_panes.contains(pane) {
|
|
1520
|
+
panes.insert(pane.to_string());
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
if let Ok(live_windows) = transport.list_windows(&crate::transport::SessionName::new(
|
|
1525
|
+
leader_session.to_string(),
|
|
1526
|
+
)) {
|
|
1527
|
+
for window in live_windows {
|
|
1528
|
+
let name = window.as_str();
|
|
1529
|
+
if name == overview_prefix || name.starts_with(&format!("{overview_prefix}-")) {
|
|
1530
|
+
windows.insert(format!("{leader_session}:{name}"));
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
let live_targets = transport.list_targets().unwrap_or_default();
|
|
1535
|
+
for target in &live_targets {
|
|
1536
|
+
if leader_panes.contains(target.pane_id.as_str()) {
|
|
1537
|
+
continue;
|
|
1538
|
+
}
|
|
1539
|
+
if let Some(window) = target.window_name.as_ref() {
|
|
1540
|
+
if windows.contains(&format!("{}:{}", target.session.as_str(), window.as_str())) {
|
|
1541
|
+
panes.remove(target.pane_id.as_str());
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
for target in windows {
|
|
1546
|
+
let Some((target_session, target_window)) = target.split_once(':') else {
|
|
1547
|
+
continue;
|
|
1548
|
+
};
|
|
1549
|
+
let target = crate::transport::Target::SessionWindow {
|
|
1550
|
+
session: crate::transport::SessionName::new(target_session.to_string()),
|
|
1551
|
+
window: crate::transport::WindowName::new(target_window.to_string()),
|
|
1552
|
+
};
|
|
1553
|
+
let target_text = format!("{target_session}:{target_window}");
|
|
1554
|
+
let audit = crate::kill_audit::pre_kill_audit_scoped(
|
|
1555
|
+
&event_log,
|
|
1556
|
+
transport,
|
|
1557
|
+
"shutdown.legacy_display_window",
|
|
1558
|
+
"kill-window",
|
|
1559
|
+
std::slice::from_ref(&target_text),
|
|
1560
|
+
workspace,
|
|
1561
|
+
team_key,
|
|
1562
|
+
generation,
|
|
1563
|
+
"session_marker+state_display_window+team_tag",
|
|
1564
|
+
"positive workspace/team ownership",
|
|
1565
|
+
);
|
|
1566
|
+
if audit.is_ok() {
|
|
1567
|
+
let _ = transport.kill_window(&target);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
for pane in panes {
|
|
1571
|
+
let audit = crate::kill_audit::pre_kill_audit_scoped(
|
|
1572
|
+
&event_log,
|
|
1573
|
+
transport,
|
|
1574
|
+
"shutdown.legacy_display_pane",
|
|
1575
|
+
"kill-pane",
|
|
1576
|
+
std::slice::from_ref(&pane),
|
|
1577
|
+
workspace,
|
|
1578
|
+
team_key,
|
|
1579
|
+
generation,
|
|
1580
|
+
"state_display_pane+team_session",
|
|
1581
|
+
"positive workspace/team ownership",
|
|
1582
|
+
);
|
|
1583
|
+
if audit.is_ok() {
|
|
1584
|
+
let _ = transport.kill_pane(&crate::transport::PaneId::new(pane));
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1476
1589
|
/// 0.5.x Windows portability Batch 6 Option A: locate and
|
|
1477
1590
|
/// terminate the ConPTY shim if `state.transport.shim.pid` is
|
|
1478
1591
|
/// recorded. Returns a JSON blob for the shutdown response so
|
|
@@ -2635,7 +2748,6 @@ pub mod lifecycle_port {
|
|
|
2635
2748
|
workspace: &Path,
|
|
2636
2749
|
agent: &str,
|
|
2637
2750
|
force: bool,
|
|
2638
|
-
open_display: bool,
|
|
2639
2751
|
allow_fresh: bool,
|
|
2640
2752
|
team: Option<&str>,
|
|
2641
2753
|
) -> Result<Value, CliError> {
|
|
@@ -2644,7 +2756,7 @@ pub mod lifecycle_port {
|
|
|
2644
2756
|
workspace,
|
|
2645
2757
|
&agent_id,
|
|
2646
2758
|
force,
|
|
2647
|
-
|
|
2759
|
+
true,
|
|
2648
2760
|
allow_fresh,
|
|
2649
2761
|
team,
|
|
2650
2762
|
) {
|
|
@@ -2712,7 +2824,6 @@ pub mod lifecycle_port {
|
|
|
2712
2824
|
workspace: &Path,
|
|
2713
2825
|
agent: &str,
|
|
2714
2826
|
discard_session: bool,
|
|
2715
|
-
open_display: bool,
|
|
2716
2827
|
team: Option<&str>,
|
|
2717
2828
|
) -> Result<Value, CliError> {
|
|
2718
2829
|
let agent_id = crate::model::ids::AgentId::new(agent);
|
|
@@ -2720,7 +2831,7 @@ pub mod lifecycle_port {
|
|
|
2720
2831
|
workspace,
|
|
2721
2832
|
&agent_id,
|
|
2722
2833
|
discard_session,
|
|
2723
|
-
|
|
2834
|
+
true,
|
|
2724
2835
|
team,
|
|
2725
2836
|
) {
|
|
2726
2837
|
Ok(crate::lifecycle::ResetAgentOutcome::Reset {
|
|
@@ -2763,7 +2874,6 @@ pub mod lifecycle_port {
|
|
|
2763
2874
|
workspace: &Path,
|
|
2764
2875
|
agent: &str,
|
|
2765
2876
|
role_file: &str,
|
|
2766
|
-
open_display: bool,
|
|
2767
2877
|
team: Option<&str>,
|
|
2768
2878
|
force: bool,
|
|
2769
2879
|
) -> Result<Value, CliError> {
|
|
@@ -2772,7 +2882,7 @@ pub mod lifecycle_port {
|
|
|
2772
2882
|
workspace,
|
|
2773
2883
|
&agent_id,
|
|
2774
2884
|
Path::new(role_file),
|
|
2775
|
-
|
|
2885
|
+
true,
|
|
2776
2886
|
team,
|
|
2777
2887
|
force,
|
|
2778
2888
|
) {
|
|
@@ -2811,12 +2921,11 @@ pub mod lifecycle_port {
|
|
|
2811
2921
|
source_agent: &str,
|
|
2812
2922
|
as_agent_id: &str,
|
|
2813
2923
|
label: Option<&str>,
|
|
2814
|
-
open_display: bool,
|
|
2815
2924
|
team: Option<&str>,
|
|
2816
2925
|
) -> Result<Value, CliError> {
|
|
2817
2926
|
let source = crate::model::ids::AgentId::new(source_agent);
|
|
2818
2927
|
let dest = crate::model::ids::AgentId::new(as_agent_id);
|
|
2819
|
-
match crate::lifecycle::fork_agent(workspace, &source, &dest, label,
|
|
2928
|
+
match crate::lifecycle::fork_agent(workspace, &source, &dest, label, true, team) {
|
|
2820
2929
|
Ok(report) => Ok(json!({
|
|
2821
2930
|
"ok": true,
|
|
2822
2931
|
"source_agent_id": report.source_agent_id.as_str(),
|
|
@@ -2833,12 +2942,11 @@ pub mod lifecycle_port {
|
|
|
2833
2942
|
source_agent: &str,
|
|
2834
2943
|
as_agent_id: &str,
|
|
2835
2944
|
label: Option<&str>,
|
|
2836
|
-
open_display: bool,
|
|
2837
2945
|
team: Option<&str>,
|
|
2838
2946
|
) -> Result<Value, CliError> {
|
|
2839
2947
|
let source = crate::model::ids::AgentId::new(source_agent);
|
|
2840
2948
|
let dest = crate::model::ids::AgentId::new(as_agent_id);
|
|
2841
|
-
match crate::lifecycle::clone_agent(workspace, &source, &dest, label,
|
|
2949
|
+
match crate::lifecycle::clone_agent(workspace, &source, &dest, label, true, team) {
|
|
2842
2950
|
Ok(report) => Ok(json!({
|
|
2843
2951
|
"ok": true,
|
|
2844
2952
|
"status": "cloned",
|
|
@@ -3362,7 +3470,6 @@ pub mod lifecycle_port {
|
|
|
3362
3470
|
launch,
|
|
3363
3471
|
next_actions,
|
|
3364
3472
|
attach_commands,
|
|
3365
|
-
display_backend,
|
|
3366
3473
|
worker_readiness,
|
|
3367
3474
|
team,
|
|
3368
3475
|
} => {
|
|
@@ -3502,7 +3609,6 @@ pub mod lifecycle_port {
|
|
|
3502
3609
|
"team": team,
|
|
3503
3610
|
"agent_ids": launch.started.iter().map(|agent| agent.agent_id.as_str()).collect::<Vec<_>>(),
|
|
3504
3611
|
"dry_run": launch.dry_run,
|
|
3505
|
-
"display_backend": display_backend,
|
|
3506
3612
|
"next_actions": next_actions,
|
|
3507
3613
|
"attach_commands": attach_commands,
|
|
3508
3614
|
"reminder": crate::cli::QUICK_START_REMINDER,
|
|
@@ -3638,12 +3744,6 @@ pub mod lifecycle_port {
|
|
|
3638
3744
|
claude_config_dir: None,
|
|
3639
3745
|
provider_projects_root: None,
|
|
3640
3746
|
managed_mcp_config: false,
|
|
3641
|
-
layout_window: None,
|
|
3642
|
-
layout_index: None,
|
|
3643
|
-
pane_index: None,
|
|
3644
|
-
display: crate::lifecycle::WorkerDisplay::Blocked {
|
|
3645
|
-
reason: crate::lifecycle::AdaptiveBlockReason::AggregatorRebuildFailed,
|
|
3646
|
-
},
|
|
3647
3747
|
}],
|
|
3648
3748
|
dry_run: false,
|
|
3649
3749
|
tmux_endpoint: None,
|
|
@@ -3655,7 +3755,6 @@ pub mod lifecycle_port {
|
|
|
3655
3755
|
}),
|
|
3656
3756
|
next_actions: Vec::new(),
|
|
3657
3757
|
attach_commands: Vec::new(),
|
|
3658
|
-
display_backend: "none".to_string(),
|
|
3659
3758
|
worker_readiness: crate::lifecycle::QuickStartReadiness::PendingToolLoad,
|
|
3660
3759
|
team: "team-demo".to_string(),
|
|
3661
3760
|
});
|