@team-agent/installer 0.5.112 → 0.5.113

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 (44) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +100 -44
  4. package/crates/team-agent/src/cli/emit.rs +127 -98
  5. package/crates/team-agent/src/cli/leaders.rs +32 -32
  6. package/crates/team-agent/src/cli/mod.rs +6 -6
  7. package/crates/team-agent/src/cli/named_address.rs +17 -16
  8. package/crates/team-agent/src/cli/route.rs +4 -4
  9. package/crates/team-agent/src/cli/send/presentation.rs +19 -18
  10. package/crates/team-agent/src/cli/send/resolve.rs +11 -11
  11. package/crates/team-agent/src/cli/send.rs +4 -4
  12. package/crates/team-agent/src/cli/spec.rs +29 -29
  13. package/crates/team-agent/src/cli/status.rs +7 -7
  14. package/crates/team-agent/src/cli/tests/base.rs +6 -6
  15. package/crates/team-agent/src/cli/tests/divergence.rs +3 -2
  16. package/crates/team-agent/src/cli/tests/lane_c.rs +1 -1
  17. package/crates/team-agent/src/cli/tests/named_address.rs +3 -3
  18. package/crates/team-agent/src/cli/tests/status_send.rs +7 -7
  19. package/crates/team-agent/src/cli/triage.rs +53 -2
  20. package/crates/team-agent/src/cli/types.rs +8 -8
  21. package/crates/team-agent/src/compiler/tests.rs +12 -0
  22. package/crates/team-agent/src/compiler.rs +0 -9
  23. package/crates/team-agent/src/leader/start.rs +5 -0
  24. package/crates/team-agent/src/leader/tests/identity.rs +21 -0
  25. package/crates/team-agent/src/lifecycle/launch/identity.rs +172 -13
  26. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +325 -14
  27. package/crates/team-agent/src/lifecycle/launch.rs +2 -2
  28. package/crates/team-agent/src/lifecycle/profile_launch.rs +58 -46
  29. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +97 -52
  30. package/crates/team-agent/src/lifecycle/restart.rs +1 -1
  31. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +3 -2
  32. package/crates/team-agent/src/provider/adapter.rs +8 -59
  33. package/crates/team-agent/src/provider/adapters/claude.rs +6 -14
  34. package/crates/team-agent/src/provider/adapters/codex.rs +8 -18
  35. package/crates/team-agent/src/provider/adapters/copilot.rs +5 -22
  36. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +8 -45
  37. package/crates/team-agent/src/provider/adapters/grok.rs +7 -31
  38. package/crates/team-agent/src/provider/adapters/pi.rs +7 -18
  39. package/crates/team-agent/src/provider/command_helpers.rs +45 -0
  40. package/crates/team-agent/src/provider/mod.rs +1 -0
  41. package/crates/team-agent/src/provider/model_catalog.rs +21 -28
  42. package/crates/team-agent/src/provider/tests/adapter.rs +70 -0
  43. package/crates/team-agent/src/provider/tests/command_helpers.rs +55 -0
  44. package/package.json +4 -4
@@ -124,7 +124,7 @@ fn send_hint(entry: &LeaderRegistryEntry) -> String {
124
124
  format!(
125
125
  "team-agent send {} {}",
126
126
  quote_cli_arg(&to),
127
- quote_cli_arg("消息")
127
+ quote_cli_arg("message")
128
128
  )
129
129
  }
130
130
 
@@ -183,19 +183,19 @@ fn format_leaders_human(rows: &[LeaderRow], view: LeadersView) -> String {
183
183
  if rows.is_empty() {
184
184
  return match view {
185
185
  LeadersView::Live => {
186
- "没有可用主控;运行 team-agent doctor --workspace . 检查当前队伍。\n".to_string()
186
+ "No live leaders. Run team-agent doctor --workspace . for the current team.\n".to_string()
187
187
  }
188
- LeadersView::All => "没有已登记主控;首次协作用 team-agent pi 打开主控。\n".to_string(),
189
- LeadersView::Stale => "没有已失效的主控登记。\n".to_string(),
188
+ LeadersView::All => "No registered leaders. Open a leader with team-agent pi for first-time collaboration.\n".to_string(),
189
+ LeadersView::Stale => "No stale leader registrations.\n".to_string(),
190
190
  };
191
191
  }
192
- let mut out = String::from("主控\t状态\t项目\t队伍\t发送命令\n");
192
+ let mut out = String::from("leader\tstatus\tworkspace\tteam\tsend command\n");
193
193
  for row in rows {
194
194
  out.push_str("leader\t");
195
195
  out.push_str(match row.status {
196
- "LIVE" => "可用",
197
- "STALE" => "已失效",
198
- "AMBIGUOUS" => "需确认归属",
196
+ "LIVE" => "LIVE",
197
+ "STALE" => "STALE",
198
+ "AMBIGUOUS" => "AMBIGUOUS",
199
199
  other => other,
200
200
  });
201
201
  out.push('\t');
@@ -212,7 +212,7 @@ fn format_leaders_human(rows: &[LeaderRow], view: LeadersView) -> String {
212
212
  &row.entry.workspace,
213
213
  Some(&row.entry.team_key),
214
214
  )
215
- .unwrap_or_else(|| "请核对项目路径".to_string()),
215
+ .unwrap_or_else(|| "Verify the workspace path".to_string()),
216
216
  );
217
217
  }
