@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.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +100 -44
- package/crates/team-agent/src/cli/emit.rs +127 -98
- package/crates/team-agent/src/cli/leaders.rs +32 -32
- package/crates/team-agent/src/cli/mod.rs +6 -6
- package/crates/team-agent/src/cli/named_address.rs +17 -16
- package/crates/team-agent/src/cli/route.rs +4 -4
- package/crates/team-agent/src/cli/send/presentation.rs +19 -18
- package/crates/team-agent/src/cli/send/resolve.rs +11 -11
- package/crates/team-agent/src/cli/send.rs +4 -4
- package/crates/team-agent/src/cli/spec.rs +29 -29
- package/crates/team-agent/src/cli/status.rs +7 -7
- package/crates/team-agent/src/cli/tests/base.rs +6 -6
- package/crates/team-agent/src/cli/tests/divergence.rs +3 -2
- package/crates/team-agent/src/cli/tests/lane_c.rs +1 -1
- package/crates/team-agent/src/cli/tests/named_address.rs +3 -3
- package/crates/team-agent/src/cli/tests/status_send.rs +7 -7
- package/crates/team-agent/src/cli/triage.rs +53 -2
- package/crates/team-agent/src/cli/types.rs +8 -8
- package/crates/team-agent/src/compiler/tests.rs +12 -0
- package/crates/team-agent/src/compiler.rs +0 -9
- package/crates/team-agent/src/leader/start.rs +5 -0
- package/crates/team-agent/src/leader/tests/identity.rs +21 -0
- package/crates/team-agent/src/lifecycle/launch/identity.rs +172 -13
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +325 -14
- package/crates/team-agent/src/lifecycle/launch.rs +2 -2
- package/crates/team-agent/src/lifecycle/profile_launch.rs +58 -46
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +97 -52
- package/crates/team-agent/src/lifecycle/restart.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +3 -2
- package/crates/team-agent/src/provider/adapter.rs +8 -59
- package/crates/team-agent/src/provider/adapters/claude.rs +6 -14
- package/crates/team-agent/src/provider/adapters/codex.rs +8 -18
- package/crates/team-agent/src/provider/adapters/copilot.rs +5 -22
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +8 -45
- package/crates/team-agent/src/provider/adapters/grok.rs +7 -31
- package/crates/team-agent/src/provider/adapters/pi.rs +7 -18
- package/crates/team-agent/src/provider/command_helpers.rs +45 -0
- package/crates/team-agent/src/provider/mod.rs +1 -0
- package/crates/team-agent/src/provider/model_catalog.rs +21 -28
- package/crates/team-agent/src/provider/tests/adapter.rs +70 -0
- package/crates/team-agent/src/provider/tests/command_helpers.rs +55 -0
- package/package.json +4 -4
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
|
@@ -19,6 +19,10 @@ pub fn cmd_quick_start(args: &QuickStartArgs) -> Result<CmdResult, CliError> {
|
|
|
19
19
|
return Ok(result);
|
|
20
20
|
}
|
|
21
21
|
append_send_guidance(&mut value, &args.workspace, args.team_id.as_deref());
|
|
22
|
+
finish_quick_start(value, args)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fn finish_quick_start(mut value: Value, args: &QuickStartArgs) -> Result<CmdResult, CliError> {
|
|
22
26
|
let readiness = value.get("readiness").and_then(Value::as_object);
|
|
23
27
|
let all_resumable_have_session = readiness
|
|
24
28
|
.and_then(|readiness| readiness.get("all_resumable_have_session"))
|
|
@@ -36,7 +40,7 @@ pub fn cmd_quick_start(args: &QuickStartArgs) -> Result<CmdResult, CliError> {
|
|
|
36
40
|
.get("status")
|
|
37
41
|
.and_then(Value::as_str)
|
|
38
42
|
.map(str::to_string);
|
|
39
|
-
if !args.detail {
|
|
43
|
+
if !args.detail && value.get("ok").and_then(Value::as_bool) != Some(false) {
|
|
40
44
|
lifecycle_port::compact_quick_start_value(&mut value);
|
|
41
45
|
}
|
|
42
46
|
if args.json
|
|
@@ -45,30 +49,18 @@ pub fn cmd_quick_start(args: &QuickStartArgs) -> Result<CmdResult, CliError> {
|
|
|
45
49
|
|| !readiness_ready
|
|
46
50
|
{
|
|
47
51
|
let mut result = CmdResult::from_json(value, args.json);
|
|
48
|
-
if
|
|
52
|
+
if status.as_deref() == Some("pending_tool_load") {
|
|
49
53
|
result.exit = ExitCode::Ok;
|
|
50
54
|
}
|
|
51
55
|
if !args.json {
|
|
52
56
|
if let CmdOutput::Json(value) = &result.output {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
} else {
|
|
62
|
-
"队伍尚未准备好接收任务;请等待工具完成启动。".to_string()
|
|
63
|
-
};
|
|
64
|
-
let mut doctor = format!(
|
|
65
|
-
"team-agent doctor --workspace {}",
|
|
66
|
-
shell_quote(&args.workspace.to_string_lossy())
|
|
67
|
-
);
|
|
68
|
-
if let Some(team) = args.team_id.as_deref() {
|
|
69
|
-
doctor.push_str(&format!(" --team {}", shell_quote(team)));
|
|
70
|
-
}
|
|
71
|
-
result.output = CmdOutput::Human(format!("{explanation}\n下一步:运行 {doctor},按体检提示处理;用 status 查看状态,不反复起队或重发任务。"));
|
|
57
|
+
// Typed refusals often have no `error`. Preserve the complete
|
|
58
|
+
// report instead of replacing its reason/actions with a guess.
|
|
59
|
+
let safe = crate::redaction::redact_external_value(value);
|
|
60
|
+
result.output = CmdOutput::Human(format!(
|
|
61
|
+
"quick-start report:\n{}",
|
|
62
|
+
serde_json::to_string_pretty(&safe)?
|
|
63
|
+
));
|
|
72
64
|
}
|
|
73
65
|
}
|
|
74
66
|
Ok(result)
|
|
@@ -126,11 +118,11 @@ fn quick_start_config_guidance(value: &mut Value, args: &QuickStartArgs) -> Opti
|
|
|
126
118
|
retry.push_str(" --json");
|
|
127
119
|
}
|
|
128
120
|
let explanation = if missing_team {
|
|
129
|
-
format!("
|
|
121
|
+
format!("Team configuration is missing: {}. No workers were started. Create the two files below; this command did not write them. Error: {error}", team_path.display())
|
|
130
122
|
} else {
|
|
131
|
-
format!("
|
|
123
|
+
format!("Worker configuration is incomplete: {detail}. Add the role directory or required fields. The examples below do not overwrite existing files. Error: {error}")
|
|
132
124
|
};
|
|
133
|
-
let next = format!("
|
|
125
|
+
let next = format!("Check that Pi is installed and signed in; verify the model with team-agent models --provider pi.\nRun team-agent pi, then execute this command in that leader's tool context:\n{retry}");
|
|
134
126
|
let mut templates =
|
|
135
127
|
vec![serde_json::json!({"path": role_path, "content": super::emit::WORKER_TEMPLATE})];
|
|
136
128
|
let mut human = explanation.clone();
|
|
@@ -140,13 +132,13 @@ fn quick_start_config_guidance(value: &mut Value, args: &QuickStartArgs) -> Opti
|
|
|
140
132
|
serde_json::json!({"path": team_path, "content": super::emit::TEAM_TEMPLATE}),
|
|
141
133
|
);
|
|
142
134
|
human.push_str(&format!(
|
|
143
|
-
"\n\n{}
|
|
135
|
+
"\n\n{}:\n{}",
|
|
144
136
|
team_path.display(),
|
|
145
137
|
super::emit::TEAM_TEMPLATE
|
|
146
138
|
));
|
|
147
139
|
}
|
|
148
140
|
human.push_str(&format!(
|
|
149
|
-
"\n\n{}
|
|
141
|
+
"\n\n{}:\n{}\nNext steps:\n{next}",
|
|
150
142
|
role_path.display(),
|
|
151
143
|
super::emit::WORKER_TEMPLATE
|
|
152
144
|
));
|
|
@@ -166,11 +158,7 @@ fn quick_start_config_guidance(value: &mut Value, args: &QuickStartArgs) -> Opti
|
|
|
166
158
|
/// E13:quick-start "team 起了" 人类输出 = summary + attach 块。所有成功出口共用(别每分支手拷)。
|
|
167
159
|
/// attach_commands 缺/空 → 只 summary(向后兼容)。
|
|
168
160
|
fn quickstart_human(value: &Value) -> String {
|
|
169
|
-
let summary =
|
|
170
|
-
"发现已有队伍;请查看返回的连接方式,不会另建同名队伍。"
|
|
171
|
-
} else {
|
|
172
|
-
"队伍已启动;下面是连接方式和派发任务的命令。"
|
|
173
|
-
};
|
|
161
|
+
let summary = value.get("summary").and_then(Value::as_str).unwrap_or("Team started.");
|
|
174
162
|
let attach: Vec<&str> = value
|
|
175
163
|
.get("attach_commands")
|
|
176
164
|
.and_then(Value::as_array)
|
|
@@ -183,14 +171,14 @@ fn quickstart_human(value: &Value) -> String {
|
|
|
183
171
|
.unwrap_or_default();
|
|
184
172
|
let mut out = String::from(summary);
|
|
185
173
|
if !attach.is_empty() {
|
|
186
|
-
out.push_str("\n\
|
|
174
|
+
out.push_str("\n\nConnect to the team:");
|
|
187
175
|
for cmd in attach {
|
|
188
176
|
out.push_str("\n ");
|
|
189
177
|
out.push_str(cmd);
|
|
190
178
|
}
|
|
191
179
|
}
|
|
192
180
|
if !sends.is_empty() {
|
|
193
|
-
out.push_str("\n\
|
|
181
|
+
out.push_str("\n\nSend a task (replace the example message):");
|
|
194
182
|
for cmd in sends {
|
|
195
183
|
out.push_str("\n ");
|
|
196
184
|
out.push_str(cmd);
|
|
@@ -257,7 +245,7 @@ pub(crate) fn send_command(agent: &str, workspace: &Path, team: Option<&str>) ->
|
|
|
257
245
|
let mut command = format!(
|
|
258
246
|
"team-agent send {} {} --workspace {}",
|
|
259
247
|
shell_quote(agent),
|
|
260
|
-
shell_quote("
|
|
248
|
+
shell_quote("Complete the task and reply to the leader."),
|
|
261
249
|
shell_quote(workspace)
|
|
262
250
|
);
|
|
263
251
|
if let Some(team) = team {
|
|
@@ -1014,12 +1002,13 @@ fn finalize_doctor_report(report: &mut Value, default_report: bool) {
|
|
|
1014
1002
|
|
|
1015
1003
|
#[cfg(test)]
|
|
1016
1004
|
mod tests {
|
|
1017
|
-
#![allow(clippy::unwrap_used)]
|
|
1005
|
+
#![allow(clippy::unwrap_used, clippy::panic)]
|
|
1018
1006
|
|
|
1019
1007
|
use super::{
|
|
1020
|
-
append_send_guidance, format_inbox_human, quickstart_human,
|
|
1021
|
-
split_shell_argv,
|
|
1008
|
+
append_send_guidance, finish_quick_start, format_inbox_human, quickstart_human,
|
|
1009
|
+
send_command, split_shell_argv,
|
|
1022
1010
|
};
|
|
1011
|
+
use crate::cli::{CmdOutput, ExitCode, QuickStartArgs};
|
|
1023
1012
|
use serde_json::{json, Value};
|
|
1024
1013
|
use std::path::{Path, PathBuf};
|
|
1025
1014
|
|
|
@@ -1057,11 +1046,11 @@ mod tests {
|
|
|
1057
1046
|
});
|
|
1058
1047
|
let out = quickstart_human(&value);
|
|
1059
1048
|
assert!(
|
|
1060
|
-
out.contains("
|
|
1049
|
+
out.contains("team started"),
|
|
1061
1050
|
"must show startup summary; got {out}"
|
|
1062
1051
|
);
|
|
1063
1052
|
assert!(
|
|
1064
|
-
out.contains("
|
|
1053
|
+
out.contains("Connect to the team:"),
|
|
1065
1054
|
"must render attach block; got {out}"
|
|
1066
1055
|
);
|
|
1067
1056
|
assert!(
|
|
@@ -1100,7 +1089,7 @@ mod tests {
|
|
|
1100
1089
|
assert_eq!(
|
|
1101
1090
|
quickstart_human(&value),
|
|
1102
1091
|
format!(
|
|
1103
|
-
"
|
|
1092
|
+
"quick-start complete\n{}",
|
|
1104
1093
|
crate::cli::QUICK_START_REMINDER
|
|
1105
1094
|
)
|
|
1106
1095
|
);
|
|
@@ -1109,7 +1098,7 @@ mod tests {
|
|
|
1109
1098
|
assert_eq!(
|
|
1110
1099
|
quickstart_human(&value2),
|
|
1111
1100
|
format!(
|
|
1112
|
-
"
|
|
1101
|
+
"s\n{}",
|
|
1113
1102
|
crate::cli::QUICK_START_REMINDER
|
|
1114
1103
|
)
|
|
1115
1104
|
);
|
|
@@ -1130,7 +1119,7 @@ mod tests {
|
|
|
1130
1119
|
"team-agent",
|
|
1131
1120
|
"send",
|
|
1132
1121
|
"worker name; echo unsafe",
|
|
1133
|
-
"
|
|
1122
|
+
"Complete the task and reply to the leader.",
|
|
1134
1123
|
"--workspace",
|
|
1135
1124
|
"/tmp/my workspace",
|
|
1136
1125
|
"--team",
|
|
@@ -1149,7 +1138,7 @@ mod tests {
|
|
|
1149
1138
|
.unwrap();
|
|
1150
1139
|
assert_eq!(
|
|
1151
1140
|
command,
|
|
1152
|
-
"team-agent send 'worker name; echo unsafe' '
|
|
1141
|
+
"team-agent send 'worker name; echo unsafe' 'Complete the task and reply to the leader.' --workspace '/tmp/my workspace' --team team-a"
|
|
1153
1142
|
);
|
|
1154
1143
|
}
|
|
1155
1144
|
|
|
@@ -1206,7 +1195,7 @@ mod tests {
|
|
|
1206
1195
|
"team-agent",
|
|
1207
1196
|
"send",
|
|
1208
1197
|
"worker",
|
|
1209
|
-
"
|
|
1198
|
+
"Complete the task and reply to the leader.",
|
|
1210
1199
|
"--workspace",
|
|
1211
1200
|
"/tmp/ws",
|
|
1212
1201
|
"--team",
|
|
@@ -1215,4 +1204,71 @@ mod tests {
|
|
|
1215
1204
|
);
|
|
1216
1205
|
}
|
|
1217
1206
|
|
|
1207
|
+
fn quick_start_args(as_json: bool) -> QuickStartArgs {
|
|
1208
|
+
QuickStartArgs {
|
|
1209
|
+
workspace: PathBuf::from("/tmp/first-launch"),
|
|
1210
|
+
agents_dir: PathBuf::from("/tmp/first-launch/.team/current"),
|
|
1211
|
+
name: None,
|
|
1212
|
+
team_id: None,
|
|
1213
|
+
yes: true,
|
|
1214
|
+
json: as_json,
|
|
1215
|
+
detail: false,
|
|
1216
|
+
backend: None,
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
#[test]
|
|
1221
|
+
fn quick_start_human_preserves_typed_refusals_without_error_field() {
|
|
1222
|
+
for status in ["existing_runtime", "preflight_blocked", "leader_binding_refused"] {
|
|
1223
|
+
let value = json!({
|
|
1224
|
+
"ok": false,
|
|
1225
|
+
"status": status,
|
|
1226
|
+
"reason": "the exact underlying refusal",
|
|
1227
|
+
"summary": "creation refused",
|
|
1228
|
+
"blockers": [{"stage": "identity", "reason": "owner mismatch"}],
|
|
1229
|
+
"next_actions": ["team-agent restart --workspace /tmp/first-launch --team current"],
|
|
1230
|
+
"state_path": "/tmp/first-launch/.team/runtime/state.json",
|
|
1231
|
+
"readiness": {"reason": "underlying readiness evidence"}
|
|
1232
|
+
});
|
|
1233
|
+
let result = finish_quick_start(value.clone(), &quick_start_args(false)).unwrap();
|
|
1234
|
+
assert_eq!(result.exit, ExitCode::Error);
|
|
1235
|
+
let CmdOutput::Human(text) = result.output else { panic!("expected human report") };
|
|
1236
|
+
let rendered: Value = serde_json::from_str(text.strip_prefix("quick-start report:\n").unwrap()).unwrap();
|
|
1237
|
+
assert_eq!(rendered, value, "human projection lost fields for {status}");
|
|
1238
|
+
assert!(!text.contains("team-agent doctor"), "must not replace actual actions");
|
|
1239
|
+
let json_result = finish_quick_start(value.clone(), &quick_start_args(true)).unwrap();
|
|
1240
|
+
assert_eq!(json_result.exit, ExitCode::Error);
|
|
1241
|
+
assert_eq!(json_result.output, CmdOutput::Json(value));
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
#[test]
|
|
1246
|
+
fn quick_start_human_preserves_original_error_and_actions() {
|
|
1247
|
+
let value = json!({
|
|
1248
|
+
"ok": false,
|
|
1249
|
+
"error": "database initialization failed at /tmp/first-launch/.team/team.db: permission denied",
|
|
1250
|
+
"action": "repair directory permissions",
|
|
1251
|
+
"next_actions": ["inspect the exact database path"]
|
|
1252
|
+
});
|
|
1253
|
+
let result = finish_quick_start(value.clone(), &quick_start_args(false)).unwrap();
|
|
1254
|
+
assert_eq!(result.exit, ExitCode::Error);
|
|
1255
|
+
let CmdOutput::Human(text) = result.output else { panic!("expected human report") };
|
|
1256
|
+
let rendered: Value = serde_json::from_str(text.strip_prefix("quick-start report:\n").unwrap()).unwrap();
|
|
1257
|
+
assert_eq!(rendered, value);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
#[test]
|
|
1261
|
+
fn pending_tool_load_is_not_reported_as_failed_team_creation() {
|
|
1262
|
+
for as_json in [false, true] {
|
|
1263
|
+
let value = json!({
|
|
1264
|
+
"ok": true,
|
|
1265
|
+
"status": "pending_tool_load",
|
|
1266
|
+
"summary": "Team started; worker tool loading is not yet verified",
|
|
1267
|
+
"readiness": {"ready": false},
|
|
1268
|
+
"next_actions": ["send a task and wait for the actual reply"]
|
|
1269
|
+
});
|
|
1270
|
+
let result = finish_quick_start(value, &quick_start_args(as_json)).unwrap();
|
|
1271
|
+
assert_eq!(result.exit, ExitCode::Ok);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1218
1274
|
}
|