@team-agent/installer 0.5.77 → 0.5.80
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/adapters.rs +161 -29
- package/crates/team-agent/src/cli/diagnose.rs +333 -68
- package/crates/team-agent/src/cli/emit.rs +24 -8
- package/crates/team-agent/src/cli/mod.rs +543 -98
- package/crates/team-agent/src/cli/models.rs +393 -32
- package/crates/team-agent/src/cli/named_address.rs +19 -5
- package/crates/team-agent/src/cli/profile.rs +35 -4
- package/crates/team-agent/src/cli/spec.rs +7 -2
- package/crates/team-agent/src/cli/status_port/compact.rs +12 -8
- package/crates/team-agent/src/cli/status_port/runtime.rs +3 -1
- package/crates/team-agent/src/cli/status_port/snapshot.rs +15 -12
- package/crates/team-agent/src/cli/status_port/store.rs +1 -1
- package/crates/team-agent/src/cli/status_port/tests.rs +37 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +62 -8
- package/crates/team-agent/src/cli/tests/named_address.rs +70 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +81 -6
- package/crates/team-agent/src/cli/types.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +122 -2
- package/crates/team-agent/src/leader/lease.rs +492 -33
- package/crates/team-agent/src/leader/owner_bind.rs +40 -12
- package/crates/team-agent/src/leader/rediscover/tests.rs +65 -0
- package/crates/team-agent/src/leader/rediscover.rs +36 -6
- package/crates/team-agent/src/leader/start.rs +197 -88
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +15 -9
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +28 -227
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -18
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +94 -227
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +59 -10
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +86 -23
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +1449 -282
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +349 -4
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +11 -11
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +35 -3
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +16 -0
- package/crates/team-agent/src/lifecycle/launch.rs +30 -7
- package/crates/team-agent/src/lifecycle/profile_launch.rs +37 -3
- package/crates/team-agent/src/lifecycle/restart/agent.rs +112 -100
- package/crates/team-agent/src/lifecycle/restart/common.rs +82 -52
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +996 -66
- package/crates/team-agent/src/lifecycle/restart.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +15 -0
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +5 -0
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +11 -13
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +119 -4
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +12 -0
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +22 -0
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +12 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +265 -198
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +14 -30
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/fixtures/pi_list_models_spaced_ids.stdout.txt +9 -0
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +2 -5
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +10 -0
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +58 -35
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +10 -0
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +9 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -168
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +145 -212
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +16 -2
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +54 -9
- package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +71 -0
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +78 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +51 -10
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +50 -7
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +137 -0
- package/crates/team-agent/src/lifecycle/types.rs +8 -0
- package/crates/team-agent/src/mcp_server/wire.rs +140 -11
- package/crates/team-agent/src/messaging/delivery.rs +221 -80
- package/crates/team-agent/src/messaging/leader_channel.rs +56 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +127 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +10 -2
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +2 -5
- package/crates/team-agent/src/provider/session_scan/common/tests.rs +204 -0
- package/crates/team-agent/src/provider/session_scan/common.rs +24 -2
- package/crates/team-agent/src/state/abnormal_watch/tests/mod.rs +248 -0
- package/crates/team-agent/src/state/abnormal_watch.rs +144 -0
- package/crates/team-agent/src/state/mod.rs +1 -0
- package/crates/team-agent/src/state/persist.rs +102 -4
- package/crates/team-agent/src/state/projection.rs +7 -1
- package/crates/team-agent/src/state/repository.rs +29 -0
- package/crates/team-agent/src/test_support/models_timeout_fixture.rs +43 -21
- package/crates/team-agent/src/tmux_backend/tests.rs +149 -4
- package/crates/team-agent/src/tmux_backend.rs +239 -127
- package/crates/team-agent/src/transport.rs +78 -0
- package/crates/team-agent/src/transport_factory.rs +53 -0
- package/package.json +4 -5
- package/skills/team-agent/SKILL.md +45 -17
- package/skills/team-agent/command-coverage.json +4 -29
- package/npm/check-skill-links.mjs +0 -88
- package/skills/team-agent/references/team-agent-operator.md +0 -672
|
@@ -28,10 +28,10 @@ use crate::layout::worker_env::{
|
|
|
28
28
|
use crate::model::enums::{PaneLiveness, Provider};
|
|
29
29
|
use crate::transport::{
|
|
30
30
|
command_basename, normalize_capture, tmux_capture_argv, tmux_query_argv, tmux_send_keys_argv,
|
|
31
|
-
tmux_spawn_argv, tmux_submit_key_name, AttachOutcome,
|
|
32
|
-
InjectPayload, InjectStage, InjectVerification, InputSurfaceProbe, Key,
|
|
33
|
-
|
|
34
|
-
TransportError, TurnVerification, WindowName,
|
|
31
|
+
tmux_spawn_argv, tmux_submit_key_name, AttachOutcome, BusySignalKind, CaptureRange,
|
|
32
|
+
CaptureSampleOutcome, InjectPayload, InjectStage, InjectVerification, InputSurfaceProbe, Key,
|
|
33
|
+
PaneField, PaneId, QueryOutcome, SessionName, SetEnvOutcome, SubmitConsumptionReason,
|
|
34
|
+
SubmitVerification, Target, Transport, TransportError, TurnVerification, WindowName,
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
type RecordedArgv = Arc<Mutex<Vec<Vec<String>>>>;
|
|
@@ -355,6 +355,34 @@ fn backend_with(default: MockResp, queued: Vec<MockResp>) -> (TmuxBackend, Recor
|
|
|
355
355
|
(TmuxBackend::with_runner(Box::new(runner)), recorded)
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
+
#[test]
|
|
359
|
+
fn provider_exit_receipt_accepts_only_shell_exit_status() {
|
|
360
|
+
for (text, expected) in [
|
|
361
|
+
("", None),
|
|
362
|
+
("running", None),
|
|
363
|
+
("[team-agent] pi exited with 0", None),
|
|
364
|
+
("256", None),
|
|
365
|
+
("0\n", Some(0)),
|
|
366
|
+
("17\n", Some(17)),
|
|
367
|
+
("143\n", Some(143)),
|
|
368
|
+
] {
|
|
369
|
+
let (backend, recorded) = backend_with(MockResp::Out(ok(text)), Vec::new());
|
|
370
|
+
assert_eq!(
|
|
371
|
+
backend.provider_exit_status(&PaneId::new("%47")).unwrap(),
|
|
372
|
+
expected
|
|
373
|
+
);
|
|
374
|
+
let calls = recorded.lock().unwrap();
|
|
375
|
+
assert_eq!(calls.len(), 1);
|
|
376
|
+
assert_eq!(calls[0][4], "%47");
|
|
377
|
+
assert_eq!(calls[0][5], "#{@team-agent-provider-exit-status}");
|
|
378
|
+
}
|
|
379
|
+
let (backend, _) = backend_with(MockResp::Out(fail(1, "pane unavailable")), Vec::new());
|
|
380
|
+
assert_eq!(
|
|
381
|
+
backend.provider_exit_status(&PaneId::new("%47")).unwrap(),
|
|
382
|
+
None
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
358
386
|
fn backend_with_stdin(
|
|
359
387
|
default: MockResp,
|
|
360
388
|
queued: Vec<MockResp>,
|
|
@@ -1051,6 +1079,15 @@ fn inject_text_runs_buffer_paste_submit_sequence_and_reports_submit() {
|
|
|
1051
1079
|
SubmitVerification::EnterSentWithoutPlaceholderCheck
|
|
1052
1080
|
);
|
|
1053
1081
|
assert_eq!(report.turn_verification, TurnVerification::NotYetObserved);
|
|
1082
|
+
let diagnostics = report.submit_diagnostics.expect("diagnostics");
|
|
1083
|
+
assert_eq!(
|
|
1084
|
+
diagnostics.consumption_reason,
|
|
1085
|
+
SubmitConsumptionReason::NoMarker
|
|
1086
|
+
);
|
|
1087
|
+
assert_eq!(diagnostics.busy_signal_kind, None);
|
|
1088
|
+
assert_eq!(diagnostics.current_marker_in_bottom_15, None);
|
|
1089
|
+
assert_eq!(diagnostics.paste_identity_in_composer, None);
|
|
1090
|
+
assert_eq!(diagnostics.consumption_from_capture_result, None);
|
|
1054
1091
|
}
|
|
1055
1092
|
|
|
1056
1093
|
#[test]
|
|
@@ -1409,10 +1446,18 @@ fn e46_post_submit_matched_token_without_scroll_is_unverified() {
|
|
|
1409
1446
|
"token still in composer and no busy must report 没开跑, not unknown/started"
|
|
1410
1447
|
);
|
|
1411
1448
|
let diagnostics = report.submit_diagnostics.expect("diagnostics");
|
|
1449
|
+
assert_eq!(diagnostics.busy_signal_kind, None);
|
|
1450
|
+
assert_eq!(diagnostics.current_marker_in_bottom_15, Some(true));
|
|
1451
|
+
assert_eq!(diagnostics.paste_identity_in_composer, None);
|
|
1452
|
+
assert_eq!(diagnostics.consumption_from_capture_result, Some(false));
|
|
1412
1453
|
assert!(
|
|
1413
1454
|
diagnostics.attempts_detail.iter().any(|obs| obs.matched),
|
|
1414
1455
|
"the unverified verdict must still record that paste landed"
|
|
1415
1456
|
);
|
|
1457
|
+
assert_eq!(
|
|
1458
|
+
diagnostics.consumption_reason,
|
|
1459
|
+
SubmitConsumptionReason::Unverified
|
|
1460
|
+
);
|
|
1416
1461
|
}
|
|
1417
1462
|
|
|
1418
1463
|
#[test]
|
|
@@ -1452,6 +1497,56 @@ fn e46_unconsumed_token_with_live_busy_state_is_treated_as_processing() {
|
|
|
1452
1497
|
"busy-state capture should be recorded in attempts_detail: {:?}",
|
|
1453
1498
|
diagnostics.attempts_detail
|
|
1454
1499
|
);
|
|
1500
|
+
assert_eq!(
|
|
1501
|
+
diagnostics.consumption_reason,
|
|
1502
|
+
SubmitConsumptionReason::FallbackBusy
|
|
1503
|
+
);
|
|
1504
|
+
assert_eq!(diagnostics.before_busy_signal_kind, None);
|
|
1505
|
+
assert_eq!(diagnostics.busy_signal_kind, Some(BusySignalKind::Working));
|
|
1506
|
+
assert_eq!(diagnostics.busy_line_from_bottom, Some(0));
|
|
1507
|
+
assert_eq!(diagnostics.current_marker_in_bottom_15, Some(true));
|
|
1508
|
+
assert_eq!(diagnostics.paste_identity_in_composer, None);
|
|
1509
|
+
assert_eq!(diagnostics.consumption_from_capture_result, Some(false));
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
#[test]
|
|
1513
|
+
fn e46_capture_error_clears_previous_consumption_observation() {
|
|
1514
|
+
let token_text = "Team Agent message from leader:\n\nhi\n\n[team-agent-token:msg_capture_error]";
|
|
1515
|
+
let busy_tail = format!("{token_text}\n● Working (1s · esc to interrupt)\n");
|
|
1516
|
+
let visible = ok(token_text);
|
|
1517
|
+
let queued = vec![
|
|
1518
|
+
MockResp::Out(ok("")), // set-buffer
|
|
1519
|
+
MockResp::Out(ok("")), // paste-buffer
|
|
1520
|
+
MockResp::Out(ok("")), // delete-buffer
|
|
1521
|
+
MockResp::Out(visible.clone()), // pasted-content prompt: continue
|
|
1522
|
+
MockResp::Out(visible), // pre-submit token visibility
|
|
1523
|
+
MockResp::Out(ok("")), // Escape
|
|
1524
|
+
MockResp::Out(ok("")), // Enter
|
|
1525
|
+
MockResp::Out(ok(&busy_tail)), // first post-Enter capture: busy
|
|
1526
|
+
// Default capture error forces the next poll/fallback/resend reads to fail.
|
|
1527
|
+
];
|
|
1528
|
+
let (be, _rec) = backend_with(MockResp::Io(std::io::ErrorKind::Other), queued);
|
|
1529
|
+
let report = be
|
|
1530
|
+
.inject(
|
|
1531
|
+
&Target::Pane(PaneId::new("%7")),
|
|
1532
|
+
&InjectPayload::Text(token_text.to_string()),
|
|
1533
|
+
Key::Enter,
|
|
1534
|
+
true,
|
|
1535
|
+
)
|
|
1536
|
+
.expect("inject runs through capture failure");
|
|
1537
|
+
let diagnostics = report.submit_diagnostics.expect("diagnostics");
|
|
1538
|
+
assert_eq!(
|
|
1539
|
+
report.submit_verification,
|
|
1540
|
+
SubmitVerification::SubmitConsumptionUnverified
|
|
1541
|
+
);
|
|
1542
|
+
assert_eq!(diagnostics.consumption_reason, SubmitConsumptionReason::Unverified);
|
|
1543
|
+
assert!(diagnostics.capture_err_count > 0);
|
|
1544
|
+
assert_eq!(diagnostics.before_busy_signal_kind, None);
|
|
1545
|
+
assert_eq!(diagnostics.busy_signal_kind, None);
|
|
1546
|
+
assert_eq!(diagnostics.busy_line_from_bottom, None);
|
|
1547
|
+
assert_eq!(diagnostics.current_marker_in_bottom_15, None);
|
|
1548
|
+
assert_eq!(diagnostics.paste_identity_in_composer, None);
|
|
1549
|
+
assert_eq!(diagnostics.consumption_from_capture_result, None);
|
|
1455
1550
|
}
|
|
1456
1551
|
|
|
1457
1552
|
/// NeverSeen + 无占位符:空 pane 不得再把「token 不在底部」写成 consumed。
|
|
@@ -1521,6 +1616,14 @@ fn e46_inject_text_with_token_consumed_after_enter_keeps_enter_sent_without_plac
|
|
|
1521
1616
|
hold (provider_submit_verification_red.rs:113-159). Got {:?}",
|
|
1522
1617
|
report.submit_verification
|
|
1523
1618
|
);
|
|
1619
|
+
let diagnostics = report.submit_diagnostics.expect("diagnostics");
|
|
1620
|
+
assert_eq!(
|
|
1621
|
+
diagnostics.consumption_reason,
|
|
1622
|
+
SubmitConsumptionReason::ConsumptionFromCapture
|
|
1623
|
+
);
|
|
1624
|
+
assert_eq!(diagnostics.busy_signal_kind, None);
|
|
1625
|
+
assert_eq!(diagnostics.current_marker_in_bottom_15, Some(false));
|
|
1626
|
+
assert_eq!(diagnostics.consumption_from_capture_result, Some(true));
|
|
1524
1627
|
}
|
|
1525
1628
|
|
|
1526
1629
|
/// **E46 RED-3 (resend-to-cap, no double-submit)**: when the FIRST Enter
|
|
@@ -3289,6 +3392,15 @@ fn cursor_single_enter_busy_transcript_placeholder_does_not_retry() {
|
|
|
3289
3392
|
"busy after first Enter is consumption for cursor; got {:?}",
|
|
3290
3393
|
report.submit_verification
|
|
3291
3394
|
);
|
|
3395
|
+
let diagnostics = report.submit_diagnostics.expect("diagnostics");
|
|
3396
|
+
assert_eq!(
|
|
3397
|
+
diagnostics.consumption_reason,
|
|
3398
|
+
SubmitConsumptionReason::CursorPollingBusy
|
|
3399
|
+
);
|
|
3400
|
+
assert_eq!(diagnostics.busy_signal_kind, Some(BusySignalKind::Working));
|
|
3401
|
+
assert!(diagnostics.busy_line_from_bottom.is_some());
|
|
3402
|
+
assert!(diagnostics.current_marker_in_bottom_15.is_some());
|
|
3403
|
+
assert!(diagnostics.consumption_from_capture_result.is_some());
|
|
3292
3404
|
let calls = rec.lock().unwrap().clone();
|
|
3293
3405
|
assert_eq!(
|
|
3294
3406
|
count_submit_enters(&calls),
|
|
@@ -3570,6 +3682,39 @@ fn grok_fold_worker_text_payload_polls_consumption() {
|
|
|
3570
3682
|
);
|
|
3571
3683
|
}
|
|
3572
3684
|
|
|
3685
|
+
#[test]
|
|
3686
|
+
fn provider_busy_signal_match_preserves_category_priority_and_tail_boundary() {
|
|
3687
|
+
let cases = [
|
|
3688
|
+
("working", BusySignalKind::Working),
|
|
3689
|
+
("thinking", BusySignalKind::Thinking),
|
|
3690
|
+
("processing", BusySignalKind::Processing),
|
|
3691
|
+
("esc to interrupt", BusySignalKind::EscToInterrupt),
|
|
3692
|
+
("⠋", BusySignalKind::SpinnerGlyph),
|
|
3693
|
+
("working ⠋", BusySignalKind::Working),
|
|
3694
|
+
];
|
|
3695
|
+
for (text, expected) in cases {
|
|
3696
|
+
let matched = super::provider_busy_signal_match(text).expect("busy match");
|
|
3697
|
+
assert_eq!(matched.kind, expected, "text={text:?}");
|
|
3698
|
+
assert_eq!(matched.line_from_bottom, 0, "text={text:?}");
|
|
3699
|
+
assert!(super::provider_busy_signal_in_tail(text));
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3702
|
+
let inside_bottom_15 = std::iter::once("working".to_string())
|
|
3703
|
+
.chain((0..14).map(|index| format!("tail-{index}")))
|
|
3704
|
+
.collect::<Vec<_>>()
|
|
3705
|
+
.join("\n");
|
|
3706
|
+
let matched = super::provider_busy_signal_match(&inside_bottom_15).expect("15th line");
|
|
3707
|
+
assert_eq!(matched.kind, BusySignalKind::Working);
|
|
3708
|
+
assert_eq!(matched.line_from_bottom, 14);
|
|
3709
|
+
|
|
3710
|
+
let outside_bottom_15 = std::iter::once("working".to_string())
|
|
3711
|
+
.chain((0..15).map(|index| format!("tail-{index}")))
|
|
3712
|
+
.collect::<Vec<_>>()
|
|
3713
|
+
.join("\n");
|
|
3714
|
+
assert!(super::provider_busy_signal_match(&outside_bottom_15).is_none());
|
|
3715
|
+
assert!(!super::provider_busy_signal_in_tail(&outside_bottom_15));
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3573
3718
|
const G4_TOKEN: &str = "[team-agent-token:msg_g4]";
|
|
3574
3719
|
|
|
3575
3720
|
#[test]
|