218
218
  out.push('\n');
@@ -240,33 +240,33 @@ fn prune_json(report: &RegistryPruneReport) -> Value {
240
240
  }
241
241
 
242
242
  fn format_prune_human(report: &RegistryPruneReport) -> String {
243
- let mut out = format!("仅预览:{}\n", report.dry_run);
243
+ let mut out = format!("dry_run: {}\n", report.dry_run);
244
244
  for (label, items) in [
245
- ("可清理登记", &report.candidates),
246
- ("已清理", &report.removed),
247
- ("保留", &report.kept),
248
- ("跳过", &report.skipped),
249
- ("错误", &report.errors),
245
+ ("candidates", &report.candidates),
246
+ ("removed", &report.removed),
247
+ ("kept", &report.kept),
248
+ ("skipped", &report.skipped),
249
+ ("errors", &report.errors),
250
250
  ] {
251
251
  out.push_str(&format!("{label}: {}\n", items.len()));
252
252
  for item in items {
253
253
  out.push_str(" ");
254
254
  out.push_str(&item.workspace.display().to_string());
255
- out.push_str(",队伍:");
255
+ out.push_str(", team: ");
256
256
  out.push_str(&item.team_key);
257
257
  out.push_str(" [");
258
258
  out.push_str(match item.reason.as_str() {
259
- "LIVE" => "仍可用,保留登记",
260
- "team_key_not_found" => "队伍已不在项目中",
261
- "team_not_alive" => "队伍已停止",
262
- "registry_entry_missing" => "登记已不存在",
259
+ "LIVE" => "still live; registration retained",
260
+ "team_key_not_found" => "team no longer exists in the workspace",
261
+ "team_not_alive" => "team is stopped",
262
+ "registry_entry_missing" => "registration no longer exists",
263
263
  "registry_entry_changed" | "canonical_state_changed" => {
264
- "登记或队伍已变化,停止清理"
264
+ "registration or team changed; cleanup refused"
265
265
  }
266
- "canonical_state_unavailable" => "无法读取队伍状态,保留登记",
267
- "registry_lock_unavailable" => "登记正被其他操作使用,停止清理",
268
- "remove_failed" => "删除登记失败,请查看文件权限",
269
- _ => "无法安全确认该登记;请体检所选项目",
266
+ "canonical_state_unavailable" => "team state unavailable; registration retained",
267
+ "registry_lock_unavailable" => "registry lock unavailable; cleanup refused",
268
+ "remove_failed" => "registration removal failed; inspect file permissions",
269
+ _ => "registration could not be verified safely; diagnose the selected workspace",
270
270
  });
271
271
  out.push_str("]\n");
272
272
  }
@@ -337,13 +337,13 @@ mod tests {
337
337
  assert_eq!(lines.len(), 3, "one header and both selected rows: {out}");
338
338
  let header = lines[0];
339
339
  assert_eq!(header.split('\t').count(), 5);
340
- assert!(header.contains("状态") && header.contains("项目") && header.contains("队伍"));
340
+ assert!(header.contains("status") && header.contains("workspace") && header.contains("team"));
341
341
  let live: Vec<_> = lines[1].split('\t').collect();
342
342
  assert_eq!(
343
343
  &live[..4],
344
344
  &[
345
345
  "leader",
346
- "可用",
346
+ "LIVE",
347
347
  "/Volumes/nvme/Projects/讨论team-agent",
348
348
  "wiki-team"
349
349
  ]
@@ -354,7 +354,7 @@ mod tests {
354
354
  "team-agent",
355
355
  "send",
356
356
  "leader",
357
- "请完成任务并把答案回复给 leader。",
357
+ "Complete the task and reply to the leader.",
358
358
  "--workspace",
359
359
  "/Volumes/nvme/Projects/讨论team-agent",
360
360
  "--team",
@@ -364,7 +364,7 @@ mod tests {
364
364
  let stale: Vec<_> = lines[2].split('\t').collect();
365
365
  assert_eq!(
366
366
  &stale[..4],
367
- &["leader", "已失效", "/Users/alauda/stale", "old-team"]
367
+ &["leader", "STALE", "/Users/alauda/stale", "old-team"]
368
368
  );
369
369
  assert_eq!(stale[4], "-", "stale rows must never suggest a send: {out}");
370
370
  }
@@ -404,9 +404,9 @@ mod tests {
404
404
  #[test]
405
405
  fn empty_view_names_are_explicit() {
406
406
  for (view, empty, next) in [
407
- (LeadersView::Live, "没有可用主控", Some("team-agent doctor")),
408
- (LeadersView::Stale, "没有已失效的主控登记", None),
409
- (LeadersView::All, "没有已登记主控", Some("team-agent pi")),
407
+ (LeadersView::Live, "No live leaders", Some("team-agent doctor")),
408
+ (LeadersView::Stale, "No stale leader registrations", None),
409
+ (LeadersView::All, "No registered leaders", Some("team-agent pi")),
410
410
  ] {
411
411
  let out = format_leaders_human(&[], view);
412
412
  assert!(out.contains(empty) && out.ends_with('\n'), "{out}");
@@ -49,12 +49,12 @@ use crate::messaging::{self, MessageTarget, SendOptions, TrustedSender};
49
49
  use crate::model::ids::{TaskId, TeamKey};
50
50
 
51
51
  pub(crate) const COMMS_BOUNDARY_TEXT: &str =
52
- "这里只检查终端连接是否一致,不实际发送消息,也不证明队友已回复。";
53
- pub(crate) const QUICK_START_REMINDER: &str = "下一步:向队友派发任务;用 team-agent status 看状态,用 team-agent inbox leader -n 3 看回复,不读取队友终端内容。";
52
+ "This checks terminal connection consistency only; it does not send a message or prove that a worker replied.";
53
+ pub(crate) const QUICK_START_REMINDER: &str = "Next: send a task. Use team-agent status for status and team-agent inbox leader -n 3 for replies; do not inspect worker terminal content.";
54
54
  pub(crate) const SEND_REMINDER: &str =
55
- "等队友真正回复,用 team-agent inbox leader -n 3 查看;不要读取队友终端内容。";
55
+ "Wait for an actual reply; use team-agent inbox leader -n 3. Do not inspect worker terminal content.";
56
56
  pub(crate) const STATUS_REMINDER: &str =
57
- "下一步:用 team-agent inbox leader -n 3 查看回复;状态不是任务完成证明,不读取队友终端内容。";
57
+ "Next: use team-agent inbox leader -n 3 for replies. Status is not proof of task completion; do not inspect worker terminal content.";
58
58
 
59
59
  pub mod adapters;
60
60
  pub mod attach_app_server_leader;
@@ -4176,7 +4176,7 @@ pub mod lifecycle_port {
4176
4176
  "team-agent".to_string(),
4177
4177
  "send".to_string(),
4178
4178
  "implementer".to_string(),
4179
- "请完成任务并把答案回复给 leader。".to_string(),
4179
+ "Complete the task and reply to the leader.".to_string(),
4180
4180
  "--workspace".to_string(),
4181
4181
  team_dir.to_string_lossy().into_owned(),
4182
4182
  "--team".to_string(),
@@ -4213,7 +4213,7 @@ pub mod lifecycle_port {
4213
4213
  "team-agent".to_string(),
4214
4214
  "send".to_string(),
4215
4215
  "implementer".to_string(),
4216
- "请完成任务并把答案回复给 leader。".to_string(),
4216
+ "Complete the task and reply to the leader.".to_string(),
4217
4217
  "--workspace".to_string(),
4218
4218
  team_dir.to_string_lossy().into_owned(),
4219
4219
  "--team".to_string(),
@@ -78,16 +78,16 @@ pub(crate) struct NamedAddressError {
78
78
 
79
79
  pub(crate) fn human_address_reason(reason: &str) -> Option<&'static str> {
80
80
  Some(match reason {
81
- "name_invalid" => "收信队友名不正确;请使用队友列表中的名称。",
82
- "workspace_not_found" => "所选项目目录不存在;请核对项目路径。",
81
+ "name_invalid" => "Invalid recipient name; use a name from the agent list.",
82
+ "workspace_not_found" => "The selected workspace directory does not exist; verify the path.",
83
83
  "state_not_found" | "workspace_no_state" => {
84
- "所选项目还没有可用队伍;首次起队用 quick-start,已有队伍恢复用 restart。"
84
+ "No usable team exists in the selected workspace; use quick-start for initial creation or restart for an initialized team."
85
85
  }
86
- "team_key_not_found" => "所选项目没有这支队伍;请核对 --workspace 和 --team。",
87
- "leader_not_attached" => "主控还没有连接到这支队伍;请先体检,按提示恢复连接。",
88
- "name_not_resolvable" => "当前队伍没有这个队友;请先查看队友列表。",
89
- "name_not_live" => "该队友当前未运行或连接已失效;请查看状态再恢复。",
90
- "name_ambiguous" => "有多个同名对象;请明确选择项目和队伍,不猜对象。",
86
+ "team_key_not_found" => "The selected workspace has no such team; verify --workspace and --team.",
87
+ "leader_not_attached" => "No leader is attached to this team; diagnose it and follow the recovery action.",
88
+ "name_not_resolvable" => "This team has no such agent; check the agent list.",
89
+ "name_not_live" => "The agent is not running or its channel is stale; check status before recovery.",
90
+ "name_ambiguous" => "Multiple targets share this name; select an explicit workspace and team.",
91
91
  _ => return None,
92
92
  })
93
93
  }
@@ -121,23 +121,24 @@ impl NamedAddressError {
121
121
  pub(crate) fn human_guidance(&self, requested: &str) -> (String, String) {
122
122
  let workspace = self.human_scope.as_deref();
123
123
  let mut message = format!(
124
- "{}\n你刚才填写的是 {requested:?}。",
125
- human_address_reason(self.kind.as_str()).unwrap_or("未能找到可用的收信队友。")
124
+ "{}\nRequested recipient: {requested:?}\nReason: {}",
125
+ human_address_reason(self.kind.as_str()).unwrap_or("No usable recipient could be resolved."),
126
+ self.message
126
127
  );
127
128
  if let Some(workspace) = workspace {
128
- message.push_str(&format!("\n所选项目:{:?}。", workspace.to_string_lossy()));
129
+ message.push_str(&format!("\nSelected workspace: {:?}", workspace.to_string_lossy()));
129
130
  }
130
131
  if let Some(team) = self.human_team.as_deref() {
131
- message.push_str(&format!("\n所选队伍:{team:?}。"));
132
+ message.push_str(&format!("\nSelected team: {team:?}"));
132
133
  }
133
- let mut action = "没有可靠的拼写建议;请先核对项目和队伍,不猜对象。".to_string();
134
+ let mut action = "No reliable spelling suggestion is available; verify the workspace and team before choosing a target.".to_string();
134
135
  for candidate in &self.candidates {
135
136
  if let (Some(agent), Some(team)) = (
136
137
  candidate.get("agent_id").and_then(Value::as_str),
137
138
  candidate.get("team_key").and_then(Value::as_str),
138
139
  ) {
139
140
  message.push_str(&format!(
140
- "\n候选队伍 {team:?},队友 {agent:?};请确认是否是你要找的对象。"
141
+ "\nCandidate team {team:?}, agent {agent:?}; confirm the intended target."
141
142
  ));
142
143
  }
143
144
  }
@@ -162,7 +163,7 @@ impl NamedAddressError {
162
163
  if let Some(command) =
163
164
  super::adapters::send_command(agent, workspace, Some(team))
164
165
  {
165
- action = format!("你是否想发给 {agent:?}、队伍 {team:?}?确认后将任务内容替换到这个例子;本次没有发送:\n{command}");
166
+ action = format!("Did you mean agent {agent:?} in team {team:?}? After confirmation, replace the example message below. Nothing was sent:\n{command}");
166
167
  }
167
168
  }
168
169
  }
@@ -171,7 +172,7 @@ impl NamedAddressError {
171
172
  workspace.filter(|path| !path.to_string_lossy().chars().any(char::is_control))
172
173
  {
173
174
  action.push_str(&format!(
174
- "\n也可查看可用队友列表:\nteam-agent status --workspace {}",
175
+ "\nList available agents with:\nteam-agent status --workspace {}",
175
176
  super::adapters::shell_quote(&workspace.to_string_lossy())
176
177
  ));
177
178
  }
@@ -5,7 +5,7 @@ use crate::provider::argv_route::{self, Config, Mutation, Override, RouteError};
5
5
  use crate::provider::Provider;
6
6
  use serde_json::{json, Value};
7
7
 
8
- pub(crate) const HELP: &str = "做什么:\n设置工具启动时额外使用的命令行参数,默认关闭。\n用法:team-agent route [status|enable|disable|show [TOOL]|set TOOL -- ARG...|add TOOL -- ARG...|clear TOOL] [--json]\n\n怎么用:\nstatus 看开关;enable 开启;disable 关闭;show 看全部或指定工具的参数。\nset 替换参数;add 追加参数;clear 清除指定工具的参数;--json 给程序读取。\nTOOL 是已支持的工具名称,如 pi/codex/claude/copilot/grok/cursor_agent。\n第一个 -- 后全是工具的字面参数,包含 --help/--json 也不会被这里解析。\n配置保存在 ~/.team-agent/argv-routing.json;影响全机,不按项目或队伍隔离。\nTEAM_AGENT_CLI_ARGV_ROUTING 环境变量优先于保存的开关。\nExamples(可复制):\nteam-agent route status\nteam-agent route set pi -- --mode text\nteam-agent route enable\n\n下一步(Next Action):\n用 route show pi 核对参数;仅影响下一次启动,不改变正在运行的对话。\n没有开启或没有配置时,工具仍按原参数启动;不了解参数用途时保持关闭。";
8
+ pub(crate) const HELP: &str = "Purpose:\nConfigure additional provider launch arguments. Disabled by default.\nUsage: team-agent route [status|enable|disable|show [TOOL]|set TOOL -- ARG...|add TOOL -- ARG...|clear TOOL] [--json]\n\nOptions:\nstatus reports the switch; enable/disable change it; show lists all or one provider's arguments.\nset replaces arguments; add appends; clear removes a provider's arguments. Use --json for structured output.\nTOOL is a supported provider name, such as pi/codex/claude/copilot/grok/cursor_agent.\nEverything after the first -- is a literal provider argument, including --help and --json.\nConfiguration: ~/.team-agent/argv-routing.json. This is host-global, not isolated by workspace or team.\nTEAM_AGENT_CLI_ARGV_ROUTING overrides the persisted switch.\nExamples:\nteam-agent route status\nteam-agent route set pi -- --mode text\nteam-agent route enable\n\nNext Action:\nVerify arguments with route show pi. Changes apply to the next launch, not an existing session.\nWithout an enabled configuration, providers retain their original arguments. Leave routing disabled unless the arguments are understood.";
9
9
 
10
10
  struct Request {
11
11
  operation: String,
@@ -16,9 +16,9 @@ struct Request {
16
16
 
17
17
  fn usage() -> RouteError {
18
18
  RouteError {
19
- error: "参数不完整或不正确;set/add 需要工具名、-- 和至少一个工具参数".to_string(),
19
+ error: "Invalid or incomplete arguments; set/add require a provider name, -- and at least one provider argument".to_string(),
20
20
  reason: "argv_route_usage",
21
- action: "请按 team-agent route --help 的 Examples 填写;例如 team-agent route set pi -- --mode text".to_string(),
21
+ action: "Follow the Examples in team-agent route --help, such as team-agent route set pi -- --mode text".to_string(),
22
22
  config_path: None,
23
23
  }
24
24
  }
@@ -118,7 +118,7 @@ fn execute(request: &Request) -> Result<Value, RouteError> {
118
118
  }
119
119
  if override_state != Override::Unset {
120
120
  value["notice"] = json!(format!(
121
- "当前开关由环境变量 {} 决定({})",
121
+ "Switch overridden by environment variable {} ({})",
122
122
  argv_route::ENV_NAME,
123
123
  override_state.status()
124
124
  ));
@@ -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 inbox leader -n 3 查看。"
23
+ "notice": "The leader is notified when the agent replies; use team-agent inbox leader -n 3."
24
24
  })
25
25
  }
26
26
 
@@ -188,50 +188,51 @@ pub(super) fn send_human_output(value: &Value) -> String {
188
188
  let reason = value.get("reason").and_then(Value::as_str).unwrap_or("");
189
189
  let explanation =
190
190
  crate::cli::named_address::human_address_reason(reason).unwrap_or(match reason {
191
- "target_not_in_team" | "unknown_recipient" => "当前队伍没有这个队友。",
191
+ "target_not_in_team" | "unknown_recipient" => "The selected team has no such agent.",
192
192
  "missing_permissions" | "human_confirmation_required" => {
193
- "发送被拒绝:需要先确认交流权限。"
193
+ "Send refused: communication permission or human confirmation is required."
194
194
  }
195
195
  "recipient_busy" | "recipient_pane_in_non_input_mode" => {
196
- "队友当前不能接收任务;请先查看其状态。"
196
+ "The agent cannot receive a task now; check its status."
197
197
  }
198
198
  "routing_ambiguous" | "empty_target_list" | "ambiguous" => {
199
- "没有明确选定收信队友;请填写队友名和任务内容。"
199
+ "No recipient was selected unambiguously; provide an agent name and task message."
200
200
  }
201
201
  "team_owner_mismatch" | "PaneWorkspaceMismatch" | "session_drift" => {
202
- "队伍或终端归属不匹配;已停止发送。"
202
+ "Team or pane ownership mismatch; sending was refused."
203
203
  }
204
204
  "coordinator_unavailable" | "tmux_target_missing" => {
205
- "队伍连接暂不可用;本次没有确认送达。"
205
+ "The team channel is unavailable; delivery was not confirmed."
206
206
  }
207
207
  "message_already_claimed" | "duplicate" => {
208
- "这条消息已由其他发送处理接收;不要重复发送。"
208
+ "This message is already claimed or duplicated; do not resend."
209
209
  }
210
- "no_caller_pane" => "当前终端没有可用的队伍连接;请在主控的命令行/工具上下文发送。",
210
+ "no_caller_pane" => "The current terminal has no usable team channel; send from the leader's tool context.",
211
211
  _ => value
212
212
  .get("error")
213
213
  .and_then(Value::as_str)
214
- .unwrap_or("发送未成功;没有确认任务已送达。"),
214
+ .unwrap_or("Send was unsuccessful; task delivery was not confirmed."),
215
215
  });
216
- let mut out = format!("{explanation}\n下一步:先运行 team-agent status,使用列表中的队友名;连接问题用 team-agent doctor --workspace .。不要反复重发。");
216
+ let details = crate::cli::triage::diagnostic_details(value);
217
+ let mut out = format!("{explanation}\nReport: {details}\nAdditional diagnosis: use team-agent status for agent names or team-agent doctor --workspace . for channel problems. Do not resend repeatedly.");
217
218
  if let Some(suggested) = value
218
219
  .get("suggested_name")
219
220
  .and_then(Value::as_str)
220
221
  .filter(|name| !name.is_empty() && !name.contains(['/', ':', ',', '\n', '\r']))
221
222
  {
222
223
  out.push_str(&format!(
223
- "\n你是否想发给 {suggested}?确认后使用这个队友名。"
224
+ "\nDid you mean {suggested}? Confirm before using that agent name."
224
225
  ));
225
226
  }
226
227
  return out;
227
228
  }
228
229
  if value.get("status").and_then(Value::as_str) == Some("stored_only") {
229
- return format!("已给{agent}留下消息;本次没有发送到当前对话。\n下一步:用 team-agent inbox leader -n 3 查看回复;留言不保证自动执行。");
230
+ return format!("Message stored for {agent}; it was not injected into the current conversation.\nNext: use team-agent inbox leader -n 3 for replies. Mailbox storage does not guarantee execution.");
230
231
  }
231
232
  if value.get("delivered").and_then(Value::as_bool) == Some(true) {
232
- format!("已发给{agent}。{}", crate::cli::SEND_REMINDER)
233
+ format!("Delivered to {agent}. {}", crate::cli::SEND_REMINDER)
233
234
  } else {
234
- "任务已收下,但还未送到队友的对话。\n下一步:查看 team-agent status 或 team-agent doctor --workspace .,等真实回复,不反复重发。".to_string()
235
+ "Task accepted, but delivery to the agent's conversation is still pending.\nNext: check team-agent status or team-agent doctor --workspace .; wait for an actual reply without repeated sends.".to_string()
235
236
  }
236
237
  }
237
238
 
@@ -251,7 +252,7 @@ pub(super) fn send_human_target(value: &Value) -> String {
251
252
  !name.is_empty() && *name != "*" && !name.contains(['/', ':', ',', '\n', '\r'])
252
253
  })
253
254
  .map(str::to_string)
254
- .unwrap_or_else(|| "该队友".to_string())
255
+ .unwrap_or_else(|| "the recipient".to_string())
255
256
  }
256
257
 
257
258
  pub(super) fn send_human_status(value: &Value) -> String {
@@ -286,11 +287,11 @@ pub(super) fn send_reminder_for_value(value: &Value) -> &'static str {
286
287
  let status = value.get("status").and_then(Value::as_str);
287
288
  let delivery_status = value.get("delivery_status").and_then(Value::as_str);
288
289
  if status == Some("stored_only") {
289
- "本次只留言,没有发送到当前对话;留言不保证自动执行。"
290
+ "Mailbox-only: not injected into the current conversation; storage does not guarantee execution."
290
291
  } else if delivered == Some(true) && delivery_status != Some("pending") {
291
292
  crate::cli::SEND_REMINDER
292
293
  } else {
293
- "任务已收下,但还未确认送到队友对话。查看 team-agent status/doctor,等真实回复,不反复重发。"
294
+ "Task accepted, but delivery is unconfirmed. Check team-agent status/doctor; wait for an actual reply without repeated sends."
294
295
  }
295
296
  }
296
297
 
@@ -7,11 +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.and_then(|spec| spec.sunset).unwrap_or("后续兼容版本");
10
+ let sunset = spec.and_then(|spec| spec.sunset).unwrap_or("a future compatibility release");
11
11
  let action = spec.and_then(|spec| spec.action).unwrap_or(
12
- "使用 team-agent send <agent> '任务内容',通过 --workspace/--team 选择项目和队伍",
12
+ "Use team-agent send <agent> 'task message'; select the workspace and team with --workspace/--team",
13
13
  );
14
- eprintln!("提示:{flag} 已弃用,将在{sunset}移除。下一步:{action}");
14
+ eprintln!("Warning: {flag} is deprecated and will be removed in {sunset}. Next: {action}");
15
15
  }
16
16
 
17
17
  pub(super) fn logical_to_from_args(
@@ -22,7 +22,7 @@ pub(super) fn logical_to_from_args(
22
22
  && (args.target.is_some() || args.targets.is_some() || args.to_leader.is_some())
23
23
  {
24
24
  return Err(CliError::Usage(
25
- "队友名与 --to-name/--pane/--to 不能同时使用;请只选一种收信方式".to_string(),
25
+ "An agent name cannot be combined with --to-name/--pane/--to; choose one addressing mode".to_string(),
26
26
  ));
27
27
  }
28
28
  let supplied = [
@@ -36,7 +36,7 @@ pub(super) fn logical_to_from_args(
36
36
  .count();
37
37
  if supplied > 1 {
38
38
  return Err(CliError::Usage(
39
- "队友名、--targets、--to-name 和 --to-leader 不能同时使用;请只选一种收信方式"
39
+ "An agent name, --targets, --to-name and --to-leader are mutually exclusive; choose one addressing mode"
40
40
  .to_string(),
41
41
  ));
42
42
  }
@@ -52,11 +52,11 @@ pub(super) fn logical_to_from_args(
52
52
  if args.target.is_none() && supplied > 0 && args.message.is_empty() {
53
53
  if args.to_name.is_some() {
54
54
  return Err(CliError::Usage(
55
- "请填写任务内容;--to-name 不能发送空消息".to_string(),
55
+ "Provide a task message; --to-name cannot send an empty message".to_string(),
56
56
  ));
57
57
  }
58
58
  return Err(CliError::Usage(
59
- "请在队友名后填写非空任务内容;例如 team-agent send worker '检查改动'".to_string(),
59
+ "Provide a nonempty task message after the agent name, such as team-agent send worker 'Review the changes'".to_string(),
60
60
  ));
61
61
  }
62
62
  Ok(logical_to)
@@ -182,7 +182,7 @@ pub(super) fn send_to_logical_to(
182
182
  .collect::<Vec<_>>();
183
183
  if names.is_empty() || names.len() != logical_to.split(',').count() {
184
184
  return Err(CliError::Usage(
185
- "收信列表中有空的队友名;请使用 status 返回的名称".to_string(),
185
+ "The recipient list contains an empty agent name; use names returned by status".to_string(),
186
186
  ));
187
187
  }
188
188
 
@@ -322,7 +322,7 @@ pub(super) fn adapt_positional_bare_error(
322
322
  .and_then(|suggested| suggested.rsplit('/').next())
323
323
  .map(str::to_string);
324
324
  if let Some(suggested) = error.suggested_name.as_deref() {
325
- error.action = format!("你是否想发给 {suggested}?确认后使用此队友名;通过 --workspace/--team 选择项目和队伍。");
325
+ error.action = format!("Did you mean {suggested}? Confirm the agent name; select the workspace and team with --workspace/--team.");
326
326
  }
327
327
  }
328
328
 
@@ -336,7 +336,7 @@ pub(super) fn logical_recipient_id(
336
336
  .ok_or_else(|| CliError::Runtime("resolved worker is missing agent id".to_string())),
337
337
  crate::cli::named_address::NamedTargetKind::Leader => Ok("leader".to_string()),
338
338
  crate::cli::named_address::NamedTargetKind::SessionWindow => Err(CliError::Usage(
339
- "不再支持按终端窗口发送;请使用队友名或 leader,并通过 --workspace/--team 选择队伍"
339
+ "Terminal-window addressing is no longer supported; use an agent name or leader, with --workspace/--team to select scope"
340
340
  .to_string(),
341
341
  )),
342
342
  }
@@ -350,7 +350,7 @@ pub(super) fn send_to_resolved_name(
350
350
  let recipient = logical_recipient_id(resolved)?;
351
351
  if resolved.warning.is_some() {
352
352
  eprintln!(
353
- "提示:旧收信方式已弃用;请用队友名发送,通过 --workspace/--team 选择项目和队伍。"
353
+ "Warning: legacy addressing is deprecated; send by agent name and select scope with --workspace/--team."
354
354
  );
355
355
  }
356
356
  let target = MessageTarget::Single(recipient);
@@ -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/--pane/--to 不能同时使用;请只选一种收信方式"
44
+ "An agent name cannot be combined with --to-name/--pane/--to; choose one addressing mode"
45
45
  } else {
46
- "--pane 不能与队友名、--to 或 --to-leader 同时使用"
46
+ "--pane cannot be combined with an agent name, --to or --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 不能发送空消息".to_string(),
53
+ "Provide a task message; --pane cannot send an empty message".to_string(),
54
54
  ));
55
55
  }
56
56
  return Err(CliError::Usage(format!(
57
- "--pane {pane_id} 已不再支持;请用 team-agent send <agent> '任务内容',通过 --workspace/--team 选择项目和队伍"
57
+ "--pane {pane_id} is no longer supported; use team-agent send <agent> 'task message' with --workspace/--team to select scope"
58
58
  )));
59
59
  }
60
60
  if args.targets.is_some() {
@@ -106,35 +106,35 @@ pub(crate) struct CommandSpec {
106
106
  // Only human operations belong here. Compatibility commands are private in emit.rs.
107
107
  #[rustfmt::skip]
108
108
  pub(crate) const COMMAND_SPECS: &[CommandSpec] = &[
109
- 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 },
110
- 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 },
111
- 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 },
112
- 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 },
113
- 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 },
114
- 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 },
115
- 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 },
116
- 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 },
117
- 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 },
118
- 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 },
119
- 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 },
120
- 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 },
121
- 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 },
122
- 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 },
123
- 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 },
124
- 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 },
125
- 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 },
126
- 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 },
127
- 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 },
128
- 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 },
129
- 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 },
130
- 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 },
131
- 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 },
132
- 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 },
133
- 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 },
134
- 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 },
135
- 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 },
136
- 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 },
137
- 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 },
109
+ CommandSpec { name: "quick-start", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::QuickStart), summary: "Create a team from role files; use restart for an initialized team", 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 },
110
+ CommandSpec { name: "send", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Send), summary: "Send a task to a specified agent", 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("a future compatibility release"), action: Some("Use team-agent send <agent> 'task message'; select scope with --workspace and --team"), governance: None },
111
+ CommandSpec { name: "status", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Status), summary: "Check agent status without reading conversation content", 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 },
112
+ CommandSpec { name: "models", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Models), summary: "Discover model names supported by the native provider", 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 },
113
+ CommandSpec { name: "inbox", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::Dispatch(DispatchKind::Inbox), summary: "Read agent replies", 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 },
114
+ CommandSpec { name: "restart", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Restart), summary: "Restart an existing team using saved sessions when available", 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 },
115
+ CommandSpec { name: "shutdown", tier: CommandTier::Core, category: CommandCategory::TeamLifecycle, kind: CommandKind::Dispatch(DispatchKind::Shutdown), summary: "Shut down the selected team and report residual resources", 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 },
116
+ CommandSpec { name: "add-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::AddAgent), summary: "Add and start an agent", 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 },
117
+ CommandSpec { name: "start-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StartAgent), summary: "Start an existing team agent", 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 },
118
+ CommandSpec { name: "stop-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::StopAgent), summary: "Stop an agent while retaining configuration and session history", 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 },
119
+ CommandSpec { name: "reset-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ResetAgent), summary: "Discard an agent's saved session association", 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 },
120
+ CommandSpec { name: "clone-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::CloneAgent), summary: "Clone agent configuration into a new agent", 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 },
121
+ CommandSpec { name: "fork-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::ForkAgent), summary: "Fork an agent session where supported by the provider", 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 },
122
+ CommandSpec { name: "remove-agent", tier: CommandTier::Core, category: CommandCategory::WorkerLifecycle, kind: CommandKind::Dispatch(DispatchKind::RemoveAgent), summary: "Remove an agent after confirmation", 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 },
123
+ CommandSpec { name: "leaders", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Leaders), summary: "List local leaders and their team scopes", 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 },
124
+ CommandSpec { name: "doctor", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Doctor), summary: "Diagnose a team and suggest recovery; read-only by default", 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 },
125
+ CommandSpec { name: "approvals", tier: CommandTier::Core, category: CommandCategory::Observe, kind: CommandKind::Dispatch(DispatchKind::Approvals), summary: "List pending agent approvals", 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 },
126
+ CommandSpec { name: "route", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Route), summary: "Configure additional provider launch arguments", 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 },
127
+ CommandSpec { name: "profile", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::Profile), summary: "Manage authentication and proxy profiles", 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 },
128
+ CommandSpec { name: "install-skill", tier: CommandTier::Core, category: CommandCategory::Setup, kind: CommandKind::Dispatch(DispatchKind::InstallSkill), summary: "Optionally install an existing public operation skill", 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 },
129
+ CommandSpec { name: "claim-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::ClaimLeader), summary: "Register the current terminal as leader only when diagnosis recommends it", 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 },
130
+ CommandSpec { name: "takeover", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::Takeover), summary: "Take over an existing team only after diagnosis and confirmation", 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 },
131
+ CommandSpec { name: "attach-leader", tier: CommandTier::Guided, category: CommandCategory::GuidedRecovery, kind: CommandKind::Dispatch(DispatchKind::AttachLeader), summary: "Attach a verified leader terminal only when diagnosis recommends it", 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 },
132
+ CommandSpec { name: "pi", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "pi" }, summary: "Open a leader session with 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 },
133
+ CommandSpec { name: "codex", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "codex" }, summary: "Open a leader session with 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 },
134
+ CommandSpec { name: "claude", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "claude" }, summary: "Open a leader session with 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 },
135
+ CommandSpec { name: "copilot", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "copilot" }, summary: "Open a leader session with 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 },
136
+ CommandSpec { name: "grok", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "grok" }, summary: "Open a leader session with 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 },
137
+ CommandSpec { name: "cursor", tier: CommandTier::Core, category: CommandCategory::Start, kind: CommandKind::LeaderPassthrough { provider: "cursor_agent" }, summary: "Open a leader session with 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 },
138
138
  ];
139
139
 
140
140
  pub(crate) fn command_spec(name: &str) -> Option<&'static CommandSpec> {