@team-agent/installer 0.3.1 → 0.3.3
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 +34 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +234 -26
- package/crates/team-agent/src/cli/diagnose.rs +144 -10
- package/crates/team-agent/src/cli/emit.rs +289 -54
- package/crates/team-agent/src/cli/leader.rs +37 -8
- package/crates/team-agent/src/cli/mod.rs +1281 -196
- package/crates/team-agent/src/cli/status_port.rs +195 -46
- package/crates/team-agent/src/cli/tests/divergence.rs +1 -2
- package/crates/team-agent/src/cli/tests/lane_c.rs +23 -13
- package/crates/team-agent/src/cli/tests/main_preserved.rs +2 -0
- package/crates/team-agent/src/cli/tests/run_delegation.rs +59 -3
- package/crates/team-agent/src/cli/types.rs +18 -0
- package/crates/team-agent/src/compiler.rs +15 -5
- package/crates/team-agent/src/coordinator/health.rs +95 -17
- package/crates/team-agent/src/coordinator/mod.rs +4 -0
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +500 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +58 -0
- package/crates/team-agent/src/coordinator/tick.rs +222 -69
- package/crates/team-agent/src/coordinator/types.rs +15 -3
- package/crates/team-agent/src/db/schema.rs +37 -2
- package/crates/team-agent/src/diagnose/comms.rs +226 -0
- package/crates/team-agent/src/diagnose/mod.rs +45 -0
- package/crates/team-agent/src/diagnose/orphans.rs +658 -0
- package/crates/team-agent/src/fake_worker.rs +146 -3
- package/crates/team-agent/src/leader/start.rs +121 -23
- package/crates/team-agent/src/leader/types.rs +44 -1
- package/crates/team-agent/src/lib.rs +3 -0
- package/crates/team-agent/src/lifecycle/display.rs +645 -47
- package/crates/team-agent/src/lifecycle/launch.rs +1061 -146
- package/crates/team-agent/src/lifecycle/mod.rs +2 -0
- package/crates/team-agent/src/lifecycle/profile_launch.rs +810 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +522 -0
- package/crates/team-agent/src/lifecycle/restart/agent.rs +99 -23
- package/crates/team-agent/src/lifecycle/restart/common.rs +183 -24
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +498 -22
- package/crates/team-agent/src/lifecycle/restart/remove.rs +27 -7
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +19 -0
- package/crates/team-agent/src/lifecycle/restart.rs +24 -1
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +5 -5
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +37 -7
- package/crates/team-agent/src/lifecycle/types.rs +19 -0
- package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +341 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +10 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +158 -0
- package/crates/team-agent/src/mcp_server/mod.rs +3 -74
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +1 -1
- package/crates/team-agent/src/mcp_server/tests/send.rs +6 -5
- package/crates/team-agent/src/mcp_server/tools.rs +312 -111
- package/crates/team-agent/src/mcp_server/types.rs +6 -4
- package/crates/team-agent/src/mcp_server/wire.rs +19 -7
- package/crates/team-agent/src/message_store.rs +21 -4
- package/crates/team-agent/src/messaging/delivery.rs +470 -59
- package/crates/team-agent/src/messaging/mod.rs +9 -6
- package/crates/team-agent/src/messaging/results.rs +353 -63
- package/crates/team-agent/src/messaging/selftest.rs +199 -12
- package/crates/team-agent/src/messaging/send.rs +35 -3
- package/crates/team-agent/src/messaging/tests/runtime.rs +19 -4
- package/crates/team-agent/src/messaging/types.rs +11 -3
- package/crates/team-agent/src/os_probe.rs +119 -0
- package/crates/team-agent/src/packaging/migrate.rs +10 -2
- package/crates/team-agent/src/packaging/tests.rs +23 -0
- package/crates/team-agent/src/provider/adapter.rs +564 -63
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +1 -7
- package/crates/team-agent/src/provider/classify.rs +51 -4
- package/crates/team-agent/src/provider/helpers.rs +10 -1
- package/crates/team-agent/src/provider/startup_prompt.rs +94 -0
- package/crates/team-agent/src/provider/types.rs +47 -0
- package/crates/team-agent/src/session_capture.rs +616 -0
- package/crates/team-agent/src/state/persist.rs +170 -1
- package/crates/team-agent/src/state/projection.rs +141 -8
- package/crates/team-agent/src/state/selector.rs +5 -2
- package/crates/team-agent/src/tmux_backend.rs +161 -64
- package/crates/team-agent/src/transport/test_support.rs +9 -0
- package/crates/team-agent/src/transport/tests/wire.rs +4 -0
- package/crates/team-agent/src/transport.rs +13 -2
- package/package.json +4 -4
|
@@ -134,13 +134,18 @@ pub(crate) fn build_preflight_report(team: &std::path::Path) -> Result<Value, Cl
|
|
|
134
134
|
|| team.join("profiles").exists();
|
|
135
135
|
let profile_dir_check = json!({
|
|
136
136
|
"name": "profile_dir",
|
|
137
|
-
"ok": profile_dir_exists,
|
|
138
|
-
});
|
|
139
|
-
let profile_smoke_check = json!({
|
|
140
|
-
"name": "profile_smoke",
|
|
141
137
|
"ok": true,
|
|
142
|
-
"status": if profile_dir_exists { "
|
|
138
|
+
"status": if profile_dir_exists { "present" } else { "not_required" },
|
|
143
139
|
});
|
|
140
|
+
let profile_smoke_check = build_profile_smoke_check_for_team(team)?;
|
|
141
|
+
if profile_smoke_check.get("ok").and_then(Value::as_bool) == Some(false) {
|
|
142
|
+
let reason = profile_smoke_check
|
|
143
|
+
.get("reason")
|
|
144
|
+
.or_else(|| profile_smoke_check.get("error"))
|
|
145
|
+
.and_then(Value::as_str)
|
|
146
|
+
.unwrap_or("profile smoke failed");
|
|
147
|
+
next_actions.push(json!(format!("fix compatible_api profile smoke: {reason}")));
|
|
148
|
+
}
|
|
144
149
|
checks.push(json!({
|
|
145
150
|
"name": "profiles",
|
|
146
151
|
"ok": true,
|
|
@@ -197,14 +202,110 @@ pub(crate) fn build_preflight_report(team: &std::path::Path) -> Result<Value, Cl
|
|
|
197
202
|
Ok(report)
|
|
198
203
|
}
|
|
199
204
|
|
|
205
|
+
pub(crate) fn build_profile_smoke_check_for_team(team: &std::path::Path) -> Result<Value, CliError> {
|
|
206
|
+
let workspace = crate::model::paths::team_workspace(team)
|
|
207
|
+
.map_err(|error| CliError::Runtime(error.to_string()))?;
|
|
208
|
+
let spec = match crate::compiler::compile_team(team) {
|
|
209
|
+
Ok(spec) => spec,
|
|
210
|
+
Err(error) => {
|
|
211
|
+
return Ok(json!({
|
|
212
|
+
"name": "profile_smoke",
|
|
213
|
+
"ok": false,
|
|
214
|
+
"status": "profile_invalid",
|
|
215
|
+
"reason": error.to_string(),
|
|
216
|
+
"secret_values_printed": false,
|
|
217
|
+
"checks": [],
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
let agents = spec
|
|
222
|
+
.get("agents")
|
|
223
|
+
.and_then(crate::model::yaml::Value::as_list)
|
|
224
|
+
.unwrap_or(&[]);
|
|
225
|
+
let checks = crate::lifecycle::profile_smoke::profile_smoke_checks_for_agents_with_profile_dir(
|
|
226
|
+
&workspace,
|
|
227
|
+
agents,
|
|
228
|
+
Some(&team.join("profiles")),
|
|
229
|
+
crate::lifecycle::profile_smoke::DEFAULT_PROFILE_SMOKE_TIMEOUT,
|
|
230
|
+
);
|
|
231
|
+
Ok(aggregate_profile_smoke_checks(checks))
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
fn aggregate_profile_smoke_checks(checks: Vec<Value>) -> Value {
|
|
235
|
+
let failed = checks
|
|
236
|
+
.iter()
|
|
237
|
+
.filter(|check| check.get("ok").and_then(Value::as_bool) == Some(false))
|
|
238
|
+
.cloned()
|
|
239
|
+
.collect::<Vec<_>>();
|
|
240
|
+
let ok = failed.is_empty();
|
|
241
|
+
let status = if !ok {
|
|
242
|
+
failed
|
|
243
|
+
.first()
|
|
244
|
+
.and_then(|check| check.get("status").and_then(Value::as_str))
|
|
245
|
+
.unwrap_or("smoke_failed")
|
|
246
|
+
} else if checks
|
|
247
|
+
.iter()
|
|
248
|
+
.any(|check| check.get("status").and_then(Value::as_str) == Some("smoke_passed"))
|
|
249
|
+
{
|
|
250
|
+
"smoke_passed"
|
|
251
|
+
} else if checks
|
|
252
|
+
.iter()
|
|
253
|
+
.any(|check| check.get("status").and_then(Value::as_str) == Some("skipped_by_profile"))
|
|
254
|
+
{
|
|
255
|
+
"skipped_by_profile"
|
|
256
|
+
} else {
|
|
257
|
+
"not_required"
|
|
258
|
+
};
|
|
259
|
+
let mut out = json!({
|
|
260
|
+
"name": "profile_smoke",
|
|
261
|
+
"ok": ok,
|
|
262
|
+
"status": status,
|
|
263
|
+
"checks": checks,
|
|
264
|
+
"secret_values_printed": false,
|
|
265
|
+
});
|
|
266
|
+
if let Some(first) = failed.first() {
|
|
267
|
+
copy_optional_field(first, &mut out, "reason");
|
|
268
|
+
copy_optional_field(first, &mut out, "http_status");
|
|
269
|
+
copy_optional_field(first, &mut out, "endpoint");
|
|
270
|
+
copy_optional_field(first, &mut out, "error");
|
|
271
|
+
} else if let Some(first_passed) = checks
|
|
272
|
+
.iter()
|
|
273
|
+
.find(|check| check.get("status").and_then(Value::as_str) == Some("smoke_passed"))
|
|
274
|
+
{
|
|
275
|
+
copy_optional_field(first_passed, &mut out, "http_status");
|
|
276
|
+
copy_optional_field(first_passed, &mut out, "endpoint");
|
|
277
|
+
}
|
|
278
|
+
out
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
fn copy_optional_field(from: &Value, to: &mut Value, key: &str) {
|
|
282
|
+
let Some(value) = from.get(key).cloned() else {
|
|
283
|
+
return;
|
|
284
|
+
};
|
|
285
|
+
let Some(obj) = to.as_object_mut() else {
|
|
286
|
+
return;
|
|
287
|
+
};
|
|
288
|
+
obj.insert(key.to_string(), value);
|
|
289
|
+
}
|
|
290
|
+
|
|
200
291
|
pub(crate) fn build_wait_ready_report(workspace: &std::path::Path, timeout: f64) -> Result<Value, CliError> {
|
|
292
|
+
let selected = crate::state::selector::resolve_active_team(
|
|
293
|
+
workspace,
|
|
294
|
+
None,
|
|
295
|
+
crate::state::selector::SelectorMode::RuntimeOnly,
|
|
296
|
+
)
|
|
297
|
+
.map_err(|e| CliError::Runtime(e.to_string()))?;
|
|
201
298
|
let timeout = if timeout.is_finite() && timeout > 0.0 { timeout } else { 0.0 };
|
|
202
299
|
let deadline = std::time::Instant::now() + std::time::Duration::from_secs_f64(timeout);
|
|
203
300
|
let mut readiness;
|
|
204
301
|
loop {
|
|
205
|
-
let mut state = crate::state::
|
|
206
|
-
|
|
207
|
-
|
|
302
|
+
let mut state = crate::state::projection::select_runtime_state(
|
|
303
|
+
&selected.run_workspace,
|
|
304
|
+
Some(&selected.team_key),
|
|
305
|
+
)
|
|
306
|
+
.unwrap_or_else(|_| selected.state.clone());
|
|
307
|
+
inject_tmux_session_present(&selected.run_workspace, &mut state);
|
|
308
|
+
inject_message_counts(&selected.run_workspace, &mut state)?;
|
|
208
309
|
readiness = wait_readiness(&state);
|
|
209
310
|
let awaiting_trust = readiness
|
|
210
311
|
.get("awaiting_trust_prompt")
|
|
@@ -231,6 +332,14 @@ pub(crate) fn build_wait_ready_report(workspace: &std::path::Path, timeout: f64)
|
|
|
231
332
|
)
|
|
232
333
|
} else if ready {
|
|
233
334
|
(true, "ready", "ready", "workers ready", Vec::new())
|
|
335
|
+
} else if readiness.get("session_capture_complete").and_then(Value::as_bool) == Some(false) {
|
|
336
|
+
(
|
|
337
|
+
false,
|
|
338
|
+
"pending",
|
|
339
|
+
"session_capture_incomplete",
|
|
340
|
+
"provider session capture is incomplete",
|
|
341
|
+
vec![json!("wait for provider session capture before restart")],
|
|
342
|
+
)
|
|
234
343
|
} else {
|
|
235
344
|
(
|
|
236
345
|
false,
|
|
@@ -241,7 +350,7 @@ pub(crate) fn build_wait_ready_report(workspace: &std::path::Path, timeout: f64)
|
|
|
241
350
|
)
|
|
242
351
|
};
|
|
243
352
|
let details_log = write_details_log(
|
|
244
|
-
|
|
353
|
+
&selected.run_workspace,
|
|
245
354
|
"wait-ready",
|
|
246
355
|
&json!({
|
|
247
356
|
"ok": ok,
|
|
@@ -282,6 +391,20 @@ pub(crate) fn wait_readiness(state: &Value) -> Value {
|
|
|
282
391
|
let mut mcp_ready = false;
|
|
283
392
|
let mut task_prompt_delivered = false;
|
|
284
393
|
let mut awaiting_trust_prompt = false;
|
|
394
|
+
let mut incomplete_sessions = Vec::new();
|
|
395
|
+
let all_attached_receiver = state
|
|
396
|
+
.get("leader_receiver")
|
|
397
|
+
.and_then(Value::as_object)
|
|
398
|
+
.is_none_or(|receiver| {
|
|
399
|
+
receiver
|
|
400
|
+
.get("status")
|
|
401
|
+
.and_then(Value::as_str)
|
|
402
|
+
== Some("attached")
|
|
403
|
+
|| receiver
|
|
404
|
+
.get("pane_id")
|
|
405
|
+
.and_then(Value::as_str)
|
|
406
|
+
.is_some_and(|pane| !pane.is_empty() && pane != "__team_agent_unbound__")
|
|
407
|
+
});
|
|
285
408
|
|
|
286
409
|
if let Some(agents) = agents {
|
|
287
410
|
process_started = state
|
|
@@ -314,14 +437,25 @@ pub(crate) fn wait_readiness(state: &Value) -> Value {
|
|
|
314
437
|
.and_then(Value::as_str)
|
|
315
438
|
== Some("awaiting_trust_prompt")
|
|
316
439
|
});
|
|
440
|
+
incomplete_sessions = crate::session_capture::incomplete_interacted_resumable_agent_ids(state);
|
|
317
441
|
}
|
|
318
|
-
let
|
|
442
|
+
let all_resumable_have_session = incomplete_sessions.is_empty();
|
|
443
|
+
let session_capture_incomplete = !all_resumable_have_session;
|
|
444
|
+
let all_spawned = process_started && cli_prompt_ready && mcp_ready;
|
|
445
|
+
let ready = all_spawned && all_attached_receiver && all_resumable_have_session;
|
|
319
446
|
json!({
|
|
447
|
+
"all_attached_receiver": all_attached_receiver,
|
|
448
|
+
"all_resumable_have_session": all_resumable_have_session,
|
|
449
|
+
"all_spawned": all_spawned,
|
|
320
450
|
"awaiting_trust_prompt": awaiting_trust_prompt,
|
|
321
451
|
"cli_prompt_ready": cli_prompt_ready,
|
|
452
|
+
"incomplete_session_capture_agents": incomplete_sessions.clone(),
|
|
322
453
|
"mcp_ready": mcp_ready,
|
|
323
454
|
"process_started": process_started,
|
|
324
455
|
"ready": ready,
|
|
456
|
+
"session_capture_complete": all_resumable_have_session,
|
|
457
|
+
"session_capture_incomplete": session_capture_incomplete,
|
|
458
|
+
"pending_session_agent_ids": incomplete_sessions,
|
|
325
459
|
"task_prompt_delivered": task_prompt_delivered,
|
|
326
460
|
})
|
|
327
461
|
}
|