@team-agent/installer 0.5.109 → 0.5.111

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.
Files changed (34) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/README.md +33 -0
  4. package/README.zh.md +30 -0
  5. package/crates/team-agent/src/cli/adapters.rs +234 -73
  6. package/crates/team-agent/src/cli/emit.rs +494 -201
  7. package/crates/team-agent/src/cli/leader.rs +4 -9
  8. package/crates/team-agent/src/cli/leaders.rs +90 -29
  9. package/crates/team-agent/src/cli/mod.rs +348 -161
  10. package/crates/team-agent/src/cli/models.rs +80 -24
  11. package/crates/team-agent/src/cli/named_address.rs +114 -25
  12. package/crates/team-agent/src/cli/route.rs +212 -0
  13. package/crates/team-agent/src/cli/send/presentation.rs +60 -41
  14. package/crates/team-agent/src/cli/send/resolve.rs +25 -18
  15. package/crates/team-agent/src/cli/send.rs +4 -4
  16. package/crates/team-agent/src/cli/spec.rs +56 -106
  17. package/crates/team-agent/src/cli/tests/base.rs +189 -82
  18. package/crates/team-agent/src/cli/tests/lane_c.rs +1 -2
  19. package/crates/team-agent/src/cli/tests/named_address.rs +19 -22
  20. package/crates/team-agent/src/cli/tests/status_send.rs +15 -10
  21. package/crates/team-agent/src/cli/tests/verb_install_skill.rs +2 -2
  22. package/crates/team-agent/src/cli/types.rs +22 -13
  23. package/crates/team-agent/src/leader/registry.rs +3 -3
  24. package/crates/team-agent/src/leader/start.rs +5 -1
  25. package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -0
  26. package/crates/team-agent/src/lifecycle/restart/common.rs +2 -0
  27. package/crates/team-agent/src/lifecycle/tests/cli_argv_routing_red.rs +1457 -0
  28. package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +4 -9
  29. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +3 -1
  30. package/crates/team-agent/src/lifecycle/tests.rs +1 -0
  31. package/crates/team-agent/src/provider/argv_route.rs +409 -0
  32. package/crates/team-agent/src/provider/mod.rs +3 -2
  33. package/package.json +4 -4
  34. package/skills/team-agent/SKILL.md +32 -0
@@ -20,7 +20,7 @@ pub(super) fn watch_notice_json(target: &MessageTarget, opts: &SendOptions) -> V
20
20
  "watcher_id": format!("watch-{agent_id}"),
21
21
  "task_id": opts.task_id.as_ref().map(|t| t.as_str().to_string()),
22
22
  "agent_id": agent_id,
23
- "notice": "Team Agent will collect the result and notify the leader when this task reports completion."
23
+ "notice": "队友回复后会通知主控;用 team-agent inbox leader -n 3 查看。"
24
24
  })
25
25
  }
26
26
 
@@ -183,39 +183,56 @@ pub(super) fn cmd_send_result(value: Value, as_json: bool) -> CmdResult {
183
183
  }
184
184
 
