@team-agent/installer 0.5.16 → 0.5.18
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/mod.rs +51 -70
- package/crates/team-agent/src/cli/status_port.rs +5 -0
- package/crates/team-agent/src/cli/tests/lane_c.rs +17 -7
- package/crates/team-agent/src/coordinator/backoff.rs +15 -14
- package/crates/team-agent/src/coordinator/health.rs +142 -12
- package/crates/team-agent/src/coordinator/tests/basics.rs +4 -0
- package/crates/team-agent/src/coordinator/tests/mod.rs +3 -0
- package/crates/team-agent/src/coordinator/tick.rs +70 -68
- package/crates/team-agent/src/coordinator/types.rs +47 -0
- package/crates/team-agent/src/diagnose/orphans.rs +35 -13
- package/crates/team-agent/src/leader/registry.rs +104 -0
- package/crates/team-agent/src/lifecycle/restart/agent.rs +4 -2
- package/crates/team-agent/src/lifecycle/restart/common.rs +6 -3
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +39 -20
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/lifecycle_lock.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +218 -39
- package/crates/team-agent/src/lifecycle/types.rs +48 -0
- package/crates/team-agent/src/messaging/results.rs +7 -0
- package/package.json +4 -4
|
@@ -242,7 +242,7 @@ fn r2_lifecycle_lock_exists_precondition() {
|
|
|
242
242
|
assert_public_operation(&rebuild, "restart");
|
|
243
243
|
let drop_idx = rebuild.find("drop(lifecycle_lock);").unwrap();
|
|
244
244
|
let coordinator_idx = rebuild
|
|
245
|
-
.find("start_coordinator_for_workspace(&selected.run_workspace)")
|
|
245
|
+
.find("start_coordinator_for_workspace(&selected.run_workspace, Some(&selected.team_key))")
|
|
246
246
|
.unwrap();
|
|
247
247
|
let readiness_idx = rebuild.find("wait_restart_readiness_or_timeout(").unwrap();
|
|
248
248
|
assert!(
|
|
@@ -19,6 +19,9 @@ use serde_json::json;
|
|
|
19
19
|
use std::collections::BTreeSet;
|
|
20
20
|
use std::time::Duration;
|
|
21
21
|
|
|
22
|
+
#[allow(dead_code)]
|
|
23
|
+
struct HermeticTestEnv;
|
|
24
|
+
|
|
22
25
|
#[test]
|
|
23
26
|
fn concurrent_reset_discard_session_serializes() {
|
|
24
27
|
let ids = (1..=6).map(|n| format!("w{n}")).collect::<Vec<_>>();
|
|
@@ -9,22 +9,89 @@ use crate::transport::WindowName;
|
|
|
9
9
|
use serde_json::{json, Map, Value};
|
|
10
10
|
use std::collections::{BTreeMap, BTreeSet};
|
|
11
11
|
use std::path::{Path, PathBuf};
|
|
12
|
+
use std::sync::atomic::{AtomicU64, Ordering};
|
|
12
13
|
|
|
13
14
|
const ANCESTRY_ENV: &str = "TEAM_AGENT_TEST_PROCESS_ANCESTRY_ARGV_JSON";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
|
|
16
|
+
static HERMETIC_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
17
|
+
|
|
18
|
+
struct HermeticTestEnv {
|
|
19
|
+
root: PathBuf,
|
|
20
|
+
previous: Vec<(&'static str, Option<String>)>,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl HermeticTestEnv {
|
|
24
|
+
fn enter(tag: &str) -> Self {
|
|
25
|
+
let base = std::env::var_os("TEAM_AGENT_TEST_TMP")
|
|
26
|
+
.map(PathBuf::from)
|
|
27
|
+
.unwrap_or_else(std::env::temp_dir);
|
|
28
|
+
std::fs::create_dir_all(&base).expect("create hermetic test tmp root");
|
|
29
|
+
let root = base.join(format!(
|
|
30
|
+
"ta-phase-golden-{tag}-{}-{}",
|
|
31
|
+
std::process::id(),
|
|
32
|
+
HERMETIC_COUNTER.fetch_add(1, Ordering::Relaxed)
|
|
33
|
+
));
|
|
34
|
+
let _ = std::fs::remove_dir_all(&root);
|
|
35
|
+
std::fs::create_dir_all(root.join("home/.team-agent/leaders"))
|
|
36
|
+
.expect("create phase golden hermetic root");
|
|
37
|
+
let root = std::fs::canonicalize(root).expect("canonicalize phase golden hermetic root");
|
|
38
|
+
let home = root.join("home");
|
|
39
|
+
let mut previous = Vec::new();
|
|
40
|
+
for key in std::iter::once("HOME").chain(hermetic_caller_envs().iter().copied()) {
|
|
41
|
+
previous.push((key, std::env::var(key).ok()));
|
|
42
|
+
}
|
|
43
|
+
unsafe {
|
|
44
|
+
std::env::set_var("HOME", &home);
|
|
45
|
+
for key in hermetic_caller_envs() {
|
|
46
|
+
std::env::remove_var(key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
Self { root, previous }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn workspace(&self, tag: &str) -> PathBuf {
|
|
53
|
+
let path = self.root.join(format!(
|
|
54
|
+
"workspace-{tag}-{}",
|
|
55
|
+
HERMETIC_COUNTER.fetch_add(1, Ordering::Relaxed)
|
|
56
|
+
));
|
|
57
|
+
std::fs::create_dir_all(&path).expect("create phase golden workspace");
|
|
58
|
+
std::fs::canonicalize(path).expect("canonicalize phase golden workspace")
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
impl Drop for HermeticTestEnv {
|
|
63
|
+
fn drop(&mut self) {
|
|
64
|
+
for (key, value) in self.previous.drain(..).rev() {
|
|
65
|
+
unsafe {
|
|
66
|
+
if let Some(value) = value {
|
|
67
|
+
std::env::set_var(key, value);
|
|
68
|
+
} else {
|
|
69
|
+
std::env::remove_var(key);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if std::env::var("TEAM_AGENT_KEEP_TEST_TMP").as_deref() != Ok("1") {
|
|
74
|
+
let _ = std::fs::remove_dir_all(&self.root);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fn hermetic_caller_envs() -> &'static [&'static str] {
|
|
80
|
+
&[
|
|
81
|
+
"TMUX",
|
|
82
|
+
"TMUX_PANE",
|
|
83
|
+
"TEAM_AGENT_LEADER_PANE_ID",
|
|
84
|
+
"TEAM_AGENT_LEADER_SESSION_UUID",
|
|
85
|
+
"TEAM_AGENT_LEADER_SESSION_UUID_OVERRIDE",
|
|
86
|
+
"TEAM_AGENT_LEADER_PROVIDER",
|
|
87
|
+
"TEAM_AGENT_MACHINE_FINGERPRINT",
|
|
88
|
+
"TEAM_AGENT_WORKSPACE",
|
|
89
|
+
"TEAM_AGENT_TEAM_ID",
|
|
90
|
+
"TEAM_AGENT_OWNER_TEAM_ID",
|
|
91
|
+
"TEAM_AGENT_ACTIVE_TEAM",
|
|
92
|
+
"TEAM_AGENT_ID",
|
|
93
|
+
]
|
|
94
|
+
}
|
|
28
95
|
|
|
29
96
|
#[test]
|
|
30
97
|
#[serial_test::serial(env)]
|
|
@@ -154,12 +221,9 @@ struct PhaseGolden {
|
|
|
154
221
|
}
|
|
155
222
|
|
|
156
223
|
fn run_phase_golden(spec: PhaseGolden) -> Value {
|
|
224
|
+
let hermetic = HermeticTestEnv::enter(spec.phase);
|
|
157
225
|
let _permission_mode = EnvVarGuard::set(ANCESTRY_ENV, "[]");
|
|
158
|
-
let
|
|
159
|
-
.iter()
|
|
160
|
-
.map(|key| EnvVarGuard::unset(key))
|
|
161
|
-
.collect::<Vec<_>>();
|
|
162
|
-
let team = two_worker_team_dir();
|
|
226
|
+
let team = two_worker_team_dir(&hermetic);
|
|
163
227
|
let workspace = team.parent().expect("workspace").to_path_buf();
|
|
164
228
|
seed_healthy_coordinator(&workspace);
|
|
165
229
|
let launch_transport = codex_ready_transport();
|
|
@@ -298,8 +362,8 @@ fn phase_b_reset_discard_session(
|
|
|
298
362
|
}
|
|
299
363
|
}
|
|
300
364
|
|
|
301
|
-
fn two_worker_team_dir() -> PathBuf {
|
|
302
|
-
let team =
|
|
365
|
+
fn two_worker_team_dir(hermetic: &HermeticTestEnv) -> PathBuf {
|
|
366
|
+
let team = hermetic.workspace("team").join("teamdir");
|
|
303
367
|
std::fs::create_dir_all(team.join("agents")).unwrap();
|
|
304
368
|
std::fs::write(
|
|
305
369
|
team.join("TEAM.md"),
|
|
@@ -414,14 +478,6 @@ impl EnvVarGuard {
|
|
|
414
478
|
}
|
|
415
479
|
Self { key, previous }
|
|
416
480
|
}
|
|
417
|
-
|
|
418
|
-
fn unset(key: &'static str) -> Self {
|
|
419
|
-
let previous = std::env::var(key).ok();
|
|
420
|
-
unsafe {
|
|
421
|
-
std::env::remove_var(key);
|
|
422
|
-
}
|
|
423
|
-
Self { key, previous }
|
|
424
|
-
}
|
|
425
481
|
}
|
|
426
482
|
|
|
427
483
|
impl Drop for EnvVarGuard {
|
|
@@ -524,6 +580,9 @@ fn normalize_string(text: String, ctx: &mut NormalizeCtx, key: Option<&str>) ->
|
|
|
524
580
|
if key_is_timestamp(key) {
|
|
525
581
|
return json!("<TS>");
|
|
526
582
|
}
|
|
583
|
+
if text == crate::packaging::Version::current().as_str() {
|
|
584
|
+
return json!("<VERSION>");
|
|
585
|
+
}
|
|
527
586
|
if key.contains("endpoint") && value_looks_like_endpoint_path(&text) {
|
|
528
587
|
return json!("<SOCKET>");
|
|
529
588
|
}
|
|
@@ -545,6 +604,7 @@ fn normalize_string(text: String, ctx: &mut NormalizeCtx, key: Option<&str>) ->
|
|
|
545
604
|
|
|
546
605
|
fn normalize_path_string(text: &str, ctx: &NormalizeCtx) -> String {
|
|
547
606
|
let mut out = text.to_string();
|
|
607
|
+
out = normalize_team_agent_binary_path(&out);
|
|
548
608
|
for alias in &ctx.workspace_aliases {
|
|
549
609
|
out = out.replace(alias, "<WORKSPACE>");
|
|
550
610
|
}
|
|
@@ -552,7 +612,6 @@ fn normalize_path_string(text: &str, ctx: &NormalizeCtx) -> String {
|
|
|
552
612
|
for alias in &ctx.temp_aliases {
|
|
553
613
|
out = out.replace(alias, "<TMP>");
|
|
554
614
|
}
|
|
555
|
-
out = normalize_team_agent_binary_path(&out);
|
|
556
615
|
out = normalize_tmux_socket_dir(&out);
|
|
557
616
|
normalize_socket_token(&out)
|
|
558
617
|
}
|
|
@@ -565,7 +624,7 @@ fn value_looks_like_endpoint_path(text: &str) -> bool {
|
|
|
565
624
|
}
|
|
566
625
|
|
|
567
626
|
fn normalize_team_agent_binary_path(text: &str) -> String {
|
|
568
|
-
let mut out = text
|
|
627
|
+
let mut out = replace_known_team_agent_binary_paths(text);
|
|
569
628
|
// 0.5.0 hermetic 教训「环境路径类 token 化」的直接延伸
|
|
570
629
|
// (leader msg_6ee04cf5aee8):归一化改为结构判据,不绑路径前缀。
|
|
571
630
|
// 用户 CARGO_TARGET_DIR 可以指到任意目录(默认 `<repo>/target`,
|
|
@@ -585,6 +644,30 @@ fn normalize_team_agent_binary_path(text: &str) -> String {
|
|
|
585
644
|
out
|
|
586
645
|
}
|
|
587
646
|
|
|
647
|
+
fn replace_known_team_agent_binary_paths(text: &str) -> String {
|
|
648
|
+
let mut out = text.to_string();
|
|
649
|
+
for alias in known_team_agent_binary_path_aliases() {
|
|
650
|
+
out = out.replace(&alias, "<TEAM_AGENT_BIN>");
|
|
651
|
+
}
|
|
652
|
+
out
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
fn known_team_agent_binary_path_aliases() -> Vec<String> {
|
|
656
|
+
let mut aliases = Vec::new();
|
|
657
|
+
if let Some(path) = option_env!("CARGO_BIN_EXE_team-agent") {
|
|
658
|
+
push_path_alias(&mut aliases, PathBuf::from(path));
|
|
659
|
+
}
|
|
660
|
+
if let Some(path) = std::env::var_os("CARGO_BIN_EXE_team-agent") {
|
|
661
|
+
push_path_alias(&mut aliases, PathBuf::from(path));
|
|
662
|
+
}
|
|
663
|
+
if let Ok(path) = std::env::current_exe() {
|
|
664
|
+
push_path_alias(&mut aliases, path);
|
|
665
|
+
}
|
|
666
|
+
aliases.sort_by(|a, b| b.len().cmp(&a.len()).then_with(|| a.cmp(b)));
|
|
667
|
+
aliases.dedup();
|
|
668
|
+
aliases
|
|
669
|
+
}
|
|
670
|
+
|
|
588
671
|
/// Structural (path-prefix-independent) normalization for
|
|
589
672
|
/// `/…/deps/team_agent-<hex>(.exe)?` occurrences. Scans the input for
|
|
590
673
|
/// every `/deps/team_agent-` marker and rewrites the containing
|
|
@@ -693,17 +776,31 @@ fn normalize_tmux_uid_with_prefix(mut text: String, prefix: &str) -> String {
|
|
|
693
776
|
}
|
|
694
777
|
|
|
695
778
|
fn normalize_socket_token(text: &str) -> String {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
779
|
+
const CONTEXT: &str = "/tmux-<UID>/";
|
|
780
|
+
let mut out = String::with_capacity(text.len());
|
|
781
|
+
let mut search_from = 0;
|
|
782
|
+
while let Some(offset) = text[search_from..].find(CONTEXT) {
|
|
783
|
+
let context_start = search_from + offset;
|
|
784
|
+
let token_start = context_start + CONTEXT.len();
|
|
785
|
+
if !text[token_start..].starts_with("ta-") {
|
|
786
|
+
out.push_str(&text[search_from..token_start]);
|
|
787
|
+
search_from = token_start;
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
let end = text[token_start..]
|
|
699
791
|
.find(|c: char| !(c.is_ascii_alphanumeric() || c == '-'))
|
|
700
|
-
.map(|offset|
|
|
701
|
-
.unwrap_or_else(||
|
|
702
|
-
if end ==
|
|
703
|
-
|
|
792
|
+
.map(|offset| token_start + offset)
|
|
793
|
+
.unwrap_or_else(|| text.len());
|
|
794
|
+
if end == token_start + 3 {
|
|
795
|
+
out.push_str(&text[search_from..end]);
|
|
796
|
+
search_from = end;
|
|
797
|
+
continue;
|
|
704
798
|
}
|
|
705
|
-
out.
|
|
799
|
+
out.push_str(&text[search_from..token_start]);
|
|
800
|
+
out.push_str("ta-<SOCKET>");
|
|
801
|
+
search_from = end;
|
|
706
802
|
}
|
|
803
|
+
out.push_str(&text[search_from..]);
|
|
707
804
|
out
|
|
708
805
|
}
|
|
709
806
|
|
|
@@ -744,3 +841,85 @@ fn pretty(value: &Value) -> String {
|
|
|
744
841
|
text.push('\n');
|
|
745
842
|
text
|
|
746
843
|
}
|
|
844
|
+
|
|
845
|
+
#[test]
|
|
846
|
+
fn phase_golden_normalizer_maps_custom_cargo_target_deps_binary_before_tmp_aliasing() {
|
|
847
|
+
let ctx = NormalizeCtx {
|
|
848
|
+
workspace_aliases: Vec::new(),
|
|
849
|
+
temp_aliases: vec!["/Volumes/nvme/tmp".to_string()],
|
|
850
|
+
pane_ids: BTreeMap::new(),
|
|
851
|
+
};
|
|
852
|
+
let input = concat!(
|
|
853
|
+
"mcp_servers.team_orchestrator.command=\"",
|
|
854
|
+
"/Volumes/nvme/tmp/ta-0517-target/debug/deps/team_agent-c924abc123",
|
|
855
|
+
"\""
|
|
856
|
+
);
|
|
857
|
+
|
|
858
|
+
assert_eq!(
|
|
859
|
+
normalize_path_string(input, &ctx),
|
|
860
|
+
"mcp_servers.team_orchestrator.command=\"<TEAM_AGENT_BIN>\"",
|
|
861
|
+
"custom CARGO_TARGET_DIR binary paths must normalize to <TEAM_AGENT_BIN> before tmp/socket tokenization"
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
#[test]
|
|
866
|
+
fn phase_golden_normalizer_maps_current_test_binary_to_team_agent_marker() {
|
|
867
|
+
let ctx = NormalizeCtx {
|
|
868
|
+
workspace_aliases: Vec::new(),
|
|
869
|
+
temp_aliases: vec!["/Volumes/nvme/tmp".to_string()],
|
|
870
|
+
pane_ids: BTreeMap::new(),
|
|
871
|
+
};
|
|
872
|
+
let input = format!(
|
|
873
|
+
"mcp_servers.team_orchestrator.command=\"{}\"",
|
|
874
|
+
std::env::current_exe()
|
|
875
|
+
.expect("current test binary path")
|
|
876
|
+
.display()
|
|
877
|
+
);
|
|
878
|
+
|
|
879
|
+
assert_eq!(
|
|
880
|
+
normalize_path_string(&input, &ctx),
|
|
881
|
+
"mcp_servers.team_orchestrator.command=\"<TEAM_AGENT_BIN>\"",
|
|
882
|
+
"actual test argv0/current_exe path must normalize to <TEAM_AGENT_BIN>"
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
#[test]
|
|
887
|
+
fn phase_golden_normalizer_does_not_treat_cargo_target_dir_as_socket_token() {
|
|
888
|
+
let ctx = NormalizeCtx {
|
|
889
|
+
workspace_aliases: Vec::new(),
|
|
890
|
+
temp_aliases: vec!["/Volumes/nvme/tmp".to_string()],
|
|
891
|
+
pane_ids: BTreeMap::new(),
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
assert_eq!(
|
|
895
|
+
normalize_path_string("/Volumes/nvme/tmp/ta-0517-target/build.log", &ctx),
|
|
896
|
+
"<TMP>/ta-0517-target/build.log",
|
|
897
|
+
"ta-* directory names outside tmux socket context must not be rewritten as ta-<SOCKET>"
|
|
898
|
+
);
|
|
899
|
+
assert_eq!(
|
|
900
|
+
normalize_path_string("tmux -S /tmp/tmux-501/ta-a60d10b25edd attach", &ctx),
|
|
901
|
+
"tmux -S <TMP>/tmux-<UID>/ta-<SOCKET> attach",
|
|
902
|
+
"real tmux socket paths still need stable socket tokenization"
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
#[test]
|
|
907
|
+
fn phase_golden_normalizer_maps_current_version_by_value_only() {
|
|
908
|
+
let mut ctx = NormalizeCtx {
|
|
909
|
+
workspace_aliases: Vec::new(),
|
|
910
|
+
temp_aliases: Vec::new(),
|
|
911
|
+
pane_ids: BTreeMap::new(),
|
|
912
|
+
};
|
|
913
|
+
let current = crate::packaging::Version::current().as_str().to_string();
|
|
914
|
+
|
|
915
|
+
assert_eq!(
|
|
916
|
+
normalize_string(current.clone(), &mut ctx, Some("arbitrary_field")),
|
|
917
|
+
json!("<VERSION>"),
|
|
918
|
+
"current binary version values must normalize without depending on field names"
|
|
919
|
+
);
|
|
920
|
+
assert_eq!(
|
|
921
|
+
normalize_string(format!("version={current}"), &mut ctx, Some("binary_version")),
|
|
922
|
+
json!(format!("version={current}")),
|
|
923
|
+
"version normalization must be exact-value based, not a broad substring or field-name rewrite"
|
|
924
|
+
);
|
|
925
|
+
}
|
|
@@ -83,6 +83,52 @@ impl PlanId {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
87
|
+
pub struct CoordinatorStartSummary {
|
|
88
|
+
pub ok: bool,
|
|
89
|
+
pub status: String,
|
|
90
|
+
pub pid: Option<u32>,
|
|
91
|
+
pub binary_path: Option<String>,
|
|
92
|
+
pub binary_version: Option<String>,
|
|
93
|
+
pub rotation_reason: Option<String>,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
impl CoordinatorStartSummary {
|
|
97
|
+
pub fn from_start_report(report: &crate::coordinator::StartReport) -> Self {
|
|
98
|
+
Self {
|
|
99
|
+
ok: report.ok,
|
|
100
|
+
status: coordinator_start_status_wire(report.status).to_string(),
|
|
101
|
+
pid: report.pid.map(|pid| pid.get()),
|
|
102
|
+
binary_path: report.binary_path.clone(),
|
|
103
|
+
binary_version: report.binary_version.clone(),
|
|
104
|
+
rotation_reason: report.rotation_reason.clone(),
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fn coordinator_start_status_wire(status: crate::coordinator::StartOutcome) -> &'static str {
|
|
110
|
+
match status {
|
|
111
|
+
crate::coordinator::StartOutcome::AlreadyRunning => "already_running",
|
|
112
|
+
crate::coordinator::StartOutcome::RestartIncompatibleStopFailed => {
|
|
113
|
+
"restart_incompatible_stop_failed"
|
|
114
|
+
}
|
|
115
|
+
crate::coordinator::StartOutcome::SchemaIncompatible => "schema_incompatible",
|
|
116
|
+
crate::coordinator::StartOutcome::Started => "started",
|
|
117
|
+
crate::coordinator::StartOutcome::StartedAfterRotation => "started_after_rotation",
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pub fn coordinator_start_summary_value(summary: &CoordinatorStartSummary) -> serde_json::Value {
|
|
122
|
+
serde_json::json!({
|
|
123
|
+
"ok": summary.ok,
|
|
124
|
+
"status": summary.status,
|
|
125
|
+
"pid": summary.pid,
|
|
126
|
+
"binary_path": summary.binary_path,
|
|
127
|
+
"binary_version": summary.binary_version,
|
|
128
|
+
"rotation_reason": summary.rotation_reason,
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
86
132
|
impl std::fmt::Display for PlanId {
|
|
87
133
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
88
134
|
f.write_str(&self.0)
|
|
@@ -650,6 +696,7 @@ pub enum RestartReport {
|
|
|
650
696
|
session_name: SessionName,
|
|
651
697
|
agents: Vec<RestartedAgent>,
|
|
652
698
|
coordinator_started: bool,
|
|
699
|
+
coordinator: CoordinatorStartSummary,
|
|
653
700
|
next_actions: Vec<String>,
|
|
654
701
|
attach_commands: Vec<String>,
|
|
655
702
|
},
|
|
@@ -660,6 +707,7 @@ pub enum RestartReport {
|
|
|
660
707
|
agents: Vec<RestartedAgent>,
|
|
661
708
|
failed_agents: Vec<RestartFailedAgent>,
|
|
662
709
|
coordinator_started: bool,
|
|
710
|
+
coordinator: CoordinatorStartSummary,
|
|
663
711
|
next_actions: Vec<String>,
|
|
664
712
|
attach_commands: Vec<String>,
|
|
665
713
|
},
|
|
@@ -301,12 +301,19 @@ fn start_report_value(report: &crate::coordinator::StartReport) -> serde_json::V
|
|
|
301
301
|
}
|
|
302
302
|
crate::coordinator::StartOutcome::SchemaIncompatible => "schema_incompatible",
|
|
303
303
|
crate::coordinator::StartOutcome::Started => "started",
|
|
304
|
+
crate::coordinator::StartOutcome::StartedAfterRotation => "started_after_rotation",
|
|
304
305
|
};
|
|
305
306
|
let mut value = serde_json::json!({
|
|
306
307
|
"ok": report.ok,
|
|
307
308
|
"pid": report.pid.map(|p| p.get()),
|
|
308
309
|
"status": status,
|
|
310
|
+
"binary_path": report.binary_path.clone(),
|
|
311
|
+
"binary_version": report.binary_version.clone(),
|
|
312
|
+
"rotation_reason": report.rotation_reason.clone(),
|
|
309
313
|
});
|
|
314
|
+
if let Some(previous_pid) = report.previous_pid {
|
|
315
|
+
value["previous_pid"] = serde_json::json!(previous_pid.get());
|
|
316
|
+
}
|
|
310
317
|
if let Some(log) = &report.log {
|
|
311
318
|
value["log"] = serde_json::json!(log.to_string_lossy().to_string());
|
|
312
319
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-agent/installer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.18",
|
|
4
4
|
"description": "npx installer for Team Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"team-agent-installer": "npm/install.mjs"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@team-agent/cli-darwin-arm64": "0.5.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.5.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.5.
|
|
23
|
+
"@team-agent/cli-darwin-arm64": "0.5.18",
|
|
24
|
+
"@team-agent/cli-darwin-x64": "0.5.18",
|
|
25
|
+
"@team-agent/cli-linux-x64": "0.5.18"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postinstall": "node npm/bincheck.mjs",
|