@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.
Files changed (95) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +161 -29
  4. package/crates/team-agent/src/cli/diagnose.rs +333 -68
  5. package/crates/team-agent/src/cli/emit.rs +24 -8
  6. package/crates/team-agent/src/cli/mod.rs +543 -98
  7. package/crates/team-agent/src/cli/models.rs +393 -32
  8. package/crates/team-agent/src/cli/named_address.rs +19 -5
  9. package/crates/team-agent/src/cli/profile.rs +35 -4
  10. package/crates/team-agent/src/cli/spec.rs +7 -2
  11. package/crates/team-agent/src/cli/status_port/compact.rs +12 -8
  12. package/crates/team-agent/src/cli/status_port/runtime.rs +3 -1
  13. package/crates/team-agent/src/cli/status_port/snapshot.rs +15 -12
  14. package/crates/team-agent/src/cli/status_port/store.rs +1 -1
  15. package/crates/team-agent/src/cli/status_port/tests.rs +37 -1
  16. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +62 -8
  17. package/crates/team-agent/src/cli/tests/named_address.rs +70 -0
  18. package/crates/team-agent/src/cli/tests/verb_profile.rs +81 -6
  19. package/crates/team-agent/src/cli/types.rs +1 -0
  20. package/crates/team-agent/src/coordinator/steps/abnormal.rs +122 -2
  21. package/crates/team-agent/src/leader/lease.rs +492 -33
  22. package/crates/team-agent/src/leader/owner_bind.rs +40 -12
  23. package/crates/team-agent/src/leader/rediscover/tests.rs +65 -0
  24. package/crates/team-agent/src/leader/rediscover.rs +36 -6
  25. package/crates/team-agent/src/leader/start.rs +197 -88
  26. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +15 -9
  27. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +28 -227
  28. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -18
  29. package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +94 -227
  30. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +59 -10
  31. package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +86 -23
  32. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +1449 -282
  33. package/crates/team-agent/src/lifecycle/launch/readiness.rs +349 -4
  34. package/crates/team-agent/src/lifecycle/launch/spawn.rs +11 -11
  35. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +35 -3
  36. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +16 -0
  37. package/crates/team-agent/src/lifecycle/launch.rs +30 -7
  38. package/crates/team-agent/src/lifecycle/profile_launch.rs +37 -3
  39. package/crates/team-agent/src/lifecycle/restart/agent.rs +112 -100
  40. package/crates/team-agent/src/lifecycle/restart/common.rs +82 -52
  41. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +996 -66
  42. package/crates/team-agent/src/lifecycle/restart.rs +2 -2
  43. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +3 -0
  44. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +15 -0
  45. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +5 -0
  46. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +11 -13
  47. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +119 -4
  48. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +12 -0
  49. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +22 -0
  50. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +12 -0
  51. package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +265 -198
  52. package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +14 -30
  53. package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +3 -0
  54. package/crates/team-agent/src/lifecycle/tests/fixtures/pi_list_models_spaced_ids.stdout.txt +9 -0
  55. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +2 -5
  56. package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +10 -0
  57. package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +58 -35
  58. package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +10 -0
  59. package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +9 -0
  60. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -2
  61. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -168
  62. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +145 -212
  63. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +16 -2
  64. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +54 -9
  65. package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +71 -0
  66. package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +78 -0
  67. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +3 -0
  68. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +51 -10
  69. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +50 -7
  70. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +137 -0
  71. package/crates/team-agent/src/lifecycle/types.rs +8 -0
  72. package/crates/team-agent/src/mcp_server/wire.rs +140 -11
  73. package/crates/team-agent/src/messaging/delivery.rs +221 -80
  74. package/crates/team-agent/src/messaging/leader_channel.rs +56 -0
  75. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +127 -0
  76. package/crates/team-agent/src/messaging/tests/runtime.rs +10 -2
  77. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +2 -5
  78. package/crates/team-agent/src/provider/session_scan/common/tests.rs +204 -0
  79. package/crates/team-agent/src/provider/session_scan/common.rs +24 -2
  80. package/crates/team-agent/src/state/abnormal_watch/tests/mod.rs +248 -0
  81. package/crates/team-agent/src/state/abnormal_watch.rs +144 -0
  82. package/crates/team-agent/src/state/mod.rs +1 -0
  83. package/crates/team-agent/src/state/persist.rs +102 -4
  84. package/crates/team-agent/src/state/projection.rs +7 -1
  85. package/crates/team-agent/src/state/repository.rs +29 -0
  86. package/crates/team-agent/src/test_support/models_timeout_fixture.rs +43 -21
  87. package/crates/team-agent/src/tmux_backend/tests.rs +149 -4
  88. package/crates/team-agent/src/tmux_backend.rs +239 -127
  89. package/crates/team-agent/src/transport.rs +78 -0
  90. package/crates/team-agent/src/transport_factory.rs +53 -0
  91. package/package.json +4 -5
  92. package/skills/team-agent/SKILL.md +45 -17
  93. package/skills/team-agent/command-coverage.json +4 -29
  94. package/npm/check-skill-links.mjs +0 -88
  95. 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, CaptureRange, CaptureSampleOutcome,
32
- InjectPayload, InjectStage, InjectVerification, InputSurfaceProbe, Key, PaneField, PaneId,
33
- QueryOutcome, SessionName, SetEnvOutcome, SubmitVerification, Target, Transport,
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]