@team-agent/installer 0.5.113 → 0.5.115
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 +252 -84
- package/Cargo.toml +3 -1
- package/crates/team-agent/Cargo.toml +3 -0
- package/crates/team-agent/src/cli/adapters.rs +28 -15
- package/crates/team-agent/src/cli/diagnose.rs +36 -13
- package/crates/team-agent/src/cli/emit.rs +57 -22
- package/crates/team-agent/src/cli/leader.rs +16 -0
- package/crates/team-agent/src/cli/leader_prompt.rs +261 -0
- package/crates/team-agent/src/cli/mod.rs +157 -8
- package/crates/team-agent/src/cli/models.rs +119 -18
- package/crates/team-agent/src/cli/spec.rs +7 -1
- package/crates/team-agent/src/cli/status_port/brief.rs +268 -101
- package/crates/team-agent/src/cli/tests/base.rs +88 -0
- package/crates/team-agent/src/cli/tests/status_send.rs +2 -0
- package/crates/team-agent/src/compiler.rs +66 -18
- package/crates/team-agent/src/contract_runtime/backend.rs +959 -0
- package/crates/team-agent/src/contract_runtime/commands.rs +245 -0
- package/crates/team-agent/src/contract_runtime/config.rs +340 -0
- package/crates/team-agent/src/contract_runtime/config_tests.rs +56 -0
- package/crates/team-agent/src/contract_runtime/discovery.rs +383 -0
- package/crates/team-agent/src/contract_runtime/forward.rs +229 -0
- package/crates/team-agent/src/contract_runtime/framework.rs +294 -0
- package/crates/team-agent/src/contract_runtime/mcp.rs +396 -0
- package/crates/team-agent/src/contract_runtime/mod.rs +16 -0
- package/crates/team-agent/src/contract_runtime/prompt.rs +216 -0
- package/crates/team-agent/src/contract_runtime/pump.rs +269 -0
- package/crates/team-agent/src/contract_runtime/registry.rs +197 -0
- package/crates/team-agent/src/contract_runtime/workspace.rs +160 -0
- package/crates/team-agent/src/coordinator/tick.rs +26 -8
- package/crates/team-agent/src/leader/mod.rs +1 -0
- package/crates/team-agent/src/leader/prompt.rs +906 -0
- package/crates/team-agent/src/leader/start.rs +353 -21
- package/crates/team-agent/src/leader/tests/mod.rs +2 -0
- package/crates/team-agent/src/leader/tests/prompt_contract.rs +268 -0
- package/crates/team-agent/src/leader/types.rs +6 -0
- package/crates/team-agent/src/lib.rs +4 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +571 -389
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +38 -9
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +15 -0
- package/crates/team-agent/src/lifecycle/launch.rs +45 -28
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +23 -1
- package/crates/team-agent/src/lifecycle/restart/selection.rs +34 -0
- package/crates/team-agent/src/lifecycle/role_config.rs +17 -1
- package/crates/team-agent/src/lifecycle/types.rs +4 -1
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +37 -27
- package/crates/team-agent/src/main.rs +6 -0
- package/crates/team-agent/src/messaging/delivery.rs +50 -1
- package/crates/team-agent/src/messaging/send.rs +10 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +131 -0
- package/crates/team-agent/src/model/spec.rs +24 -12
- package/crates/team-agent/src/state/persist.rs +73 -0
- package/package.json +4 -4
|
@@ -28,6 +28,9 @@ chrono.workspace = true
|
|
|
28
28
|
libc.workspace = true
|
|
29
29
|
rusqlite.workspace = true # step 3 db(bundled SQLite,静态链接)
|
|
30
30
|
|
|
31
|
+
[target.'cfg(unix)'.dependencies]
|
|
32
|
+
team-agent-contract = { path = "../team-agent-contract" }
|
|
33
|
+
|
|
31
34
|
# 0.5.x Windows portability Batch 2/3: uses the same `windows = "0.61"`
|
|
32
35
|
# crate as `win-conpty-phase0` so the workspace shares a single
|
|
33
36
|
# Windows-API crate + already-locked Cargo.lock version.
|
|
@@ -7,6 +7,9 @@ use super::*;
|
|
|
7
7
|
|
|
8
8
|
/// `cmd_quick_start`(`commands.py:18`)。`--json` 或 `!ok` → 整 dict;否则 `result["summary"]`。
|
|
9
9
|
pub fn cmd_quick_start(args: &QuickStartArgs) -> Result<CmdResult, CliError> {
|
|
10
|
+
#[cfg(unix)]
|
|
11
|
+
crate::contract_runtime::config::read_team(args)
|
|
12
|
+
.map_err(|error| CliError::Runtime(error.to_string()))?;
|
|
10
13
|
let mut value = lifecycle_port::quick_start(
|
|
11
14
|
&args.workspace,
|
|
12
15
|
&args.agents_dir,
|
|
@@ -158,7 +161,10 @@ fn quick_start_config_guidance(value: &mut Value, args: &QuickStartArgs) -> Opti
|
|
|
158
161
|
/// E13:quick-start "team 起了" 人类输出 = summary + attach 块。所有成功出口共用(别每分支手拷)。
|
|
159
162
|
/// attach_commands 缺/空 → 只 summary(向后兼容)。
|
|
160
163
|
fn quickstart_human(value: &Value) -> String {
|
|
161
|
-
let summary = value
|
|
164
|
+
let summary = value
|
|
165
|
+
.get("summary")
|
|
166
|
+
.and_then(Value::as_str)
|
|
167
|
+
.unwrap_or("Team started.");
|
|
162
168
|
let attach: Vec<&str> = value
|
|
163
169
|
.get("attach_commands")
|
|
164
170
|
.and_then(Value::as_array)
|
|
@@ -1088,19 +1094,13 @@ mod tests {
|
|
|
1088
1094
|
let value = json!({"summary": "quick-start complete"});
|
|
1089
1095
|
assert_eq!(
|
|
1090
1096
|
quickstart_human(&value),
|
|
1091
|
-
format!(
|
|
1092
|
-
"quick-start complete\n{}",
|
|
1093
|
-
crate::cli::QUICK_START_REMINDER
|
|
1094
|
-
)
|
|
1097
|
+
format!("quick-start complete\n{}", crate::cli::QUICK_START_REMINDER)
|
|
1095
1098
|
);
|
|
1096
1099
|
// 空数组也只显示人类摘要与下一步,不凭空编造连接方式。
|
|
1097
1100
|
let value2 = json!({"summary": "s", "attach_commands": []});
|
|
1098
1101
|
assert_eq!(
|
|
1099
1102
|
quickstart_human(&value2),
|
|
1100
|
-
format!(
|
|
1101
|
-
"s\n{}",
|
|
1102
|
-
crate::cli::QUICK_START_REMINDER
|
|
1103
|
-
)
|
|
1103
|
+
format!("s\n{}", crate::cli::QUICK_START_REMINDER)
|
|
1104
1104
|
);
|
|
1105
1105
|
}
|
|
1106
1106
|
|
|
@@ -1219,7 +1219,11 @@ mod tests {
|
|
|
1219
1219
|
|
|
1220
1220
|
#[test]
|
|
1221
1221
|
fn quick_start_human_preserves_typed_refusals_without_error_field() {
|
|
1222
|
-
for status in [
|
|
1222
|
+
for status in [
|
|
1223
|
+
"existing_runtime",
|
|
1224
|
+
"preflight_blocked",
|
|
1225
|
+
"leader_binding_refused",
|
|
1226
|
+
] {
|
|
1223
1227
|
let value = json!({
|
|
1224
1228
|
"ok": false,
|
|
1225
1229
|
"status": status,
|
|
@@ -1232,10 +1236,16 @@ mod tests {
|
|
|
1232
1236
|
});
|
|
1233
1237
|
let result = finish_quick_start(value.clone(), &quick_start_args(false)).unwrap();
|
|
1234
1238
|
assert_eq!(result.exit, ExitCode::Error);
|
|
1235
|
-
let CmdOutput::Human(text) = result.output else {
|
|
1236
|
-
|
|
1239
|
+
let CmdOutput::Human(text) = result.output else {
|
|
1240
|
+
panic!("expected human report")
|
|
1241
|
+
};
|
|
1242
|
+
let rendered: Value =
|
|
1243
|
+
serde_json::from_str(text.strip_prefix("quick-start report:\n").unwrap()).unwrap();
|
|
1237
1244
|
assert_eq!(rendered, value, "human projection lost fields for {status}");
|
|
1238
|
-
assert!(
|
|
1245
|
+
assert!(
|
|
1246
|
+
!text.contains("team-agent doctor"),
|
|
1247
|
+
"must not replace actual actions"
|
|
1248
|
+
);
|
|
1239
1249
|
let json_result = finish_quick_start(value.clone(), &quick_start_args(true)).unwrap();
|
|
1240
1250
|
assert_eq!(json_result.exit, ExitCode::Error);
|
|
1241
1251
|
assert_eq!(json_result.output, CmdOutput::Json(value));
|
|
@@ -1252,8 +1262,11 @@ mod tests {
|
|
|
1252
1262
|
});
|
|
1253
1263
|
let result = finish_quick_start(value.clone(), &quick_start_args(false)).unwrap();
|
|
1254
1264
|
assert_eq!(result.exit, ExitCode::Error);
|
|
1255
|
-
let CmdOutput::Human(text) = result.output else {
|
|
1256
|
-
|
|
1265
|
+
let CmdOutput::Human(text) = result.output else {
|
|
1266
|
+
panic!("expected human report")
|
|
1267
|
+
};
|
|
1268
|
+
let rendered: Value =
|
|
1269
|
+
serde_json::from_str(text.strip_prefix("quick-start report:\n").unwrap()).unwrap();
|
|
1257
1270
|
assert_eq!(rendered, value);
|
|
1258
1271
|
}
|
|
1259
1272
|
|
|
@@ -342,7 +342,13 @@ pub(crate) fn diagnose_runtime_for_workspace(
|
|
|
342
342
|
&mut repairs,
|
|
343
343
|
);
|
|
344
344
|
append_legacy_snapshot_issue(workspace, state, &mut issues);
|
|
345
|
-
append_coordinator_health_issue(
|
|
345
|
+
append_coordinator_health_issue(
|
|
346
|
+
workspace,
|
|
347
|
+
state,
|
|
348
|
+
coordinator_health,
|
|
349
|
+
&mut issues,
|
|
350
|
+
&mut repairs,
|
|
351
|
+
);
|
|
346
352
|
append_runtime_bindings_stale_after_boot_issue(workspace, state, &mut issues, &mut repairs);
|
|
347
353
|
(issues, repairs)
|
|
348
354
|
}
|
|
@@ -373,7 +379,9 @@ pub(crate) fn workspace_has_existing_team_runtime(
|
|
|
373
379
|
let terminal = team_state
|
|
374
380
|
.get("status")
|
|
375
381
|
.and_then(Value::as_str)
|
|
376
|
-
.is_some_and(|status|
|
|
382
|
+
.is_some_and(|status| {
|
|
383
|
+
matches!(status, "stopped" | "shutdown" | "archived" | "terminal")
|
|
384
|
+
});
|
|
377
385
|
if terminal {
|
|
378
386
|
return false;
|
|
379
387
|
}
|
|
@@ -695,14 +703,13 @@ pub(crate) fn append_registry_channel_unbound_to_report(
|
|
|
695
703
|
repairs.push(recovery_hint(&team_key, issue_id, repair));
|
|
696
704
|
object.insert("issues".to_string(), Value::Array(issues));
|
|
697
705
|
object.insert("suggested_repairs".to_string(), Value::Array(repairs));
|
|
698
|
-
let is_healthy_unattached_host =
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
.is_some_and(|checks| !checks.is_empty());
|
|
706
|
+
let is_healthy_unattached_host = class == crate::lifecycle::launch::LeaderBindingClass::Unbound
|
|
707
|
+
&& object.get("ok").and_then(Value::as_bool) == Some(true)
|
|
708
|
+
&& object
|
|
709
|
+
.get("profile_smoke")
|
|
710
|
+
.and_then(|profile| profile.get("checks"))
|
|
711
|
+
.and_then(Value::as_array)
|
|
712
|
+
.is_some_and(|checks| !checks.is_empty());
|
|
706
713
|
if !is_healthy_unattached_host {
|
|
707
714
|
object.insert("ok".to_string(), Value::Bool(false));
|
|
708
715
|
}
|
|
@@ -1054,8 +1061,7 @@ mod tests {
|
|
|
1054
1061
|
pane_pid: None,
|
|
1055
1062
|
leader_env: Default::default(),
|
|
1056
1063
|
}]);
|
|
1057
|
-
let Some((_, repair)) =
|
|
1058
|
-
live_leader_workspace_mismatch(&workspace, &state, &transport)
|
|
1064
|
+
let Some((_, repair)) = live_leader_workspace_mismatch(&workspace, &state, &transport)
|
|
1059
1065
|
else {
|
|
1060
1066
|
panic!("workspace mismatch repair required");
|
|
1061
1067
|
};
|
|
@@ -1109,7 +1115,8 @@ mod tests {
|
|
|
1109
1115
|
.as_nanos()
|
|
1110
1116
|
));
|
|
1111
1117
|
std::fs::create_dir_all(&workspace).unwrap();
|
|
1112
|
-
let state =
|
|
1118
|
+
let state =
|
|
1119
|
+
json!({"agents": {}, "tasks": [], "session_name": null, "active_team_key": null});
|
|
1113
1120
|
let mut issues = json!([]);
|
|
1114
1121
|
let mut repairs = json!([]);
|
|
1115
1122
|
append_registry_channel_unbound_issue(
|
|
@@ -1574,6 +1581,22 @@ pub(crate) fn provider_doctor_checks() -> Value {
|
|
|
1574
1581
|
}),
|
|
1575
1582
|
);
|
|
1576
1583
|
}
|
|
1584
|
+
#[cfg(unix)]
|
|
1585
|
+
for descriptor in crate::contract_runtime::registry::descriptors() {
|
|
1586
|
+
let identity = &descriptor.identity;
|
|
1587
|
+
// Inventory only: finding the launcher is not an engine, auth or readiness probe.
|
|
1588
|
+
providers.insert(
|
|
1589
|
+
identity.id.to_string(),
|
|
1590
|
+
json!({
|
|
1591
|
+
"auth": crate::provider::AuthHintStatus::Unknown,
|
|
1592
|
+
"command": identity.binary,
|
|
1593
|
+
"installed": crate::contract_runtime::discovery::executable(identity.binary).is_ok(),
|
|
1594
|
+
"version": "unknown",
|
|
1595
|
+
"probe_status": "not_run",
|
|
1596
|
+
"provider_probe_status": "not_run",
|
|
1597
|
+
}),
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1577
1600
|
Value::Object(providers)
|
|
1578
1601
|
}
|
|
1579
1602
|
|
|
@@ -68,6 +68,9 @@ pub fn run(argv: &[String], cwd: &Path) -> ExitCode {
|
|
|
68
68
|
if command == "route" {
|
|
69
69
|
return super::route::run(&argv[1..]);
|
|
70
70
|
}
|
|
71
|
+
if command == "leader-prompt" {
|
|
72
|
+
return super::leader_prompt::run(&argv[1..]);
|
|
73
|
+
}
|
|
71
74
|
if is_leader_passthrough_command(command) {
|
|
72
75
|
return match cmd_leader_passthrough(command, &argv[1..], cwd) {
|
|
73
76
|
Ok(result) => emit_result(result),
|
|
@@ -212,6 +215,9 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
212
215
|
if command == "route" {
|
|
213
216
|
return Ok(super::route::run(args));
|
|
214
217
|
}
|
|
218
|
+
if command == "leader-prompt" {
|
|
219
|
+
return Ok(super::leader_prompt::run(args));
|
|
220
|
+
}
|
|
215
221
|
// Keep the removed flag harmless for older scripts and persisted command
|
|
216
222
|
// lines; the default tmux backend is already the only runtime path.
|
|
217
223
|
let filtered_args: Vec<String> = args
|
|
@@ -290,6 +296,7 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
290
296
|
// delivery path — no separate route authority.
|
|
291
297
|
"leaders" => cmd_leaders(&leaders_args(args, cwd)?).map(emit_result),
|
|
292
298
|
"models" => cmd_models(&models_args(args)?).map(emit_result),
|
|
299
|
+
"kiro" => Ok(emit_result(cmd_kiro_leader(args))),
|
|
293
300
|
|
|
294
301
|
"install-skill" => cmd_install_skill(&install_skill_args(args)?).map(emit_result),
|
|
295
302
|
"profile" => cmd_profile(&profile_args(args, cwd)?).map(emit_result),
|
|
@@ -300,10 +307,7 @@ fn dispatch(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliE
|
|
|
300
307
|
|
|
301
308
|
// Script compatibility is deliberately outside the human catalog and suggestions.
|
|
302
309
|
fn is_machine_command(command: &str) -> bool {
|
|
303
|
-
matches!(
|
|
304
|
-
command,
|
|
305
|
-
"wait" | "coordinator" | "attach-app-server-leader"
|
|
306
|
-
)
|
|
310
|
+
matches!(command, "wait" | "coordinator" | "attach-app-server-leader")
|
|
307
311
|
}
|
|
308
312
|
|
|
309
313
|
fn dispatch_machine(command: &str, args: &[String], cwd: &Path) -> Result<ExitCode, CliError> {
|
|
@@ -365,7 +369,11 @@ pub(crate) fn default_help() -> String {
|
|
|
365
369
|
"Observation and collaboration",
|
|
366
370
|
&["leaders", "doctor", "approvals"],
|
|
367
371
|
);
|
|
368
|
-
append_help_section(
|
|
372
|
+
append_help_section(
|
|
373
|
+
&mut out,
|
|
374
|
+
"Configuration",
|
|
375
|
+
&["route", "leader-prompt", "profile", "install-skill"],
|
|
376
|
+
);
|
|
369
377
|
append_help_section(
|
|
370
378
|
&mut out,
|
|
371
379
|
"Guided recovery",
|
|
@@ -374,7 +382,7 @@ pub(crate) fn default_help() -> String {
|
|
|
374
382
|
append_help_section(
|
|
375
383
|
&mut out,
|
|
376
384
|
"Leader launch",
|
|
377
|
-
&["pi", "codex", "claude", "copilot", "grok", "cursor"],
|
|
385
|
+
&["pi", "codex", "claude", "copilot", "grok", "cursor", "kiro"],
|
|
378
386
|
);
|
|
379
387
|
out.push_str("\nCommand arguments and examples: team-agent <command> --help");
|
|
380
388
|
out
|
|
@@ -425,6 +433,9 @@ pub(super) fn command_help(command: Option<&str>) -> String {
|
|
|
425
433
|
if name == "route" {
|
|
426
434
|
return super::route::HELP.to_string();
|
|
427
435
|
}
|
|
436
|
+
if name == "leader-prompt" {
|
|
437
|
+
return super::leader_prompt::HELP.to_string();
|
|
438
|
+
}
|
|
428
439
|
let (details, examples, next) = match name {
|
|
429
440
|
"quick-start" => (
|
|
430
441
|
"TEAMDIR contains TEAM.md and agents/; --workspace selects the runtime project.\n--name sets the team name; --team/--team-id selects the team; --yes retains compatibility; --detail includes full diagnostics.\nProviders must be installed and signed in. Declare provider/model/effort in role files; permission bypass defaults to false.\n--backend tmux is for POSIX; conpty requires a Windows host and an installed ConPTY shim.",
|
|
@@ -437,8 +448,8 @@ pub(super) fn command_help(command: Option<&str>) -> String {
|
|
|
437
448
|
"team-agent inbox leader -n 3\nteam-agent inbox worker --limit 5\nteam-agent inbox leader --workspace . --team help-demo --json", "Wait for a natural reply, then check team-agent status if needed. Do not inspect worker terminal content."),
|
|
438
449
|
"status" => ("Optional <agent> selects one agent. --summary/--detail retain compatibility and do not add fields.\nNine fields: name/provider/model/effort/runtime_status/activity/health/session_name/tmux_command.\nRuntime, activity and health are distinct. unknown means insufficient evidence; null means unset. No default model is guessed.",
|
|
439
450
|
"team-agent status\nteam-agent status worker\nteam-agent status --workspace . --team help-demo --json", "Read replies with team-agent inbox leader -n 3; diagnose problems with team-agent doctor --workspace ."),
|
|
440
|
-
"models" => ("--provider selects the provider, default pi. QUERY or --search performs keyword search; they are mutually exclusive.\nUse
|
|
441
|
-
"team-agent models --provider pi\nteam-agent models --provider pi --search luna\nteam-agent models --provider
|
|
451
|
+
"models" => ("--provider selects the provider, default pi. QUERY or --search performs keyword search; they are mutually exclusive.\nUse cursor for the contract-native Cursor catalog; cursor_agent retains the legacy entrypoint. Copilot has no model discovery entrypoint here. Results come from the native catalog, not guesses.",
|
|
452
|
+
"team-agent models --provider pi\nteam-agent models --provider pi --search luna\nteam-agent models --provider cursor --json", "Use the exact returned model name in a role file or add-agent --model before launch."),
|
|
442
453
|
"restart" => ("WORKSPACE defaults to the current project; saved sessions are preferred.\nUse --allow-fresh only after explicit authorization to lose saved context. --session-converge-deadline sets the wait in seconds.",
|
|
443
454
|
"team-agent restart .\nteam-agent restart . --team help-demo --json", "Check status after restart. Obtain authorization before creating a fresh session; takeover is not a substitute for restart."),
|
|
444
455
|
"shutdown" => ("Shuts down only the selected workspace/team. Logs are retained by default; --keep-logs remains compatible.\n--json reports scope, degradation and owned residuals. Success does not mean other teams were shut down.",
|
|
@@ -473,6 +484,8 @@ pub(super) fn command_help(command: Option<&str>) -> String {
|
|
|
473
484
|
"team-agent takeover --workspace . --team help-demo --confirm\nteam-agent takeover --workspace . --team help-demo --confirm --json", "Verify leader/team ownership before confirmation. Check status/doctor afterwards; do not take over someone else's team."),
|
|
474
485
|
"attach-leader" => ("PANE must be a verified leader terminal, not a guessed pane id.\n--provider selects the actual provider; --confirm authorizes attachment to an existing leader. Use only when doctor recommends it.",
|
|
475
486
|
"team-agent attach-leader --pane \"$PANE\" --provider pi --workspace .\nteam-agent attach-leader --pane \"$PANE\" --provider pi --workspace . --team help-demo --confirm --json", "Set PANE to the verified terminal. Confirm attachment with doctor before sending a task."),
|
|
487
|
+
"kiro" => ("Kiro leader launching is not admitted by this candidate. This entry returns the stable capability refusal kiro_leader_not_admitted (exit 1).\nNo native process, leader binding, attach or provider fallback is attempted. --help/-h is read-only and exits 0.",
|
|
488
|
+
"team-agent kiro\nteam-agent kiro --json", "Use provider: kiro in a worker role with team-agent quick-start; worker support does not grant leader capability."),
|
|
476
489
|
_ => ("Install the provider and complete native sign-in first. The current directory is the workspace.\nUse --attach-existing/--confirm only after verifying leader ownership and receiving authorization; --attach-session selects a verified session.\n--external-leader selects an external leader; --allow-nested-attach requires explicit authorization for nested terminals.\nArguments after -- pass through unchanged. Bare --help/-h displays this help without starting the provider.",
|
|
477
490
|
"", "Run team-agent quick-start in the opened leader's tool context, not in an ordinary worker conversation."),
|
|
478
491
|
};
|
|
@@ -486,12 +499,17 @@ pub(super) fn command_help(command: Option<&str>) -> String {
|
|
|
486
499
|
} else {
|
|
487
500
|
examples.to_string()
|
|
488
501
|
};
|
|
489
|
-
let scope = if
|
|
502
|
+
let scope = if name == "kiro" {
|
|
503
|
+
"Use --json for the structured capability refusal. Native arguments and attach options cannot enable this capability."
|
|
504
|
+
} else if matches!(spec.kind, CommandKind::LeaderPassthrough { .. }) {
|
|
490
505
|
"Use --json for structured output. --workspace/--team are not launcher options here; they pass to the native provider."
|
|
491
506
|
} else {
|
|
492
507
|
"Use --json for structured output. --workspace selects the project; supported commands use --team to select the team."
|
|
493
508
|
};
|
|
494
|
-
let mut out = format!(
|
|
509
|
+
let mut out = format!(
|
|
510
|
+
"Purpose:\n{}.\nUsage: {}\n\nOptions:\n{}\n{}\nExamples:\n{}\n\nNext Action:\n{}",
|
|
511
|
+
spec.summary, spec.usage, details, scope, examples, next
|
|
512
|
+
);
|
|
495
513
|
if name == "quick-start" {
|
|
496
514
|
out.push_str(&format!("\n\nMinimal two-file configuration (create manually; not written automatically):\nTEAM.md:\n{TEAM_TEMPLATE}\nagents/worker.md:\n{WORKER_TEMPLATE}"));
|
|
497
515
|
}
|
|
@@ -499,7 +517,9 @@ pub(super) fn command_help(command: Option<&str>) -> String {
|
|
|
499
517
|
out.push_str("\nDiscover models with team-agent models --provider cursor_agent.");
|
|
500
518
|
}
|
|
501
519
|
if name == "copilot" {
|
|
502
|
-
out.push_str(
|
|
520
|
+
out.push_str(
|
|
521
|
+
"\nCopilot has no team-agent models entrypoint; consult native provider help.",
|
|
522
|
+
);
|
|
503
523
|
}
|
|
504
524
|
out
|
|
505
525
|
}
|
|
@@ -1250,16 +1270,20 @@ fn warn_send_legacy_delivery_flags(args: &[String]) {
|
|
|
1250
1270
|
"--message-id",
|
|
1251
1271
|
];
|
|
1252
1272
|
let spec = command_spec("send");
|
|
1253
|
-
let sunset = spec
|
|
1254
|
-
|
|
1255
|
-
.
|
|
1256
|
-
|
|
1273
|
+
let sunset = spec
|
|
1274
|
+
.and_then(|spec| spec.sunset)
|
|
1275
|
+
.unwrap_or("a future compatibility release");
|
|
1276
|
+
let action = spec.and_then(|spec| spec.action).unwrap_or(
|
|
1277
|
+
"Use team-agent send <agent> 'task message'; select scope with --workspace/--team",
|
|
1278
|
+
);
|
|
1257
1279
|
for flag in FLAGS {
|
|
1258
1280
|
if args
|
|
1259
1281
|
.iter()
|
|
1260
1282
|
.any(|arg| arg == flag || arg.starts_with(&format!("{flag}=")))
|
|
1261
1283
|
{
|
|
1262
|
-
eprintln!(
|
|
1284
|
+
eprintln!(
|
|
1285
|
+
"Warning: {flag} is deprecated and will be removed in {sunset}. Next: {action}"
|
|
1286
|
+
);
|
|
1263
1287
|
}
|
|
1264
1288
|
}
|
|
1265
1289
|
}
|
|
@@ -2074,7 +2098,11 @@ mod tests {
|
|
|
2074
2098
|
.filter(|spec| spec.default_help)
|
|
2075
2099
|
.map(|spec| spec.name)
|
|
2076
2100
|
.collect();
|
|
2077
|
-
assert_eq!(
|
|
2101
|
+
assert_eq!(
|
|
2102
|
+
expected.len(),
|
|
2103
|
+
31,
|
|
2104
|
+
"the public catalog includes Leader prompt management and the Kiro capability gate"
|
|
2105
|
+
);
|
|
2078
2106
|
for spec_name in &expected {
|
|
2079
2107
|
assert!(
|
|
2080
2108
|
visible.iter().any(|command| command == spec_name),
|
|
@@ -2088,7 +2116,7 @@ mod tests {
|
|
|
2088
2116
|
expected_sorted.sort();
|
|
2089
2117
|
assert_eq!(
|
|
2090
2118
|
actual, expected_sorted,
|
|
2091
|
-
"default help must match the exact
|
|
2119
|
+
"default help must match the exact public spec set, not a slack threshold; got {visible:?}"
|
|
2092
2120
|
);
|
|
2093
2121
|
assert!(
|
|
2094
2122
|
top_help.contains("copilot"),
|
|
@@ -2145,7 +2173,10 @@ mod tests {
|
|
|
2145
2173
|
!is_machine_command(command),
|
|
2146
2174
|
"retired Machine route: {command}"
|
|
2147
2175
|
);
|
|
2148
|
-
assert!(
|
|
2176
|
+
assert!(
|
|
2177
|
+
!is_known_subcommand(command),
|
|
2178
|
+
"retired help gate: {command}"
|
|
2179
|
+
);
|
|
2149
2180
|
}
|
|
2150
2181
|
}
|
|
2151
2182
|
|
|
@@ -2332,9 +2363,13 @@ mod tests {
|
|
|
2332
2363
|
assert_english(&command_help(Some(spec.name)));
|
|
2333
2364
|
}
|
|
2334
2365
|
for text in [
|
|
2335
|
-
TEAM_TEMPLATE,
|
|
2336
|
-
|
|
2337
|
-
|
|
2366
|
+
TEAM_TEMPLATE,
|
|
2367
|
+
WORKER_TEMPLATE,
|
|
2368
|
+
HUMAN_NAVIGATION,
|
|
2369
|
+
crate::cli::route::HELP,
|
|
2370
|
+
crate::cli::COMMS_BOUNDARY_TEXT,
|
|
2371
|
+
crate::cli::QUICK_START_REMINDER,
|
|
2372
|
+
crate::cli::SEND_REMINDER,
|
|
2338
2373
|
crate::cli::STATUS_REMINDER,
|
|
2339
2374
|
] {
|
|
2340
2375
|
assert_english(text);
|
|
@@ -116,6 +116,22 @@ pub fn cmd_leader_passthrough(
|
|
|
116
116
|
Ok(CmdResult::from_json(value, as_json))
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/// Public capability gate, not a legacy passthrough or a native launch attempt.
|
|
120
|
+
pub(crate) fn cmd_kiro_leader(args: &[String]) -> CmdResult {
|
|
121
|
+
CmdResult::from_json(
|
|
122
|
+
json!({
|
|
123
|
+
"schema_version": "leader_launch.v1",
|
|
124
|
+
"ok": false,
|
|
125
|
+
"provider": "kiro",
|
|
126
|
+
"capability": "leader_launch",
|
|
127
|
+
"reason": "kiro_leader_not_admitted",
|
|
128
|
+
"error": "Kiro leader launching is not admitted by this candidate; no native process was started.",
|
|
129
|
+
"action": "Use provider: kiro in a worker role with team-agent quick-start. Worker support does not grant leader capability.",
|
|
130
|
+
}),
|
|
131
|
+
leader_launcher_json(args),
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
119
135
|
/// Closed-set verb → Provider. `None` = not a passthrough verb (must not become ClaudeCode).
|
|
120
136
|
pub(crate) fn leader_passthrough_provider(command: &str) -> Option<crate::model::enums::Provider> {
|
|
121
137
|
use crate::model::enums::Provider;
|