@team-agent/installer 0.5.3 → 0.5.5
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 +9 -1
- package/crates/team-agent/src/cli/diagnose.rs +191 -31
- package/crates/team-agent/src/cli/mod.rs +93 -34
- package/crates/team-agent/src/cli/send.rs +69 -2
- package/crates/team-agent/src/cli/status_port.rs +62 -0
- package/crates/team-agent/src/cli/tests/status_send.rs +12 -19
- package/crates/team-agent/src/coordinator/tick.rs +13 -0
- package/crates/team-agent/src/lifecycle/launch.rs +14 -6
- package/crates/team-agent/src/lifecycle/restart/agent.rs +44 -1
- package/crates/team-agent/src/lifecycle/restart/common.rs +53 -2
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +108 -6
- package/crates/team-agent/src/lifecycle/restart/selection.rs +47 -18
- package/crates/team-agent/src/lifecycle/restart.rs +16 -6
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +287 -53
- package/crates/team-agent/src/lifecycle/tests/restart.rs +144 -5
- package/crates/team-agent/src/lifecycle/types.rs +1 -0
- package/crates/team-agent/src/messaging/delivery.rs +209 -30
- package/crates/team-agent/src/messaging/leader_receiver.rs +60 -25
- package/crates/team-agent/src/messaging/tests/runtime.rs +446 -0
- package/crates/team-agent/src/messaging/watchers.rs +36 -19
- package/crates/team-agent/src/provider/adapter.rs +103 -41
- package/crates/team-agent/src/provider/session/capture.rs +328 -66
- package/crates/team-agent/src/provider/session/resume.rs +30 -28
- package/crates/team-agent/src/provider/session_scan/common.rs +117 -1
- package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
- package/crates/team-agent/src/provider/session_scan.rs +1 -0
- package/crates/team-agent/src/state/persist.rs +17 -0
- package/crates/team-agent/src/state/projection.rs +59 -4
- package/package.json +4 -4
|
@@ -67,7 +67,11 @@ pub fn classify_first_send_at(raw: &serde_json::Value) -> FirstSendAtState {
|
|
|
67
67
|
/// * lifecycle/restart/common.rs::restart_required_missing_session_agent_ids
|
|
68
68
|
pub(crate) fn restart_agent_has_context_to_preserve(agent: &serde_json::Value) -> bool {
|
|
69
69
|
let has_valid_first_send_at = matches!(
|
|
70
|
-
classify_first_send_at(
|
|
70
|
+
classify_first_send_at(
|
|
71
|
+
agent
|
|
72
|
+
.get("first_send_at")
|
|
73
|
+
.unwrap_or(&serde_json::Value::Null)
|
|
74
|
+
),
|
|
71
75
|
FirstSendAtState::Valid
|
|
72
76
|
);
|
|
73
77
|
if has_valid_first_send_at {
|
|
@@ -242,6 +246,7 @@ pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
|
242
246
|
let provider = agent_provider(agent);
|
|
243
247
|
let provider_wire = provider_wire(provider);
|
|
244
248
|
let provider_can_resume = provider_supports_resume(provider);
|
|
249
|
+
let rollout_path = agent_rollout_path(agent);
|
|
245
250
|
// Layer 2 self-healing (leader follow-up 2026-06-22): use the
|
|
246
251
|
// structured probe so we can carry the list of paths the runtime
|
|
247
252
|
// actually checked into the refusal — operators need to see WHICH
|
|
@@ -256,16 +261,15 @@ pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
|
256
261
|
agent,
|
|
257
262
|
provider,
|
|
258
263
|
session,
|
|
259
|
-
|
|
264
|
+
rollout_path.as_ref(),
|
|
260
265
|
);
|
|
261
266
|
(probe.exists, probe.checked_paths)
|
|
262
267
|
}
|
|
263
268
|
(None, Some(_), true) if resumable_provider_requires_backing(provider_wire) => {
|
|
264
|
-
let
|
|
265
|
-
let exists = path_opt
|
|
269
|
+
let exists = rollout_path
|
|
266
270
|
.as_ref()
|
|
267
271
|
.is_some_and(|path| path.as_path().exists());
|
|
268
|
-
let checked =
|
|
272
|
+
let checked = rollout_path
|
|
269
273
|
.as_ref()
|
|
270
274
|
.map(|p| vec![p.as_path().to_path_buf()])
|
|
271
275
|
.unwrap_or_default();
|
|
@@ -273,6 +277,12 @@ pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
|
273
277
|
}
|
|
274
278
|
_ => (true, Vec::new()),
|
|
275
279
|
};
|
|
280
|
+
let identity_probe =
|
|
281
|
+
session_identity_probe_for_agent(&agent_id, provider, rollout_path.as_ref());
|
|
282
|
+
let session_identity_mismatch = session_id.is_some()
|
|
283
|
+
&& provider_can_resume
|
|
284
|
+
&& resume_backing_exists
|
|
285
|
+
&& identity_probe.identity_ok == Some(false);
|
|
276
286
|
// 0.4.7 partial-resume + RESTART-RESUME-001 (0.4.8): when a worker
|
|
277
287
|
// has NEVER been captured (no session_id AND no context-bearing
|
|
278
288
|
// signal at all), it is structurally non-resumable — there is no
|
|
@@ -292,7 +302,11 @@ pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
|
292
302
|
let _ = first_send_at_state; // retained for the Corrupt branch above
|
|
293
303
|
let never_captured =
|
|
294
304
|
restart_agent_never_captured(agent, session_id.as_ref().map(|s| s.as_str()));
|
|
295
|
-
let decision = if session_id.is_some()
|
|
305
|
+
let decision = if session_id.is_some()
|
|
306
|
+
&& provider_can_resume
|
|
307
|
+
&& resume_backing_exists
|
|
308
|
+
&& !session_identity_mismatch
|
|
309
|
+
{
|
|
296
310
|
ResumeDecision::Resume
|
|
297
311
|
} else if session_id.is_some() && allow_fresh {
|
|
298
312
|
ResumeDecision::FreshStart
|
|
@@ -313,7 +327,24 @@ pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
|
313
327
|
// (round-tripped through ResumeRefusalReason::wire) so the
|
|
314
328
|
// CLI/JSON contract does not change.
|
|
315
329
|
let (reason_str, structured) = if session_id.is_some() {
|
|
316
|
-
if
|
|
330
|
+
if session_identity_mismatch {
|
|
331
|
+
let session = session_id
|
|
332
|
+
.as_ref()
|
|
333
|
+
.map(|session| session.as_str().to_string())
|
|
334
|
+
.unwrap_or_default();
|
|
335
|
+
(
|
|
336
|
+
"session_identity_mismatch".to_string(),
|
|
337
|
+
crate::provider::session::ResumeRefusalReason::SessionIdentityMismatch {
|
|
338
|
+
expected_agent_id: agent_id.as_str().to_string(),
|
|
339
|
+
embedded_agent_id: identity_probe
|
|
340
|
+
.embedded_agent_id
|
|
341
|
+
.clone()
|
|
342
|
+
.unwrap_or_default(),
|
|
343
|
+
session_id: session,
|
|
344
|
+
rollout_path: identity_probe.rollout_path.clone(),
|
|
345
|
+
},
|
|
346
|
+
)
|
|
347
|
+
} else if !provider_can_resume {
|
|
317
348
|
(
|
|
318
349
|
"session_unresumable".to_string(),
|
|
319
350
|
crate::provider::session::ResumeRefusalReason::ProviderResumeUnsupported {
|
|
@@ -330,17 +361,15 @@ pub(crate) fn classify_restart_plan_with_resume_validation(
|
|
|
330
361
|
// a recovery hint pointing at the agent_id (used as
|
|
331
362
|
// launch-time `--name`) and spawn_cwd. Operator-facing
|
|
332
363
|
// diagnostic only — no auto-resume off the hint.
|
|
333
|
-
let recovery_hint = Some(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
spawn_cwd
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
},
|
|
343
|
-
);
|
|
364
|
+
let recovery_hint = Some(crate::provider::session::RecoveryHint {
|
|
365
|
+
provider_session_name_hint: Some(agent_id.as_str().to_string()),
|
|
366
|
+
spawn_cwd: agent
|
|
367
|
+
.get("spawn_cwd")
|
|
368
|
+
.and_then(|v| v.as_str())
|
|
369
|
+
.filter(|s| !s.is_empty())
|
|
370
|
+
.map(std::path::PathBuf::from),
|
|
371
|
+
provider: provider_wire.to_string(),
|
|
372
|
+
});
|
|
344
373
|
(
|
|
345
374
|
"session_unresumable".to_string(),
|
|
346
375
|
crate::provider::session::ResumeRefusalReason::SessionBackingStoreMissing {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! lifecycle::restart —— 单 worker 起/停/重置/删 + 整队 Route B 重建 + plan halt/status。
|
|
2
2
|
|
|
3
|
-
use std::path::Path;
|
|
4
3
|
use std::collections::BTreeMap;
|
|
4
|
+
use std::path::Path;
|
|
5
5
|
|
|
6
6
|
use crate::model::enums::{AuthMode, Provider};
|
|
7
7
|
use crate::model::ids::AgentId;
|
|
@@ -32,22 +32,28 @@ mod remove;
|
|
|
32
32
|
mod selection;
|
|
33
33
|
mod team_state;
|
|
34
34
|
|
|
35
|
-
pub use agent::{reset_agent, reset_agent_with_transport, start_agent, start_agent_with_transport, stop_agent, stop_agent_with_transport};
|
|
36
35
|
pub(crate) use agent::start_agent_at_paths;
|
|
36
|
+
pub use agent::{
|
|
37
|
+
reset_agent, reset_agent_with_transport, start_agent, start_agent_with_transport, stop_agent,
|
|
38
|
+
stop_agent_with_transport,
|
|
39
|
+
};
|
|
37
40
|
pub(crate) use common::refresh_missing_provider_sessions;
|
|
38
41
|
pub(crate) use common::restart_required_missing_session_agent_ids;
|
|
42
|
+
pub(crate) use common::session_identity_probe_for_agent;
|
|
39
43
|
// 0.3.24 add-agent socket drift fix: state-aware tmux resolver shared with
|
|
40
44
|
// `lifecycle::launch::add_agent` / `fork_agent` so all three (restart / add / fork)
|
|
41
45
|
// route to the SAME tmux socket the live team uses.
|
|
42
46
|
pub(crate) use common::lifecycle_worker_tmux_backend_for_selected_state;
|
|
43
47
|
pub use orchestrator::{halt_plan, plan_status};
|
|
48
|
+
pub(crate) use rebuild::restart_with_transport_with_session_convergence_deadline;
|
|
44
49
|
pub use rebuild::{
|
|
45
50
|
restart, restart_candidates, restart_with_session_convergence_deadline, restart_with_transport,
|
|
46
51
|
restart_with_transport_with_readiness_deadline, select_restart_state,
|
|
47
52
|
};
|
|
48
|
-
pub(crate) use rebuild::restart_with_transport_with_session_convergence_deadline;
|
|
49
53
|
pub use remove::{remove_agent, remove_agent_with_transport};
|
|
50
|
-
pub use selection::{
|
|
54
|
+
pub use selection::{
|
|
55
|
+
classify_first_send_at, classify_restart_plan, decide_start_mode, python_type_name,
|
|
56
|
+
};
|
|
51
57
|
// Layer 2 (leader follow-up 2026-06-22): test-visible workspace-aware
|
|
52
58
|
// classification so lifecycle/tests/restart.rs can exercise the
|
|
53
59
|
// SessionBackingStoreMissing + checked_paths + RecoveryHint path
|
|
@@ -55,7 +61,9 @@ pub use selection::{classify_first_send_at, classify_restart_plan, decide_start_
|
|
|
55
61
|
pub(crate) use selection::classify_restart_plan_with_resume_validation;
|
|
56
62
|
pub(crate) use team_state::write_team_state;
|
|
57
63
|
|
|
58
|
-
pub(crate) fn lifecycle_run_workspace(
|
|
64
|
+
pub(crate) fn lifecycle_run_workspace(
|
|
65
|
+
workspace: &Path,
|
|
66
|
+
) -> Result<std::path::PathBuf, LifecycleError> {
|
|
59
67
|
crate::model::paths::canonical_run_workspace(workspace)
|
|
60
68
|
.map_err(|e| LifecycleError::StatePersist(e.to_string()))
|
|
61
69
|
}
|
|
@@ -93,7 +101,9 @@ fn lifecycle_paths(workspace: &Path, team: Option<&str>) -> Result<LifecyclePath
|
|
|
93
101
|
.spec_workspace
|
|
94
102
|
.clone()
|
|
95
103
|
.or_else(|| selected_state_spec_workspace(&selected.state))
|
|
96
|
-
.ok_or_else(||
|
|
104
|
+
.ok_or_else(|| {
|
|
105
|
+
LifecycleError::TeamSelect("active team spec workspace not found".to_string())
|
|
106
|
+
})?;
|
|
97
107
|
Ok(LifecyclePaths {
|
|
98
108
|
run_workspace: selected.run_workspace,
|
|
99
109
|
spec_workspace,
|