@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
|
@@ -4,11 +4,11 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|
|
4
4
|
|
|
5
5
|
use crate::lifecycle::launch::launch_with_transport_in_workspace;
|
|
6
6
|
use crate::lifecycle::launch::pi_mcp::{
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
PiExecutableChain, PiExecutableFileType, PiMaterializeRequest, PiSessionScope,
|
|
8
|
+
PiWrapperRequest, materialize_pi_plan, materialize_pi_resume_plan,
|
|
9
9
|
parse_pi_list_models_table, pi_seat_paths, resolve_pi_executable_chain,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
validate_pi_executable_chain, validate_pi_wrapper_source, write_pi_wrapper,
|
|
11
|
+
write_pi_wrapper_with_publish,
|
|
12
12
|
};
|
|
13
13
|
use crate::lifecycle::start_agent_with_transport;
|
|
14
14
|
use crate::model::enums::ProviderEffort;
|
|
@@ -20,8 +20,6 @@ use crate::transport::test_support::OfflineTransport;
|
|
|
20
20
|
mod hermetic_guard;
|
|
21
21
|
use hermetic_guard::HermeticTestEnv;
|
|
22
22
|
|
|
23
|
-
const PACKAGE_DIGEST: &str = "ce8b8b6154e83e9732c58bd993e7ed69390617616f4f0e7330274d5ee9e2f620";
|
|
24
|
-
const INDEX_DIGEST: &str = "16d260ac25b66346baab6ecef76680324336953bafc7be8cf95b3df5c611b89e";
|
|
25
23
|
const CATALOG_DIGEST: &str = "726cedb6c3f6fe80a0d7b98918d8ed5063695e01f510a48f46c4bad5daab49fe";
|
|
26
24
|
static NEXT_ROOT: AtomicU32 = AtomicU32::new(0);
|
|
27
25
|
const PI_WRAPPER_CHILD: &str = "TEAM_AGENT_TEST_PI_WRAPPER_CHILD";
|
|
@@ -88,25 +86,6 @@ fn temp_root(label: &str) -> PathBuf {
|
|
|
88
86
|
root
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
fn adapter_identity(root: &Path) -> PiAdapterIdentity {
|
|
92
|
-
let package_root = root.join("pi-mcp-adapter");
|
|
93
|
-
std::fs::create_dir_all(&package_root).expect("create adapter package root");
|
|
94
|
-
let package_json = package_root.join("package.json");
|
|
95
|
-
let index_ts = package_root.join("index.ts");
|
|
96
|
-
std::fs::write(&package_json, b"{}").expect("write adapter package receipt");
|
|
97
|
-
std::fs::write(&index_ts, b"export const createMcpAdapter = () => {};\n")
|
|
98
|
-
.expect("write loadable adapter entry");
|
|
99
|
-
PiAdapterIdentity {
|
|
100
|
-
package_name: "pi-mcp-adapter".to_string(),
|
|
101
|
-
version: "2.30.0".to_string(),
|
|
102
|
-
extension_entry: "./index.ts".to_string(),
|
|
103
|
-
package_json,
|
|
104
|
-
index_ts,
|
|
105
|
-
package_json_sha256: PACKAGE_DIGEST.to_string(),
|
|
106
|
-
index_ts_sha256: INDEX_DIGEST.to_string(),
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
89
|
fn mcp_config(candidate: &Path, workspace: &Path, agent_id: &str) -> McpConfig {
|
|
111
90
|
McpConfig {
|
|
112
91
|
raw: serde_json::json!({
|
|
@@ -126,8 +105,7 @@ fn mcp_config(candidate: &Path, workspace: &Path, agent_id: &str) -> McpConfig {
|
|
|
126
105
|
}
|
|
127
106
|
|
|
128
107
|
#[test]
|
|
129
|
-
fn
|
|
130
|
-
let root = temp_root("executable-chain");
|
|
108
|
+
fn pi_executable_chain_freezes_wrapper_real_binary_and_catalog() {
|
|
131
109
|
let chain = PiExecutableChain {
|
|
132
110
|
path_entry: PathBuf::from("/Users/fixture/.local/bin/pi"),
|
|
133
111
|
path_entry_type: PiExecutableFileType::Wrapper,
|
|
@@ -137,7 +115,6 @@ fn pi_executable_chain_freezes_wrapper_real_binary_catalog_and_plugin_identity()
|
|
|
137
115
|
),
|
|
138
116
|
pi_version: "0.84.3".to_string(),
|
|
139
117
|
catalog_sha256: CATALOG_DIGEST.to_string(),
|
|
140
|
-
adapter: adapter_identity(&root),
|
|
141
118
|
};
|
|
142
119
|
validate_pi_executable_chain(&chain).expect("the protocol-capable wrapper chain is valid");
|
|
143
120
|
|
|
@@ -169,17 +146,9 @@ fn pi_executable_chain_freezes_wrapper_real_binary_catalog_and_plugin_identity()
|
|
|
169
146
|
"a direct Homebrew binary must not replace the verified PATH wrapper launch entry"
|
|
170
147
|
);
|
|
171
148
|
|
|
172
|
-
let mut wrong_plugin = chain;
|
|
173
|
-
wrong_plugin.adapter.version = "2.31.0".to_string();
|
|
174
|
-
wrong_plugin.adapter.package_json_sha256 = "11".repeat(32);
|
|
175
|
-
wrong_plugin.adapter.index_ts_sha256 = "22".repeat(32);
|
|
176
|
-
validate_pi_executable_chain(&wrong_plugin)
|
|
177
|
-
.expect("adapter version and content digests are diagnostic observations only");
|
|
178
|
-
|
|
179
149
|
assert!(parse_pi_list_models_table(b"provider model\nopenai-codex gpt-5.6-luna\n").is_ok());
|
|
180
150
|
assert!(parse_pi_list_models_table(b"provider model\n").is_err());
|
|
181
151
|
assert!(parse_pi_list_models_table(b"provider model\nmalformed\n").is_err());
|
|
182
|
-
std::fs::remove_dir_all(root).expect("remove executable chain fixture");
|
|
183
152
|
}
|
|
184
153
|
|
|
185
154
|
#[test]
|
|
@@ -189,15 +158,10 @@ fn pi_standard_npm_symlink_is_a_verified_launch_entry() {
|
|
|
189
158
|
let root = temp_root("npm-symlink");
|
|
190
159
|
let bin = root.join("bin");
|
|
191
160
|
let later_bin = root.join("later-bin");
|
|
192
|
-
let package_root = root.join("pi-mcp-adapter");
|
|
193
161
|
std::fs::create_dir_all(&bin).expect("create bin");
|
|
194
162
|
std::fs::create_dir_all(&later_bin).expect("create later bin");
|
|
195
|
-
std::fs::create_dir_all(&package_root).expect("create adapter root");
|
|
196
163
|
let real = root.join("cli.js");
|
|
197
|
-
let script =
|
|
198
|
-
"#!/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",
|
|
199
|
-
package_root.display()
|
|
200
|
-
);
|
|
164
|
+
let script = "#!/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";
|
|
201
165
|
std::fs::write(&real, &script).expect("write protocol-capable Pi entry");
|
|
202
166
|
std::fs::set_permissions(&real, std::fs::Permissions::from_mode(0o755))
|
|
203
167
|
.expect("make Pi entry executable");
|
|
@@ -205,16 +169,6 @@ fn pi_standard_npm_symlink_is_a_verified_launch_entry() {
|
|
|
205
169
|
std::fs::write(later_bin.join("pi"), script).expect("write later Pi wrapper");
|
|
206
170
|
std::fs::set_permissions(later_bin.join("pi"), std::fs::Permissions::from_mode(0o755))
|
|
207
171
|
.expect("make later Pi wrapper executable");
|
|
208
|
-
std::fs::write(
|
|
209
|
-
package_root.join("package.json"),
|
|
210
|
-
br#"{"name":"pi-mcp-adapter","version":"2.30.0","pi":{"extensions":["./index.ts"]}}"#,
|
|
211
|
-
)
|
|
212
|
-
.expect("write adapter package");
|
|
213
|
-
std::fs::write(
|
|
214
|
-
package_root.join("index.ts"),
|
|
215
|
-
b"export const createMcpAdapter = () => {};\n",
|
|
216
|
-
)
|
|
217
|
-
.expect("write adapter entry");
|
|
218
172
|
unsafe {
|
|
219
173
|
std::env::set_var(
|
|
220
174
|
"PATH",
|
|
@@ -236,34 +190,6 @@ fn pi_standard_npm_symlink_is_a_verified_launch_entry() {
|
|
|
236
190
|
});
|
|
237
191
|
}
|
|
238
192
|
|
|
239
|
-
#[test]
|
|
240
|
-
fn pi_adapter_detector_requires_exact_2_30_0_entry_and_digest() {
|
|
241
|
-
let root = temp_root("adapter-identity");
|
|
242
|
-
let exact = adapter_identity(&root);
|
|
243
|
-
validate_pi_adapter_identity(&exact).expect("protocol-capable adapter identity");
|
|
244
|
-
|
|
245
|
-
let mut wrong_name = exact.clone();
|
|
246
|
-
wrong_name.package_name = "pi-mcp-adapter-fork".to_string();
|
|
247
|
-
assert!(validate_pi_adapter_identity(&wrong_name).is_err());
|
|
248
|
-
|
|
249
|
-
let mut missing_entry = exact.clone();
|
|
250
|
-
missing_entry.extension_entry.clear();
|
|
251
|
-
missing_entry.index_ts = PathBuf::new();
|
|
252
|
-
assert!(validate_pi_adapter_identity(&missing_entry).is_err());
|
|
253
|
-
|
|
254
|
-
let mut unloadable_entry = exact.clone();
|
|
255
|
-
unloadable_entry.index_ts = root.join("pi-mcp-adapter/missing.ts");
|
|
256
|
-
assert!(validate_pi_adapter_identity(&unloadable_entry).is_err());
|
|
257
|
-
|
|
258
|
-
let mut newer_observation = exact;
|
|
259
|
-
newer_observation.version = "9.7.3".to_string();
|
|
260
|
-
newer_observation.package_json_sha256 = "11".repeat(32);
|
|
261
|
-
newer_observation.index_ts_sha256 = "22".repeat(32);
|
|
262
|
-
validate_pi_adapter_identity(&newer_observation)
|
|
263
|
-
.expect("version and digests do not define adapter protocol capability");
|
|
264
|
-
std::fs::remove_dir_all(root).expect("remove adapter identity fixture");
|
|
265
|
-
}
|
|
266
|
-
|
|
267
193
|
#[test]
|
|
268
194
|
fn pi_wrapper_is_atomic_per_seat_and_embeds_exact_candidate() {
|
|
269
195
|
run_process_isolated(PI_WRAPPER_CHILD, PI_WRAPPER_TEST, || {
|
|
@@ -281,11 +207,9 @@ fn pi_wrapper_is_atomic_body(hermetic: &HermeticTestEnv) {
|
|
|
281
207
|
.expect("create candidate parent");
|
|
282
208
|
std::fs::write(&candidate, b"candidate").expect("write candidate fixture");
|
|
283
209
|
let destination = workspace.join(".team/runtime/pi/team-a/worker-a/team-mcp.ts");
|
|
284
|
-
let adapter = adapter_identity(&root);
|
|
285
210
|
|
|
286
211
|
let written = write_pi_wrapper(PiWrapperRequest {
|
|
287
212
|
destination: &destination,
|
|
288
|
-
adapter: &adapter,
|
|
289
213
|
candidate_executable: &candidate,
|
|
290
214
|
mcp_config: &mcp_config(&candidate, &workspace, "worker-a"),
|
|
291
215
|
team_id: "team-a",
|
|
@@ -308,8 +232,12 @@ fn pi_wrapper_is_atomic_body(hermetic: &HermeticTestEnv) {
|
|
|
308
232
|
assert!(source.contains(candidate.to_string_lossy().as_ref()));
|
|
309
233
|
assert!(source.contains("TEAM_AGENT_ID") && source.contains("worker-a"));
|
|
310
234
|
assert!(source.contains("TEAM_AGENT_OWNER_TEAM_ID") && source.contains("team-a"));
|
|
311
|
-
assert!(source.contains("pi
|
|
235
|
+
assert!(source.contains("pi.registerMcpServer(alias"));
|
|
236
|
+
assert!(source.contains("pi.unregisterMcpServer(alias"));
|
|
237
|
+
assert!(source.contains("toolExposure"));
|
|
312
238
|
assert!(source.contains("session_start") && source.contains("session_shutdown"));
|
|
239
|
+
assert!(!source.contains("pi-mcp-adapter"));
|
|
240
|
+
assert!(!source.contains("MCP_RUNTIME_REGISTER_EVENT"));
|
|
313
241
|
assert!(source.contains("includeTools"));
|
|
314
242
|
assert!(source.contains("send_message") && source.contains("report_result"));
|
|
315
243
|
assert!(!source.contains("createMcpAdapter"));
|
|
@@ -322,7 +250,6 @@ fn pi_wrapper_is_atomic_body(hermetic: &HermeticTestEnv) {
|
|
|
322
250
|
let other_destination = workspace.join(".team/runtime/pi/team-a/worker-b/team-mcp.ts");
|
|
323
251
|
write_pi_wrapper(PiWrapperRequest {
|
|
324
252
|
destination: &other_destination,
|
|
325
|
-
adapter: &adapter,
|
|
326
253
|
candidate_executable: &candidate,
|
|
327
254
|
mcp_config: &mcp_config(&candidate, &workspace, "worker-b"),
|
|
328
255
|
team_id: "team-a",
|
|
@@ -363,10 +290,8 @@ fn pi_leader_wrapper_materializes_from_empty_unicode_wsl_workspace() {
|
|
|
363
290
|
);
|
|
364
291
|
|
|
365
292
|
let paths = pi_seat_paths(&workspace, "current", "leader");
|
|
366
|
-
let adapter = adapter_identity(&root);
|
|
367
293
|
let written = write_pi_wrapper(PiWrapperRequest {
|
|
368
294
|
destination: &paths.wrapper,
|
|
369
|
-
adapter: &adapter,
|
|
370
295
|
candidate_executable: &candidate,
|
|
371
296
|
mcp_config: &mcp_config(&candidate, &workspace, "leader"),
|
|
372
297
|
team_id: "current",
|
|
@@ -383,7 +308,7 @@ fn pi_leader_wrapper_materializes_from_empty_unicode_wsl_workspace() {
|
|
|
383
308
|
"leader runtime root must be created recursively"
|
|
384
309
|
);
|
|
385
310
|
let source = std::fs::read_to_string(&written).expect("read complete leader wrapper");
|
|
386
|
-
validate_pi_wrapper_source(&source, &
|
|
311
|
+
validate_pi_wrapper_source(&source, &candidate)
|
|
387
312
|
.expect("published leader wrapper must be complete and valid");
|
|
388
313
|
assert!(source.contains("TEAM_AGENT_ID") && source.contains("leader"));
|
|
389
314
|
assert!(source.contains("TEAM_AGENT_OWNER_TEAM_ID") && source.contains("current"));
|
|
@@ -427,11 +352,9 @@ fn pi_wrapper_publish_needs_no_final_path_metadata_lookup() {
|
|
|
427
352
|
let paths = pi_seat_paths(&workspace, "current", "leader");
|
|
428
353
|
let published_parent = paths.runtime_root.clone();
|
|
429
354
|
let hidden_parent = published_parent.with_file_name("leader-after-rename");
|
|
430
|
-
let adapter = adapter_identity(&root);
|
|
431
355
|
write_pi_wrapper_with_publish(
|
|
432
356
|
PiWrapperRequest {
|
|
433
357
|
destination: &paths.wrapper,
|
|
434
|
-
adapter: &adapter,
|
|
435
358
|
candidate_executable: &candidate,
|
|
436
359
|
mcp_config: &mcp_config(&candidate, &workspace, "leader"),
|
|
437
360
|
team_id: "current",
|
|
@@ -490,10 +413,8 @@ fn pi_wrapper_import_failure_body(hermetic: &HermeticTestEnv) {
|
|
|
490
413
|
.expect("write malicious ambient config");
|
|
491
414
|
|
|
492
415
|
let destination = workspace.join(".team/runtime/pi/team-a/worker-a/team-mcp.ts");
|
|
493
|
-
let adapter = adapter_identity(&root);
|
|
494
416
|
write_pi_wrapper(PiWrapperRequest {
|
|
495
417
|
destination: &destination,
|
|
496
|
-
adapter: &adapter,
|
|
497
418
|
candidate_executable: &candidate,
|
|
498
419
|
mcp_config: &mcp_config(&candidate, &workspace, "worker-a"),
|
|
499
420
|
team_id: "team-a",
|
|
@@ -504,14 +425,16 @@ fn pi_wrapper_import_failure_body(hermetic: &HermeticTestEnv) {
|
|
|
504
425
|
.expect("runtime wrapper leaves ambient config to direct Pi");
|
|
505
426
|
let source = std::fs::read_to_string(&destination).expect("wrapper source");
|
|
506
427
|
assert!(!source.contains("ambient-evil"));
|
|
507
|
-
validate_pi_wrapper_source(&source, &
|
|
428
|
+
validate_pi_wrapper_source(&source, &candidate)
|
|
508
429
|
.expect("runtime registration and exact candidate");
|
|
430
|
+
assert!(source.contains("pi.registerMcpServer(alias"));
|
|
509
431
|
assert!(!source.contains("createMcpAdapter"));
|
|
432
|
+
assert!(!source.contains("pi-mcp-adapter"));
|
|
510
433
|
assert!(!source.contains("--mcp-config"));
|
|
511
434
|
|
|
512
|
-
let
|
|
513
|
-
validate_pi_wrapper_source(&
|
|
514
|
-
.expect_err("wrapper
|
|
435
|
+
let other_candidate = root.join("candidate/other-team-agent");
|
|
436
|
+
validate_pi_wrapper_source(&source, &other_candidate)
|
|
437
|
+
.expect_err("wrapper bound to a different candidate must refuse");
|
|
515
438
|
|
|
516
439
|
std::fs::remove_dir_all(root).expect("remove wrapper fixture");
|
|
517
440
|
}
|
|
@@ -528,29 +451,14 @@ fn pi_materializer_and_worker_routes_use_the_recorded_scope() {
|
|
|
528
451
|
fn pi_materializer_and_worker_routes_body(hermetic: &HermeticTestEnv) {
|
|
529
452
|
let fixture_root = hermetic.root().join("materializer-fixture");
|
|
530
453
|
let bin = fixture_root.join("bin");
|
|
531
|
-
let adapter_root = fixture_root.join("pi-mcp-adapter");
|
|
532
454
|
let candidate = fixture_root.join("candidate/team-agent");
|
|
533
455
|
let real = fixture_root.join("pi-real");
|
|
534
456
|
std::fs::create_dir_all(&bin).expect("create Pi fixture bin");
|
|
535
|
-
std::fs::create_dir_all(&adapter_root).expect("create Pi adapter fixture");
|
|
536
457
|
std::fs::create_dir_all(candidate.parent().expect("candidate parent"))
|
|
537
458
|
.expect("create candidate parent");
|
|
538
459
|
std::fs::write(&candidate, b"candidate").expect("write candidate fixture");
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
br#"{"name":"pi-mcp-adapter","version":"2.30.0","pi":{"extensions":["./index.ts"]}}"#,
|
|
542
|
-
)
|
|
543
|
-
.expect("write adapter package");
|
|
544
|
-
std::fs::write(
|
|
545
|
-
adapter_root.join("index.ts"),
|
|
546
|
-
b"export const createMcpAdapter = () => {};\n",
|
|
547
|
-
)
|
|
548
|
-
.expect("write adapter entry");
|
|
549
|
-
let pi_script = format!(
|
|
550
|
-
"#!/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 0 ;;\nesac\n",
|
|
551
|
-
adapter_root.display()
|
|
552
|
-
);
|
|
553
|
-
std::fs::write(&real, &pi_script).expect("write Pi real fixture");
|
|
460
|
+
let pi_script = "#!/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 0 ;;\nesac\n";
|
|
461
|
+
std::fs::write(&real, pi_script).expect("write Pi real fixture");
|
|
554
462
|
std::fs::set_permissions(&real, std::fs::Permissions::from_mode(0o755))
|
|
555
463
|
.expect("make Pi real fixture executable");
|
|
556
464
|
std::os::unix::fs::symlink(&real, bin.join("pi")).expect("create Pi PATH symlink");
|
|
@@ -47,25 +47,14 @@ impl PathEnvGuard {
|
|
|
47
47
|
fn with_fake_pi(root: &Path) -> Self {
|
|
48
48
|
let wrapper_bin = root.join("bin/wrapper");
|
|
49
49
|
let real_bin = root.join("bin/real");
|
|
50
|
-
let package_root = root.join("node_modules/pi-mcp-adapter");
|
|
51
50
|
fs::create_dir_all(&wrapper_bin).expect("create fake wrapper bin");
|
|
52
51
|
fs::create_dir_all(&real_bin).expect("create fake real bin");
|
|
53
|
-
fs::create_dir_all(&package_root).expect("create fake adapter package");
|
|
54
52
|
let wrapper = wrapper_bin.join("pi");
|
|
55
|
-
let wrapper_script =
|
|
56
|
-
"#!/bin/sh\ncase \"$1\" in\n--version) echo 0.87.1 ;;\n--list-models) printf 'provider model\\nteam-agent qwen3.8-27b\\n' ;;\nlist) printf 'npm:pi-mcp-adapter\\n{}\\n' ;;\nesac\nexit 0\n",
|
|
57
|
-
package_root.display()
|
|
58
|
-
);
|
|
53
|
+
let wrapper_script = "#!/bin/sh\ncase \"$1\" in\n--version) echo 0.87.1 ;;\n--list-models) printf 'provider model\\nteam-agent qwen3.8-27b\\n' ;;\nlist) exit 64 ;;\nesac\nexit 0\n";
|
|
59
54
|
fs::write(&wrapper, wrapper_script).expect("write offline Pi wrapper");
|
|
60
55
|
let real = real_bin.join("pi");
|
|
61
56
|
fs::write(&real, "#!/bin/sh\necho 0.87.1\nexit 0\n")
|
|
62
57
|
.expect("write offline Pi real-binary stand-in");
|
|
63
|
-
let package =
|
|
64
|
-
json!({"name":"pi-mcp-adapter","version":"0.1.0","pi":{"extensions":["./index.ts"]}});
|
|
65
|
-
fs::write(package_root.join("package.json"), package.to_string())
|
|
66
|
-
.expect("write offline adapter package metadata");
|
|
67
|
-
fs::write(package_root.join("index.ts"), "export {};\n")
|
|
68
|
-
.expect("write offline adapter extension entry");
|
|
69
58
|
for pi in [&wrapper, &real] {
|
|
70
59
|
let mut permissions = fs::metadata(pi).expect("fake Pi metadata").permissions();
|
|
71
60
|
permissions.set_mode(0o755);
|