@team-agent/installer 0.5.106 → 0.5.108

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.
Files changed (41) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +1 -1
  4. package/crates/team-agent/src/cli/emit.rs +3 -3
  5. package/crates/team-agent/src/cli/mod.rs +87 -4
  6. package/crates/team-agent/src/cli/models.rs +252 -3
  7. package/crates/team-agent/src/cli/spec.rs +1 -1
  8. package/crates/team-agent/src/cli/status_port/brief.rs +155 -37
  9. package/crates/team-agent/src/cli/tests/base.rs +112 -225
  10. package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +184 -0
  11. package/crates/team-agent/src/cli/tests/status_brief.rs +624 -0
  12. package/crates/team-agent/src/compiler/tests.rs +46 -59
  13. package/crates/team-agent/src/leader/tests/byte_findings.rs +1 -14
  14. package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +57 -173
  15. package/crates/team-agent/src/lifecycle/launch/pi_mcp_extension.js +226 -0
  16. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +0 -37
  17. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +0 -9
  18. package/crates/team-agent/src/lifecycle/tests/fixtures/pi_native_mcp_host.mjs +71 -0
  19. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -66
  20. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +0 -392
  21. package/crates/team-agent/src/lifecycle/tests/lifecycle_lock.rs +0 -5
  22. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +2 -361
  23. package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +1 -16
  24. package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +20 -112
  25. package/crates/team-agent/src/lifecycle/tests/pi_fork_session_inheritance_red.rs +1 -12
  26. package/crates/team-agent/src/lifecycle/tests/pi_native_mcp_capability_red.rs +546 -0
  27. package/crates/team-agent/src/lifecycle/tests.rs +1 -0
  28. package/crates/team-agent/src/lifecycle/worker_command_context.rs +11 -54
  29. package/crates/team-agent/src/messaging/tests/wave2.rs +2 -302
  30. package/crates/team-agent/src/model/name_similarity.rs +52 -67
  31. package/crates/team-agent/src/model/task_graph.rs +37 -124
  32. package/crates/team-agent/src/model/yaml/tests.rs +46 -165
  33. package/crates/team-agent/src/provider/model_catalog.rs +166 -3
  34. package/crates/team-agent/src/provider/testdata/cursor-list-models-native.stdout +250 -0
  35. package/crates/team-agent/src/provider/testdata/grok-models-authenticated.stdout +9 -0
  36. package/crates/team-agent/src/provider/testdata/grok-models-unauthenticated.stdout +7 -0
  37. package/crates/team-agent/src/provider/tests/adapter.rs +0 -20
  38. package/crates/team-agent/src/provider/tests/classify.rs +106 -198
  39. package/crates/team-agent/src/tmux_backend/tests.rs +178 -501
  40. package/crates/team-agent/src/transport/tests/wire.rs +0 -55
  41. package/package.json +4 -4
@@ -1930,3 +1930,187 @@ fn unit0_sessions_to_kill_leader_prefixed_session_is_always_spared() {
1930
1930
  ),
1931
1931
  }
1932
1932
  }
