@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
@@ -2800,130 +2800,6 @@ fn fork_refuses_source_with_partial_tuple() {
2800
2800
  );
2801
2801
  }
2802
2802
 
2803
- #[test]
2804
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
2805
- fn add_agent_adaptive_splits_last_non_full_layout_window() {
2806
- let roles = [("w1.md", role_doc("w1")), ("w2.md", role_doc("w2"))];
2807
- let role_refs = roles
2808
- .iter()
2809
- .map(|(file, doc)| (*file, doc.as_str()))
2810
- .collect::<Vec<_>>();
2811
- let team = quick_start_team_dir_with_roles(&role_refs);
2812
- let session = "team-layout-add";
2813
- crate::state::persist::save_runtime_state(
2814
- &team,
2815
- &json!({
2816
- "session_name": session,
2817
- "legacy_display_key": "adaptive",
2818
- "active_team_key": "teamdir",
2819
- "agents": {
2820
- "w1": {"status": "running", "provider": "codex", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 0, "pane_id": "%1"},
2821
- "w2": {"status": "running", "provider": "codex", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 1, "pane_id": "%2"}
2822
- }
2823
- }),
2824
- )
2825
- .unwrap();
2826
- seed_healthy_coordinator(&team);
2827
- let role_file = team.join("w3-role.md");
2828
- std::fs::write(&role_file, role_doc("w3")).unwrap();
2829
- let transport = OfflineTransport::new()
2830
- .with_session_present(true)
2831
- .with_targets(vec![
2832
- layout_pane(session, "team-w1", "%1", 0),
2833
- layout_pane(session, "team-w1", "%2", 1),
2834
- ])
2835
- .with_pane_presence("%1", true)
2836
- .with_pane_presence("%2", true);
2837
-
2838
- add_agent_with_transport(
2839
- &team,
2840
- &AgentId::new("w3"),
2841
- &role_file,
2842
- true,
2843
- None,
2844
- &transport,
2845
- )
2846
- .expect("adaptive add-agent should start");
2847
-
2848
- assert_eq!(
2849
- transport.spawn_window_records().last(),
2850
- Some(&(String::from("spawn_split"), String::from("team-w1"))),
2851
- "last non-full layout window should be split"
2852
- );
2853
- let (_raw, state) = raw_runtime_state(&team);
2854
- assert_eq!(
2855
- state.pointer("/agents/w3/layout_window"),
2856
- Some(&json!("team-w1"))
2857
- );
2858
- assert_eq!(state.pointer("/agents/w3/pane_index"), Some(&json!(2)));
2859
- }
2860
-
2861
- #[test]
2862
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
2863
- fn add_agent_adaptive_creates_suffix_window_when_last_layout_full_and_name_collides() {
2864
- let roles = [
2865
- ("w1.md", role_doc("w1")),
2866
- ("w2.md", role_doc("w2")),
2867
- ("w3.md", role_doc("w3")),
2868
- ];
2869
- let role_refs = roles
2870
- .iter()
2871
- .map(|(file, doc)| (*file, doc.as_str()))
2872
- .collect::<Vec<_>>();
2873
- let team = quick_start_team_dir_with_roles(&role_refs);
2874
- let session = "team-layout-add-full";
2875
- crate::state::persist::save_runtime_state(
2876
- &team,
2877
- &json!({
2878
- "session_name": session,
2879
- "legacy_display_key": "adaptive",
2880
- "active_team_key": "teamdir",
2881
- "agents": {
2882
- "w1": {"status": "running", "provider": "codex", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 0, "pane_id": "%1"},
2883
- "w2": {"status": "running", "provider": "codex", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 1, "pane_id": "%2"},
2884
- "w3": {"status": "running", "provider": "codex", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 2, "pane_id": "%3"}
2885
- }
2886
- }),
2887
- )
2888
- .unwrap();
2889
- seed_healthy_coordinator(&team);
2890
- let role_file = team.join("w4-role.md");
2891
- std::fs::write(&role_file, role_doc("w4")).unwrap();
2892
- let transport = OfflineTransport::new()
2893
- .with_session_present(true)
2894
- .with_targets(vec![
2895
- layout_pane(session, "team-w1", "%1", 0),
2896
- layout_pane(session, "team-w1", "%2", 1),
2897
- layout_pane(session, "team-w1", "%3", 2),
2898
- layout_pane(session, "team-w2", "%9", 0),
2899
- ])
2900
- .with_pane_presence("%1", true)
2901
- .with_pane_presence("%2", true)
2902
- .with_pane_presence("%3", true);
2903
-
2904
- add_agent_with_transport(
2905
- &team,
2906
- &AgentId::new("w4"),
2907
- &role_file,
2908
- true,
2909
- None,
2910
- &transport,
2911
- )
2912
- .expect("adaptive add-agent should start");
2913
-
2914
- assert_eq!(
2915
- transport.spawn_window_records().last(),
2916
- Some(&(String::from("spawn_into"), String::from("team-w2-2"))),
2917
- "full last layout window should create next window with collision suffix"
2918
- );
2919
- let (_raw, state) = raw_runtime_state(&team);
2920
- assert_eq!(
2921
- state.pointer("/agents/w4/layout_window"),
2922
- Some(&json!("team-w2-2"))
2923
- );
2924
- assert_eq!(state.pointer("/agents/w4/pane_index"), Some(&json!(0)));
2925
- }
2926
-
2927
2803
  #[test]
