@team-agent/installer 0.5.110 → 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.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +234 -73
- package/crates/team-agent/src/cli/emit.rs +487 -201
- package/crates/team-agent/src/cli/leader.rs +4 -9
- package/crates/team-agent/src/cli/leaders.rs +90 -29
- package/crates/team-agent/src/cli/mod.rs +346 -160
- package/crates/team-agent/src/cli/models.rs +80 -24
- package/crates/team-agent/src/cli/named_address.rs +114 -25
- package/crates/team-agent/src/cli/route.rs +10 -5
- package/crates/team-agent/src/cli/send/presentation.rs +60 -41
- package/crates/team-agent/src/cli/send/resolve.rs +25 -18
- package/crates/team-agent/src/cli/send.rs +4 -4
- package/crates/team-agent/src/cli/spec.rs +56 -109
- package/crates/team-agent/src/cli/tests/base.rs +189 -82
- package/crates/team-agent/src/cli/tests/lane_c.rs +1 -2
- package/crates/team-agent/src/cli/tests/named_address.rs +19 -22
- package/crates/team-agent/src/cli/tests/status_send.rs +15 -10
- package/crates/team-agent/src/cli/tests/verb_install_skill.rs +2 -2
- package/crates/team-agent/src/cli/types.rs +22 -13
- package/crates/team-agent/src/leader/registry.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +4 -9
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +3 -1
- package/package.json +4 -4
|
@@ -105,24 +105,19 @@ pub fn cmd_leader_passthrough(
|
|
|
105
105
|
cwd: &Path,
|
|
106
106
|
) -> Result<CmdResult, CliError> {
|
|
107
107
|
if provider_args == ["-h"] || provider_args == ["--help"] {
|
|
108
|
-
return Ok(CmdResult::
|
|
108
|
+
return Ok(CmdResult::human(&super::emit::command_help(Some(command))));
|
|
109
109
|
}
|
|
110
110
|
let as_json = leader_launcher_json(provider_args);
|
|
111
111
|
let launcher_args = without_leader_json(provider_args);
|
|
112
112
|
let attach = leader_launcher_args(&launcher_args)?;
|
|
113
|
-
let provider = leader_passthrough_provider(command)
|
|
114
|
-
CliError::Usage(format!(
|
|
115
|
-
"unknown leader passthrough command: {command}"
|
|
116
|
-
))
|
|
117
|
-
})?;
|
|
113
|
+
let provider = leader_passthrough_provider(command)
|
|
114
|
+
.ok_or_else(|| CliError::Usage(format!("unknown leader passthrough command: {command}")))?;
|
|
118
115
|
let value = lifecycle_port::start_leader(provider, &attach.provider_args, cwd, &attach)?;
|
|
119
116
|
Ok(CmdResult::from_json(value, as_json))
|
|
120
117
|
}
|
|
121
118
|
|
|
122
119
|
/// Closed-set verb → Provider. `None` = not a passthrough verb (must not become ClaudeCode).
|
|
123
|
-
pub(crate) fn leader_passthrough_provider(
|
|
124
|
-
command: &str,
|
|
125
|
-
) -> Option<crate::model::enums::Provider> {
|
|
120
|
+
pub(crate) fn leader_passthrough_provider(command: &str) -> Option<crate::model::enums::Provider> {
|
|
126
121
|
use crate::model::enums::Provider;
|
|
127
122
|
match command {
|
|
128
123
|
"codex" => Some(Provider::Codex),
|
|
@@ -182,20 +182,39 @@ fn quote_cli_arg(raw: &str) -> String {
|
|
|
182
182
|
fn format_leaders_human(rows: &[LeaderRow], view: LeadersView) -> String {
|
|
183
183
|
if rows.is_empty() {
|
|
184
184
|
return match view {
|
|
185
|
-
LeadersView::Live =>
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
LeadersView::Live => {
|
|
186
|
+
"没有可用主控;运行 team-agent doctor --workspace . 检查当前队伍。\n".to_string()
|
|
187
|
+
}
|
|
188
|
+
LeadersView::All => "没有已登记主控;首次协作用 team-agent pi 打开主控。\n".to_string(),
|
|
189
|
+
LeadersView::Stale => "没有已失效的主控登记。\n".to_string(),
|
|
188
190
|
};
|
|
189
191
|
}
|
|
190
|
-
let mut out = String::from("
|
|
192
|
+
let mut out = String::from("主控\t状态\t项目\t队伍\t发送命令\n");
|
|
191
193
|
for row in rows {
|
|
192
|
-
out.push_str(
|
|
194
|
+
out.push_str("leader\t");
|
|
195
|
+
out.push_str(match row.status {
|
|
196
|
+
"LIVE" => "可用",
|
|
197
|
+
"STALE" => "已失效",
|
|
198
|
+
"AMBIGUOUS" => "需确认归属",
|
|
199
|
+
other => other,
|
|
200
|
+
});
|
|
193
201
|
out.push('\t');
|
|
194
202
|
out.push_str(&row.entry.workspace.display().to_string());
|
|
195
203
|
out.push('\t');
|
|
196
204
|
out.push_str(&row.entry.team_key);
|
|
197
205
|
out.push('\t');
|
|
198
|
-
|
|
206
|
+
if row.status == "STALE" {
|
|
207
|
+
out.push('-');
|
|
208
|
+
} else {
|
|
209
|
+
out.push_str(
|
|
210
|
+
&super::adapters::send_command(
|
|
211
|
+
"leader",
|
|
212
|
+
&row.entry.workspace,
|
|
213
|
+
Some(&row.entry.team_key),
|
|
214
|
+
)
|
|
215
|
+
.unwrap_or_else(|| "请核对项目路径".to_string()),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
199
218
|
out.push('\n');
|
|
200
219
|
}
|
|
201
220
|
out
|
|
@@ -221,22 +240,34 @@ fn prune_json(report: &RegistryPruneReport) -> Value {
|
|
|
221
240
|
}
|
|
222
241
|
|
|
223
242
|
fn format_prune_human(report: &RegistryPruneReport) -> String {
|
|
224
|
-
let mut out = format!("
|
|
243
|
+
let mut out = format!("仅预览:{}\n", report.dry_run);
|
|
225
244
|
for (label, items) in [
|
|
226
|
-
("
|
|
227
|
-
("
|
|
228
|
-
("
|
|
229
|
-
("
|
|
230
|
-
("
|
|
245
|
+
("可清理登记", &report.candidates),
|
|
246
|
+
("已清理", &report.removed),
|
|
247
|
+
("保留", &report.kept),
|
|
248
|
+
("跳过", &report.skipped),
|
|
249
|
+
("错误", &report.errors),
|
|
231
250
|
] {
|
|
232
251
|
out.push_str(&format!("{label}: {}\n", items.len()));
|
|
233
252
|
for item in items {
|
|
234
253
|
out.push_str(" ");
|
|
235
254
|
out.push_str(&item.workspace.display().to_string());
|
|
236
|
-
out.push_str("
|
|
255
|
+
out.push_str(",队伍:");
|
|
237
256
|
out.push_str(&item.team_key);
|
|
238
257
|
out.push_str(" [");
|
|
239
|
-
out.push_str(
|
|
258
|
+
out.push_str(match item.reason.as_str() {
|
|
259
|
+
"LIVE" => "仍可用,保留登记",
|
|
260
|
+
"team_key_not_found" => "队伍已不在项目中",
|
|
261
|
+
"team_not_alive" => "队伍已停止",
|
|
262
|
+
"registry_entry_missing" => "登记已不存在",
|
|
263
|
+
"registry_entry_changed" | "canonical_state_changed" => {
|
|
264
|
+
"登记或队伍已变化,停止清理"
|
|
265
|
+
}
|
|
266
|
+
"canonical_state_unavailable" => "无法读取队伍状态,保留登记",
|
|
267
|
+
"registry_lock_unavailable" => "登记正被其他操作使用,停止清理",
|
|
268
|
+
"remove_failed" => "删除登记失败,请查看文件权限",
|
|
269
|
+
_ => "无法安全确认该登记;请体检所选项目",
|
|
270
|
+
});
|
|
240
271
|
out.push_str("]\n");
|
|
241
272
|
}
|
|
242
273
|
}
|
|
@@ -302,9 +333,40 @@ mod tests {
|
|
|
302
333
|
row("/Users/alauda/stale", "old-team", "STALE", "-"),
|
|
303
334
|
];
|
|
304
335
|
let out = format_leaders_human(&rows, LeadersView::All);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
336
|
+
let lines: Vec<_> = out.lines().collect();
|
|
337
|
+
assert_eq!(lines.len(), 3, "one header and both selected rows: {out}");
|
|
338
|
+
let header = lines[0];
|
|
339
|
+
assert_eq!(header.split('\t').count(), 5);
|
|
340
|
+
assert!(header.contains("状态") && header.contains("项目") && header.contains("队伍"));
|
|
341
|
+
let live: Vec<_> = lines[1].split('\t').collect();
|
|
342
|
+
assert_eq!(
|
|
343
|
+
&live[..4],
|
|
344
|
+
&[
|
|
345
|
+
"leader",
|
|
346
|
+
"可用",
|
|
347
|
+
"/Volumes/nvme/Projects/讨论team-agent",
|
|
348
|
+
"wiki-team"
|
|
349
|
+
]
|
|
350
|
+
);
|
|
351
|
+
assert_eq!(
|
|
352
|
+
super::super::adapters::split_shell_argv(live[4]),
|
|
353
|
+
[
|
|
354
|
+
"team-agent",
|
|
355
|
+
"send",
|
|
356
|
+
"leader",
|
|
357
|
+
"请完成任务并把答案回复给 leader。",
|
|
358
|
+
"--workspace",
|
|
359
|
+
"/Volumes/nvme/Projects/讨论team-agent",
|
|
360
|
+
"--team",
|
|
361
|
+
"wiki-team"
|
|
362
|
+
]
|
|
363
|
+
);
|
|
364
|
+
let stale: Vec<_> = lines[2].split('\t').collect();
|
|
365
|
+
assert_eq!(
|
|
366
|
+
&stale[..4],
|
|
367
|
+
&["leader", "已失效", "/Users/alauda/stale", "old-team"]
|
|
368
|
+
);
|
|
369
|
+
assert_eq!(stale[4], "-", "stale rows must never suggest a send: {out}");
|
|
308
370
|
}
|
|
309
371
|
|
|
310
372
|
#[test]
|
|
@@ -341,17 +403,16 @@ mod tests {
|
|
|
341
403
|
|
|
342
404
|
#[test]
|
|
343
405
|
fn empty_view_names_are_explicit() {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
"
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
format_leaders_human(&[],
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
);
|
|
406
|
+
for (view, empty, next) in [
|
|
407
|
+
(LeadersView::Live, "没有可用主控", Some("team-agent doctor")),
|
|
408
|
+
(LeadersView::Stale, "没有已失效的主控登记", None),
|
|
409
|
+
(LeadersView::All, "没有已登记主控", Some("team-agent pi")),
|
|
410
|
+
] {
|
|
411
|
+
let out = format_leaders_human(&[], view);
|
|
412
|
+
assert!(out.contains(empty) && out.ends_with('\n'), "{out}");
|
|
413
|
+
if let Some(next) = next {
|
|
414
|
+
assert!(out.contains(next), "{out}");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
356
417
|
}
|
|
357
418
|
}
|