1933
+
1934
+ const ISSUE_269_ROOT_PID: u32 = 2_147_000_001;
1935
+
1936
+ std::thread_local! {
1937
+ static ISSUE_269_LIVENESS_CALLS: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
1938
+ static ISSUE_269_FIRST_ALIVE: std::cell::RefCell<Option<std::time::Instant>> = const { std::cell::RefCell::new(None) };
1939
+ static ISSUE_269_DEATH_DELAY: std::cell::Cell<Option<std::time::Duration>> = const { std::cell::Cell::new(None) };
1940
+ }
1941
+
1942
+ struct ShutdownWorkspaceCleanup(PathBuf);
1943
+
1944
+ impl Drop for ShutdownWorkspaceCleanup {
1945
+ fn drop(&mut self) {
1946
+ let _ = std::fs::remove_dir_all(&self.0);
1947
+ }
1948
+ }
1949
+
1950
+ fn reset_issue_269_probe_state() {
1951
+ ISSUE_269_LIVENESS_CALLS.with(|calls| calls.set(0));
1952
+ ISSUE_269_FIRST_ALIVE.with(|first| *first.borrow_mut() = None);
1953
+ ISSUE_269_DEATH_DELAY.with(|delay| delay.set(None));
1954
+ }
1955
+
1956
+ fn issue_269_liveness_call_count() -> usize {
1957
+ ISSUE_269_LIVENESS_CALLS.with(std::cell::Cell::get)
1958
+ }
1959
+
1960
+ fn issue_269_empty_process_table() -> Result<Vec<String>, String> {
1961
+ Ok(Vec::new())
1962
+ }
1963
+
1964
+ fn issue_269_transient_liveness(pid: u32) -> bool {
1965
+ if pid != ISSUE_269_ROOT_PID {
1966
+ return false;
1967
+ }
1968
+ ISSUE_269_LIVENESS_CALLS.with(|calls| {
1969
+ let call = calls.get();
1970
+ calls.set(call + 1);
1971
+ match call {
1972
+ 0 => {
1973
+ ISSUE_269_FIRST_ALIVE.with(|first| *first.borrow_mut() = Some(std::time::Instant::now()));
1974
+ true
1975
+ }
1976
+ 1 => {
1977
+ let elapsed = ISSUE_269_FIRST_ALIVE.with(|first| {
1978
+ first.borrow().as_ref().map(std::time::Instant::elapsed)
1979
+ });
1980
+ ISSUE_269_DEATH_DELAY.with(|delay| delay.set(elapsed));
1981
+ false
1982
+ }
1983
+ _ => false,
1984
+ }
1985
+ })
1986
+ }
1987
+
1988
+ fn issue_269_persistent_liveness(pid: u32) -> bool {
1989
+ if pid == ISSUE_269_ROOT_PID {
1990
+ ISSUE_269_LIVENESS_CALLS.with(|calls| calls.set(calls.get() + 1));
1991
+ true
1992
+ } else {
1993
+ false
1994
+ }
1995
+ }
1996
+
1997
+ fn issue_269_already_gone_liveness(pid: u32) -> bool {
1998
+ if pid == ISSUE_269_ROOT_PID {
1999
+ ISSUE_269_LIVENESS_CALLS.with(|calls| calls.set(calls.get() + 1));
2000
+ }
2001
+ false
2002
+ }
2003
+
2004
+ fn save_issue_269_root_state(workspace: &Path, session: &str) {
2005
+ crate::state::persist::save_runtime_state(
2006
+ workspace,
2007
+ &json!({
2008
+ "session_name": session,
2009
+ "team_key": session,
2010
+ "generation": session,
2011
+ "agents": {
2012
+ "worker": {
2013
+ "status": "running",
2014
+ "provider": "fake",
2015
+ "window": "worker",
2016
+ "provider_pid": ISSUE_269_ROOT_PID
2017
+ }
2018
+ }
2019
+ }),
2020
+ )
2021
+ .unwrap();
2022
+ }
2023
+
2024
+ fn shutdown_issue_269_with_probes(
2025
+ workspace: &Path,
2026
+ session: &str,
2027
+ liveness: fn(u32) -> bool,
2028
+ ) -> serde_json::Value {
2029
+ let transport = CleanShutdownTransport::new().with_owned_session(
2030
+ workspace,
2031
+ session,
2032
+ session,
2033
+ session,
2034
+ );
2035
+ crate::cli::lifecycle_port::with_process_table_test_probe(
2036
+ issue_269_empty_process_table,
2037
+ || {
2038
+ crate::cli::lifecycle_port::with_pid_liveness_test_probe(liveness, || {
2039
+ crate::cli::lifecycle_port::shutdown_with_transport(
2040
+ workspace,
2041
+ true,
2042
+ None,
2043
+ &transport,
2044
+ )
2045
+ .expect("shutdown should complete")
2046
+ })
2047
+ },
2048
+ )
2049
+ }
2050
+
2051
+ #[test]
2052
+ fn issue269_transient_unmatched_root_converges_inside_grace() {
2053
+ let workspace = tmp_shutdown_workspace("issue269-transient-root");
2054
+ let _workspace_cleanup = ShutdownWorkspaceCleanup(workspace.clone());
2055
+ let session = "team-issue269-transient";
2056
+ save_issue_269_root_state(&workspace, session);
2057
+ reset_issue_269_probe_state();
2058
+
2059
+ let started = std::time::Instant::now();
2060
+ let out = shutdown_issue_269_with_probes(&workspace, session, issue_269_transient_liveness);
2061
+ let elapsed = started.elapsed();
2062
+ let calls = issue_269_liveness_call_count();
2063
+ let death_delay = ISSUE_269_DEATH_DELAY.with(std::cell::Cell::get);
2064
+
2065
+ assert_eq!(
2066
+ out["ok"],
2067
+ json!(true),
2068
+ "an absent final process-table row plus a root that dies during the bounded grace must converge; ppid=0/empty-command is only a conservative placeholder, not a measured identity: {out}"
2069
+ );
2070
+ assert_eq!(out["residuals"]["processes"], json!([]), "{out}");
2071
+ assert!(calls >= 2, "the wait must observe both live and gone states; calls={calls}");
2072
+ assert!(death_delay.is_some_and(|delay| delay <= std::time::Duration::from_millis(500)), "root did not disappear within the bounded grace: {death_delay:?}");
2073
+ assert!(elapsed < std::time::Duration::from_secs(2), "shutdown exceeded the bounded wait: {elapsed:?}");
2074
+ }
2075
+
2076
+ #[test]
2077
+ fn issue269_persistent_unmatched_root_remains_a_residual_after_grace() {
2078
+ let workspace = tmp_shutdown_workspace("issue269-persistent-root");
2079
+ let _workspace_cleanup = ShutdownWorkspaceCleanup(workspace.clone());
2080
+ let session = "team-issue269-persistent";
2081
+ save_issue_269_root_state(&workspace, session);
2082
+ reset_issue_269_probe_state();
2083
+
2084
+ let started = std::time::Instant::now();
2085
+ let out = shutdown_issue_269_with_probes(&workspace, session, issue_269_persistent_liveness);
2086
+ let elapsed = started.elapsed();
2087
+ let calls = issue_269_liveness_call_count();
2088
+ let residuals = out["residuals"]["processes"].as_array().unwrap();
2089
+
2090
+ assert_eq!(out["ok"], json!(false), "a live root must not be filtered by placeholder fields: {out}");
2091
+ assert_eq!(residuals.len(), 1, "{out}");
2092
+ assert_eq!(residuals[0]["pid"], json!(ISSUE_269_ROOT_PID), "{out}");
2093
+ assert_eq!(residuals[0]["ppid"], json!(0), "{out}");
2094
+ assert_eq!(residuals[0]["command"], json!(""), "{out}");
2095
+ assert!((2..=30).contains(&calls), "persistent-root polling must remain bounded; calls={calls}");
2096
+ assert!(elapsed < std::time::Duration::from_secs(2), "shutdown exceeded the bounded wait: {elapsed:?}");
2097
+ }
2098
+
2099
+ #[test]
2100
+ fn issue269_already_gone_root_returns_without_fixed_grace_sleep() {
2101
+ let workspace = tmp_shutdown_workspace("issue269-already-gone-root");
2102
+ let _workspace_cleanup = ShutdownWorkspaceCleanup(workspace.clone());
2103
+ let session = "team-issue269-gone";
2104
+ save_issue_269_root_state(&workspace, session);
2105
+ reset_issue_269_probe_state();
2106
+
2107
+ let started = std::time::Instant::now();
2108
+ let out = shutdown_issue_269_with_probes(&workspace, session, issue_269_already_gone_liveness);
2109
+ let elapsed = started.elapsed();
2110
+ let calls = issue_269_liveness_call_count();
2111
+
2112
+ assert_eq!(out["ok"], json!(true), "{out}");
2113
+ assert_eq!(out["residuals"]["processes"], json!([]), "{out}");
2114
+ assert!(calls >= 2, "the final verification path and wait path must both observe liveness; calls={calls}");
2115
+ assert!(elapsed < std::time::Duration::from_millis(450), "already-gone roots must not incur a fixed grace sleep: {elapsed:?}");
2116
+ }