2928
2804
  fn stop_agent_adaptive_kills_target_pane_not_shared_layout_window() {
2929
2805
  let roles = [("w1.md", role_doc("w1")), ("w2.md", role_doc("w2"))];
@@ -2978,55 +2854,6 @@ fn stop_agent_adaptive_kills_target_pane_not_shared_layout_window() {
2978
2854
  );
2979
2855
  }
2980
2856
 
2981
- #[test]
2982
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
2983
- fn start_agent_adaptive_restarts_missing_pane_in_existing_layout_window() {
2984
- let ws = temp_ws();
2985
- crate::state::persist::save_runtime_state(
2986
- &ws,
2987
- &json!({
2988
- "session_name": "team-layout-restart",
2989
- "legacy_display_key": "adaptive",
2990
- "agents": {
2991
- "w1": {"status": "running", "provider": "codex", "role": "w1", "model": "gpt-5.5", "auth_mode": "subscription", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 0, "pane_id": "%1"},
2992
- "w2": {"status": "running", "provider": "codex", "role": "w2", "model": "gpt-5.5", "auth_mode": "subscription", "window": "team-w1", "layout_window": "team-w1", "layout_index": 0, "pane_index": 1, "pane_id": "%2"}
2993
- }
2994
- }),
2995
- )
2996
- .unwrap();
2997
- seed_healthy_coordinator(&ws);
2998
- let transport = OfflineTransport::new()
2999
- .with_session_present(true)
3000
- .with_targets(vec![layout_pane("team-layout-restart", "team-w1", "%2", 1)])
3001
- .with_pane_presence("%1", false)
3002
- .with_pane_presence("%2", true);
3003
-
3004
- let outcome = start_agent_with_transport(
3005
- &ws,
3006
- &AgentId::new("w1"),
3007
- false,
3008
- true,
3009
- true,
3010
- None,
3011
- &transport,
3012
- )
3013
- .expect("adaptive restart should spawn");
3014
-
3015
- assert!(matches!(outcome, StartAgentOutcome::Running { .. }));
3016
- assert_eq!(
3017
- transport.spawn_window_records().last(),
3018
- Some(&(String::from("spawn_split"), String::from("team-w1"))),
3019
- "missing worker pane should be rebuilt in its existing layout window"
3020
- );
3021
- let (_raw, state) = raw_runtime_state(&ws);
3022
- assert_eq!(
3023
- state.pointer("/agents/w1/layout_window"),
3024
- Some(&json!("team-w1"))
3025
- );
3026
- assert_eq!(state.pointer("/agents/w1/window"), Some(&json!("team-w1")));
3027
- assert_eq!(state.pointer("/agents/w2/pane_id"), Some(&json!("%2")));
3028
- }
3029
-
3030
2857
  // ═════════════════════════════════════════════════════════════════════════
3031
2858
  // WAVE 2 · LANE A — agent-lifecycle byte-parity contracts. stop_agent / reset_agent / remove_agent /
3032
2859
  // fork_agent are stubs (OwnerRefused / RequirementUnmet / "session_id missing"). These RED contracts
@@ -3714,175 +3541,6 @@ fn e43_adaptive_placement_skips_existing_agent_whose_live_pane_window_name_diffe
3714
3541
  }
3715
3542
  }
3716
3543
 
