@team-agent/installer 0.4.8 → 0.4.10
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 +52 -0
- package/crates/team-agent/src/cli/mod.rs +10 -0
- package/crates/team-agent/src/cli/status_port.rs +4 -1
- package/crates/team-agent/src/compiler.rs +78 -9
- package/crates/team-agent/src/coordinator/tick.rs +96 -0
- package/crates/team-agent/src/leader/start.rs +180 -6
- package/crates/team-agent/src/lifecycle/launch.rs +155 -3
- package/crates/team-agent/src/lifecycle/profile_launch.rs +20 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +10 -0
- package/crates/team-agent/src/lifecycle/restart/common.rs +17 -1
- package/crates/team-agent/src/messaging/mod.rs +2 -1
- package/crates/team-agent/src/messaging/types.rs +86 -0
- package/crates/team-agent/src/model/enums.rs +65 -0
- package/crates/team-agent/src/model/spec.rs +34 -2
- package/crates/team-agent/src/os_probe.rs +79 -0
- package/crates/team-agent/src/provider/adapter.rs +11 -3
- package/crates/team-agent/src/provider/adapters/claude.rs +8 -0
- package/crates/team-agent/src/provider/adapters/codex.rs +10 -0
- package/crates/team-agent/src/provider/types.rs +8 -0
- package/crates/team-agent/src/tmux_backend.rs +134 -1
- package/crates/team-agent/src/transport/test_support.rs +62 -3
- package/crates/team-agent/src/transport.rs +38 -0
- package/package.json +4 -4
|
@@ -410,7 +410,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
410
410
|
Provider::Claude | Provider::ClaudeCode => {
|
|
411
411
|
Ok(claude_launch_command(self, auth_mode, mcp_config, system_prompt, model, tools)?)
|
|
412
412
|
}
|
|
413
|
-
Provider::Codex => Ok(codex_base_command(None, auth_mode, mcp_config, system_prompt, model, tools, None)),
|
|
413
|
+
Provider::Codex => Ok(codex_base_command(None, auth_mode, mcp_config, system_prompt, model, tools, None, None)),
|
|
414
414
|
// §C1 worker argv 形态 + C-1/C-5/C-6 cr verdict:
|
|
415
415
|
// copilot --no-color --no-auto-update [<dangerous|granular>] [--model]
|
|
416
416
|
// --additional-mcp-config <inline json> --session-id <expected_uuid> -C <cwd>
|
|
@@ -469,6 +469,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
469
469
|
model,
|
|
470
470
|
ctx.tools,
|
|
471
471
|
managed,
|
|
472
|
+
ctx.effort,
|
|
472
473
|
)?;
|
|
473
474
|
argv.push("--session-id".to_string());
|
|
474
475
|
argv.push(expected.clone());
|
|
@@ -507,6 +508,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
507
508
|
ctx.model,
|
|
508
509
|
ctx.tools,
|
|
509
510
|
ctx.profile_launch.map(|profile| &profile.command_overrides),
|
|
511
|
+
ctx.effort,
|
|
510
512
|
))),
|
|
511
513
|
// §C1 + §C4 cr verdict — copilot plan 端预定 UUID + workspace `-C` 双保险:
|
|
512
514
|
// * `--session-id <uuid>`(claude 同法,捕获免目录扫描,sqlite 仅校验)
|
|
@@ -638,13 +640,14 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
638
640
|
model,
|
|
639
641
|
tools,
|
|
640
642
|
None,
|
|
643
|
+
None,
|
|
641
644
|
);
|
|
642
645
|
argv.push(session_id.as_str().to_string());
|
|
643
646
|
Ok(argv)
|
|
644
647
|
}
|
|
645
648
|
Provider::Claude | Provider::ClaudeCode => {
|
|
646
649
|
let mut argv =
|
|
647
|
-
claude_base_command(self, auth_mode, mcp_config, system_prompt, model, tools, false)?;
|
|
650
|
+
claude_base_command(self, auth_mode, mcp_config, system_prompt, model, tools, false, None)?;
|
|
648
651
|
argv.push("--resume".to_string());
|
|
649
652
|
argv.push(session_id.as_str().to_string());
|
|
650
653
|
Ok(argv)
|
|
@@ -686,6 +689,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
686
689
|
model,
|
|
687
690
|
ctx.tools,
|
|
688
691
|
managed,
|
|
692
|
+
ctx.effort,
|
|
689
693
|
)?;
|
|
690
694
|
argv.push("--resume".to_string());
|
|
691
695
|
argv.push(session_id.as_str().to_string());
|
|
@@ -725,6 +729,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
725
729
|
ctx.model,
|
|
726
730
|
ctx.tools,
|
|
727
731
|
ctx.profile_launch.map(|profile| &profile.command_overrides),
|
|
732
|
+
ctx.effort,
|
|
728
733
|
);
|
|
729
734
|
argv.push(session_id.as_str().to_string());
|
|
730
735
|
Ok(CommandPlan::argv_only(argv))
|
|
@@ -779,13 +784,14 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
779
784
|
model,
|
|
780
785
|
tools,
|
|
781
786
|
None,
|
|
787
|
+
None,
|
|
782
788
|
);
|
|
783
789
|
argv.push(session_id.as_str().to_string());
|
|
784
790
|
Ok(argv)
|
|
785
791
|
}
|
|
786
792
|
Provider::Claude | Provider::ClaudeCode => {
|
|
787
793
|
let mut argv =
|
|
788
|
-
claude_base_command(self, auth_mode, mcp_config, system_prompt, model, tools, false)?;
|
|
794
|
+
claude_base_command(self, auth_mode, mcp_config, system_prompt, model, tools, false, None)?;
|
|
789
795
|
argv.push("--session-id".to_string());
|
|
790
796
|
argv.push(next_session_token());
|
|
791
797
|
argv.push("--resume".to_string());
|
|
@@ -837,6 +843,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
837
843
|
model,
|
|
838
844
|
ctx.tools,
|
|
839
845
|
managed,
|
|
846
|
+
ctx.effort,
|
|
840
847
|
)?;
|
|
841
848
|
argv.push("--session-id".to_string());
|
|
842
849
|
argv.push(expected.clone());
|
|
@@ -870,6 +877,7 @@ impl ProviderAdapter for BasicProviderAdapter {
|
|
|
870
877
|
ctx.model,
|
|
871
878
|
ctx.tools,
|
|
872
879
|
ctx.profile_launch.map(|profile| &profile.command_overrides),
|
|
880
|
+
ctx.effort,
|
|
873
881
|
);
|
|
874
882
|
argv.push(session_id.as_str().to_string());
|
|
875
883
|
Ok(CommandPlan::argv_only(argv))
|
|
@@ -34,6 +34,7 @@ pub(crate) fn claude_launch_command(
|
|
|
34
34
|
model,
|
|
35
35
|
tools,
|
|
36
36
|
false,
|
|
37
|
+
None,
|
|
37
38
|
)?;
|
|
38
39
|
argv.push("--session-id".to_string());
|
|
39
40
|
argv.push(next_session_token());
|
|
@@ -48,6 +49,9 @@ pub(crate) fn claude_base_command(
|
|
|
48
49
|
model: Option<&str>,
|
|
49
50
|
tools: &[&str],
|
|
50
51
|
managed_mcp_config: bool,
|
|
52
|
+
// 0.4.x provider effort MVP step 5: when Some, inject `--effort <level>`
|
|
53
|
+
// immediately after the model (before prompt/MCP).
|
|
54
|
+
effort: Option<crate::model::enums::ProviderEffort>,
|
|
51
55
|
) -> Result<Vec<String>, ProviderError> {
|
|
52
56
|
let mut argv = vec!["claude".to_string()];
|
|
53
57
|
if claude_dangerous_auto_approve(tools) {
|
|
@@ -60,6 +64,10 @@ pub(crate) fn claude_base_command(
|
|
|
60
64
|
argv.push("--model".to_string());
|
|
61
65
|
argv.push(model.to_string());
|
|
62
66
|
}
|
|
67
|
+
if let Some(effort) = effort {
|
|
68
|
+
argv.push("--effort".to_string());
|
|
69
|
+
argv.push(effort.as_str().to_string());
|
|
70
|
+
}
|
|
63
71
|
if let Some(prompt) = system_prompt {
|
|
64
72
|
argv.push("--append-system-prompt".to_string());
|
|
65
73
|
argv.push(prompt.to_string());
|
|
@@ -17,6 +17,12 @@ pub(crate) fn codex_base_command(
|
|
|
17
17
|
model: Option<&str>,
|
|
18
18
|
tools: &[&str],
|
|
19
19
|
overrides: Option<&ProviderCommandOverrides>,
|
|
20
|
+
// 0.4.x provider effort MVP step 6: when Some, inject
|
|
21
|
+
// `-c model_reasoning_effort=<level>` AFTER existing profile
|
|
22
|
+
// codex_config overrides — explicit launch effort wins over profile.
|
|
23
|
+
// Codex does not support `max`; the caller filters that case via
|
|
24
|
+
// `ProviderEffort::is_supported_by` before reaching this point.
|
|
25
|
+
effort: Option<crate::model::enums::ProviderEffort>,
|
|
20
26
|
) -> Vec<String> {
|
|
21
27
|
let mut argv = vec!["codex".to_string()];
|
|
22
28
|
if let Some(subcommand) = subcommand {
|
|
@@ -51,6 +57,10 @@ pub(crate) fn codex_base_command(
|
|
|
51
57
|
argv.push(config.clone());
|
|
52
58
|
}
|
|
53
59
|
}
|
|
60
|
+
if let Some(effort) = effort {
|
|
61
|
+
argv.push("-c".to_string());
|
|
62
|
+
argv.push(format!("model_reasoning_effort={}", effort.as_str()));
|
|
63
|
+
}
|
|
54
64
|
if let Some(prompt) = system_prompt {
|
|
55
65
|
// codex.py:120 — escape order matters: backslash first, then quote, then newline.
|
|
56
66
|
let escaped = prompt
|
|
@@ -347,6 +347,14 @@ pub struct ProviderCommandContext<'a> {
|
|
|
347
347
|
/// no `--name` CLI flag (probe verdict 2026-06-22) and ignores this
|
|
348
348
|
/// field. None = legacy callers (the field is purely additive).
|
|
349
349
|
pub agent_id_hint: Option<&'a str>,
|
|
350
|
+
/// 0.4.x provider effort MVP step 4: reasoning effort level resolved
|
|
351
|
+
/// from role doc / TEAM.md / provider default. `None` means the
|
|
352
|
+
/// framework passes no effort flag (provider default).
|
|
353
|
+
/// - Claude / ClaudeCode: low|medium|high|xhigh|max → `--effort <level>`
|
|
354
|
+
/// - Codex: low|medium|high|xhigh → `-c model_reasoning_effort=<level>`
|
|
355
|
+
/// - Copilot / Gemini / Fake: ignored, warning event emitted at the
|
|
356
|
+
/// caller (lifecycle/launch.rs / lifecycle/restart) before construct.
|
|
357
|
+
pub effort: Option<crate::model::enums::ProviderEffort>,
|
|
350
358
|
}
|
|
351
359
|
|
|
352
360
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
@@ -636,7 +636,21 @@ impl TmuxBackend {
|
|
|
636
636
|
first: bool,
|
|
637
637
|
) -> Result<SpawnResult, TransportError> {
|
|
638
638
|
let command = shell_command(argv, cwd, env, env_unset);
|
|
639
|
-
|
|
639
|
+
self.spawn_with_command(session, window, &command, first)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/// 0.4.x (CR C-2): spawn variant that takes a pre-built shell command
|
|
643
|
+
/// (used by `spawn_first_with_leader_shell_wrapper` /
|
|
644
|
+
/// `spawn_into_with_leader_shell_wrapper` to inject the leader wrapper
|
|
645
|
+
/// shape without going through `shell_command`'s `exec`-only template).
|
|
646
|
+
fn spawn_with_command(
|
|
647
|
+
&self,
|
|
648
|
+
session: &SessionName,
|
|
649
|
+
window: &WindowName,
|
|
650
|
+
command: &str,
|
|
651
|
+
first: bool,
|
|
652
|
+
) -> Result<SpawnResult, TransportError> {
|
|
653
|
+
let spawn_argv = tmux_spawn_argv(session, window, command, first);
|
|
640
654
|
self.run_spawn(&spawn_argv)?;
|
|
641
655
|
let pane_argv = vec![
|
|
642
656
|
"tmux".to_string(),
|
|
@@ -1307,6 +1321,8 @@ fn shell_command(
|
|
|
1307
1321
|
env: &BTreeMap<String, String>,
|
|
1308
1322
|
env_unset: &[String],
|
|
1309
1323
|
) -> String {
|
|
1324
|
+
let unset_set: std::collections::BTreeSet<&str> =
|
|
1325
|
+
env_unset.iter().map(String::as_str).collect();
|
|
1310
1326
|
let mut parts = Vec::new();
|
|
1311
1327
|
parts.push("cd".to_string());
|
|
1312
1328
|
parts.push(shell_quote(&cwd.to_string_lossy()));
|
|
@@ -1319,7 +1335,16 @@ fn shell_command(
|
|
|
1319
1335
|
parts.push(key.clone());
|
|
1320
1336
|
parts.push("&&".to_string());
|
|
1321
1337
|
}
|
|
1338
|
+
// 0.4.x ordering fix (env-leak symptom #3): KEY=val exports must NOT
|
|
1339
|
+
// re-introduce any key that was just unset. Filter env entries whose key
|
|
1340
|
+
// appears in env_unset so the unset wins on the final shell line. This
|
|
1341
|
+
// matters when inherited env (worker_spawn_env / apply_profile_launch_env)
|
|
1342
|
+
// contains the very keys we want to scrub (e.g. CLAUDE_EFFORT carried
|
|
1343
|
+
// forward from the launching shell into the env map).
|
|
1322
1344
|
for (key, value) in env {
|
|
1345
|
+
if unset_set.contains(key.as_str()) {
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1323
1348
|
parts.push(format!("{key}={}", shell_quote(value)));
|
|
1324
1349
|
}
|
|
1325
1350
|
parts.push("exec".to_string());
|
|
@@ -1327,6 +1352,82 @@ fn shell_command(
|
|
|
1327
1352
|
parts.join(" ")
|
|
1328
1353
|
}
|
|
1329
1354
|
|
|
1355
|
+
/// 0.4.x (CR R6): single-source marker prefix. The exit marker emitted by
|
|
1356
|
+
/// `leader_shell_wrapper_command` and the substring detected by
|
|
1357
|
+
/// `leader_provider_health` MUST share this prefix exactly. Format:
|
|
1358
|
+
/// `"[team-agent] {provider_label} exited with {rc}"`.
|
|
1359
|
+
pub const LEADER_PROVIDER_EXIT_MARKER_PREFIX: &str = "[team-agent]";
|
|
1360
|
+
pub const LEADER_PROVIDER_EXIT_MARKER_SUFFIX: &str = "exited with";
|
|
1361
|
+
|
|
1362
|
+
/// 0.4.x (CR R6): build the leader exit marker text for `provider_label`.
|
|
1363
|
+
/// Used by both the shell wrapper (printf source) and the health check
|
|
1364
|
+
/// (capture substring) so they cannot drift.
|
|
1365
|
+
pub fn leader_provider_exit_marker(provider_label: &str) -> String {
|
|
1366
|
+
format!(
|
|
1367
|
+
"{LEADER_PROVIDER_EXIT_MARKER_PREFIX} {provider_label} {LEADER_PROVIDER_EXIT_MARKER_SUFFIX}"
|
|
1368
|
+
)
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/// 0.4.x (CR C-2): leader shell wrapper — provider runs as a CHILD of a
|
|
1372
|
+
/// long-lived shell, not as the pane's primary process. When the provider
|
|
1373
|
+
/// exits, the pane returns to an interactive shell with an explicit exit
|
|
1374
|
+
/// marker, matching manual `tmux new-session` then `claude` behaviour.
|
|
1375
|
+
///
|
|
1376
|
+
/// Four required envelope sections (CR C-2):
|
|
1377
|
+
/// 1. cd <cwd> — same as `shell_command`
|
|
1378
|
+
/// 2. unset <KEY> ... — provider env_unset block
|
|
1379
|
+
/// 3. KEY=val ... <provider> — env exports + provider invocation
|
|
1380
|
+
/// (NO `exec` — runs as child)
|
|
1381
|
+
/// 4. printf exit marker; exec shell -l
|
|
1382
|
+
///
|
|
1383
|
+
/// `provider_label` is a human-readable provider name (e.g. "claude",
|
|
1384
|
+
/// "codex") embedded in the exit marker for diagnostics.
|
|
1385
|
+
pub fn leader_shell_wrapper_command(
|
|
1386
|
+
argv: &[String],
|
|
1387
|
+
cwd: &Path,
|
|
1388
|
+
env: &BTreeMap<String, String>,
|
|
1389
|
+
env_unset: &[String],
|
|
1390
|
+
provider_label: &str,
|
|
1391
|
+
) -> String {
|
|
1392
|
+
let unset_set: std::collections::BTreeSet<&str> =
|
|
1393
|
+
env_unset.iter().map(String::as_str).collect();
|
|
1394
|
+
let mut parts = Vec::new();
|
|
1395
|
+
// 1. cd
|
|
1396
|
+
parts.push("cd".to_string());
|
|
1397
|
+
parts.push(shell_quote(&cwd.to_string_lossy()));
|
|
1398
|
+
parts.push("&&".to_string());
|
|
1399
|
+
// 2. unset
|
|
1400
|
+
for key in env_unset {
|
|
1401
|
+
parts.push("unset".to_string());
|
|
1402
|
+
parts.push(key.clone());
|
|
1403
|
+
parts.push("&&".to_string());
|
|
1404
|
+
}
|
|
1405
|
+
// 3. env exports + provider (NO `exec` so the provider is a child).
|
|
1406
|
+
// 0.4.x ordering fix: skip keys present in env_unset so KEY=val does not
|
|
1407
|
+
// re-introduce a just-unset variable from the inherited env map.
|
|
1408
|
+
for (key, value) in env {
|
|
1409
|
+
if unset_set.contains(key.as_str()) {
|
|
1410
|
+
continue;
|
|
1411
|
+
}
|
|
1412
|
+
parts.push(format!("{key}={}", shell_quote(value)));
|
|
1413
|
+
}
|
|
1414
|
+
parts.extend(argv.iter().map(|arg| shell_quote(arg)));
|
|
1415
|
+
parts.push(";".to_string());
|
|
1416
|
+
// 4. exit marker + fall back to interactive shell
|
|
1417
|
+
parts.push("rc=$?;".to_string());
|
|
1418
|
+
parts.push("printf".to_string());
|
|
1419
|
+
// CR R6: marker text comes from single-source `leader_provider_exit_marker`.
|
|
1420
|
+
parts.push(shell_quote(&format!(
|
|
1421
|
+
"\n{} %s\n",
|
|
1422
|
+
leader_provider_exit_marker(provider_label)
|
|
1423
|
+
)));
|
|
1424
|
+
parts.push("\"$rc\";".to_string());
|
|
1425
|
+
parts.push("exec".to_string());
|
|
1426
|
+
parts.push("\"${SHELL:-/bin/zsh}\"".to_string());
|
|
1427
|
+
parts.push("-l".to_string());
|
|
1428
|
+
parts.join(" ")
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1330
1431
|
fn shell_quote(raw: &str) -> String {
|
|
1331
1432
|
if raw.is_empty() {
|
|
1332
1433
|
return "''".to_string();
|
|
@@ -1422,6 +1523,38 @@ impl Transport for TmuxBackend {
|
|
|
1422
1523
|
self.spawn_split(session, window, argv, cwd, env, env_unset)
|
|
1423
1524
|
}
|
|
1424
1525
|
|
|
1526
|
+
/// 0.4.x (CR C-2): TmuxBackend override of the leader-shell-wrapper
|
|
1527
|
+
/// variant. Builds the wrapper shell line via
|
|
1528
|
+
/// `leader_shell_wrapper_command` and runs it through
|
|
1529
|
+
/// `spawn_with_command` (bypassing the default `exec <cmd>` shape).
|
|
1530
|
+
fn spawn_first_with_leader_shell_wrapper(
|
|
1531
|
+
&self,
|
|
1532
|
+
session: &SessionName,
|
|
1533
|
+
window: &WindowName,
|
|
1534
|
+
argv: &[String],
|
|
1535
|
+
cwd: &Path,
|
|
1536
|
+
env: &BTreeMap<String, String>,
|
|
1537
|
+
env_unset: &[String],
|
|
1538
|
+
provider_label: &str,
|
|
1539
|
+
) -> Result<SpawnResult, TransportError> {
|
|
1540
|
+
let command = leader_shell_wrapper_command(argv, cwd, env, env_unset, provider_label);
|
|
1541
|
+
self.spawn_with_command(session, window, &command, true)
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
fn spawn_into_with_leader_shell_wrapper(
|
|
1545
|
+
&self,
|
|
1546
|
+
session: &SessionName,
|
|
1547
|
+
window: &WindowName,
|
|
1548
|
+
argv: &[String],
|
|
1549
|
+
cwd: &Path,
|
|
1550
|
+
env: &BTreeMap<String, String>,
|
|
1551
|
+
env_unset: &[String],
|
|
1552
|
+
provider_label: &str,
|
|
1553
|
+
) -> Result<SpawnResult, TransportError> {
|
|
1554
|
+
let command = leader_shell_wrapper_command(argv, cwd, env, env_unset, provider_label);
|
|
1555
|
+
self.spawn_with_command(session, window, &command, false)
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1425
1558
|
fn inject(
|
|
1426
1559
|
&self,
|
|
1427
1560
|
target: &Target,
|
|
@@ -50,6 +50,9 @@ struct OfflineState {
|
|
|
50
50
|
/// U1-C Tail-peek contract: every `capture()` call records its `CaptureRange`,
|
|
51
51
|
/// in order, so a test can prove the delivery peek site narrowed Full → Tail(80).
|
|
52
52
|
capture_ranges: Vec<CaptureRange>,
|
|
53
|
+
/// 0.4.x (CR C-3 / CR C-5): pre-staged `query(PaneField::PaneCurrentCommand)`
|
|
54
|
+
/// answer keyed by pane id. Used by leader provider health tests.
|
|
55
|
+
pane_current_commands: BTreeMap<String, String>,
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
impl Default for OfflineState {
|
|
@@ -73,6 +76,7 @@ impl Default for OfflineState {
|
|
|
73
76
|
list_targets_error: None,
|
|
74
77
|
capture_text: BTreeMap::new(),
|
|
75
78
|
capture_ranges: Vec::new(),
|
|
79
|
+
pane_current_commands: BTreeMap::new(),
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
82
|
}
|
|
@@ -163,6 +167,52 @@ impl OfflineTransport {
|
|
|
163
167
|
self
|
|
164
168
|
}
|
|
165
169
|
|
|
170
|
+
/// 0.4.x (CR C-3 / CR C-5): pre-stage a `pane_current_command` answer
|
|
171
|
+
/// for `query(PaneField::PaneCurrentCommand)`. Used by leader provider
|
|
172
|
+
/// health tests to simulate "pane is now in a shell" vs
|
|
173
|
+
/// "pane is running the provider".
|
|
174
|
+
pub fn with_pane_current_command(
|
|
175
|
+
self,
|
|
176
|
+
pane_id: impl Into<String>,
|
|
177
|
+
command: impl Into<String>,
|
|
178
|
+
) -> Self {
|
|
179
|
+
self.with_state(|state| {
|
|
180
|
+
state.pane_current_commands.insert(pane_id.into(), command.into());
|
|
181
|
+
});
|
|
182
|
+
self
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/// 0.4.x (CR C-3 / CR C-5): mutable setters for fluent test seeding
|
|
186
|
+
/// (alternative to builder chain when the transport already exists).
|
|
187
|
+
pub fn set_pane_addressable(&self, pane: &PaneId, addressable: bool) {
|
|
188
|
+
self.with_state(|state| {
|
|
189
|
+
state.liveness.insert(
|
|
190
|
+
pane.as_str().to_string(),
|
|
191
|
+
if addressable {
|
|
192
|
+
PaneLiveness::Live
|
|
193
|
+
} else {
|
|
194
|
+
PaneLiveness::Dead
|
|
195
|
+
},
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
pub fn set_pane_current_command(&self, pane: &PaneId, command: &str) {
|
|
201
|
+
self.with_state(|state| {
|
|
202
|
+
state
|
|
203
|
+
.pane_current_commands
|
|
204
|
+
.insert(pane.as_str().to_string(), command.to_string());
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
pub fn set_pane_capture(&self, pane: &PaneId, text: &str) {
|
|
209
|
+
self.with_state(|state| {
|
|
210
|
+
state
|
|
211
|
+
.capture_text
|
|
212
|
+
.insert(pane.as_str().to_string(), text.to_string());
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
166
216
|
/// Pre-stage `capture()` output for a `Target::SessionWindow{session,window}` key.
|
|
167
217
|
pub fn with_capture_for_session_window(
|
|
168
218
|
self,
|
|
@@ -378,11 +428,20 @@ impl Transport for OfflineTransport {
|
|
|
378
428
|
|
|
379
429
|
fn query(
|
|
380
430
|
&self,
|
|
381
|
-
|
|
382
|
-
|
|
431
|
+
target: &Target,
|
|
432
|
+
field: PaneField,
|
|
383
433
|
) -> Result<Option<String>, TransportError> {
|
|
384
434
|
self.record("query");
|
|
385
|
-
|
|
435
|
+
if !matches!(field, PaneField::PaneCurrentCommand) {
|
|
436
|
+
return Ok(None);
|
|
437
|
+
}
|
|
438
|
+
let pane_id = match target {
|
|
439
|
+
Target::Pane(p) => p.as_str().to_string(),
|
|
440
|
+
Target::SessionWindow { .. } => return Ok(None),
|
|
441
|
+
};
|
|
442
|
+
Ok(self.with_state(|state| {
|
|
443
|
+
state.pane_current_commands.get(&pane_id).cloned()
|
|
444
|
+
}))
|
|
386
445
|
}
|
|
387
446
|
|
|
388
447
|
fn liveness(&self, pane: &PaneId) -> Result<PaneLiveness, TransportError> {
|
|
@@ -584,6 +584,44 @@ pub trait Transport: Send + Sync {
|
|
|
584
584
|
self.spawn_into(session, window, argv, cwd, env)
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
+
/// 0.4.x (CR C-2): leader-specific spawn variant. Instead of `exec <cmd>`
|
|
588
|
+
/// (which makes the provider the pane's primary process and turns the
|
|
589
|
+
/// pane into `[exited]` when the provider exits), build a shell line
|
|
590
|
+
/// that runs the provider as a CHILD of a long-lived shell:
|
|
591
|
+
/// `cd ... && unset ... && KEY=val ... <cmd>; rc=$?; printf '\n[team-agent] <provider> exited with %s\n' "$rc"; exec "${SHELL:-/bin/zsh}" -l`.
|
|
592
|
+
/// When the provider exits, the pane returns to an interactive shell with
|
|
593
|
+
/// an explicit exit marker — matching manual `tmux new-session` then
|
|
594
|
+
/// `claude` behaviour. Default falls back to plain `spawn_first_with_env_unset`
|
|
595
|
+
/// for backends that have no shell layer (test-only `OfflineTransport`).
|
|
596
|
+
fn spawn_first_with_leader_shell_wrapper(
|
|
597
|
+
&self,
|
|
598
|
+
session: &SessionName,
|
|
599
|
+
window: &WindowName,
|
|
600
|
+
argv: &[String],
|
|
601
|
+
cwd: &Path,
|
|
602
|
+
env: &BTreeMap<String, String>,
|
|
603
|
+
env_unset: &[String],
|
|
604
|
+
provider_label: &str,
|
|
605
|
+
) -> Result<SpawnResult, TransportError> {
|
|
606
|
+
let _ = provider_label;
|
|
607
|
+
self.spawn_first_with_env_unset(session, window, argv, cwd, env, env_unset)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/// 同 [`Transport::spawn_first_with_leader_shell_wrapper`],对应 `spawn_into`。
|
|
611
|
+
fn spawn_into_with_leader_shell_wrapper(
|
|
612
|
+
&self,
|
|
613
|
+
session: &SessionName,
|
|
614
|
+
window: &WindowName,
|
|
615
|
+
argv: &[String],
|
|
616
|
+
cwd: &Path,
|
|
617
|
+
env: &BTreeMap<String, String>,
|
|
618
|
+
env_unset: &[String],
|
|
619
|
+
provider_label: &str,
|
|
620
|
+
) -> Result<SpawnResult, TransportError> {
|
|
621
|
+
let _ = provider_label;
|
|
622
|
+
self.spawn_into_with_env_unset(session, window, argv, cwd, env, env_unset)
|
|
623
|
+
}
|
|
624
|
+
|
|
587
625
|
// —— INJECT / CAPTURE / QUERY(RIE):按稳定 Target 寻址 ——
|
|
588
626
|
|
|
589
627
|
/// 归并 set/load-buffer + paste-buffer + send submit;空文本走纯 send-keys
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-agent/installer",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "npx installer for Team Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"team-agent-installer": "npm/install.mjs"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@team-agent/cli-darwin-arm64": "0.4.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.4.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.4.
|
|
23
|
+
"@team-agent/cli-darwin-arm64": "0.4.10",
|
|
24
|
+
"@team-agent/cli-darwin-x64": "0.4.10",
|
|
25
|
+
"@team-agent/cli-linux-x64": "0.4.10"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postinstall": "node npm/bincheck.mjs",
|