@team-agent/installer 0.5.68 → 0.5.70
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/diagnose.rs +74 -0
- package/crates/team-agent/src/cli/emit.rs +5 -4
- package/crates/team-agent/src/cli/leader.rs +1 -0
- package/crates/team-agent/src/cli/spec.rs +1 -0
- package/crates/team-agent/src/compiler.rs +54 -7
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
- package/crates/team-agent/src/layout/worker_window_helpers.rs +1 -0
- package/crates/team-agent/src/leader/start.rs +53 -12
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +67 -15
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +18 -0
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +260 -44
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp_iso.rs +120 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +5 -1
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +10 -59
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +838 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +9 -3
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +60 -28
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch.rs +10 -2
- package/crates/team-agent/src/lifecycle/profile_launch.rs +3 -2
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +1 -0
- package/crates/team-agent/src/lifecycle/restart/agent.rs +90 -160
- package/crates/team-agent/src/lifecycle/restart/common.rs +136 -28
- package/crates/team-agent/src/lifecycle/restart/remove.rs +37 -1
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +24 -3
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +195 -18
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +30 -12
- package/crates/team-agent/src/lifecycle/tests/fixtures/pi_list_models_g0.stdout.txt +222 -0
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +5 -2
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +35 -48
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +97 -0
- package/crates/team-agent/src/lifecycle/tests/pi_command_red.rs +145 -0
- package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +243 -0
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +856 -0
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +387 -0
- package/crates/team-agent/src/lifecycle/tests/pi_lifecycle_doctor_red.rs +98 -0
- package/crates/team-agent/src/lifecycle/tests/pi_session_delivery_red.rs +216 -0
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1 -0
- package/crates/team-agent/src/lifecycle/tests.rs +7 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +61 -4
- package/crates/team-agent/src/messaging/delivery.rs +36 -12
- package/crates/team-agent/src/model/enums.rs +3 -1
- package/crates/team-agent/src/model/permissions.rs +1 -1
- package/crates/team-agent/src/provider/adapter.rs +29 -3
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +5 -2
- package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
- package/crates/team-agent/src/provider/adapters/pi.rs +146 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +1 -0
- package/crates/team-agent/src/provider/classify.rs +2 -2
- package/crates/team-agent/src/provider/faults.rs +1 -1
- package/crates/team-agent/src/provider/session/context_fork.rs +2 -1
- package/crates/team-agent/src/provider/session_scan/common.rs +1 -0
- package/crates/team-agent/src/provider/session_scan/pi.rs +172 -0
- package/crates/team-agent/src/provider/session_scan.rs +4 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +80 -0
- package/crates/team-agent/src/provider/wire.rs +7 -1
- package/crates/team-agent/src/tmux_backend.rs +52 -0
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +9 -5
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
//! what: 写了 model 则该值进入 `--model <值>`
|
|
9
9
|
//! - name: cursor-effort-refuses-compile
|
|
10
10
|
//! what: 角色写 effort 则失败,不得丢掉后仍起席
|
|
11
|
-
//! - name: cursor-second-seat-
|
|
12
|
-
//! what:
|
|
11
|
+
//! - name: cursor-second-seat-isolated-identity
|
|
12
|
+
//! what: 默认 per-seat MCP 隔离时同 workspace 两个 CursorAgent 都启动且身份各自保留
|
|
13
13
|
//! boundary:
|
|
14
14
|
//! - 只钉 Provider::CursorAgent;不改 grok/claude 路径
|
|
15
15
|
//! maturity: wired
|
|
@@ -26,6 +26,7 @@ use std::path::{Path, PathBuf};
|
|
|
26
26
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
27
27
|
|
|
28
28
|
use serial_test::serial;
|
|
29
|
+
use team_agent::lifecycle::cursor_mcp_json_path;
|
|
29
30
|
use team_agent::lifecycle::quick_start_with_transport_in_workspace;
|
|
30
31
|
use team_agent::transport::test_support::OfflineTransport;
|
|
31
32
|
|
|
@@ -126,7 +127,9 @@ fn cursor_role_with_effort_refuses_to_start() {
|
|
|
126
127
|
|
|
127
128
|
#[test]
|
|
128
129
|
#[serial(env)]
|
|
129
|
-
fn
|
|
130
|
+
fn cursor_second_seat_in_same_workspace_uses_isolated_identity() {
|
|
131
|
+
let previous_isolation = std::env::var("TEAM_AGENT_CURSOR_MCP_ISOLATION").ok();
|
|
132
|
+
std::env::remove_var("TEAM_AGENT_CURSOR_MCP_ISOLATION");
|
|
130
133
|
let ws = tmp_dir("cursor-two");
|
|
131
134
|
let team = ws.join("cursortm");
|
|
132
135
|
std::fs::create_dir_all(team.join("agents")).unwrap();
|
|
@@ -153,21 +156,36 @@ fn cursor_second_seat_in_same_workspace_is_refused() {
|
|
|
153
156
|
Some("cursortm"),
|
|
154
157
|
&transport,
|
|
155
158
|
);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
restore_isolation_env(previous_isolation);
|
|
160
|
+
result.expect("default per-seat MCP isolation must allow both Cursor seats");
|
|
161
|
+
let records = transport.spawn_records();
|
|
162
|
+
assert_eq!(
|
|
163
|
+
records.len(),
|
|
164
|
+
2,
|
|
165
|
+
"both Cursor seats must spawn; records={records:?}"
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
let first = std::fs::read_to_string(cursor_mcp_json_path(&ws, "cursor_a").unwrap())
|
|
169
|
+
.expect("first seat MCP config");
|
|
170
|
+
let second = std::fs::read_to_string(cursor_mcp_json_path(&ws, "cursor_b").unwrap())
|
|
171
|
+
.expect("second seat MCP config");
|
|
160
172
|
assert!(
|
|
161
|
-
|
|
162
|
-
"
|
|
173
|
+
first.contains("\"cursor_a\"") && !first.contains("\"cursor_b\""),
|
|
174
|
+
"first seat must retain its own TEAM_AGENT_ID"
|
|
163
175
|
);
|
|
164
176
|
assert!(
|
|
165
|
-
|
|
166
|
-
"
|
|
167
|
-
transport.spawn_records()
|
|
177
|
+
second.contains("\"cursor_b\"") && !second.contains("\"cursor_a\""),
|
|
178
|
+
"second seat must retain its own TEAM_AGENT_ID"
|
|
168
179
|
);
|
|
169
180
|
}
|
|
170
181
|
|
|
182
|
+
fn restore_isolation_env(previous: Option<String>) {
|
|
183
|
+
match previous {
|
|
184
|
+
Some(value) => std::env::set_var("TEAM_AGENT_CURSOR_MCP_ISOLATION", value),
|
|
185
|
+
None => std::env::remove_var("TEAM_AGENT_CURSOR_MCP_ISOLATION"),
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
171
189
|
fn first_spawn_argv(transport: &OfflineTransport) -> Vec<String> {
|
|
172
190
|
let records = transport.spawn_records();
|
|
173
191
|
assert!(
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
provider model context max-out thinking images
|
|
2
|
+
cursor auto 200K 16.4K no yes
|
|
3
|
+
cursor claude-fable-5@1m 1M 16.4K yes yes
|
|
4
|
+
cursor claude-fable-5@300k 300K 16.4K yes yes
|
|
5
|
+
cursor claude-haiku-4-5 200K 16.4K yes yes
|
|
6
|
+
cursor claude-opus-4-5 200K 16.4K yes yes
|
|
7
|
+
cursor claude-opus-4-6@1m 1M 16.4K yes yes
|
|
8
|
+
cursor claude-opus-4-6@200k 200K 16.4K yes yes
|
|
9
|
+
cursor claude-opus-4-7@1m 1M 16.4K yes yes
|
|
10
|
+
cursor claude-opus-4-7@1m:fast 1M 16.4K yes yes
|
|
11
|
+
cursor claude-opus-4-7@1m:slow 1M 16.4K yes yes
|
|
12
|
+
cursor claude-opus-4-7@300k 300K 16.4K yes yes
|
|
13
|
+
cursor claude-opus-4-7@300k:fast 300K 16.4K yes yes
|
|
14
|
+
cursor claude-opus-4-7@300k:slow 300K 16.4K yes yes
|
|
15
|
+
cursor claude-opus-4-8@1m 300K 16.4K yes yes
|
|
16
|
+
cursor claude-opus-4-8@1m:fast 1M 16.4K yes yes
|
|
17
|
+
cursor claude-opus-4-8@1m:slow 300K 16.4K yes yes
|
|
18
|
+
cursor claude-opus-4-8@300k 300K 16.4K yes yes
|
|
19
|
+
cursor claude-opus-4-8@300k:fast 300K 16.4K yes yes
|
|
20
|
+
cursor claude-opus-4-8@300k:slow 300K 16.4K yes yes
|
|
21
|
+
cursor claude-opus-5@1m 1M 16.4K yes yes
|
|
22
|
+
cursor claude-opus-5@1m:fast 1M 16.4K yes yes
|
|
23
|
+
cursor claude-opus-5@1m:slow 1M 16.4K yes yes
|
|
24
|
+
cursor claude-opus-5@300k 300K 16.4K yes yes
|
|
25
|
+
cursor claude-opus-5@300k:fast 300K 16.4K yes yes
|
|
26
|
+
cursor claude-opus-5@300k:slow 300K 16.4K yes yes
|
|
27
|
+
cursor claude-sonnet-4-5@200k 200K 16.4K yes yes
|
|
28
|
+
cursor claude-sonnet-4-6@1m 1M 16.4K yes yes
|
|
29
|
+
cursor claude-sonnet-4-6@200k 200K 16.4K yes yes
|
|
30
|
+
cursor claude-sonnet-4@200k 200K 16.4K yes yes
|
|
31
|
+
cursor claude-sonnet-5@1m 1M 16.4K yes yes
|
|
32
|
+
cursor claude-sonnet-5@300k 300K 16.4K yes yes
|
|
33
|
+
cursor codex 272K 16.4K yes yes
|
|
34
|
+
cursor codex-5.3 272K 16.4K yes yes
|
|
35
|
+
cursor codex-5.3:fast 272K 16.4K yes yes
|
|
36
|
+
cursor codex-5.3:slow 272K 16.4K yes yes
|
|
37
|
+
cursor codex-latest 272K 16.4K yes yes
|
|
38
|
+
cursor codex-latest:fast 272K 16.4K yes yes
|
|
39
|
+
cursor codex-latest:slow 272K 16.4K yes yes
|
|
40
|
+
cursor codex:fast 272K 16.4K yes yes
|
|
41
|
+
cursor codex:slow 272K 16.4K yes yes
|
|
42
|
+
cursor composer 200K 16.4K no yes
|
|
43
|
+
cursor composer-2 200K 16.4K no yes
|
|
44
|
+
cursor composer-2-5 200K 16.4K no yes
|
|
45
|
+
cursor composer-2-5:fast 200K 16.4K no yes
|
|
46
|
+
cursor composer-2-5:slow 200K 16.4K no yes
|
|
47
|
+
cursor composer-2:fast 200K 16.4K no yes
|
|
48
|
+
cursor composer-2:slow 200K 16.4K no yes
|
|
49
|
+
cursor composer-2.5 200K 16.4K no yes
|
|
50
|
+
cursor composer-2.5:fast 200K 16.4K no yes
|
|
51
|
+
cursor composer-2.5:slow 200K 16.4K no yes
|
|
52
|
+
cursor composer-latest 200K 16.4K no yes
|
|
53
|
+
cursor composer-latest:fast 200K 16.4K no yes
|
|
54
|
+
cursor composer-latest:slow 200K 16.4K no yes
|
|
55
|
+
cursor composer:fast 200K 16.4K no yes
|
|
56
|
+
cursor composer:slow 200K 16.4K no yes
|
|
57
|
+
cursor default 200K 16.4K no yes
|
|
58
|
+
cursor fable-5@1m 1M 16.4K yes yes
|
|
59
|
+
cursor fable-5@300k 300K 16.4K yes yes
|
|
60
|
+
cursor fable@1m 1M 16.4K yes yes
|
|
61
|
+
cursor fable@300k 300K 16.4K yes yes
|
|
62
|
+
cursor gemini 200K 16.4K no yes
|
|
63
|
+
cursor gemini-2.5-flash 200K 16.4K no yes
|
|
64
|
+
cursor gemini-3-flash 200K 16.4K no yes
|
|
65
|
+
cursor gemini-3.1-pro 200K 16.4K no yes
|
|
66
|
+
cursor gemini-3.5-flash 200K 16.4K no yes
|
|
67
|
+
cursor gemini-3.6-flash 200K 16.4K yes yes
|
|
68
|
+
cursor gemini-3.7-flash 200K 16.4K yes yes
|
|
69
|
+
cursor gemini-latest 200K 16.4K no yes
|
|
70
|
+
cursor gemini-pro 200K 16.4K no yes
|
|
71
|
+
cursor gemini-pro-latest 200K 16.4K no yes
|
|
72
|
+
cursor glm-5.2 200K 16.4K yes yes
|
|
73
|
+
cursor gpt-5-5@1m 1M 16.4K yes yes
|
|
74
|
+
cursor gpt-5-5@1m:fast 1M 16.4K yes yes
|
|
75
|
+
cursor gpt-5-5@1m:slow 1M 16.4K yes yes
|
|
76
|
+
cursor gpt-5-5@272k 272K 16.4K yes yes
|
|
77
|
+
cursor gpt-5-5@272k:fast 272K 16.4K yes yes
|
|
78
|
+
cursor gpt-5-5@272k:slow 272K 16.4K yes yes
|
|
79
|
+
cursor gpt-5-6-luna@1m 1M 16.4K yes yes
|
|
80
|
+
cursor gpt-5-6-luna@1m:fast 1M 16.4K yes yes
|
|
81
|
+
cursor gpt-5-6-luna@1m:slow 1M 16.4K yes yes
|
|
82
|
+
cursor gpt-5-6-luna@272k 272K 16.4K yes yes
|
|
83
|
+
cursor gpt-5-6-luna@272k:fast 272K 16.4K yes yes
|
|
84
|
+
cursor gpt-5-6-luna@272k:slow 272K 16.4K yes yes
|
|
85
|
+
cursor gpt-5-6-sol@1m 1M 16.4K yes yes
|
|
86
|
+
cursor gpt-5-6-sol@1m:fast 1M 16.4K yes yes
|
|
87
|
+
cursor gpt-5-6-sol@1m:slow 1M 16.4K yes yes
|
|
88
|
+
cursor gpt-5-6-sol@272k 272K 16.4K yes yes
|
|
89
|
+
cursor gpt-5-6-sol@272k:fast 272K 16.4K yes yes
|
|
90
|
+
cursor gpt-5-6-sol@272k:slow 272K 16.4K yes yes
|
|
91
|
+
cursor gpt-5-6-terra@1m 1M 16.4K yes yes
|
|
92
|
+
cursor gpt-5-6-terra@1m:fast 1M 16.4K yes yes
|
|
93
|
+
cursor gpt-5-6-terra@1m:slow 1M 16.4K yes yes
|
|
94
|
+
cursor gpt-5-6-terra@272k 272K 16.4K yes yes
|
|
95
|
+
cursor gpt-5-6-terra@272k:fast 272K 16.4K yes yes
|
|
96
|
+
cursor gpt-5-6-terra@272k:slow 272K 16.4K yes yes
|
|
97
|
+
cursor gpt-5-mini 272K 16.4K no yes
|
|
98
|
+
cursor gpt-5.1 272K 16.4K yes yes
|
|
99
|
+
cursor gpt-5.2 272K 16.4K yes yes
|
|
100
|
+
cursor gpt-5.2:fast 272K 16.4K yes yes
|
|
101
|
+
cursor gpt-5.2:slow 272K 16.4K yes yes
|
|
102
|
+
cursor gpt-5.3-codex 272K 16.4K yes yes
|
|
103
|
+
cursor gpt-5.3-codex:fast 272K 16.4K yes yes
|
|
104
|
+
cursor gpt-5.3-codex:slow 272K 16.4K yes yes
|
|
105
|
+
cursor gpt-5.4-mini 272K 16.4K yes yes
|
|
106
|
+
cursor gpt-5.4-nano 272K 16.4K yes yes
|
|
107
|
+
cursor gpt-5.4@1m 1M 16.4K yes yes
|
|
108
|
+
cursor gpt-5.4@1m:fast 1M 16.4K yes yes
|
|
109
|
+
cursor gpt-5.4@1m:slow 1M 16.4K yes yes
|
|
110
|
+
cursor gpt-5.4@272k 272K 16.4K yes yes
|
|
111
|
+
cursor gpt-5.4@272k:fast 272K 16.4K yes yes
|
|
112
|
+
cursor gpt-5.4@272k:slow 272K 16.4K yes yes
|
|
113
|
+
cursor gpt-5.5@1m 1M 16.4K yes yes
|
|
114
|
+
cursor gpt-5.5@1m:fast 1M 16.4K yes yes
|
|
115
|
+
cursor gpt-5.5@1m:slow 1M 16.4K yes yes
|
|
116
|
+
cursor gpt-5.5@272k 272K 16.4K yes yes
|
|
117
|
+
cursor gpt-5.5@272k:fast 272K 16.4K yes yes
|
|
118
|
+
cursor gpt-5.5@272k:slow 272K 16.4K yes yes
|
|
119
|
+
cursor gpt-5.6-luna@1m 1M 16.4K yes yes
|
|
120
|
+
cursor gpt-5.6-luna@1m:fast 1M 16.4K yes yes
|
|
121
|
+
cursor gpt-5.6-luna@1m:slow 1M 16.4K yes yes
|
|
122
|
+
cursor gpt-5.6-luna@272k 272K 16.4K yes yes
|
|
123
|
+
cursor gpt-5.6-luna@272k:fast 272K 16.4K yes yes
|
|
124
|
+
cursor gpt-5.6-luna@272k:slow 272K 16.4K yes yes
|
|
125
|
+
cursor gpt-5.6-sol@1m 1M 16.4K yes yes
|
|
126
|
+
cursor gpt-5.6-sol@1m:fast 1M 16.4K yes yes
|
|
127
|
+
cursor gpt-5.6-sol@1m:slow 1M 16.4K yes yes
|
|
128
|
+
cursor gpt-5.6-sol@272k 272K 16.4K yes yes
|
|
129
|
+
cursor gpt-5.6-sol@272k:fast 272K 16.4K yes yes
|
|
130
|
+
cursor gpt-5.6-sol@272k:slow 272K 16.4K yes yes
|
|
131
|
+
cursor gpt-5.6-terra@1m 1M 16.4K yes yes
|
|
132
|
+
cursor gpt-5.6-terra@1m:fast 1M 16.4K yes yes
|
|
133
|
+
cursor gpt-5.6-terra@1m:slow 1M 16.4K yes yes
|
|
134
|
+
cursor gpt-5.6-terra@272k 272K 16.4K yes yes
|
|
135
|
+
cursor gpt-5.6-terra@272k:fast 272K 16.4K yes yes
|
|
136
|
+
cursor gpt-5.6-terra@272k:slow 272K 16.4K yes yes
|
|
137
|
+
cursor gpt-5.6@1m 272K 16.4K yes yes
|
|
138
|
+
cursor gpt-5.6@1m:fast 1M 16.4K yes yes
|
|
139
|
+
cursor gpt-5.6@1m:slow 272K 16.4K yes yes
|
|
140
|
+
cursor gpt-5.6@272k 272K 16.4K yes yes
|
|
141
|
+
cursor gpt-5.6@272k:fast 272K 16.4K yes yes
|
|
142
|
+
cursor gpt-5.6@272k:slow 272K 16.4K yes yes
|
|
143
|
+
cursor gpt-latest@1m 1M 16.4K yes yes
|
|
144
|
+
cursor gpt-latest@1m:fast 1M 16.4K yes yes
|
|
145
|
+
cursor gpt-latest@1m:slow 1M 16.4K yes yes
|
|
146
|
+
cursor gpt-latest@272k 272K 16.4K yes yes
|
|
147
|
+
cursor gpt-latest@272k:fast 272K 16.4K yes yes
|
|
148
|
+
cursor gpt-latest@272k:slow 272K 16.4K yes yes
|
|
149
|
+
cursor gpt-mini-latest 272K 16.4K yes yes
|
|
150
|
+
cursor gpt-nano 272K 16.4K yes yes
|
|
151
|
+
cursor gpt-nano-latest 272K 16.4K yes yes
|
|
152
|
+
cursor grok-4.5 256K 16.4K yes yes
|
|
153
|
+
cursor grok-4.5:fast 256K 16.4K yes yes
|
|
154
|
+
cursor grok-4.5:slow 256K 16.4K yes yes
|
|
155
|
+
cursor grok-4.6 256K 16.4K yes yes
|
|
156
|
+
cursor grok-4.6:fast 256K 16.4K yes yes
|
|
157
|
+
cursor grok-4.6:slow 256K 16.4K yes yes
|
|
158
|
+
cursor haiku 200K 16.4K yes yes
|
|
159
|
+
cursor haiku-4-5 200K 16.4K yes yes
|
|
160
|
+
cursor haiku-4.5 200K 16.4K yes yes
|
|
161
|
+
cursor haiku-latest 200K 16.4K yes yes
|
|
162
|
+
cursor kimi 200K 16.4K no yes
|
|
163
|
+
cursor kimi-k2.7-code 200K 16.4K no yes
|
|
164
|
+
cursor kimi-k3 200K 16.4K yes yes
|
|
165
|
+
cursor kimi-latest 200K 16.4K no yes
|
|
166
|
+
cursor opus-4-5 200K 16.4K yes yes
|
|
167
|
+
cursor opus-4-6@1m 1M 16.4K yes yes
|
|
168
|
+
cursor opus-4-6@200k 200K 16.4K yes yes
|
|
169
|
+
cursor opus-4-7@1m 1M 16.4K yes yes
|
|
170
|
+
cursor opus-4-7@1m:fast 1M 16.4K yes yes
|
|
171
|
+
cursor opus-4-7@1m:slow 1M 16.4K yes yes
|
|
172
|
+
cursor opus-4-7@300k 300K 16.4K yes yes
|
|
173
|
+
cursor opus-4-7@300k:fast 300K 16.4K yes yes
|
|
174
|
+
cursor opus-4-7@300k:slow 300K 16.4K yes yes
|
|
175
|
+
cursor opus-4-8@1m 300K 16.4K yes yes
|
|
176
|
+
cursor opus-4-8@1m:fast 1M 16.4K yes yes
|
|
177
|
+
cursor opus-4-8@1m:slow 300K 16.4K yes yes
|
|
178
|
+
cursor opus-4-8@300k 300K 16.4K yes yes
|
|
179
|
+
cursor opus-4-8@300k:fast 300K 16.4K yes yes
|
|
180
|
+
cursor opus-4-8@300k:slow 300K 16.4K yes yes
|
|
181
|
+
cursor opus-4.5 200K 16.4K yes yes
|
|
182
|
+
cursor opus-4.6@1m 1M 16.4K yes yes
|
|
183
|
+
cursor opus-4.6@200k 200K 16.4K yes yes
|
|
184
|
+
cursor opus-4.7@1m 1M 16.4K yes yes
|
|
185
|
+
cursor opus-4.7@1m:fast 1M 16.4K yes yes
|
|
186
|
+
cursor opus-4.7@1m:slow 1M 16.4K yes yes
|
|
187
|
+
cursor opus-4.7@300k 300K 16.4K yes yes
|
|
188
|
+
cursor opus-4.7@300k:fast 300K 16.4K yes yes
|
|
189
|
+
cursor opus-4.7@300k:slow 300K 16.4K yes yes
|
|
190
|
+
cursor opus-4.8@1m 300K 16.4K yes yes
|
|
191
|
+
cursor opus-4.8@1m:fast 1M 16.4K yes yes
|
|
192
|
+
cursor opus-4.8@1m:slow 300K 16.4K yes yes
|
|
193
|
+
cursor opus-4.8@300k 300K 16.4K yes yes
|
|
194
|
+
cursor opus-4.8@300k:fast 300K 16.4K yes yes
|
|
195
|
+
cursor opus-4.8@300k:slow 300K 16.4K yes yes
|
|
196
|
+
cursor opus-5@1m 1M 16.4K yes yes
|
|
197
|
+
cursor opus-5@1m:fast 1M 16.4K yes yes
|
|
198
|
+
cursor opus-5@1m:slow 1M 16.4K yes yes
|
|
199
|
+
cursor opus-5@300k 300K 16.4K yes yes
|
|
200
|
+
cursor opus-5@300k:fast 300K 16.4K yes yes
|
|
201
|
+
cursor opus-5@300k:slow 300K 16.4K yes yes
|
|
202
|
+
cursor sonnet-4-5@200k 200K 16.4K yes yes
|
|
203
|
+
cursor sonnet-4-6@1m 1M 16.4K yes yes
|
|
204
|
+
cursor sonnet-4-6@200k 200K 16.4K yes yes
|
|
205
|
+
cursor sonnet-4.5@200k 200K 16.4K yes yes
|
|
206
|
+
cursor sonnet-4.6@1m 1M 16.4K yes yes
|
|
207
|
+
cursor sonnet-4.6@200k 200K 16.4K yes yes
|
|
208
|
+
cursor sonnet-4@200k 200K 16.4K yes yes
|
|
209
|
+
cursor sonnet-5@1m 1M 16.4K yes yes
|
|
210
|
+
cursor sonnet-5@300k 300K 16.4K yes yes
|
|
211
|
+
openai-codex gpt-5.3-codex-spark 128K 128K yes no
|
|
212
|
+
openai-codex gpt-5.4 272K 128K yes yes
|
|
213
|
+
openai-codex gpt-5.4-mini 272K 128K yes yes
|
|
214
|
+
openai-codex gpt-5.5 272K 128K yes yes
|
|
215
|
+
openai-codex gpt-5.6-luna 272K 128K yes yes
|
|
216
|
+
openai-codex gpt-5.6-sol 272K 128K yes yes
|
|
217
|
+
openai-codex gpt-5.6-terra 272K 128K yes yes
|
|
218
|
+
team-agent qwen3.8-27b 262.1K 32.8K yes no
|
|
219
|
+
xai grok-4.3 1M 30K yes yes
|
|
220
|
+
xai grok-4.5 500K 500K yes yes
|
|
221
|
+
xai grok-4.6 500K 500K yes yes
|
|
222
|
+
xai grok-build-0.1 256K 256K yes yes
|
|
@@ -518,8 +518,11 @@ fn assert_provider_mcp_table(case: &Case, provider: Provider, clone_id: &str) {
|
|
|
518
518
|
}
|
|
519
519
|
Provider::CursorAgent => {
|
|
520
520
|
apply_cursor_mcp_overlay(&overlay_root, &cfg).expect("cursor overlay");
|
|
521
|
-
let text = std::fs::read_to_string(
|
|
522
|
-
|
|
521
|
+
let text = std::fs::read_to_string(
|
|
522
|
+
team_agent::lifecycle::cursor_mcp_json_path(&overlay_root, clone_id)
|
|
523
|
+
.expect("iso path"),
|
|
524
|
+
)
|
|
525
|
+
.expect("cursor mcp.json");
|
|
523
526
|
assert!(
|
|
524
527
|
text.contains("\"team_orchestrator\""),
|
|
525
528
|
"cursor MCP injection must keep team_orchestrator; text={text}"
|
|
@@ -183,7 +183,7 @@ fn sample_mcp_config(agent_id: &str, workspace: &str) -> McpConfig {
|
|
|
183
183
|
fn two_grok_seats_coexist_when_toml_has_no_per_seat_keys() {
|
|
184
184
|
let ws = tmp_dir("grok-cwd-coexist");
|
|
185
185
|
let home = tmp_dir("grok-cwd-coexist-home");
|
|
186
|
-
seed_grok_home(&home
|
|
186
|
+
seed_grok_home(&home);
|
|
187
187
|
let _guard = HomeGuard::set(&home);
|
|
188
188
|
let team = write_grok_team_agents(&ws, "grokteam", &["g1", "g2"]);
|
|
189
189
|
|
|
@@ -211,7 +211,7 @@ fn two_grok_seats_coexist_when_toml_has_no_per_seat_keys() {
|
|
|
211
211
|
fn leftover_per_seat_key_is_cleared_before_start() {
|
|
212
212
|
let ws = tmp_dir("grok-cwd-per-seat");
|
|
213
213
|
let home = tmp_dir("grok-cwd-per-seat-home");
|
|
214
|
-
seed_grok_home(&home
|
|
214
|
+
seed_grok_home(&home);
|
|
215
215
|
let _guard = HomeGuard::set(&home);
|
|
216
216
|
let grok = ws.join(".grok");
|
|
217
217
|
std::fs::create_dir_all(&grok).unwrap();
|
|
@@ -279,45 +279,12 @@ TEAM_AGENT_WORKSPACE = "/stale-ws"
|
|
|
279
279
|
);
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
#[test]
|
|
283
|
-
#[serial(env)]
|
|
284
|
-
fn grok_untrusted_folder_refuses_to_start() {
|
|
285
|
-
let ws = tmp_dir("grok-untrusted");
|
|
286
|
-
let home = tmp_dir("grok-untrusted-home");
|
|
287
|
-
seed_grok_home(&home, None);
|
|
288
|
-
let _guard = HomeGuard::set(&home);
|
|
289
|
-
let team = write_grok_team(&ws, "grokteam", "grok_writer");
|
|
290
|
-
let err = quick_start_with_transport_in_workspace(
|
|
291
|
-
&ws,
|
|
292
|
-
&team,
|
|
293
|
-
None,
|
|
294
|
-
true,
|
|
295
|
-
Some("grokteam"),
|
|
296
|
-
&OfflineTransport::new(),
|
|
297
|
-
)
|
|
298
|
-
.expect_err("untrusted folder must not start a grok seat");
|
|
299
|
-
let text = err.to_string();
|
|
300
|
-
assert!(
|
|
301
|
-
text.contains("not trusted") && text.contains("action:"),
|
|
302
|
-
"untrusted-folder error must be actionable; err={text}"
|
|
303
|
-
);
|
|
304
|
-
assert!(
|
|
305
|
-
text.contains("grok --trust") || text.contains("/hooks-trust"),
|
|
306
|
-
"next step must name grok --trust or /hooks-trust; err={text}"
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
282
|
#[test]
|
|
311
283
|
#[serial(env)]
|
|
312
284
|
fn grok_missing_login_refuses_to_start() {
|
|
313
285
|
let ws = tmp_dir("grok-nologin");
|
|
314
286
|
let home = tmp_dir("grok-nologin-home");
|
|
315
287
|
std::fs::create_dir_all(home.join(".grok")).unwrap();
|
|
316
|
-
std::fs::write(
|
|
317
|
-
home.join(".grok").join("trusted_folders.toml"),
|
|
318
|
-
format!("[folders.\"{}\"]\ntrusted = true\n", ws.display()),
|
|
319
|
-
)
|
|
320
|
-
.unwrap();
|
|
321
288
|
let _guard = HomeGuard::set(&home);
|
|
322
289
|
let err = ensure_grok_login_and_folder_trust(&ws).expect_err("missing auth.json");
|
|
323
290
|
match err {
|
|
@@ -331,12 +298,29 @@ fn grok_missing_login_refuses_to_start() {
|
|
|
331
298
|
}
|
|
332
299
|
}
|
|
333
300
|
|
|
301
|
+
#[test]
|
|
302
|
+
#[serial(env)]
|
|
303
|
+
fn grok_login_present_allows_start_without_inspect_or_toml_trust() {
|
|
304
|
+
let ws = tmp_dir("grok-login-only");
|
|
305
|
+
let home = tmp_dir("grok-login-only-home");
|
|
306
|
+
seed_grok_home(&home);
|
|
307
|
+
let _guard = HomeGuard::set(&home);
|
|
308
|
+
|
|
309
|
+
assert!(!home.join("bin/grok").exists(), "no inspect shim may exist");
|
|
310
|
+
assert!(
|
|
311
|
+
!home.join(".grok/trusted_folders.toml").exists(),
|
|
312
|
+
"no trusted TOML may be required"
|
|
313
|
+
);
|
|
314
|
+
ensure_grok_login_and_folder_trust(&ws)
|
|
315
|
+
.expect("valid login alone must allow Grok TUI to own folder consent");
|
|
316
|
+
}
|
|
317
|
+
|
|
334
318
|
#[test]
|
|
335
319
|
#[serial(env)]
|
|
336
320
|
fn grok_spawn_writes_resolved_team_agent_into_project_grok_config() {
|
|
337
321
|
let ws = tmp_dir("grok-mcp-overlay");
|
|
338
322
|
let home = tmp_dir("grok-mcp-overlay-home");
|
|
339
|
-
seed_grok_home(&home
|
|
323
|
+
seed_grok_home(&home);
|
|
340
324
|
let _guard = HomeGuard::set(&home);
|
|
341
325
|
let team = write_grok_team(&ws, "grokteam", "grok_writer");
|
|
342
326
|
let config_path = ws.join(".grok").join("config.toml");
|
|
@@ -451,37 +435,40 @@ fn write_grok_team_agents(ws: &Path, team_key: &str, agent_ids: &[&str]) -> Path
|
|
|
451
435
|
team
|
|
452
436
|
}
|
|
453
437
|
|
|
454
|
-
fn seed_grok_home(home: &Path
|
|
438
|
+
fn seed_grok_home(home: &Path) {
|
|
455
439
|
let grok = home.join(".grok");
|
|
456
440
|
std::fs::create_dir_all(&grok).unwrap();
|
|
457
441
|
std::fs::write(grok.join("auth.json"), r#"{"test":"ok"}"#).unwrap();
|
|
458
|
-
if let Some(cwd) = trusted_cwd {
|
|
459
|
-
std::fs::write(
|
|
460
|
-
grok.join("trusted_folders.toml"),
|
|
461
|
-
format!("[folders.\"{}\"]\ntrusted = true\n", cwd.display()),
|
|
462
|
-
)
|
|
463
|
-
.unwrap();
|
|
464
|
-
}
|
|
465
442
|
}
|
|
466
443
|
|
|
467
444
|
struct HomeGuard {
|
|
468
|
-
|
|
445
|
+
prev_home: Option<String>,
|
|
446
|
+
prev_path: Option<String>,
|
|
469
447
|
}
|
|
470
448
|
|
|
471
449
|
impl HomeGuard {
|
|
472
450
|
fn set(home: &Path) -> Self {
|
|
473
|
-
let
|
|
451
|
+
let prev_home = std::env::var("HOME").ok();
|
|
452
|
+
let prev_path = std::env::var("PATH").ok();
|
|
474
453
|
std::env::set_var("HOME", home);
|
|
475
|
-
|
|
454
|
+
std::env::set_var("PATH", home.join("bin"));
|
|
455
|
+
Self {
|
|
456
|
+
prev_home,
|
|
457
|
+
prev_path,
|
|
458
|
+
}
|
|
476
459
|
}
|
|
477
460
|
}
|
|
478
461
|
|
|
479
462
|
impl Drop for HomeGuard {
|
|
480
463
|
fn drop(&mut self) {
|
|
481
|
-
match &self.
|
|
464
|
+
match &self.prev_home {
|
|
482
465
|
Some(value) => std::env::set_var("HOME", value),
|
|
483
466
|
None => std::env::remove_var("HOME"),
|
|
484
467
|
}
|
|
468
|
+
match &self.prev_path {
|
|
469
|
+
Some(value) => std::env::set_var("PATH", value),
|
|
470
|
+
None => std::env::remove_var("PATH"),
|
|
471
|
+
}
|
|
485
472
|
}
|
|
486
473
|
}
|
|
487
474
|
|
|
@@ -229,7 +229,7 @@ got {status:?}"
|
|
|
229
229
|
#[test]
|
|
230
230
|
#[serial(t3_event)]
|
|
231
231
|
fn t3_unknown_business_status_is_preserved_without_normalized_event() {
|
|
232
|
-
let harness = McpSimHarness::
|
|
232
|
+
let harness = McpSimHarness::new_without_tmux();
|
|
233
233
|
let mut worker = harness.spawn_mcp_client("worker_a", "teamA");
|
|
234
234
|
let status = "garbage-status-xyz";
|
|
235
235
|
let call = worker.call_tool(
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
use std::collections::BTreeSet;
|
|
2
|
+
use std::path::Path;
|
|
3
|
+
|
|
4
|
+
use crate::lifecycle::launch::pi_mcp::{
|
|
5
|
+
parse_pi_list_models_table, select_exact_pi_model, verify_started_pi_model,
|
|
6
|
+
};
|
|
7
|
+
use crate::model::enums::ProviderEffort;
|
|
8
|
+
use crate::provider::adapters::pi::{build_pi_command_argv, PiCommandRequest, PiSessionSelector};
|
|
9
|
+
|
|
10
|
+
const CATALOG: &[u8] = include_bytes!("fixtures/pi_list_models_g0.stdout.txt");
|
|
11
|
+
|
|
12
|
+
fn argv_has_pair(argv: &[String], flag: &str, value: &str) -> bool {
|
|
13
|
+
argv.windows(2)
|
|
14
|
+
.any(|pair| pair[0] == flag && pair[1] == value)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn command_for_model(model: &str) -> Vec<String> {
|
|
18
|
+
build_pi_command_argv(PiCommandRequest {
|
|
19
|
+
executable: Path::new("/verified/pi"),
|
|
20
|
+
extension: Path::new("/workspace/.team/runtime/pi/t1/w1/team-mcp.ts"),
|
|
21
|
+
model: Some(model),
|
|
22
|
+
effort: Some(ProviderEffort::Medium),
|
|
23
|
+
system_prompt: "worker contract",
|
|
24
|
+
tool_categories: &["mcp_team"],
|
|
25
|
+
session_dir: Path::new("/workspace/.team/runtime/pi/t1/w1/sessions"),
|
|
26
|
+
session: PiSessionSelector::Fresh {
|
|
27
|
+
session_id: "716ba0cb-c491-4471-b41a-43c8d5e1f05a",
|
|
28
|
+
},
|
|
29
|
+
agent_id: "w1",
|
|
30
|
+
})
|
|
31
|
+
.expect("catalog member must build a semantic Pi argv")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[test]
|
|
35
|
+
fn pi_catalog_discovers_all_exact_ids_and_rejects_invalid_or_ambiguous_selection() {
|
|
36
|
+
let models = parse_pi_list_models_table(CATALOG).expect("frozen unfiltered table must parse");
|
|
37
|
+
let unique: BTreeSet<&str> = models.iter().map(String::as_str).collect();
|
|
38
|
+
assert_eq!(models.len(), 221, "the frozen table has 221 data rows");
|
|
39
|
+
assert_eq!(unique.len(), 221, "exact catalog IDs must be unique");
|
|
40
|
+
assert!(unique.contains("team-agent/qwen3.8-27b"));
|
|
41
|
+
assert!(unique.iter().any(|id| id.contains('@')));
|
|
42
|
+
assert!(unique.iter().any(|id| id.ends_with(":fast")));
|
|
43
|
+
assert!(unique.iter().any(|id| id.ends_with(":slow")));
|
|
44
|
+
|
|
45
|
+
for exact in &models {
|
|
46
|
+
let selected = select_exact_pi_model(&models, exact)
|
|
47
|
+
.unwrap_or_else(|error| panic!("exact catalog member {exact} must select: {error}"));
|
|
48
|
+
assert_eq!(selected, *exact, "exact catalog member must round-trip");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for invalid in [
|
|
52
|
+
"",
|
|
53
|
+
"foo/bar",
|
|
54
|
+
"cursor/",
|
|
55
|
+
"team-agent/*",
|
|
56
|
+
"gpt-5.4-mini",
|
|
57
|
+
"grok-4.5",
|
|
58
|
+
"grok-4.6",
|
|
59
|
+
"qwen3.8-27b",
|
|
60
|
+
"sonnet:high",
|
|
61
|
+
] {
|
|
62
|
+
assert!(
|
|
63
|
+
select_exact_pi_model(&models, invalid).is_err(),
|
|
64
|
+
"invalid, wildcard, or ambiguous model must refuse: {invalid:?}"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#[test]
|
|
70
|
+
fn pi_exact_catalog_id_is_forwarded_and_started_identity_must_match() {
|
|
71
|
+
let models = parse_pi_list_models_table(CATALOG).expect("frozen unfiltered table must parse");
|
|
72
|
+
assert_eq!(models.len(), 221);
|
|
73
|
+
|
|
74
|
+
for exact in &models {
|
|
75
|
+
let selected = select_exact_pi_model(&models, exact).expect("exact member");
|
|
76
|
+
let argv = command_for_model(&selected);
|
|
77
|
+
assert!(
|
|
78
|
+
argv_has_pair(&argv, "--model", exact),
|
|
79
|
+
"catalog ID must be forwarded byte-for-byte: {exact}; argv={argv:?}"
|
|
80
|
+
);
|
|
81
|
+
assert_eq!(
|
|
82
|
+
argv.iter().filter(|arg| arg.as_str() == "--model").count(),
|
|
83
|
+
1,
|
|
84
|
+
"model selector must occur exactly once: {argv:?}"
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
assert!(verify_started_pi_model("team-agent/qwen3.8-27b", "team-agent/qwen3.8-27b").is_ok());
|
|
89
|
+
assert!(
|
|
90
|
+
verify_started_pi_model("team-agent/qwen3.8-27b", "xai/grok-4.6").is_err(),
|
|
91
|
+
"started identity mismatch must refuse rather than trust pane chrome"
|
|
92
|
+
);
|
|
93
|
+
assert!(
|
|
94
|
+
verify_started_pi_model("team-agent/qwen3.8-27b", "").is_err(),
|
|
95
|
+
"missing objective started-model evidence must not pass"
|
|
96
|
+
);
|
|
97
|
+
}
|