3717
- /// **Regression guard — Fix A**: when an existing agent's live pane DOES
3718
- /// reside under the claimed layout_window, placement keeps the prior
3719
- /// behaviour (groups the new agent into that window). This is the canonical
3720
- /// adaptive 1-window-multiple-panes use case.
3721
- #[test]
3722
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
3723
- fn e43_adaptive_placement_groups_into_layout_window_when_live_pane_matches_claim() {
3724
- use crate::lifecycle::launch::adaptive_placement_for_agent;
3725
- use crate::model::ids::AgentId;
3726
- use crate::transport::{SessionName, WindowName};
3727
-
3728
- let state = json!({
3729
- "legacy_display_key": "adaptive",
3730
- "session_name": "team-iso",
3731
- "agents": {
3732
- "alpha": {
3733
- "status": "running",
3734
- "provider": "codex",
3735
- "layout_window": "team-w1",
3736
- "pane_id": "%1",
3737
- }
3738
- }
3739
- });
3740
-
3741
- let transport = OfflineTransport::new()
3742
- .with_targets(vec![layout_pane("team-iso", "team-w1", "%1", 0)])
3743
- .with_windows(vec![WindowName::new("team-w1")]);
3744
-
3745
- let placement = adaptive_placement_for_agent(
3746
- &state,
3747
- &transport,
3748
- &SessionName::new("team-iso"),
3749
- &AgentId::new("beta"),
3750
- )
3751
- .expect("placement should succeed");
3752
-
3753
- assert_eq!(
3754
- placement.layout_window.as_str(),
3755
- "team-w1",
3756
- "E43 Fix A regression guard: when alpha's live pane DOES live under \
3757
- layout_window 'team-w1', the new agent beta should be grouped into \
3758
- the same window (canonical adaptive behaviour). Got {placement:?}"
3759
- );
3760
- assert!(
3761
- !placement.starts_window,
3762
- "E43 Fix A regression guard: grouping into an existing window means \
3763
- starts_window=false (split into the window). Got {placement:?}"
3764
- );
3765
- }
3766
-
3767
- /// **RED — Fix B**: `adaptive_existing_placement_for_agent` must NOT return a
3768
- /// `starts_window=true` placement that names a window NOT present in
3769
- /// `live_windows`. When the agent's claimed `layout_window` is stale and the
3770
- /// session is effectively per-agent (live windows are named after agent_ids),
3771
- /// the placement must fall back to a per-agent window named after the
3772
- /// agent_id itself — so the subsequent spawn opens a new window, not a split
3773
- /// of a phantom.
3774
- #[test]
3775
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
3776
- fn e43_adaptive_existing_placement_falls_back_to_agent_id_window_when_claim_missing_from_live() {
3777
- use crate::lifecycle::launch::adaptive_existing_placement_for_agent;
3778
- use crate::model::ids::AgentId;
3779
- use crate::transport::{SessionName, WindowName};
3780
-
3781
- let state = json!({
3782
- "legacy_display_key": "adaptive",
3783
- "session_name": "team-iso",
3784
- "agents": {
3785
- "demo-director": {
3786
- "status": "running",
3787
- "provider": "codex",
3788
- // Stale claim — live session has no team-w2 window.
3789
- "layout_window": "team-w2",
3790
- "pane_id": "%99",
3791
- }
3792
- }
3793
- });
3794
-
3795
- let transport = OfflineTransport::new()
3796
- .with_targets(vec![
3797
- layout_pane("team-iso", "architect", "%1", 0),
3798
- layout_pane("team-iso", "test-engineer", "%2", 0),
3799
- ])
3800
- .with_windows(vec![
3801
- WindowName::new("architect"),
3802
- WindowName::new("test-engineer"),
3803
- ]);
3804
-
3805
- let placement = adaptive_existing_placement_for_agent(
3806
- &state,
3807
- &transport,
3808
- &SessionName::new("team-iso"),
3809
- &AgentId::new("demo-director"),
3810
- )
3811
- .expect("placement should resolve");
3812
-
3813
- assert_ne!(
3814
- placement.layout_window.as_str(),
3815
- "team-w2",
3816
- "E43 Fix B: stale claim 'team-w2' is not in live_windows; placement \
3817
- must NOT reuse that name (otherwise spawn issues split -t :team-w2 \
3818
- and tmux says 'can't find window: team-w2'). Got {placement:?}"
3819
- );
3820
- assert_eq!(
3821
- placement.layout_window.as_str(),
3822
- "demo-director",
3823
- "E43 Fix B: when the claim is stale and the live layout is \
3824
- per-agent-named, fall back to a window named after the agent_id \
3825
- (canonical per-agent pattern). Got {placement:?}"
3826
- );
3827
- assert!(
3828
- placement.starts_window,
3829
- "E43 Fix B: the fallback opens a NEW window (starts_window=true); \
3830
- do not try to split an existing window with the wrong name. Got \
3831
- {placement:?}"
3832
- );
3833
- }
3834
-
3835
- /// **Regression guard — Fix B**: when the agent's claimed layout_window IS
3836
- /// in live_windows, the existing-placement path keeps its current behaviour
3837
- /// (return a starts_window=false placement that splits into the existing
3838
- /// window).
3839
- #[test]
3840
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
3841
- fn e43_adaptive_existing_placement_keeps_starts_window_false_when_claim_in_live_windows() {
3842
- use crate::lifecycle::launch::adaptive_existing_placement_for_agent;
3843
- use crate::model::ids::AgentId;
3844
- use crate::transport::{SessionName, WindowName};
3845
-
3846
- let state = json!({
3847
- "legacy_display_key": "adaptive",
3848
- "session_name": "team-iso",
3849
- "agents": {
3850
- "alpha": {
3851
- "status": "running",
3852
- "provider": "codex",
3853
- "layout_window": "team-w1",
3854
- "pane_id": "%1",
3855
- "pane_index": 1u64,
3856
- }
3857
- }
3858
- });
3859
-
3860
- let transport = OfflineTransport::new()
3861
- .with_targets(vec![layout_pane("team-iso", "team-w1", "%1", 0)])
3862
- .with_windows(vec![WindowName::new("team-w1")]);
3863
-
3864
- let placement = adaptive_existing_placement_for_agent(
3865
- &state,
3866
- &transport,
3867
- &SessionName::new("team-iso"),
3868
- &AgentId::new("alpha"),
3869
- )
3870
- .expect("placement should resolve");
3871
-
3872
- assert_eq!(
3873
- placement.layout_window.as_str(),
3874
- "team-w1",
3875
- "E43 Fix B regression guard: when claim 'team-w1' IS in live_windows, \
3876
- existing-placement must keep it. Got {placement:?}"
3877
- );
3878
- // pane_index=1 → starts_window=false in the existing behaviour.
3879
- assert!(
3880
- !placement.starts_window,
3881
- "E43 Fix B regression guard: existing window + pane_index>0 → \
3882
- starts_window=false. Got {placement:?}"
3883
- );
3884
- }
3885
-
3886
3544
  /// **RED — Fix C end-to-end**: `add_agent` end-to-end must NOT emit a
3887
3545
  /// spawn_split with the stale window name. With state carrying
3888
3546
  /// `legacy_display_key=adaptive` + stale `layout_window=team-w2` residue and
@@ -4178,56 +3836,6 @@ fn e45_add_agent_opens_new_window_does_not_split_into_per_agent_window() {
4178
3836
  );
4179
3837
  }
