@team-agent/installer 0.3.1 → 0.3.3
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 +34 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +234 -26
- package/crates/team-agent/src/cli/diagnose.rs +144 -10
- package/crates/team-agent/src/cli/emit.rs +289 -54
- package/crates/team-agent/src/cli/leader.rs +37 -8
- package/crates/team-agent/src/cli/mod.rs +1281 -196
- package/crates/team-agent/src/cli/status_port.rs +195 -46
- package/crates/team-agent/src/cli/tests/divergence.rs +1 -2
- package/crates/team-agent/src/cli/tests/lane_c.rs +23 -13
- package/crates/team-agent/src/cli/tests/main_preserved.rs +2 -0
- package/crates/team-agent/src/cli/tests/run_delegation.rs +59 -3
- package/crates/team-agent/src/cli/types.rs +18 -0
- package/crates/team-agent/src/compiler.rs +15 -5
- package/crates/team-agent/src/coordinator/health.rs +95 -17
- package/crates/team-agent/src/coordinator/mod.rs +4 -0
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +500 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +58 -0
- package/crates/team-agent/src/coordinator/tick.rs +222 -69
- package/crates/team-agent/src/coordinator/types.rs +15 -3
- package/crates/team-agent/src/db/schema.rs +37 -2
- package/crates/team-agent/src/diagnose/comms.rs +226 -0
- package/crates/team-agent/src/diagnose/mod.rs +45 -0
- package/crates/team-agent/src/diagnose/orphans.rs +658 -0
- package/crates/team-agent/src/fake_worker.rs +146 -3
- package/crates/team-agent/src/leader/start.rs +121 -23
- package/crates/team-agent/src/leader/types.rs +44 -1
- package/crates/team-agent/src/lib.rs +3 -0
- package/crates/team-agent/src/lifecycle/display.rs +645 -47
- package/crates/team-agent/src/lifecycle/launch.rs +1061 -146
- package/crates/team-agent/src/lifecycle/mod.rs +2 -0
- package/crates/team-agent/src/lifecycle/profile_launch.rs +810 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +522 -0
- package/crates/team-agent/src/lifecycle/restart/agent.rs +99 -23
- package/crates/team-agent/src/lifecycle/restart/common.rs +183 -24
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +498 -22
- package/crates/team-agent/src/lifecycle/restart/remove.rs +27 -7
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +19 -0
- package/crates/team-agent/src/lifecycle/restart.rs +24 -1
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +5 -5
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +37 -7
- package/crates/team-agent/src/lifecycle/types.rs +19 -0
- package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +341 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +10 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +158 -0
- package/crates/team-agent/src/mcp_server/mod.rs +3 -74
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +1 -1
- package/crates/team-agent/src/mcp_server/tests/send.rs +6 -5
- package/crates/team-agent/src/mcp_server/tools.rs +312 -111
- package/crates/team-agent/src/mcp_server/types.rs +6 -4
- package/crates/team-agent/src/mcp_server/wire.rs +19 -7
- package/crates/team-agent/src/message_store.rs +21 -4
- package/crates/team-agent/src/messaging/delivery.rs +470 -59
- package/crates/team-agent/src/messaging/mod.rs +9 -6
- package/crates/team-agent/src/messaging/results.rs +353 -63
- package/crates/team-agent/src/messaging/selftest.rs +199 -12
- package/crates/team-agent/src/messaging/send.rs +35 -3
- package/crates/team-agent/src/messaging/tests/runtime.rs +19 -4
- package/crates/team-agent/src/messaging/types.rs +11 -3
- package/crates/team-agent/src/os_probe.rs +119 -0
- package/crates/team-agent/src/packaging/migrate.rs +10 -2
- package/crates/team-agent/src/packaging/tests.rs +23 -0
- package/crates/team-agent/src/provider/adapter.rs +564 -63
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +1 -7
- package/crates/team-agent/src/provider/classify.rs +51 -4
- package/crates/team-agent/src/provider/helpers.rs +10 -1
- package/crates/team-agent/src/provider/startup_prompt.rs +94 -0
- package/crates/team-agent/src/provider/types.rs +47 -0
- package/crates/team-agent/src/session_capture.rs +616 -0
- package/crates/team-agent/src/state/persist.rs +170 -1
- package/crates/team-agent/src/state/projection.rs +141 -8
- package/crates/team-agent/src/state/selector.rs +5 -2
- package/crates/team-agent/src/tmux_backend.rs +161 -64
- package/crates/team-agent/src/transport/test_support.rs +9 -0
- package/crates/team-agent/src/transport/tests/wire.rs +4 -0
- package/crates/team-agent/src/transport.rs +13 -2
- package/package.json +4 -4
|
@@ -40,19 +40,18 @@ pub fn run(argv: &[String], cwd: &Path) -> ExitCode {
|
|
|
40
40
|
println!("{}", command_help(None));
|
|
41
41
|
return ExitCode::Ok;
|
|
42
42
|
}
|
|
43
|
-
// CR-063/G4: every
|
|
44
|
-
// before argument validation, leader-pane checks, or runtime-state writes.
|
|
45
|
-
// `command_has_help` whitelist (quick-start/start/stop/...) silently dropped `--help`
|
|
46
|
-
// for add-agent / stop-agent / reset-agent / claim-leader / attach-leader, so those
|
|
47
|
-
// fell into handlers that emitted "missing agent" or "caller_not_leader_shaped" and
|
|
48
|
-
// created `.team/logs/cli-error-*.log` under cwd.
|
|
43
|
+
// CR-063/G4: every registered subcommand's `--help` must short-circuit before dispatch,
|
|
44
|
+
// before argument validation, leader-pane checks, or runtime-state writes.
|
|
49
45
|
//
|
|
50
46
|
// The gate stays on KNOWN subcommands so an unknown command still falls through to
|
|
51
47
|
// the argparse-style invalid-choice path (golden parser.py:84; covered by
|
|
52
48
|
// `cli_unknown_command_red` and the `claude_code` divergence guard which would
|
|
53
49
|
// otherwise be silently passthrough-shaped).
|
|
54
50
|
if is_known_subcommand(command)
|
|
55
|
-
&& argv
|
|
51
|
+
&& argv
|
|
52
|
+
.iter()
|
|
53
|
+
.skip(1)
|
|
54
|
+
.any(|arg| matches!(arg.as_str(), "-h" | "--help"))
|
|
56
55
|
{
|
|
57
56
|
println!("{}", command_help(Some(command)));
|
|
58
57
|
return ExitCode::Ok;
|
|
@@ -78,8 +77,11 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
78
77
|
"quick-start" => cmd_quick_start(&quick_start_args(args, cwd)?).map(emit_result),
|
|
79
78
|
"compile" => cmd_compile(&compile_args(args, cwd)?).map(emit_result),
|
|
80
79
|
"send" => cmd_send(&send_args(args, cwd)?).map(emit_result),
|
|
81
|
-
"allow-peer-talk" =>
|
|
82
|
-
|
|
80
|
+
"allow-peer-talk" => {
|
|
81
|
+
cmd_allow_peer_talk(&allow_peer_talk_args(args, cwd)?).map(emit_result)
|
|
82
|
+
}
|
|
83
|
+
"status" => cmd_status_for_team(&status_args(args, cwd), parse_args(args).team.as_deref())
|
|
84
|
+
.map(emit_result),
|
|
83
85
|
"stop" => cmd_shutdown(&shutdown_args(args, cwd)).map(emit_result),
|
|
84
86
|
"shutdown" => cmd_shutdown(&shutdown_args(args, cwd)).map(emit_result),
|
|
85
87
|
"restart" => cmd_restart(&restart_args(args, cwd)).map(emit_result),
|
|
@@ -92,9 +94,13 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
92
94
|
"remove-agent" => cmd_remove_agent(&remove_agent_args(args, cwd)?).map(emit_result),
|
|
93
95
|
"stuck-list" => cmd_stuck_list(&stuck_list_args(args, cwd)).map(emit_result),
|
|
94
96
|
"stuck-cancel" => cmd_stuck_cancel(&stuck_cancel_args(args, cwd)?).map(emit_result),
|
|
95
|
-
"acknowledge-idle" =>
|
|
97
|
+
"acknowledge-idle" => {
|
|
98
|
+
cmd_acknowledge_idle(&acknowledge_idle_args(args, cwd)).map(emit_result)
|
|
99
|
+
}
|
|
96
100
|
"takeover" => cmd_takeover(&takeover_args(args, cwd)).map(emit_result),
|
|
97
101
|
"claim-leader" => cmd_claim_leader(&claim_leader_args(args, cwd)).map(emit_result),
|
|
102
|
+
// Real dispatch: `cmd_attach_leader` writes the `leader_receiver` binding.
|
|
103
|
+
"attach-leader" => cmd_attach_leader(&attach_leader_args(args, cwd)?).map(emit_result),
|
|
98
104
|
"identity" => cmd_identity(&identity_args(args, cwd)).map(emit_result),
|
|
99
105
|
"approvals" => cmd_approvals(&approvals_args(args, cwd)).map(emit_result),
|
|
100
106
|
"inbox" => cmd_inbox(&inbox_args(args, cwd)?).map(emit_result),
|
|
@@ -108,7 +114,10 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
108
114
|
Ok(ExitCode::Usage)
|
|
109
115
|
}
|
|
110
116
|
"validate-result" => cmd_validate_result(&validate_result_args(args)?).map(emit_result),
|
|
111
|
-
"collect" =>
|
|
117
|
+
"collect" => {
|
|
118
|
+
cmd_collect_for_team(&collect_args(args, cwd), parse_args(args).team.as_deref())
|
|
119
|
+
.map(emit_result)
|
|
120
|
+
}
|
|
112
121
|
"settle" => cmd_settle(&settle_args(args, cwd)).map(emit_result),
|
|
113
122
|
"repair-state" => cmd_repair_state(&repair_state_args(args, cwd)?).map(emit_result),
|
|
114
123
|
"diagnose" => cmd_diagnose(&diagnose_args(args, cwd)).map(emit_result),
|
|
@@ -143,6 +152,7 @@ const DISPATCH_COMMANDS: &[&str] = &[
|
|
|
143
152
|
"acknowledge-idle",
|
|
144
153
|
"takeover",
|
|
145
154
|
"claim-leader",
|
|
155
|
+
"attach-leader",
|
|
146
156
|
"identity",
|
|
147
157
|
"approvals",
|
|
148
158
|
"inbox",
|
|
@@ -163,15 +173,15 @@ const DISPATCH_COMMANDS: &[&str] = &[
|
|
|
163
173
|
"coordinator",
|
|
164
174
|
];
|
|
165
175
|
|
|
166
|
-
const SPEC_ONLY_HELP_COMMANDS: &[&str] = &["start", "purge-agent"
|
|
176
|
+
const SPEC_ONLY_HELP_COMMANDS: &[&str] = &["start", "purge-agent"];
|
|
167
177
|
|
|
168
178
|
fn emit_missing_subcommand_usage() -> ExitCode {
|
|
169
179
|
emit_usage_error("the following arguments are required: {codex,claude,...,doctor}");
|
|
170
180
|
ExitCode::Usage
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
/// Registered subcommands (the dispatch table)
|
|
174
|
-
/// dispatch arm yet but must still respond to `--help` per CR-063/G4
|
|
183
|
+
/// Registered subcommands (the dispatch table) plus spec-only verbs that have no
|
|
184
|
+
/// dispatch arm yet but must still respond to `--help` per CR-063/G4.
|
|
175
185
|
/// Used by the `--help` short-circuit gate so unknown commands keep falling through
|
|
176
186
|
/// to the argparse invalid-choice path.
|
|
177
187
|
fn is_known_subcommand(command: &str) -> bool {
|
|
@@ -195,10 +205,10 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
195
205
|
Some("compile") => "usage: team-agent compile --team TEAM [--out FILE] [--json]".to_string(),
|
|
196
206
|
Some("send") => "usage: team-agent send TARGET MESSAGE... [--workspace WORKSPACE] [--team TEAM] [--targets AGENTS] [--task TASK] [--sender SENDER] [--watch-result] [--requires-ack|--no-ack] [--no-wait] [--timeout SECONDS] [--confirm-human] [--message-id ID] [--json]".to_string(),
|
|
197
207
|
Some("allow-peer-talk") => "usage: team-agent allow-peer-talk A B [--workspace WORKSPACE] [--json]".to_string(),
|
|
198
|
-
Some("status") => "usage: team-agent status [AGENT] [--workspace WORKSPACE] [--summary|--json] [--detail]".to_string(),
|
|
208
|
+
Some("status") => "usage: team-agent status [AGENT] [--workspace WORKSPACE] [--team TEAM] [--summary|--json] [--detail]".to_string(),
|
|
199
209
|
Some("stop") => "usage: team-agent stop [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]".to_string(),
|
|
200
210
|
Some("shutdown") => "usage: team-agent shutdown [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]".to_string(),
|
|
201
|
-
Some("restart") => "usage: team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--json]".to_string(),
|
|
211
|
+
Some("restart") => "usage: team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--session-converge-deadline SECONDS] [--json]".to_string(),
|
|
202
212
|
Some("restart-agent") => "usage: team-agent restart-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--no-display] [--json]".to_string(),
|
|
203
213
|
Some("reset-agent") => "usage: team-agent reset-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--no-display] [--json]".to_string(),
|
|
204
214
|
Some("start-agent") => "usage: team-agent start-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--force] [--allow-fresh] [--no-display] [--json]".to_string(),
|
|
@@ -212,7 +222,7 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
212
222
|
Some("acknowledge-idle") => "usage: team-agent acknowledge-idle [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
213
223
|
Some("takeover") => "usage: team-agent takeover [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]".to_string(),
|
|
214
224
|
Some("claim-leader") => "usage: team-agent claim-leader [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]".to_string(),
|
|
215
|
-
Some("attach-leader") => "usage: team-agent attach-leader [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]".to_string(),
|
|
225
|
+
Some("attach-leader") => "usage: team-agent attach-leader [--workspace WORKSPACE] [--team TEAM] [--pane PANE] [--provider PROVIDER] [--confirm] [--json]".to_string(),
|
|
216
226
|
Some("identity") => "usage: team-agent identity [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
217
227
|
Some("approvals") => "usage: team-agent approvals [AGENT] [--workspace WORKSPACE] [--json]".to_string(),
|
|
218
228
|
Some("inbox") => "usage: team-agent inbox AGENT [--workspace WORKSPACE] [--limit N] [--since CURSOR] [--json]".to_string(),
|
|
@@ -222,14 +232,14 @@ fn command_help(command: Option<&str>) -> String {
|
|
|
222
232
|
Some("validate") => "usage: team-agent validate [SPEC] [--json]".to_string(),
|
|
223
233
|
Some("profile") => "usage: team-agent profile COMMAND NAME [--workspace WORKSPACE] [--team TEAM] [--auth-mode MODE] [--json]".to_string(),
|
|
224
234
|
Some("validate-result") => "usage: team-agent validate-result [ENVELOPE] [--file FILE|--result JSON] [--json]".to_string(),
|
|
225
|
-
Some("collect") => "usage: team-agent collect [--workspace WORKSPACE] [--result-file FILE] [--json]".to_string(),
|
|
226
|
-
Some("settle") => "usage: team-agent settle [--workspace WORKSPACE] [--json]".to_string(),
|
|
235
|
+
Some("collect") => "usage: team-agent collect [--workspace WORKSPACE] [--team TEAM] [--result-file FILE] [--json]".to_string(),
|
|
236
|
+
Some("settle") => "usage: team-agent settle [--workspace WORKSPACE] [--team TEAM] [--json]".to_string(),
|
|
227
237
|
Some("repair-state") => "usage: team-agent repair-state --task TASK --status STATUS [SUMMARY] [--assignee AGENT] [--workspace WORKSPACE] [--json]".to_string(),
|
|
228
238
|
Some("diagnose") => "usage: team-agent diagnose [--workspace WORKSPACE] [--json]".to_string(),
|
|
229
239
|
Some("preflight") => "usage: team-agent preflight [TEAMDIR] [--json]".to_string(),
|
|
230
240
|
Some("wait-ready") => "usage: team-agent wait-ready [--workspace WORKSPACE] [--timeout SECONDS] [--json]".to_string(),
|
|
231
241
|
Some("e2e") => "usage: team-agent e2e [--workspace WORKSPACE] [--providers LIST] [--real] [--json]".to_string(),
|
|
232
|
-
Some("peek") => "usage: team-agent peek AGENT [--workspace WORKSPACE] [--tail N] [--allow-raw-screen] [--json]".to_string(),
|
|
242
|
+
Some("peek") => "usage: team-agent peek AGENT [--workspace WORKSPACE] [--tail N|--head N] [--search TEXT] [--allow-raw-screen] [--json]".to_string(),
|
|
233
243
|
Some("coordinator") => "usage: team-agent coordinator [--workspace WORKSPACE] [--once] [--tick-interval SECONDS]".to_string(),
|
|
234
244
|
Some(other) => format!("usage: team-agent {other} [options]"),
|
|
235
245
|
}
|
|
@@ -261,8 +271,8 @@ pub fn cmd_validate(args: &ValidateArgs) -> Result<CmdResult, CliError> {
|
|
|
261
271
|
fn validate_spec_file(spec_path: &Path) -> Result<Value, CliError> {
|
|
262
272
|
let text = std::fs::read_to_string(spec_path)?;
|
|
263
273
|
let base_dir = spec_path.parent().unwrap_or_else(|| Path::new("."));
|
|
264
|
-
let spec =
|
|
265
|
-
.map_err(model_error_to_cli)?;
|
|
274
|
+
let spec =
|
|
275
|
+
crate::model::spec::load_and_validate_spec(&text, base_dir).map_err(model_error_to_cli)?;
|
|
266
276
|
let team = spec
|
|
267
277
|
.get("team")
|
|
268
278
|
.and_then(|team| team.get("name"))
|
|
@@ -381,12 +391,28 @@ fn cli_error_log_path(workspace: &Path) -> PathBuf {
|
|
|
381
391
|
struct PythonCompactFormatter;
|
|
382
392
|
|
|
383
393
|
impl serde_json::ser::Formatter for PythonCompactFormatter {
|
|
384
|
-
fn begin_array_value<W: ?Sized + std::io::Write>(
|
|
385
|
-
|
|
394
|
+
fn begin_array_value<W: ?Sized + std::io::Write>(
|
|
395
|
+
&mut self,
|
|
396
|
+
w: &mut W,
|
|
397
|
+
first: bool,
|
|
398
|
+
) -> std::io::Result<()> {
|
|
399
|
+
if first {
|
|
400
|
+
Ok(())
|
|
401
|
+
} else {
|
|
402
|
+
w.write_all(b", ")
|
|
403
|
+
}
|
|
386
404
|
}
|
|
387
405
|
|
|
388
|
-
fn begin_object_key<W: ?Sized + std::io::Write>(
|
|
389
|
-
|
|
406
|
+
fn begin_object_key<W: ?Sized + std::io::Write>(
|
|
407
|
+
&mut self,
|
|
408
|
+
w: &mut W,
|
|
409
|
+
first: bool,
|
|
410
|
+
) -> std::io::Result<()> {
|
|
411
|
+
if first {
|
|
412
|
+
Ok(())
|
|
413
|
+
} else {
|
|
414
|
+
w.write_all(b", ")
|
|
415
|
+
}
|
|
390
416
|
}
|
|
391
417
|
|
|
392
418
|
fn begin_object_value<W: ?Sized + std::io::Write>(&mut self, w: &mut W) -> std::io::Result<()> {
|
|
@@ -430,6 +456,7 @@ struct ParsedArgs {
|
|
|
430
456
|
summary: bool,
|
|
431
457
|
keep_logs: bool,
|
|
432
458
|
allow_fresh: bool,
|
|
459
|
+
session_converge_deadline_ms: Option<u64>,
|
|
433
460
|
force: bool,
|
|
434
461
|
no_display: bool,
|
|
435
462
|
discard_session: bool,
|
|
@@ -452,6 +479,8 @@ struct ParsedArgs {
|
|
|
452
479
|
providers: Option<String>,
|
|
453
480
|
allow_raw_screen: bool,
|
|
454
481
|
tail: Option<usize>,
|
|
482
|
+
head: Option<usize>,
|
|
483
|
+
search: Option<String>,
|
|
455
484
|
result_file: Option<PathBuf>,
|
|
456
485
|
file: Option<PathBuf>,
|
|
457
486
|
result: Option<String>,
|
|
@@ -459,6 +488,8 @@ struct ParsedArgs {
|
|
|
459
488
|
assignee: Option<String>,
|
|
460
489
|
out: Option<PathBuf>,
|
|
461
490
|
auth_mode: Option<String>,
|
|
491
|
+
pane: Option<String>,
|
|
492
|
+
provider: Option<String>,
|
|
462
493
|
message_id: Option<String>,
|
|
463
494
|
}
|
|
464
495
|
|
|
@@ -486,12 +517,18 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
486
517
|
"--requires-ack" => parsed.requires_ack = true,
|
|
487
518
|
"--no-ack" => parsed.no_ack = true,
|
|
488
519
|
"--no-wait" => parsed.no_wait = true,
|
|
489
|
-
"--timeout" =>
|
|
520
|
+
"--timeout" => {
|
|
521
|
+
parsed.timeout = next_arg(args, &mut i).and_then(|v| v.parse::<f64>().ok())
|
|
522
|
+
}
|
|
490
523
|
"--confirm-human" => parsed.confirm_human = true,
|
|
491
524
|
"--detail" => parsed.detail = true,
|
|
492
525
|
"--summary" => parsed.summary = true,
|
|
493
526
|
"--keep-logs" => parsed.keep_logs = true,
|
|
494
527
|
"--allow-fresh" => parsed.allow_fresh = true,
|
|
528
|
+
"--session-converge-deadline" => {
|
|
529
|
+
parsed.session_converge_deadline_ms =
|
|
530
|
+
next_arg(args, &mut i).and_then(|v| parse_seconds_ms(&v));
|
|
531
|
+
}
|
|
495
532
|
"--force" => parsed.force = true,
|
|
496
533
|
"--no-display" => parsed.no_display = true,
|
|
497
534
|
"--discard-session" => parsed.discard_session = true,
|
|
@@ -501,7 +538,9 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
501
538
|
"--from-spec" => parsed.from_spec = true,
|
|
502
539
|
"--confirm" => parsed.confirm = true,
|
|
503
540
|
"--alert-type" => parsed.alert_type = next_arg(args, &mut i),
|
|
504
|
-
"--limit" =>
|
|
541
|
+
"--limit" => {
|
|
542
|
+
parsed.limit = next_arg(args, &mut i).and_then(|v| v.parse::<usize>().ok())
|
|
543
|
+
}
|
|
505
544
|
"--since" => parsed.since = next_arg(args, &mut i),
|
|
506
545
|
"--gate" => parsed.gate = next_arg(args, &mut i),
|
|
507
546
|
"--comms" => parsed.comms = true,
|
|
@@ -509,11 +548,15 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
509
548
|
"--fix-schema" => parsed.fix_schema = true,
|
|
510
549
|
"--cleanup-orphans" => parsed.cleanup_orphans = true,
|
|
511
550
|
"--once" => parsed.once = true,
|
|
512
|
-
"--tick-interval" =>
|
|
551
|
+
"--tick-interval" => {
|
|
552
|
+
parsed.tick_interval = next_arg(args, &mut i).and_then(|v| v.parse::<f64>().ok())
|
|
553
|
+
}
|
|
513
554
|
"--status" => parsed.status_value = next_arg(args, &mut i),
|
|
514
555
|
"--providers" => parsed.providers = next_arg(args, &mut i),
|
|
515
556
|
"--allow-raw-screen" => parsed.allow_raw_screen = true,
|
|
516
557
|
"--tail" => parsed.tail = next_arg(args, &mut i).and_then(|v| v.parse::<usize>().ok()),
|
|
558
|
+
"--head" => parsed.head = next_arg(args, &mut i).and_then(|v| v.parse::<usize>().ok()),
|
|
559
|
+
"--search" => parsed.search = next_arg(args, &mut i),
|
|
517
560
|
"--result-file" => parsed.result_file = next_arg(args, &mut i).map(PathBuf::from),
|
|
518
561
|
"--file" => parsed.file = next_arg(args, &mut i).map(PathBuf::from),
|
|
519
562
|
"--result" => parsed.result = next_arg(args, &mut i),
|
|
@@ -521,11 +564,19 @@ fn parse_args(args: &[String]) -> ParsedArgs {
|
|
|
521
564
|
"--assignee" => parsed.assignee = next_arg(args, &mut i),
|
|
522
565
|
"--out" => parsed.out = next_arg(args, &mut i).map(PathBuf::from),
|
|
523
566
|
"--auth-mode" => parsed.auth_mode = next_arg(args, &mut i),
|
|
567
|
+
"--pane" => parsed.pane = next_arg(args, &mut i),
|
|
568
|
+
"--provider" => parsed.provider = next_arg(args, &mut i),
|
|
524
569
|
"--message-id" => parsed.message_id = next_arg(args, &mut i),
|
|
525
570
|
"-h" | "--help" => {}
|
|
526
571
|
other if other.starts_with("--team=") => {
|
|
527
572
|
parsed.team = Some(other.trim_start_matches("--team=").to_string());
|
|
528
573
|
}
|
|
574
|
+
other if other.starts_with("--pane=") => {
|
|
575
|
+
parsed.pane = Some(other.trim_start_matches("--pane=").to_string());
|
|
576
|
+
}
|
|
577
|
+
other if other.starts_with("--provider=") => {
|
|
578
|
+
parsed.provider = Some(other.trim_start_matches("--provider=").to_string());
|
|
579
|
+
}
|
|
529
580
|
other if other.starts_with('-') => {}
|
|
530
581
|
other => parsed.positionals.push(other.to_string()),
|
|
531
582
|
}
|
|
@@ -539,8 +590,26 @@ fn next_arg(args: &[String], index: &mut usize) -> Option<String> {
|
|
|
539
590
|
args.get(*index).cloned()
|
|
540
591
|
}
|
|
541
592
|
|
|
593
|
+
fn parse_seconds_ms(raw: &str) -> Option<u64> {
|
|
594
|
+
let seconds = raw.parse::<f64>().ok()?;
|
|
595
|
+
if seconds.is_finite() && seconds >= 0.0 {
|
|
596
|
+
Some((seconds * 1000.0).round() as u64)
|
|
597
|
+
} else {
|
|
598
|
+
None
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
fn parse_cli_provider(raw: Option<&str>) -> Result<crate::provider::Provider, CliError> {
|
|
603
|
+
let raw = raw.unwrap_or("codex");
|
|
604
|
+
serde_json::from_value::<crate::provider::Provider>(serde_json::json!(raw))
|
|
605
|
+
.map_err(|_| CliError::Runtime(format!("unknown provider: {raw}")))
|
|
606
|
+
}
|
|
607
|
+
|
|
542
608
|
fn workspace(parsed: &ParsedArgs, cwd: &Path) -> PathBuf {
|
|
543
|
-
parsed
|
|
609
|
+
parsed
|
|
610
|
+
.workspace
|
|
611
|
+
.clone()
|
|
612
|
+
.unwrap_or_else(|| cwd.to_path_buf())
|
|
544
613
|
}
|
|
545
614
|
|
|
546
615
|
fn required_pos(parsed: &ParsedArgs, index: usize, name: &str) -> Result<String, CliError> {
|
|
@@ -565,6 +634,7 @@ fn quick_start_args(args: &[String], cwd: &Path) -> Result<QuickStartArgs, CliEr
|
|
|
565
634
|
workspace.join(agents_dir)
|
|
566
635
|
};
|
|
567
636
|
Ok(QuickStartArgs {
|
|
637
|
+
workspace,
|
|
568
638
|
agents_dir,
|
|
569
639
|
name: parsed.name,
|
|
570
640
|
team_id: parsed.team_id.or(parsed.team),
|
|
@@ -590,7 +660,9 @@ fn compile_args(args: &[String], cwd: &Path) -> Result<CompileArgs, CliError> {
|
|
|
590
660
|
.as_deref()
|
|
591
661
|
.map(PathBuf::from)
|
|
592
662
|
.ok_or_else(|| CliError::Usage("missing --team".to_string()))?;
|
|
593
|
-
let out = parsed
|
|
663
|
+
let out = parsed
|
|
664
|
+
.out
|
|
665
|
+
.unwrap_or_else(|| PathBuf::from("team.spec.yaml"));
|
|
594
666
|
Ok(CompileArgs {
|
|
595
667
|
team: resolve_cli_path(cwd, &team),
|
|
596
668
|
out: resolve_cli_path(cwd, &out),
|
|
@@ -617,7 +689,12 @@ fn send_args(args: &[String], cwd: &Path) -> Result<SendArgs, CliError> {
|
|
|
617
689
|
let workspace = workspace(&parsed, cwd);
|
|
618
690
|
Ok(SendArgs {
|
|
619
691
|
target,
|
|
620
|
-
message: parsed
|
|
692
|
+
message: parsed
|
|
693
|
+
.positionals
|
|
694
|
+
.iter()
|
|
695
|
+
.skip(message_start)
|
|
696
|
+
.cloned()
|
|
697
|
+
.collect(),
|
|
621
698
|
targets: parsed.targets,
|
|
622
699
|
workspace,
|
|
623
700
|
team: parsed.team,
|
|
@@ -702,6 +779,21 @@ fn claim_leader_args(args: &[String], cwd: &Path) -> ClaimLeaderArgs {
|
|
|
702
779
|
}
|
|
703
780
|
}
|
|
704
781
|
|
|
782
|
+
fn attach_leader_args(args: &[String], cwd: &Path) -> Result<AttachLeaderArgs, CliError> {
|
|
783
|
+
let parsed = parse_args(args);
|
|
784
|
+
Ok(AttachLeaderArgs {
|
|
785
|
+
workspace: workspace(&parsed, cwd),
|
|
786
|
+
team: parsed.team,
|
|
787
|
+
pane: parsed
|
|
788
|
+
.pane
|
|
789
|
+
.filter(|pane| !pane.is_empty())
|
|
790
|
+
.map(crate::transport::PaneId::new),
|
|
791
|
+
provider: parse_cli_provider(parsed.provider.as_deref())?,
|
|
792
|
+
confirm: parsed.confirm,
|
|
793
|
+
json: parsed.json,
|
|
794
|
+
})
|
|
795
|
+
}
|
|
796
|
+
|
|
705
797
|
fn identity_args(args: &[String], cwd: &Path) -> IdentityArgs {
|
|
706
798
|
let parsed = parse_args(args);
|
|
707
799
|
IdentityArgs {
|
|
@@ -731,6 +823,7 @@ fn restart_args(args: &[String], cwd: &Path) -> RestartArgs {
|
|
|
731
823
|
.unwrap_or_else(|| workspace(&parsed, cwd)),
|
|
732
824
|
team: parsed.team,
|
|
733
825
|
allow_fresh: parsed.allow_fresh,
|
|
826
|
+
session_converge_deadline_ms: parsed.session_converge_deadline_ms,
|
|
734
827
|
json: parsed.json,
|
|
735
828
|
}
|
|
736
829
|
}
|
|
@@ -776,7 +869,9 @@ fn add_agent_args(args: &[String], cwd: &Path) -> Result<AddAgentArgs, CliError>
|
|
|
776
869
|
agent: required_pos(&parsed, 0, "agent")?,
|
|
777
870
|
workspace: workspace(&parsed, cwd),
|
|
778
871
|
team: parsed.team,
|
|
779
|
-
role_file: parsed
|
|
872
|
+
role_file: parsed
|
|
873
|
+
.role_file
|
|
874
|
+
.ok_or_else(|| CliError::Usage("missing --role-file".to_string()))?,
|
|
780
875
|
no_display: parsed.no_display,
|
|
781
876
|
json: parsed.json,
|
|
782
877
|
})
|
|
@@ -788,7 +883,9 @@ fn fork_agent_args(args: &[String], cwd: &Path) -> Result<ForkAgentArgs, CliErro
|
|
|
788
883
|
source_agent: required_pos(&parsed, 0, "source_agent")?,
|
|
789
884
|
workspace: workspace(&parsed, cwd),
|
|
790
885
|
team: parsed.team,
|
|
791
|
-
as_agent: parsed
|
|
886
|
+
as_agent: parsed
|
|
887
|
+
.as_agent
|
|
888
|
+
.ok_or_else(|| CliError::Usage("missing --as".to_string()))?,
|
|
792
889
|
label: parsed.label,
|
|
793
890
|
no_display: parsed.no_display,
|
|
794
891
|
json: parsed.json,
|
|
@@ -934,7 +1031,9 @@ fn repair_state_args(args: &[String], cwd: &Path) -> Result<RepairStateArgs, Cli
|
|
|
934
1031
|
let parsed = parse_args(args);
|
|
935
1032
|
Ok(RepairStateArgs {
|
|
936
1033
|
workspace: workspace(&parsed, cwd),
|
|
937
|
-
task_id: parsed
|
|
1034
|
+
task_id: parsed
|
|
1035
|
+
.task
|
|
1036
|
+
.ok_or_else(|| CliError::Usage("missing --task".to_string()))?,
|
|
938
1037
|
assignee: parsed.assignee,
|
|
939
1038
|
status: parsed
|
|
940
1039
|
.status_value
|
|
@@ -1024,6 +1123,8 @@ fn peek_args(args: &[String], cwd: &Path) -> Result<PeekArgs, CliError> {
|
|
|
1024
1123
|
agent: required_pos(&parsed, 0, "agent")?,
|
|
1025
1124
|
workspace: workspace(&parsed, cwd),
|
|
1026
1125
|
tail: parsed.tail.unwrap_or(80),
|
|
1126
|
+
head: parsed.head,
|
|
1127
|
+
search: parsed.search,
|
|
1027
1128
|
allow_raw_screen: parsed.allow_raw_screen,
|
|
1028
1129
|
json: parsed.json,
|
|
1029
1130
|
})
|
|
@@ -1061,13 +1162,23 @@ fn json_dumps_like(value: &Value) -> String {
|
|
|
1061
1162
|
Err(_) => "\"\"".to_string(),
|
|
1062
1163
|
},
|
|
1063
1164
|
Value::Array(arr) => {
|
|
1064
|
-
let inner = arr
|
|
1165
|
+
let inner = arr
|
|
1166
|
+
.iter()
|
|
1167
|
+
.map(json_dumps_like)
|
|
1168
|
+
.collect::<Vec<_>>()
|
|
1169
|
+
.join(", ");
|
|
1065
1170
|
format!("[{inner}]")
|
|
1066
1171
|
}
|
|
1067
1172
|
Value::Object(obj) => {
|
|
1068
1173
|
let inner = obj
|
|
1069
1174
|
.iter()
|
|
1070
|
-
.map(|(k, v)|
|
|
1175
|
+
.map(|(k, v)| {
|
|
1176
|
+
format!(
|
|
1177
|
+
"{}: {}",
|
|
1178
|
+
json_dumps_like(&Value::String(k.clone())),
|
|
1179
|
+
json_dumps_like(v)
|
|
1180
|
+
)
|
|
1181
|
+
})
|
|
1071
1182
|
.collect::<Vec<_>>()
|
|
1072
1183
|
.join(", ");
|
|
1073
1184
|
format!("{{{inner}}}")
|
|
@@ -1159,26 +1270,144 @@ mod tests {
|
|
|
1159
1270
|
#[test]
|
|
1160
1271
|
fn t0_help_catalog_lists_command_flags() {
|
|
1161
1272
|
for (command, flags) in [
|
|
1162
|
-
(
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
(
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1273
|
+
(
|
|
1274
|
+
"quick-start",
|
|
1275
|
+
&["--workspace", "--team-id", "--yes", "--fresh", "--json"][..],
|
|
1276
|
+
),
|
|
1277
|
+
(
|
|
1278
|
+
"send",
|
|
1279
|
+
&[
|
|
1280
|
+
"--workspace",
|
|
1281
|
+
"--team",
|
|
1282
|
+
"--targets",
|
|
1283
|
+
"--watch-result",
|
|
1284
|
+
"--timeout",
|
|
1285
|
+
"--json",
|
|
1286
|
+
][..],
|
|
1287
|
+
),
|
|
1288
|
+
(
|
|
1289
|
+
"status",
|
|
1290
|
+
&["--workspace", "--team", "--summary", "--json", "--detail"][..],
|
|
1291
|
+
),
|
|
1292
|
+
(
|
|
1293
|
+
"shutdown",
|
|
1294
|
+
&["--workspace", "--team", "--keep-logs", "--json"][..],
|
|
1295
|
+
),
|
|
1296
|
+
(
|
|
1297
|
+
"restart",
|
|
1298
|
+
&[
|
|
1299
|
+
"--team",
|
|
1300
|
+
"--allow-fresh",
|
|
1301
|
+
"--session-converge-deadline",
|
|
1302
|
+
"--json",
|
|
1303
|
+
][..],
|
|
1304
|
+
),
|
|
1305
|
+
(
|
|
1306
|
+
"start-agent",
|
|
1307
|
+
&[
|
|
1308
|
+
"--workspace",
|
|
1309
|
+
"--team",
|
|
1310
|
+
"--force",
|
|
1311
|
+
"--allow-fresh",
|
|
1312
|
+
"--no-display",
|
|
1313
|
+
"--json",
|
|
1314
|
+
][..],
|
|
1315
|
+
),
|
|
1316
|
+
(
|
|
1317
|
+
"reset-agent",
|
|
1318
|
+
&[
|
|
1319
|
+
"--workspace",
|
|
1320
|
+
"--team",
|
|
1321
|
+
"--discard-session",
|
|
1322
|
+
"--no-display",
|
|
1323
|
+
"--json",
|
|
1324
|
+
][..],
|
|
1325
|
+
),
|
|
1326
|
+
(
|
|
1327
|
+
"add-agent",
|
|
1328
|
+
&[
|
|
1329
|
+
"--role-file",
|
|
1330
|
+
"--workspace",
|
|
1331
|
+
"--team",
|
|
1332
|
+
"--no-display",
|
|
1333
|
+
"--json",
|
|
1334
|
+
][..],
|
|
1335
|
+
),
|
|
1336
|
+
(
|
|
1337
|
+
"fork-agent",
|
|
1338
|
+
&[
|
|
1339
|
+
"--as",
|
|
1340
|
+
"--label",
|
|
1341
|
+
"--workspace",
|
|
1342
|
+
"--team",
|
|
1343
|
+
"--no-display",
|
|
1344
|
+
"--json",
|
|
1345
|
+
][..],
|
|
1346
|
+
),
|
|
1347
|
+
(
|
|
1348
|
+
"remove-agent",
|
|
1349
|
+
&[
|
|
1350
|
+
"--workspace",
|
|
1351
|
+
"--team",
|
|
1352
|
+
"--from-spec",
|
|
1353
|
+
"--confirm",
|
|
1354
|
+
"--force",
|
|
1355
|
+
"--json",
|
|
1356
|
+
][..],
|
|
1357
|
+
),
|
|
1358
|
+
(
|
|
1359
|
+
"doctor",
|
|
1360
|
+
&[
|
|
1361
|
+
"--workspace",
|
|
1362
|
+
"--team",
|
|
1363
|
+
"--gate",
|
|
1364
|
+
"--fix-schema",
|
|
1365
|
+
"--cleanup-orphans",
|
|
1366
|
+
"--json",
|
|
1367
|
+
][..],
|
|
1368
|
+
),
|
|
1369
|
+
(
|
|
1370
|
+
"attach-leader",
|
|
1371
|
+
&[
|
|
1372
|
+
"--workspace",
|
|
1373
|
+
"--team",
|
|
1374
|
+
"--pane",
|
|
1375
|
+
"--provider",
|
|
1376
|
+
"--confirm",
|
|
1377
|
+
"--json",
|
|
1378
|
+
][..],
|
|
1379
|
+
),
|
|
1380
|
+
(
|
|
1381
|
+
"collect",
|
|
1382
|
+
&["--workspace", "--team", "--result-file", "--json"][..],
|
|
1383
|
+
),
|
|
1384
|
+
(
|
|
1385
|
+
"repair-state",
|
|
1386
|
+
&["--task", "--status", "--assignee", "--workspace", "--json"][..],
|
|
1387
|
+
),
|
|
1175
1388
|
("wait-ready", &["--workspace", "--timeout", "--json"][..]),
|
|
1176
|
-
(
|
|
1177
|
-
|
|
1389
|
+
(
|
|
1390
|
+
"peek",
|
|
1391
|
+
&[
|
|
1392
|
+
"--workspace",
|
|
1393
|
+
"--tail",
|
|
1394
|
+
"--head",
|
|
1395
|
+
"--search",
|
|
1396
|
+
"--allow-raw-screen",
|
|
1397
|
+
"--json",
|
|
1398
|
+
][..],
|
|
1399
|
+
),
|
|
1400
|
+
(
|
|
1401
|
+
"coordinator",
|
|
1402
|
+
&["--workspace", "--once", "--tick-interval"][..],
|
|
1403
|
+
),
|
|
1178
1404
|
] {
|
|
1179
1405
|
let help = command_help(Some(command));
|
|
1180
1406
|
for flag in flags {
|
|
1181
|
-
assert!(
|
|
1407
|
+
assert!(
|
|
1408
|
+
help.contains(flag),
|
|
1409
|
+
"`team-agent {command} --help` is missing {flag}"
|
|
1410
|
+
);
|
|
1182
1411
|
}
|
|
1183
1412
|
}
|
|
1184
1413
|
}
|
|
@@ -1188,7 +1417,13 @@ mod tests {
|
|
|
1188
1417
|
let cwd = tmp_workspace();
|
|
1189
1418
|
let ws = tmp_workspace();
|
|
1190
1419
|
let args = quick_start_args(
|
|
1191
|
-
&cli_argv(&[
|
|
1420
|
+
&cli_argv(&[
|
|
1421
|
+
"--workspace",
|
|
1422
|
+
&ws.to_string_lossy(),
|
|
1423
|
+
"agents",
|
|
1424
|
+
"--yes",
|
|
1425
|
+
"--json",
|
|
1426
|
+
]),
|
|
1192
1427
|
&cwd,
|
|
1193
1428
|
)
|
|
1194
1429
|
.unwrap();
|