185
185
  pub(super) fn send_human_output(value: &Value) -> String {
186
- let mut parts = vec![
187
- send_human_field(value, "ok"),
188
- format!("status: {}", send_human_status(value)),
189
- send_human_field(value, "message_id"),
190
- format!("target: {}", send_human_target(value)),
191
- ];
192
- for key in ["verification", "stage", "reason", "channel", "turn_verification"] {
193
- if !value.get(key).is_none_or(Value::is_null) {
194
- parts.push(send_human_field(value, key));
186
+ let agent = send_human_target(value);
187
+ if value.get("ok").and_then(Value::as_bool) == Some(false) {
188
+ let reason = value.get("reason").and_then(Value::as_str).unwrap_or("");
189
+ let explanation =
190
+ crate::cli::named_address::human_address_reason(reason).unwrap_or(match reason {
191
+ "target_not_in_team" | "unknown_recipient" => "当前队伍没有这个队友。",
192
+ "missing_permissions" | "human_confirmation_required" => {
193
+ "发送被拒绝:需要先确认交流权限。"
194
+ }
195
+ "recipient_busy" | "recipient_pane_in_non_input_mode" => {
196
+ "队友当前不能接收任务;请先查看其状态。"
197
+ }
198
+ "routing_ambiguous" | "empty_target_list" | "ambiguous" => {
199
+ "没有明确选定收信队友;请填写队友名和任务内容。"
200
+ }
201
+ "team_owner_mismatch" | "PaneWorkspaceMismatch" | "session_drift" => {
202
+ "队伍或终端归属不匹配;已停止发送。"
203
+ }
204
+ "coordinator_unavailable" | "tmux_target_missing" => {
205
+ "队伍连接暂不可用;本次没有确认送达。"
206
+ }
207
+ "message_already_claimed" | "duplicate" => {
208
+ "这条消息已由其他发送处理接收;不要重复发送。"
209
+ }
210
+ "no_caller_pane" => "当前终端没有可用的队伍连接;请在主控的命令行/工具上下文发送。",
211
+ _ => value
212
+ .get("error")
213
+ .and_then(Value::as_str)
214
+ .unwrap_or("发送未成功;没有确认任务已送达。"),
215
+ });
216
+ let mut out = format!("{explanation}\n下一步:先运行 team-agent status,使用列表中的队友名;连接问题用 team-agent doctor --workspace .。不要反复重发。");
217
+ if let Some(suggested) = value
218
+ .get("suggested_name")
219
+ .and_then(Value::as_str)
220
+ .filter(|name| !name.is_empty() && !name.contains(['/', ':', ',', '\n', '\r']))
221
+ {
222
+ out.push_str(&format!(
223
+ "\n你是否想发给 {suggested}?确认后使用这个队友名。"
224
+ ));
195
225
  }
226
+ return out;
196
227
  }
197
- // 0.5.45 naming-addressing (design §3.4/§3.5, RED-3 positional):
198
- // when the refusal envelope carries a scope-safe suggestion,
199
- // surface it verbatim in human output so users can copy the
200
- // right short id. `requested_name` echoes the typo, `suggested_
201
- // name` is the copyable canonical.
202
- if let Some(requested) = value
203
- .get("requested_name")
204
- .and_then(Value::as_str)
205
- .filter(|s| !s.is_empty())
206
- {
207
- parts.push(format!("requested_name: {requested}"));
228
+ if value.get("status").and_then(Value::as_str) == Some("stored_only") {
229
+ return format!("已给{agent}留下消息;本次没有发送到当前对话。\n下一步:用 team-agent inbox leader -n 3 查看回复;留言不保证自动执行。");
208
230
  }
209
- if let Some(suggested) = value
210
- .get("suggested_name")
211
- .and_then(Value::as_str)
212
- .filter(|s| !s.is_empty())
213
- {
214
- parts.push(format!(
215
- "Did you mean `{suggested}`? suggested_name: {suggested}"
216
- ));
231
+ if value.get("delivered").and_then(Value::as_bool) == Some(true) {
232
+ format!("已发给{agent}。{}", crate::cli::SEND_REMINDER)
233
+ } else {
234
+ "任务已收下,但还未送到队友的对话。\n下一步:查看 team-agent status 或 team-agent doctor --workspace .,等真实回复,不反复重发。".to_string()
217
235
  }
218
- parts.join(" ")
219
236
  }
220
237
 
221
238
  pub(super) fn send_human_field(value: &Value, key: &str) -> String {
@@ -227,11 +244,14 @@ pub(super) fn send_human_field(value: &Value, key: &str) -> String {
227
244
  }
228
245
 
229
246
  pub(super) fn send_human_target(value: &Value) -> String {
230
- ["target", "agent_id", "pane_id", "to_name"]
231
- .iter()
232
- .find_map(|key| value.get(*key).filter(|v| !v.is_null()))
233
- .map(send_human_value)
234
- .unwrap_or_else(|| "None".to_string())
247
+ value
248
+ .get("agent_id")
249
+ .and_then(Value::as_str)
250
+ .filter(|name| {
251
+ !name.is_empty() && *name != "*" && !name.contains(['/', ':', ',', '\n', '\r'])
252
+ })
253
+ .map(str::to_string)
254
+ .unwrap_or_else(|| "该队友".to_string())
235
255
  }
236
256
 
237
257
  pub(super) fn send_human_status(value: &Value) -> String {
@@ -265,13 +285,12 @@ pub(super) fn send_reminder_for_value(value: &Value) -> &'static str {
265
285
  let delivered = value.get("delivered").and_then(Value::as_bool);
266
286
  let status = value.get("status").and_then(Value::as_str);
267
287
  let delivery_status = value.get("delivery_status").and_then(Value::as_str);
268
- if delivered == Some(false)
269
- || matches!(status, Some("queued"))
270
- || matches!(delivery_status, Some("pending"))
271
- {
272
- "Message queued; coordinator will notify when the worker receives it. Do not poll the worker terminal with capture-pane."
273
- } else {
288
+ if status == Some("stored_only") {
289
+ "本次只留言,没有发送到当前对话;留言不保证自动执行。"
290
+ } else if delivered == Some(true) && delivery_status != Some("pending") {
274
291
  crate::cli::SEND_REMINDER
292
+ } else {
293
+ "任务已收下,但还未确认送到队友对话。查看 team-agent status/doctor,等真实回复,不反复重发。"
275
294
  }
276
295
  }
277
296
 
@@ -7,13 +7,11 @@ use serde_json::{json, Value};
7
7
 
8
8
  pub(super) fn warn_send_alias(flag: &str) {
9
9
  let spec = crate::cli::spec::command_spec("send");
10
- let sunset = spec
11
- .and_then(|spec| spec.sunset)
12
- .unwrap_or("next compatibility release");
13
- let action = spec
14
- .and_then(|spec| spec.action)
15
- .unwrap_or("use positional logical TARGET addressing");
16
- eprintln!("warning: {flag} is deprecated; sunset: {sunset}; action: {action}");
10
+ let sunset = spec.and_then(|spec| spec.sunset).unwrap_or("后续兼容版本");
11
+ let action = spec.and_then(|spec| spec.action).unwrap_or(
12
+ "使用 team-agent send <agent> '任务内容',通过 --workspace/--team 选择项目和队伍",
13
+ );
14
+ eprintln!("提示:{flag} 已弃用,将在{sunset}移除。下一步:{action}");
17
15
  }
18
16
 
19
17
  pub(super) fn logical_to_from_args(
@@ -24,7 +22,7 @@ pub(super) fn logical_to_from_args(
24
22
  && (args.target.is_some() || args.targets.is_some() || args.to_leader.is_some())
25
23
  {
26
24
  return Err(CliError::Usage(
27
- "--to-name and --pane/TARGET/--to are mutually exclusive".to_string(),
25
+ "队友名与 --to-name/--pane/--to 不能同时使用;请只选一种收信方式".to_string(),
28
26
  ));
29
27
  }
30
28
  let supplied = [
@@ -38,7 +36,8 @@ pub(super) fn logical_to_from_args(
38
36
  .count();
39
37
  if supplied > 1 {
40
38
  return Err(CliError::Usage(
41
- "TARGET, --targets, --to-name, and --to-leader are mutually exclusive".to_string(),
39
+ "队友名、--targets、--to-name 和 --to-leader 不能同时使用;请只选一种收信方式"
40
+ .to_string(),
42
41
  ));
43
42
  }
44
43
  let logical_to = if args.to_leader.is_some() {
@@ -53,11 +52,11 @@ pub(super) fn logical_to_from_args(
53
52
  if args.target.is_none() && supplied > 0 && args.message.is_empty() {
54
53
  if args.to_name.is_some() {
55
54
  return Err(CliError::Usage(
56
- "--to-name requires a non-empty message".to_string(),
55
+ "请填写任务内容;--to-name 不能发送空消息".to_string(),
57
56
  ));
58
57
  }
59
58
  return Err(CliError::Usage(
60
- "send requires a non-empty message after logical TO".to_string(),
59
+ "请在队友名后填写非空任务内容;例如 team-agent send worker '检查改动'".to_string(),
61
60
  ));
62
61
  }
63
62
  Ok(logical_to)
@@ -183,12 +182,12 @@ pub(super) fn send_to_logical_to(
183
182
  .collect::<Vec<_>>();
184
183
  if names.is_empty() || names.len() != logical_to.split(',').count() {
185
184
  return Err(CliError::Usage(
186
- "logical TO comma-list contains an empty recipient".to_string(),
185
+ "收信列表中有空的队友名;请使用 status 返回的名称".to_string(),
187
186
  ));
188
187
  }
189
188
 
190
189
  let mut resolved = Vec::with_capacity(names.len());
191
- for name in names {
190
+ for (raw_name, name) in logical_to.split(',').zip(names) {
192
191
  match crate::cli::named_address::resolve_name_for_cli(
193
192
  &args.workspace,
194
193
  name,
@@ -218,7 +217,13 @@ pub(super) fn send_to_logical_to(
218
217
  if args.json {
219
218
  return Ok(error.to_json());
220
219
  }
221
- return Err(CliError::Usage(error.n38_message()));
220
+ let audit = error.n38_message();
221
+ let (message, action) = error.human_guidance(raw_name);
222
+ return Err(CliError::AddressRefusal {
223
+ audit,
224
+ error: message,
225
+ action,
226
+ });
222
227
  }
223
228
  }
224
229
  }
@@ -317,7 +322,7 @@ pub(super) fn adapt_positional_bare_error(
317
322
  .and_then(|suggested| suggested.rsplit('/').next())
318
323
  .map(str::to_string);
319
324
  if let Some(suggested) = error.suggested_name.as_deref() {
320
- error.action = format!("Did you mean `{suggested}`? Retry with `{suggested}` as TO.");
325
+ error.action = format!("你是否想发给 {suggested}?确认后使用此队友名;通过 --workspace/--team 选择项目和队伍。");
321
326
  }
322
327
  }
323
328
 
@@ -331,7 +336,7 @@ pub(super) fn logical_recipient_id(
331
336
  .ok_or_else(|| CliError::Runtime("resolved worker is missing agent id".to_string())),
332
337
  crate::cli::named_address::NamedTargetKind::Leader => Ok("leader".to_string()),
333
338
  crate::cli::named_address::NamedTargetKind::SessionWindow => Err(CliError::Usage(
334
- "named session/window delivery is sunset; use a logical agent or leader name"
339
+ "不再支持按终端窗口发送;请使用队友名或 leader,并通过 --workspace/--team 选择队伍"
335
340
  .to_string(),
336
341
  )),
337
342
  }
@@ -343,8 +348,10 @@ pub(super) fn send_to_resolved_name(
343
348
  content: &str,
344
349
  ) -> Result<Value, CliError> {
345
350
  let recipient = logical_recipient_id(resolved)?;
346
- if let Some(warning) = &resolved.warning {
347
- eprintln!("warning: {warning}");
351
+ if resolved.warning.is_some() {
352
+ eprintln!(
353
+ "提示:旧收信方式已弃用;请用队友名发送,通过 --workspace/--team 选择项目和队伍。"
354
+ );
348
355
  }
349
356
  let target = MessageTarget::Single(recipient);
350
357
  let mut value = persist_resolved_target(args, resolved, &target, content)?;
@@ -41,20 +41,20 @@ pub fn cmd_send(args: &SendArgs) -> Result<CmdResult, CliError> {
41
41
  || args.to_leader.is_some()
42
42
  {
43
43
  let message = if args.to_name.is_some() {
44
- "--to-name and --pane/TARGET/--to are mutually exclusive"
44
+ "队友名与 --to-name/--pane/--to 不能同时使用;请只选一种收信方式"
45
45
  } else {
46
- "--pane and TARGET/--to are mutually exclusive; --pane also conflicts with --to-leader"
46
+ "--pane 不能与队友名、--to 或 --to-leader 同时使用"
47
47
  };
48
48
  return Err(CliError::Usage(message.to_string()));
49
49
  }
50
50
  let content = args.message.join(" ");
51
51
  if content.is_empty() {
52
52
  return Err(CliError::Usage(
53
- "--pane requires a non-empty message".to_string(),
53
+ "请填写任务内容;--pane 不能发送空消息".to_string(),
54
54
  ));
55
55
  }
56
56
  return Err(CliError::Usage(format!(
57
- "--pane {pane_id} is deprecated and sunset; use a logical TARGET so the message is persisted before delivery"
57
+ "--pane {pane_id} 已不再支持;请用 team-agent send <agent> '任务内容',通过 --workspace/--team 选择项目和队伍"
58
58
  )));
59
59
  }
60
60
  if args.targets.is_some() {
@@ -1,7 +1,4 @@
1
- //!
2
- //! C1 command registry: one catalog for help visibility, known-command gates,
3
- //! suggestion candidates, and command-tier governance.
4
-
1
+ //! Human command catalog: help, spelling suggestions, and public dispatch guards.
5
2
  #![allow(dead_code)]
6
3
 
7
4
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -11,7 +8,6 @@ pub(crate) enum CommandTier {
11
8
  Secondary,
12
9
  DevInternal,
13
10
  }
14
-
15
11
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
16
12
  pub(crate) enum CommandCategory {
17
13
  Start,
@@ -23,103 +19,75 @@ pub(crate) enum CommandCategory {
23
19
  Observe,
24
20
  Dev,
25
21
  }
26
-
27
22
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
28
23
  pub(crate) enum CommandKind {
29
24
  Dispatch(DispatchKind),
30
25
  LeaderPassthrough { provider: &'static str },
31
26
  }
32
-
33
27
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
34
28
  pub(crate) enum TokenUsage {
35
29
  No,
36
30
  Yes,
37
31
  Conditional,
38
32
  }
39
-
40
33
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
41
34
  pub(crate) enum DispatchKind {
42
35
  QuickStart,
43
36
  Send,
44
- AllowPeerTalk,
45
37
  Status,
46
- Shutdown,
38
+ Models,
39
+ Inbox,
47
40
  Restart,
41
+ Shutdown,
42
+ AddAgent,
48
43
  StartAgent,
49
44
  StopAgent,
50
45
  ResetAgent,
51
- AddAgent,
52
46
  CloneAgent,
53
47
  ForkAgent,
54
48
  RemoveAgent,
55
- Takeover,
56
- ClaimLeader,
57
- AttachLeader,
58
- AttachAppServerLeader,
59
- Identity,
60
- Approvals,
61
- Inbox,
62
- Doctor,
63
- Watch,
64
- Sessions,
65
49
  Leaders,
66
- Validate,
67
- InstallSkill,
50
+ Doctor,
51
+ Approvals,
52
+ AllowPeerTalk,
53
+ Route,
68
54
  Profile,
69
- Results,
70
- Wait,
71
- Preflight,
72
- WaitReady,
73
- E2e,
74
- Peek,
75
- Coordinator,
76
- Models,
55
+ InstallSkill,
56
+ ClaimLeader,
57
+ Takeover,
58
+ AttachLeader,
77
59
  }
78
-
79
60
  pub(crate) const ALL_DISPATCH_KINDS: &[DispatchKind] = &[
80
61
  DispatchKind::QuickStart,
81
62
  DispatchKind::Send,
82
- DispatchKind::AllowPeerTalk,
83
63
  DispatchKind::Status,
84
- DispatchKind::Shutdown,
64
+ DispatchKind::Models,
65
+ DispatchKind::Inbox,
85
66
  DispatchKind::Restart,
67
+ DispatchKind::Shutdown,
68
+ DispatchKind::AddAgent,
86
69
  DispatchKind::StartAgent,
87
70
  DispatchKind::StopAgent,
88
71
  DispatchKind::ResetAgent,
89
- DispatchKind::AddAgent,
90
72
  DispatchKind::CloneAgent,
91
73
  DispatchKind::ForkAgent,
92
74
  DispatchKind::RemoveAgent,
93
- DispatchKind::Takeover,
94
- DispatchKind::ClaimLeader,
95
- DispatchKind::AttachLeader,
96
- DispatchKind::AttachAppServerLeader,
97
- DispatchKind::Identity,
98
- DispatchKind::Approvals,
99
- DispatchKind::Inbox,
100
- DispatchKind::Doctor,
101
- DispatchKind::Watch,
102
- DispatchKind::Sessions,
103
75
  DispatchKind::Leaders,
104
- DispatchKind::Validate,
105
- DispatchKind::InstallSkill,
76
+ DispatchKind::Doctor,
77
+ DispatchKind::Approvals,
78
+ DispatchKind::AllowPeerTalk,
79
+ DispatchKind::Route,
106
80
  DispatchKind::Profile,
107
- DispatchKind::Results,
108
- DispatchKind::Wait,
109
- DispatchKind::Preflight,
110
- DispatchKind::WaitReady,
111
- DispatchKind::E2e,
112
- DispatchKind::Peek,
113
- DispatchKind::Coordinator,
114
- DispatchKind::Models,
81
+ DispatchKind::InstallSkill,
82
+ DispatchKind::ClaimLeader,
83
+ DispatchKind::Takeover,
84
+ DispatchKind::AttachLeader,
115
85
  ];
116
-
117
86
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
118
87
  pub(crate) struct GovernanceNote {
119
88
  pub(crate) decision: &'static str,
120
89
  pub(crate) reason: &'static str,
121
90
  }
122
-
123
91
  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
124
92
  pub(crate) struct CommandSpec {
125
93
  pub(crate) name: &'static str,
@@ -137,57 +105,39 @@ pub(crate) struct CommandSpec {
137
105
  pub(crate) governance: Option<GovernanceNote>,
138
106
  }
139
107
 
140
- /// Visible default-help contract:
141
- /// - d40 / v0.5.77 published 15 names including `models` and excluding `results`.
142
- /// - `results` remains a public handler and must stay discoverable.
143
- /// - Exact composed set is d40 ∪ {results}. This is a frozen name set, not a
144
- /// numeric slack threshold.
108
+ // Only human operations belong here. Compatibility commands are private in emit.rs.
145
109
  #[rustfmt::skip]
146
110
  pub(crate) const COMMAND_SPECS: &[CommandSpec] = &[
147
- CommandSpec { name: "quick-start", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::QuickStart), summary: "start or attach a team from TEAM.md", usage: "usage: team-agent quick-start [TEAMDIR] [--workspace WORKSPACE] [--name NAME] [--team-id TEAM|--team TEAM] [--yes] [--backend tmux|conpty] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
148
- CommandSpec { name: "send", tier: CommandTier::Core, category: CommandCategory::Daily, kind: CommandKind::Dispatch(DispatchKind::Send), summary: "persist a message for an in-team short name or fully-qualified logical recipient", usage: "usage: team-agent send TO MESSAGE... [--workspace WORKSPACE] [--team TEAM] [--mailbox] [--json]\nTO forms are co-equal: an in-team short name (for example `team-agent send reviewer \"Review\"`) or `<workspace>::<team>/<agent>`.", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: Some("next compatibility release"), action: Some("use positional logical TO and the returned message id"), governance: None },
149
- CommandSpec { name: "status", tier: CommandTier::Core, category: CommandCategory::Daily, kind: CommandKind::Dispatch(DispatchKind::Status), summary: "show current team status", usage: "usage: team-agent status [AGENT] [--workspace WORKSPACE] [--team TEAM] [--summary|--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
150
- CommandSpec { name: "models", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Models), summary: "list exact provider model ids", usage: "usage: team-agent models [--provider pi|cursor_agent|codex|claude|claude_code|grok] [QUERY|--search TEXT] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
151
- CommandSpec { name: "results", tier: CommandTier::Core, category: CommandCategory::Daily, kind: CommandKind::Dispatch(DispatchKind::Results), summary: "read reported results for a case", usage: "usage: team-agent results --case CASE_ID [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
152
- CommandSpec { name: "wait", tier: CommandTier::Core, category: CommandCategory::Daily, kind: CommandKind::Dispatch(DispatchKind::Wait), summary: "block until a task result is stored", usage: "usage: team-agent wait --task TASK [--workspace WORKSPACE] [--json]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
153
- CommandSpec { name: "restart", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Restart), summary: "restart the selected team", usage: "usage: team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--session-converge-deadline SECONDS] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
154
- CommandSpec { name: "shutdown", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Shutdown), summary: "stop the selected team", usage: "usage: team-agent shutdown [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
155
- CommandSpec { name: "add-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::AddAgent), summary: "create and start a new worker", usage: "usage: team-agent add-agent AGENT [--role-file FILE] [--provider NAME] [--bypass true|false] [--model SLUG] [--effort LEVEL] [--prompt TEXT] [--profile NAME] [--force] [--workspace WORKSPACE] [--team TEAM] [--json] (provider/bypass required from CLI or role file; conflicting values rejected; force only recreates a confirmed dead registered pane)", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
156
- CommandSpec { name: "start-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StartAgent), summary: "update and start a stopped worker (stop first if running)", usage: "usage: team-agent start-agent AGENT [--model SLUG] [--effort LEVEL] [--bypass true|false] [--prompt TEXT] [--profile NAME] [--provider NAME] [--workspace WORKSPACE] [--team TEAM] [--allow-fresh] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
157
- CommandSpec { name: "stop-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StopAgent), summary: "stop a worker", usage: "usage: team-agent stop-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
158
- CommandSpec { name: "reset-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ResetAgent), summary: "reset a worker session", usage: "usage: team-agent reset-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--discard-session] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
159
- CommandSpec { name: "claim-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::ClaimLeader), summary: "bind this pane when doctor reports rebind_required", usage: "usage: team-agent claim-leader [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
160
- CommandSpec { name: "takeover", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::Takeover), summary: "replace a live leader binding with explicit consent", usage: "usage: team-agent takeover [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
161
- CommandSpec { name: "attach-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::AttachLeader), summary: "bind an external leader pane", usage: "usage: team-agent attach-leader [--workspace WORKSPACE] [--team TEAM] [--pane PANE] [--provider PROVIDER] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
162
-
163
- CommandSpec { name: "codex", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "codex" }, summary: "launch a Codex leader", usage: "usage: team-agent codex [provider args...]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
164
- CommandSpec { name: "claude", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "claude" }, summary: "launch a Claude leader", usage: "usage: team-agent claude [provider args...]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
165
- CommandSpec { name: "copilot", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "copilot" }, summary: "launch a Copilot leader", usage: "usage: team-agent copilot [provider args...]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
166
- CommandSpec { name: "grok", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "grok" }, summary: "launch a Grok leader", usage: "usage: team-agent grok [provider args...]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
167
- CommandSpec { name: "cursor", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "cursor" }, summary: "launch a Cursor leader", usage: "usage: team-agent cursor [provider args...]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
168
- CommandSpec { name: "pi", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "pi" }, summary: "launch a Pi leader", usage: "usage: team-agent pi [provider args...]", default_help: false, command_help: true, suggestion_index: true, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
169
-
170
- CommandSpec { name: "leaders", tier: CommandTier::Secondary, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Leaders), summary: "list live, stale, or ambiguous host leaders", usage: "usage: team-agent leaders [QUERY|--search TEXT] [--all|--stale] [--json] | --prune [--dry-run] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
171
- CommandSpec { name: "doctor", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Doctor), summary: "inspect environment and Team runtime health", usage: "usage: team-agent doctor [SPEC] [--workspace WORKSPACE] [--team TEAM] [--gate orphans|comms] [--comms] [--fix] [--fix-schema] [--cleanup-orphans] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
172
- CommandSpec { name: "attach-app-server-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::AttachAppServerLeader), summary: "bind an app-server leader receiver", usage: "usage: team-agent attach-app-server-leader [--workspace WORKSPACE] [--team TEAM] --socket unix:///path.sock --thread-id THREAD_ID [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
173
- CommandSpec { name: "remove-agent", tier: CommandTier::Secondary, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::RemoveAgent), summary: "remove a worker", usage: "usage: team-agent remove-agent AGENT [--workspace WORKSPACE] [--team TEAM] [--from-spec] [--confirm] [--force] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
174
- CommandSpec { name: "fork-agent", tier: CommandTier::Secondary, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ForkAgent), summary: "fork a worker", usage: "usage: team-agent fork-agent SOURCE_AGENT --as AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
175
- CommandSpec { name: "clone-agent", tier: CommandTier::Secondary, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::CloneAgent), summary: "clone a worker role into a fresh session", usage: "usage: team-agent clone-agent SOURCE_AGENT --as AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
176
- CommandSpec { name: "allow-peer-talk", tier: CommandTier::Secondary, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::AllowPeerTalk), summary: "allow direct worker peer talk", usage: "usage: team-agent allow-peer-talk A B [--workspace WORKSPACE] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: Some(GovernanceNote { decision: "secondary", reason: "capability/config surface" }) },
177
- CommandSpec { name: "approvals", tier: CommandTier::Secondary, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Approvals), summary: "inspect provider approval state", usage: "usage: team-agent approvals [AGENT] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: Some(GovernanceNote { decision: "secondary", reason: "approval diagnostics" }) },
178
- CommandSpec { name: "profile", tier: CommandTier::Secondary, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Profile), summary: "manage provider profiles", usage: "usage: team-agent profile COMMAND NAME [--workspace WORKSPACE] [--team TEAM] [--auth-mode MODE] [--proxy-mode direct|inherit] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: Some(GovernanceNote { decision: "secondary", reason: "provider/profile setup" }) },
179
- CommandSpec { name: "install-skill", tier: CommandTier::Secondary, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::InstallSkill), summary: "install or uninstall Team Agent skills", usage: "usage: team-agent install-skill (--source DIR | --uninstall) [--target codex|claude|copilot|all] [--dest DIR] [--dry-run] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: Some(GovernanceNote { decision: "secondary", reason: "capability setup" }) },
180
- CommandSpec { name: "inbox", tier: CommandTier::Secondary, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Inbox), summary: "inspect recent message summaries", usage: "usage: team-agent inbox AGENT [-n N|--limit N] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
181
-
182
- CommandSpec { name: "identity", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Identity), summary: "inspect identity metadata", usage: "usage: team-agent identity [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
183
- CommandSpec { name: "watch", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Watch), summary: "watch event logs", usage: "usage: team-agent watch [--workspace WORKSPACE] [--team TEAM]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
184
- CommandSpec { name: "sessions", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Sessions), summary: "inspect session inventory", usage: "usage: team-agent sessions [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
185
- CommandSpec { name: "validate", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Validate), summary: "validate a team spec", usage: "usage: team-agent validate [SPEC] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
186
- CommandSpec { name: "preflight", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Preflight), summary: "run preflight checks", usage: "usage: team-agent preflight [TEAMDIR] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
187
- CommandSpec { name: "wait-ready", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::WaitReady), summary: "wait for runtime readiness", usage: "usage: team-agent wait-ready [--workspace WORKSPACE] [--team TEAM] [--timeout SECONDS] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
188
- CommandSpec { name: "e2e", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::E2e), summary: "run e2e harness", usage: "usage: team-agent e2e [--workspace WORKSPACE] [--providers LIST] [--real] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::Yes, sunset: None, action: None, governance: None },
189
- CommandSpec { name: "peek", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Peek), summary: "capture low-level terminal output", usage: "usage: team-agent peek AGENT [--workspace WORKSPACE] [--tail N|--head N] [--search TEXT] [--allow-raw-screen] [--json]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
190
- CommandSpec { name: "coordinator", tier: CommandTier::DevInternal, category: CommandCategory::Dev, kind: CommandKind::Dispatch(DispatchKind::Coordinator), summary: "run the coordinator daemon", usage: "usage: team-agent coordinator [--workspace WORKSPACE] [--once] [--tick-interval SECONDS]", default_help: false, command_help: true, suggestion_index: false, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
111
+ CommandSpec { name: "quick-start", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::QuickStart), summary: "从角色文件启动队伍,或查看已有队伍的连接方式", usage: "team-agent quick-start [TEAMDIR] [--workspace WORKSPACE] [--team TEAM] [--name NAME] [--team-id TEAM] [--yes] [--backend tmux|conpty] [--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
112
+ CommandSpec { name: "send", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Send), summary: "向指定队友派发任务", usage: "team-agent send <agent> MESSAGE... [--workspace WORKSPACE] [--team TEAM] [--mailbox] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: Some("后续兼容版本"), action: Some("使用 team-agent send <agent> '任务内容',用 --workspace 和 --team 选择队伍"), governance: None },
113
+ CommandSpec { name: "status", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Status), summary: "查看队友状态,不读取队友的对话内容", usage: "team-agent status [<agent>] [--workspace WORKSPACE] [--team TEAM] [--json] [--summary|--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
114
+ CommandSpec { name: "models", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Models), summary: "查找工具实际支持的模型名称", usage: "team-agent models [--provider pi|cursor_agent|codex|claude|claude_code|grok] [QUERY|--search TEXT] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
115
+ CommandSpec { name: "inbox", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Inbox), summary: "查看队友回复", usage: "team-agent inbox <agent> [-n N|--limit N] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
116
+ CommandSpec { name: "restart", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Restart), summary: "恢复已有队伍,优先沿用已保存的会话", usage: "team-agent restart [WORKSPACE] [--team TEAM] [--allow-fresh] [--session-converge-deadline SECONDS] [--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
117
+ CommandSpec { name: "shutdown", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Shutdown), summary: "关闭指定队伍,并查看是否仍有残留资源", usage: "team-agent shutdown [--workspace WORKSPACE] [--team TEAM] [--keep-logs] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
118
+ CommandSpec { name: "add-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::AddAgent), summary: "新增并启动一位队友", usage: "team-agent add-agent <agent> [--role-file FILE] [--provider TOOL] [--model MODEL] [--effort LEVEL] [--bypass true|false] [--prompt TEXT] [--profile NAME] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
119
+ CommandSpec { name: "start-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StartAgent), summary: "启动队伍中已有的队友", usage: "team-agent start-agent <agent> [--provider TOOL] [--model MODEL] [--effort LEVEL] [--bypass true|false] [--prompt TEXT] [--profile NAME] [--workspace WORKSPACE] [--team TEAM] [--allow-fresh] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
120
+ CommandSpec { name: "stop-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StopAgent), summary: "暂停一位队友,保留其配置和会话记录", usage: "team-agent stop-agent <agent> [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
121
+ CommandSpec { name: "reset-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ResetAgent), summary: "清除队友保存的会话关联", usage: "team-agent reset-agent <agent> --discard-session [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
122
+ CommandSpec { name: "clone-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::CloneAgent), summary: "复制队友配置,创建新队友", usage: "team-agent clone-agent <agent> --as NEW_AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
123
+ CommandSpec { name: "fork-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ForkAgent), summary: "在工具支持的条件下从队友会话分出新队友", usage: "team-agent fork-agent <agent> --as NEW_AGENT [--label LABEL] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
124
+ CommandSpec { name: "remove-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::RemoveAgent), summary: "确认后移除一位队友", usage: "team-agent remove-agent <agent> --confirm [--workspace WORKSPACE] [--team TEAM] [--from-spec] [--force] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
125
+ CommandSpec { name: "leaders", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Leaders), summary: "查看本机可用的主控及其所属队伍", usage: "team-agent leaders [QUERY|--search TEXT] [--all|--stale] [--json] | --prune [--dry-run] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
126
+ CommandSpec { name: "doctor", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Doctor), summary: "检查队伍并给出恢复建议,默认不修复", usage: "team-agent doctor [SPEC] [--workspace WORKSPACE] [--team TEAM] [--comms] [--gate orphans|comms] [--fix] [--fix-schema] [--cleanup-orphans] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
127
+ CommandSpec { name: "approvals", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Approvals), summary: "查看队友正在等待的权限确认", usage: "team-agent approvals [<agent>] [--workspace WORKSPACE] [--team TEAM] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
128
+ CommandSpec { name: "allow-peer-talk", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::AllowPeerTalk), summary: "允许两位队友直接交流", usage: "team-agent allow-peer-talk <agent> OTHER_AGENT [--workspace WORKSPACE] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
129
+ CommandSpec { name: "route", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Route), summary: "设置工具启动时额外使用的命令行参数", usage: "team-agent route [status|enable|disable|show [TOOL]|set TOOL -- ARG...|add TOOL -- ARG...|clear TOOL] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
130
+ CommandSpec { name: "profile", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Profile), summary: "管理登录方式和代理设置", usage: "team-agent profile init|doctor|show NAME [--workspace WORKSPACE] [--team TEAM] [--auth-mode MODE] [--proxy-mode direct|inherit] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
131
+ CommandSpec { name: "install-skill", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::InstallSkill), summary: "可选:安装已有的公开操作指南", usage: "team-agent install-skill (--source DIR|--uninstall) [--target codex|claude|copilot|all] [--dest DIR] [--dry-run] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
132
+ CommandSpec { name: "claim-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::ClaimLeader), summary: "仅按体检提示,将当前终端登记为主控", usage: "team-agent claim-leader [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json] [--detail]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
133
+ CommandSpec { name: "takeover", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::Takeover), summary: "仅按体检提示,确认后接管现有队伍", usage: "team-agent takeover [--workspace WORKSPACE] [--team TEAM] [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
134
+ CommandSpec { name: "attach-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::AttachLeader), summary: "仅按体检提示,将已核验的终端连接为主控", usage: "team-agent attach-leader [--workspace WORKSPACE] [--team TEAM] --pane PANE --provider TOOL [--confirm] [--json]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::No, sunset: None, action: None, governance: None },
135
+ CommandSpec { name: "pi", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "pi" }, summary: "用 Pi 打开主控对话", usage: "team-agent pi [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
136
+ CommandSpec { name: "codex", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "codex" }, summary: "用 Codex 打开主控对话", usage: "team-agent codex [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
137
+ CommandSpec { name: "claude", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "claude" }, summary: "用 Claude Code 打开主控对话", usage: "team-agent claude [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
138
+ CommandSpec { name: "copilot", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "copilot" }, summary: "用 Copilot 打开主控对话", usage: "team-agent copilot [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
139
+ CommandSpec { name: "grok", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "grok" }, summary: "用 Grok 打开主控对话", usage: "team-agent grok [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
140
+ CommandSpec { name: "cursor", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "cursor_agent" }, summary: "用 Cursor 的 agent 工具打开主控对话", usage: "team-agent cursor [--attach-existing] [--confirm] [--attach-session SESSION] [--external-leader] [--allow-nested-attach] [--json] [-- TOOL_ARGS...]", default_help: true, command_help: true, suggestion_index: true, token_usage: TokenUsage::Conditional, sunset: None, action: None, governance: None },
191
141
  ];
192
142
 
193
143
  pub(crate) fn command_spec(name: &str) -> Option<&'static CommandSpec> {