4180
3838
 
4181
- /// **Regression guard**: when the live session DOES have a real `team-w1`
4182
- /// adaptive window with a live pane that matches state's claim, the
4183
- /// existing E43+adaptive grouping behaviour is preserved (split into team-w1
4184
- /// as before). E45 only changes behaviour for per-agent windows.
4185
- #[test]
4186
- #[ignore = "legacy adaptive display layout contract removed; runtime is silent tmux only"]
4187
- fn e45_real_team_w_adaptive_layout_still_groups_into_layout_window() {
4188
- use crate::lifecycle::launch::adaptive_placement_for_agent;
4189
- use crate::model::ids::AgentId;
4190
- use crate::transport::{SessionName, WindowName};
4191
-
4192
- let state = json!({
4193
- "legacy_display_key": "adaptive",
4194
- "session_name": "team-iso",
4195
- "agents": {
4196
- "alpha": {
4197
- "status": "running",
4198
- "provider": "codex",
4199
- "layout_window": "team-w1",
4200
- "layout_index": 0u64,
4201
- "pane_id": "%1",
4202
- }
4203
- }
4204
- });
4205
-
4206
- let transport = OfflineTransport::new()
4207
- .with_targets(vec![layout_pane("team-iso", "team-w1", "%1", 0)])
4208
- .with_windows(vec![WindowName::new("team-w1")]);
4209
-
4210
- let placement = adaptive_placement_for_agent(
4211
- &state,
4212
- &transport,
4213
- &SessionName::new("team-iso"),
4214
- &AgentId::new("beta"),
4215
- )
4216
- .expect("E45 regression guard: real team-w1 adaptive layout must still group new agents in");
4217
-
4218
- assert_eq!(
4219
- placement.layout_window.as_str(),
4220
- "team-w1",
4221
- "E45 regression guard: real `team-w1` adaptive window must still \
4222
- host new agents (canonical adaptive behaviour). Got {placement:?}"
4223
- );
4224
- assert!(
4225
- !placement.starts_window,
4226
- "E45 regression guard: grouping into existing team-w1 → \
4227
- starts_window=false. Got {placement:?}"
4228
- );
4229
- }
4230
-
4231
3839
  /// **Regression guard**: helper `is_adaptive_layout_window` golden cases.
4232
3840
  /// `team-w1`, `team-w42`, `team-w7-foo` are adaptive; agent_id names and
4233
3841
  /// other shapes are not.
@@ -130,11 +130,6 @@ fn lifecycle_lock_long_held_event_records_holder_and_waiter() {
130
130
  );
131
131
  }
132
132
 
133
- #[test]
134
- fn lifecycle_lock_phase_b_golden_source_guard() {
135
- r2_lifecycle_lock_exists_precondition();
136
- }
137
-
138
133
  #[test]
139
134
  fn r2_lifecycle_lock_exists_precondition() {
140
135
  let src = manifest_src();