@team-agent/installer 0.5.106 → 0.5.107
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/tests/base.rs +112 -225
- package/crates/team-agent/src/compiler/tests.rs +46 -59
- package/crates/team-agent/src/leader/tests/byte_findings.rs +1 -14
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +57 -173
- package/crates/team-agent/src/lifecycle/launch/pi_mcp_extension.js +226 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +0 -37
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +0 -9
- package/crates/team-agent/src/lifecycle/tests/fixtures/pi_native_mcp_host.mjs +71 -0
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -66
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +0 -392
- package/crates/team-agent/src/lifecycle/tests/lifecycle_lock.rs +0 -5
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +2 -361
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +1 -16
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +20 -112
- package/crates/team-agent/src/lifecycle/tests/pi_fork_session_inheritance_red.rs +1 -12
- package/crates/team-agent/src/lifecycle/tests/pi_native_mcp_capability_red.rs +546 -0
- package/crates/team-agent/src/lifecycle/tests.rs +1 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +11 -54
- package/crates/team-agent/src/messaging/tests/wave2.rs +2 -302
- package/crates/team-agent/src/model/name_similarity.rs +52 -67
- package/crates/team-agent/src/model/task_graph.rs +37 -124
- package/crates/team-agent/src/model/yaml/tests.rs +46 -165
- package/crates/team-agent/src/provider/tests/adapter.rs +0 -20
- package/crates/team-agent/src/provider/tests/classify.rs +106 -198
- package/crates/team-agent/src/tmux_backend/tests.rs +178 -501
- package/crates/team-agent/src/transport/tests/wire.rs +0 -55
- package/package.json +4 -4
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
use super::launch_spawn::seed_healthy_coordinator;
|
|
2
2
|
use super::*;
|
|
3
|
-
use crate::cli::{
|
|
4
|
-
cmd_doctor, cmd_send, cmd_status, lifecycle_port, CmdOutput, CmdResult, DoctorArgs,
|
|
5
|
-
SendArgs, StatusArgs,
|
|
6
|
-
};
|
|
3
|
+
use crate::cli::{cmd_doctor, CmdOutput, CmdResult, DoctorArgs};
|
|
7
4
|
use crate::transport::test_support::OfflineTransport;
|
|
8
|
-
use crate::transport::{PaneId, PaneInfo, SessionName, WindowName};
|
|
9
5
|
use serde_json::{json, Map, Value};
|
|
10
|
-
use std::collections::
|
|
6
|
+
use std::collections::BTreeMap;
|
|
11
7
|
use std::path::{Path, PathBuf};
|
|
12
8
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
13
9
|
|
|
@@ -96,91 +92,6 @@ fn hermetic_caller_envs() -> &'static [&'static str] {
|
|
|
96
92
|
]
|
|
97
93
|
}
|
|
98
94
|
|
|
99
|
-
#[test]
|
|
100
|
-
#[ignore = "legacy display-backed phase golden fixture superseded by silent tmux runtime"]
|
|
101
|
-
#[serial_test::serial(env)]
|
|
102
|
-
fn phase_b_golden_events_state_status_zero_drift() {
|
|
103
|
-
let baseline = phase_fixture_path("phase_b").join("golden.json");
|
|
104
|
-
let actual = run_phase_golden(PhaseGolden {
|
|
105
|
-
phase: "phase_b",
|
|
106
|
-
team_key: "teamdir",
|
|
107
|
-
lifecycle_op: phase_b_reset_discard_session,
|
|
108
|
-
});
|
|
109
|
-
let expected = load_phase_golden(&baseline);
|
|
110
|
-
assert_eq!(
|
|
111
|
-
actual, expected,
|
|
112
|
-
"phase B golden drift; surgical key edits only — do not regenerate the file"
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
#[test]
|
|
117
|
-
#[ignore = "legacy display-backed phase golden fixture superseded by silent tmux runtime"]
|
|
118
|
-
#[serial_test::serial(env)]
|
|
119
|
-
fn phase_c_golden_events_state_status_zero_drift() {
|
|
120
|
-
let baseline = phase_fixture_path("phase_c").join("golden.json");
|
|
121
|
-
let actual = run_phase_golden(PhaseGolden {
|
|
122
|
-
phase: "phase_c",
|
|
123
|
-
team_key: "teamdir",
|
|
124
|
-
lifecycle_op: phase_b_reset_discard_session,
|
|
125
|
-
});
|
|
126
|
-
let expected = load_phase_golden(&baseline);
|
|
127
|
-
assert_eq!(
|
|
128
|
-
actual, expected,
|
|
129
|
-
"phase C golden drift; surgical key edits only — do not regenerate the file"
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
#[test]
|
|
134
|
-
#[ignore = "legacy display-backed phase golden fixture superseded by silent tmux runtime"]
|
|
135
|
-
#[serial_test::serial(env)]
|
|
136
|
-
fn phase_d_golden_events_state_status_zero_drift() {
|
|
137
|
-
let baseline = phase_fixture_path("phase_d").join("golden.json");
|
|
138
|
-
let actual = run_phase_golden(PhaseGolden {
|
|
139
|
-
phase: "phase_d",
|
|
140
|
-
team_key: "teamdir",
|
|
141
|
-
lifecycle_op: phase_b_reset_discard_session,
|
|
142
|
-
});
|
|
143
|
-
let expected = load_phase_golden(&baseline);
|
|
144
|
-
assert_eq!(
|
|
145
|
-
actual, expected,
|
|
146
|
-
"phase D golden drift; surgical key edits only — do not regenerate the file"
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
#[test]
|
|
151
|
-
#[ignore = "legacy display-backed phase golden fixture superseded by silent tmux runtime"]
|
|
152
|
-
#[serial_test::serial(env)]
|
|
153
|
-
fn phase_e_golden_events_state_status_zero_drift() {
|
|
154
|
-
let baseline = phase_fixture_path("phase_e").join("golden.json");
|
|
155
|
-
let actual = run_phase_golden(PhaseGolden {
|
|
156
|
-
phase: "phase_e",
|
|
157
|
-
team_key: "teamdir",
|
|
158
|
-
lifecycle_op: phase_b_reset_discard_session,
|
|
159
|
-
});
|
|
160
|
-
let expected = load_phase_golden(&baseline);
|
|
161
|
-
assert_eq!(
|
|
162
|
-
actual, expected,
|
|
163
|
-
"phase E golden drift; surgical key edits only — do not regenerate the file"
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
#[test]
|
|
168
|
-
#[ignore = "legacy display-backed phase golden fixture superseded by silent tmux runtime"]
|
|
169
|
-
#[serial_test::serial(env)]
|
|
170
|
-
fn phase_f_golden_events_state_status_zero_drift() {
|
|
171
|
-
let baseline = phase_fixture_path("phase_f").join("golden.json");
|
|
172
|
-
let actual = run_phase_golden(PhaseGolden {
|
|
173
|
-
phase: "phase_f",
|
|
174
|
-
team_key: "teamdir",
|
|
175
|
-
lifecycle_op: phase_b_reset_discard_session,
|
|
176
|
-
});
|
|
177
|
-
let expected = load_phase_golden(&baseline);
|
|
178
|
-
assert_eq!(
|
|
179
|
-
actual, expected,
|
|
180
|
-
"phase F golden drift; surgical key edits only — do not regenerate the file"
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
95
|
#[test]
|
|
185
96
|
#[serial_test::serial(env)]
|
|
186
97
|
fn phase_golden_unbound_not_ready_requires_claim_leader() {
|
|
@@ -221,202 +132,6 @@ fn phase_golden_unbound_not_ready_requires_claim_leader() {
|
|
|
221
132
|
);
|
|
222
133
|
}
|
|
223
134
|
|
|
224
|
-
#[derive(Clone, Copy)]
|
|
225
|
-
struct PhaseGolden {
|
|
226
|
-
phase: &'static str,
|
|
227
|
-
team_key: &'static str,
|
|
228
|
-
lifecycle_op: fn(&Path, &OfflineTransport, &'static str) -> Value,
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
fn run_phase_golden(spec: PhaseGolden) -> Value {
|
|
232
|
-
let hermetic = HermeticTestEnv::enter(spec.phase);
|
|
233
|
-
let _permission_mode = EnvVarGuard::set(ANCESTRY_ENV, "[]");
|
|
234
|
-
let team = two_worker_team_dir(&hermetic);
|
|
235
|
-
let workspace = team.parent().expect("workspace").to_path_buf();
|
|
236
|
-
seed_healthy_coordinator(&workspace);
|
|
237
|
-
let _caller_pane = EnvVarGuard::set("TMUX_PANE", "%caller");
|
|
238
|
-
let launch_transport = codex_ready_transport().with_targets(vec![PaneInfo {
|
|
239
|
-
pane_id: PaneId::new("%caller"),
|
|
240
|
-
session: SessionName::new("caller"),
|
|
241
|
-
window_index: Some(0),
|
|
242
|
-
window_name: Some(WindowName::new("caller")),
|
|
243
|
-
pane_index: Some(0),
|
|
244
|
-
tty: None,
|
|
245
|
-
current_command: Some("codex".to_string()),
|
|
246
|
-
current_path: Some(workspace.clone()),
|
|
247
|
-
active: true,
|
|
248
|
-
pane_pid: None,
|
|
249
|
-
leader_env: BTreeMap::new(),
|
|
250
|
-
}])
|
|
251
|
-
.with_pane_current_command("%caller", "codex");
|
|
252
|
-
let quick_start = quick_start_with_transport_in_workspace(
|
|
253
|
-
&workspace,
|
|
254
|
-
&team,
|
|
255
|
-
None,
|
|
256
|
-
true,
|
|
257
|
-
None,
|
|
258
|
-
&launch_transport,
|
|
259
|
-
);
|
|
260
|
-
let status_compact = cmd_status(&StatusArgs {
|
|
261
|
-
agent: None,
|
|
262
|
-
workspace: workspace.clone(),
|
|
263
|
-
detail: false,
|
|
264
|
-
summary: false,
|
|
265
|
-
json: true,
|
|
266
|
-
team: Some(spec.team_key.to_string()),
|
|
267
|
-
});
|
|
268
|
-
let status_detail = cmd_status(&StatusArgs {
|
|
269
|
-
agent: None,
|
|
270
|
-
workspace: workspace.clone(),
|
|
271
|
-
detail: true,
|
|
272
|
-
summary: false,
|
|
273
|
-
json: true,
|
|
274
|
-
team: Some(spec.team_key.to_string()),
|
|
275
|
-
});
|
|
276
|
-
let send = cmd_send(&SendArgs {
|
|
277
|
-
target: Some("w1".to_string()),
|
|
278
|
-
message: vec!["phase".to_string(), "golden".to_string()],
|
|
279
|
-
targets: None,
|
|
280
|
-
workspace: workspace.clone(),
|
|
281
|
-
team: Some(spec.team_key.to_string()),
|
|
282
|
-
task: None,
|
|
283
|
-
sender: crate::messaging::TrustedSender::leader(),
|
|
284
|
-
no_ack: true,
|
|
285
|
-
no_wait: true,
|
|
286
|
-
watch_result: false,
|
|
287
|
-
timeout: 0.1,
|
|
288
|
-
confirm_human: false,
|
|
289
|
-
json: true,
|
|
290
|
-
message_id: Some("phase-golden-message".to_string()),
|
|
291
|
-
presentation: crate::messaging::presentation::PresentationRequest::default(),
|
|
292
|
-
pane: None,
|
|
293
|
-
to_name: None,
|
|
294
|
-
to_leader: None,
|
|
295
|
-
});
|
|
296
|
-
let runtime_state = crate::state::persist::load_runtime_state(&workspace)
|
|
297
|
-
.expect("quick-start state written before shutdown fixture");
|
|
298
|
-
let generation = runtime_state
|
|
299
|
-
.get("generation")
|
|
300
|
-
.and_then(Value::as_str)
|
|
301
|
-
.or_else(|| {
|
|
302
|
-
runtime_state
|
|
303
|
-
.get("agents")
|
|
304
|
-
.and_then(Value::as_object)
|
|
305
|
-
.and_then(|agents| {
|
|
306
|
-
agents.values().find_map(|agent| {
|
|
307
|
-
agent.get("spawned_at").and_then(Value::as_str)
|
|
308
|
-
})
|
|
309
|
-
})
|
|
310
|
-
})
|
|
311
|
-
.or_else(|| {
|
|
312
|
-
runtime_state
|
|
313
|
-
.pointer("/teams/teamdir/agents")
|
|
314
|
-
.and_then(Value::as_object)
|
|
315
|
-
.and_then(|agents| {
|
|
316
|
-
agents.values().find_map(|agent| {
|
|
317
|
-
agent.get("spawned_at").and_then(Value::as_str)
|
|
318
|
-
})
|
|
319
|
-
})
|
|
320
|
-
})
|
|
321
|
-
.unwrap_or("phase-golden");
|
|
322
|
-
let lifecycle_transport = codex_ready_transport()
|
|
323
|
-
.with_session_present(true)
|
|
324
|
-
.with_windows(vec![WindowName::new("w1"), WindowName::new("w2")])
|
|
325
|
-
.with_targets(vec![PaneInfo {
|
|
326
|
-
pane_id: PaneId::new("%w1"),
|
|
327
|
-
session: SessionName::new("team-phasegolden"),
|
|
328
|
-
window_index: Some(0),
|
|
329
|
-
window_name: Some(WindowName::new("w1")),
|
|
330
|
-
pane_index: Some(0),
|
|
331
|
-
tty: None,
|
|
332
|
-
current_command: Some("codex".to_string()),
|
|
333
|
-
current_path: Some(workspace.clone()),
|
|
334
|
-
active: true,
|
|
335
|
-
pane_pid: None,
|
|
336
|
-
leader_env: BTreeMap::new(),
|
|
337
|
-
}])
|
|
338
|
-
.with_session_owner(&workspace, "teamdir", generation);
|
|
339
|
-
let lifecycle = (spec.lifecycle_op)(&workspace, &lifecycle_transport, spec.team_key);
|
|
340
|
-
let shutdown = lifecycle_port::shutdown_with_transport(
|
|
341
|
-
&workspace,
|
|
342
|
-
true,
|
|
343
|
-
Some(spec.team_key),
|
|
344
|
-
&lifecycle_transport,
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
let raw = json!({
|
|
348
|
-
"phase": spec.phase,
|
|
349
|
-
"script": [
|
|
350
|
-
{
|
|
351
|
-
"step": "quick-start",
|
|
352
|
-
"exit_code": if quick_start.is_ok() { 0 } else { 1 },
|
|
353
|
-
"output": quick_start_value(quick_start),
|
|
354
|
-
},
|
|
355
|
-
{ "step": "status-json", "result": cmd_value(status_compact) },
|
|
356
|
-
{ "step": "status-detail-json", "result": cmd_value(status_detail) },
|
|
357
|
-
{ "step": "send", "result": cmd_value(send) },
|
|
358
|
-
{ "step": "phase-lifecycle-op", "output": lifecycle },
|
|
359
|
-
{
|
|
360
|
-
"step": "shutdown-keep-logs",
|
|
361
|
-
"exit_code": if shutdown.is_ok() { 0 } else { 1 },
|
|
362
|
-
"output": match shutdown {
|
|
363
|
-
Ok(value) => value,
|
|
364
|
-
Err(error) => json!({"ok": false, "error": error.to_string()}),
|
|
365
|
-
},
|
|
366
|
-
},
|
|
367
|
-
],
|
|
368
|
-
"events_jsonl": read_events(&workspace),
|
|
369
|
-
"state_json": read_state(&workspace),
|
|
370
|
-
"transport": {
|
|
371
|
-
"spawns": lifecycle_transport.spawn_window_records(),
|
|
372
|
-
},
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
let mut ctx = NormalizeCtx::new(&workspace);
|
|
376
|
-
normalize_value(raw, &mut ctx, None)
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
fn phase_b_reset_discard_session(
|
|
380
|
-
workspace: &Path,
|
|
381
|
-
transport: &OfflineTransport,
|
|
382
|
-
team_key: &'static str,
|
|
383
|
-
) -> Value {
|
|
384
|
-
match crate::lifecycle::reset_agent_with_transport(
|
|
385
|
-
workspace,
|
|
386
|
-
&aid("w1"),
|
|
387
|
-
true,
|
|
388
|
-
false,
|
|
389
|
-
Some(team_key),
|
|
390
|
-
transport,
|
|
391
|
-
) {
|
|
392
|
-
Ok(ResetAgentOutcome::Reset {
|
|
393
|
-
start_mode,
|
|
394
|
-
discarded_session_id,
|
|
395
|
-
session_id,
|
|
396
|
-
new_session_id,
|
|
397
|
-
..
|
|
398
|
-
}) => json!({
|
|
399
|
-
"ok": true,
|
|
400
|
-
"operation": "reset-agent --discard-session",
|
|
401
|
-
"status": "running",
|
|
402
|
-
"start_mode": format!("{start_mode:?}"),
|
|
403
|
-
"discarded_session_id": discarded_session_id.map(|id| id.as_str().to_string()),
|
|
404
|
-
"session_id": session_id.map(|id| id.as_str().to_string()),
|
|
405
|
-
"new_session_id": new_session_id.map(|id| id.as_str().to_string()),
|
|
406
|
-
}),
|
|
407
|
-
Ok(other) => json!({
|
|
408
|
-
"ok": true,
|
|
409
|
-
"operation": "reset-agent --discard-session",
|
|
410
|
-
"status": format!("{other:?}"),
|
|
411
|
-
}),
|
|
412
|
-
Err(error) => json!({
|
|
413
|
-
"ok": false,
|
|
414
|
-
"operation": "reset-agent --discard-session",
|
|
415
|
-
"error": error.to_string(),
|
|
416
|
-
}),
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
135
|
fn two_worker_team_dir(hermetic: &HermeticTestEnv) -> PathBuf {
|
|
421
136
|
let team = hermetic.workspace("team").join("teamdir");
|
|
422
137
|
std::fs::create_dir_all(team.join("agents")).unwrap();
|
|
@@ -445,40 +160,6 @@ fn role_doc(id: &str) -> String {
|
|
|
445
160
|
)
|
|
446
161
|
}
|
|
447
162
|
|
|
448
|
-
fn quick_start_value(result: Result<QuickStartReport, LifecycleError>) -> Value {
|
|
449
|
-
match result {
|
|
450
|
-
Ok(QuickStartReport::Ready {
|
|
451
|
-
session_name,
|
|
452
|
-
launch,
|
|
453
|
-
worker_readiness,
|
|
454
|
-
..
|
|
455
|
-
}) => {
|
|
456
|
-
let agents = launch
|
|
457
|
-
.started
|
|
458
|
-
.iter()
|
|
459
|
-
.map(|started| {
|
|
460
|
-
json!({
|
|
461
|
-
"agent_id": started.agent_id.as_str(),
|
|
462
|
-
"target": started.target,
|
|
463
|
-
"start_mode": format!("{:?}", started.start_mode),
|
|
464
|
-
"session_id": started.session_id.as_ref().map(|id| id.as_str().to_string()),
|
|
465
|
-
"rollout_path": started.rollout_path.as_ref().map(|path| path.as_path().to_string_lossy().to_string()),
|
|
466
|
-
})
|
|
467
|
-
})
|
|
468
|
-
.collect::<Vec<_>>();
|
|
469
|
-
json!({
|
|
470
|
-
"ok": true,
|
|
471
|
-
"status": "ready",
|
|
472
|
-
"session_name": session_name.as_str(),
|
|
473
|
-
"worker_readiness": format!("{worker_readiness:?}"),
|
|
474
|
-
"started": agents,
|
|
475
|
-
})
|
|
476
|
-
}
|
|
477
|
-
Ok(other) => json!({"ok": false, "status": format!("{other:?}")}),
|
|
478
|
-
Err(error) => json!({"ok": false, "error": error.to_string()}),
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
163
|
fn cmd_value(result: Result<CmdResult, crate::cli::CliError>) -> Value {
|
|
483
164
|
match result {
|
|
484
165
|
Ok(cmd) => json!({
|
|
@@ -496,46 +177,6 @@ fn cmd_value(result: Result<CmdResult, crate::cli::CliError>) -> Value {
|
|
|
496
177
|
}
|
|
497
178
|
}
|
|
498
179
|
|
|
499
|
-
fn read_events(workspace: &Path) -> Vec<Value> {
|
|
500
|
-
let path = crate::model::paths::logs_dir(workspace).join("events.jsonl");
|
|
501
|
-
std::fs::read_to_string(path)
|
|
502
|
-
.unwrap_or_default()
|
|
503
|
-
.lines()
|
|
504
|
-
.filter_map(|line| serde_json::from_str(line).ok())
|
|
505
|
-
.collect()
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
fn read_state(workspace: &Path) -> Value {
|
|
509
|
-
crate::state::persist::load_runtime_state(workspace).unwrap_or_else(|_| json!(null))
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
fn phase_fixture_path(phase: &str) -> PathBuf {
|
|
513
|
-
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
514
|
-
.join("tests")
|
|
515
|
-
.join("fixtures")
|
|
516
|
-
.join("0_5_0_phase_golden")
|
|
517
|
-
.join(phase)
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
fn load_phase_golden(path: &Path) -> Value {
|
|
521
|
-
let text = std::fs::read_to_string(path)
|
|
522
|
-
.unwrap_or_else(|e| panic!("missing golden baseline {}: {e}", path.display()));
|
|
523
|
-
let stripped = strip_full_line_json_comments(&text);
|
|
524
|
-
serde_json::from_str(&stripped).unwrap_or_else(|e| {
|
|
525
|
-
panic!(
|
|
526
|
-
"parse golden baseline {} after stripping // review comments: {e}",
|
|
527
|
-
path.display()
|
|
528
|
-
)
|
|
529
|
-
})
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
fn strip_full_line_json_comments(text: &str) -> String {
|
|
533
|
-
text.lines()
|
|
534
|
-
.filter(|line| !line.trim_start().starts_with("//"))
|
|
535
|
-
.collect::<Vec<_>>()
|
|
536
|
-
.join("\n")
|
|
537
|
-
}
|
|
538
|
-
|
|
539
180
|
fn run_diagnose_after_quick_start() -> Value {
|
|
540
181
|
let hermetic = HermeticTestEnv::enter("tombstone-claim-leader");
|
|
541
182
|
let _permission_mode = EnvVarGuard::set(ANCESTRY_ENV, "[]");
|
|
@@ -371,16 +371,11 @@ fn pi_leader_and_teammate_body(hermetic: &HermeticTestEnv) {
|
|
|
371
371
|
|
|
372
372
|
let pi_provider_root = hermetic.workspace("pi-add-provider");
|
|
373
373
|
let pi_bin = pi_provider_root.join("bin");
|
|
374
|
-
let pi_package = pi_provider_root.join("pi-mcp-adapter");
|
|
375
374
|
std::fs::create_dir_all(&pi_bin).expect("create Pi test bin");
|
|
376
|
-
std::fs::create_dir_all(&pi_package).expect("create Pi test adapter");
|
|
377
375
|
let pi_real = pi_provider_root.join("pi-cli");
|
|
378
376
|
std::fs::write(
|
|
379
377
|
&pi_real,
|
|
380
|
-
|
|
381
|
-
"#!/bin/sh\ncase \"$1\" in\n --version) printf '0.84.4\\n' ;;\n --list-models) printf 'provider model\\nteam-agent qwen3.8-27b\\n' ;;\n list) printf 'npm:pi-mcp-adapter\\n{}\\n' ;;\n *) exit 64 ;;\nesac\n",
|
|
382
|
-
pi_package.display()
|
|
383
|
-
),
|
|
378
|
+
"#!/bin/sh\ncase \"$1\" in\n --version) printf '0.84.4\\n' ;;\n --list-models) printf 'provider model\\nteam-agent qwen3.8-27b\\n' ;;\n list) exit 64 ;;\n *) exit 64 ;;\nesac\n",
|
|
384
379
|
)
|
|
385
380
|
.expect("write protocol-capable Pi test executable");
|
|
386
381
|
std::fs::set_permissions(
|
|
@@ -389,16 +384,6 @@ fn pi_leader_and_teammate_body(hermetic: &HermeticTestEnv) {
|
|
|
389
384
|
)
|
|
390
385
|
.expect("make Pi test executable");
|
|
391
386
|
std::os::unix::fs::symlink(&pi_real, pi_bin.join("pi")).expect("link Pi test executable");
|
|
392
|
-
std::fs::write(
|
|
393
|
-
pi_package.join("package.json"),
|
|
394
|
-
br#"{"name":"pi-mcp-adapter","version":"2.30.0","pi":{"extensions":["./index.ts"]}}"#,
|
|
395
|
-
)
|
|
396
|
-
.expect("write Pi test adapter package");
|
|
397
|
-
std::fs::write(
|
|
398
|
-
pi_package.join("index.ts"),
|
|
399
|
-
b"export const createMcpAdapter = () => {};\n",
|
|
400
|
-
)
|
|
401
|
-
.expect("write Pi test adapter entry");
|
|
402
387
|
let _pi_path = EnvVarGuard::set("PATH", pi_bin.as_os_str());
|
|
403
388
|
let pi_success_role = "---\nname: mate\nrole: Pi Dynamic Worker\nprovider: pi\nmodel: team-agent/qwen3.8-27b\nauth_mode: subscription\neffort: max\ntools:\n - mcp_team\ndangerously_skip_permissions: true\n---\n\ndynamic pi\n";
|
|
404
389
|
let (pi_success_team, pi_success_role_path) =
|