@team-agent/installer 0.5.106 → 0.5.108
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 +1 -1
- package/crates/team-agent/src/cli/emit.rs +3 -3
- package/crates/team-agent/src/cli/mod.rs +87 -4
- package/crates/team-agent/src/cli/models.rs +252 -3
- package/crates/team-agent/src/cli/spec.rs +1 -1
- package/crates/team-agent/src/cli/status_port/brief.rs +155 -37
- package/crates/team-agent/src/cli/tests/base.rs +112 -225
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +184 -0
- package/crates/team-agent/src/cli/tests/status_brief.rs +624 -0
- 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/model_catalog.rs +166 -3
- package/crates/team-agent/src/provider/testdata/cursor-list-models-native.stdout +250 -0
- package/crates/team-agent/src/provider/testdata/grok-models-authenticated.stdout +9 -0
- package/crates/team-agent/src/provider/testdata/grok-models-unauthenticated.stdout +7 -0
- 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
|
@@ -2778,84 +2778,68 @@ fn pasted_signal_unfixed_predicate_treats_folded_placeholder_as_consumed() {
|
|
|
2778
2778
|
unfixed_vacuous_consumed(folded, marker),
|
|
2779
2779
|
"causal: pre-fix !token_in_bottom_n is vacuously true on a folded composer"
|
|
2780
2780
|
);
|
|
2781
|
-
assert_eq!(
|
|
2782
|
-
super::consumption_from_capture(folded, marker, false, Some(super::PasteLatch::HashId(1))),
|
|
2783
|
-
Some(false),
|
|
2784
|
-
"post-fix NeverSeen + #1 still in composer must NOT be consumed"
|
|
2785
|
-
);
|
|
2786
|
-
}
|
|
2787
|
-
|
|
2788
|
-
#[test]
|
|
2789
|
-
fn pasted_signal_never_seen_without_placeholder_is_not_consumed() {
|
|
2790
|
-
let marker = "[team-agent-token:msg_empty]";
|
|
2791
|
-
assert_eq!(
|
|
2792
|
-
super::token_sighting(false, false),
|
|
2793
|
-
super::TokenSighting::NeverSeen
|
|
2794
|
-
);
|
|
2795
|
-
assert_eq!(
|
|
2796
|
-
super::consumption_from_capture("", marker, false, None),
|
|
2797
|
-
Some(false)
|
|
2798
|
-
);
|
|
2799
|
-
}
|
|
2800
|
-
|
|
2801
|
-
#[test]
|
|
2802
|
-
fn pasted_signal_never_seen_placeholder_id_gone_is_consumed() {
|
|
2803
|
-
let marker = "[team-agent-token:msg_fold]";
|
|
2804
|
-
let after = "assistant reply\n❯ \n";
|
|
2805
|
-
assert_eq!(
|
|
2806
|
-
super::consumption_from_capture(after, marker, false, Some(super::PasteLatch::HashId(7))),
|
|
2807
|
-
Some(true),
|
|
2808
|
-
"NeverSeen but latched #7 left composer ⇒ consumed (positive signal)"
|
|
2809
|
-
);
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
#[test]
|
|
2813
|
-
fn pasted_signal_never_seen_wrong_id_is_consumed() {
|
|
2814
|
-
let marker = "[team-agent-token:msg_fold]";
|
|
2815
|
-
let other = "❯ [Pasted text #2 +3 lines]\n";
|
|
2816
|
-
assert_eq!(
|
|
2817
|
-
super::consumption_from_capture(other, marker, false, Some(super::PasteLatch::HashId(1))),
|
|
2818
|
-
Some(true),
|
|
2819
|
-
"our #1 gone, a later #2 in composer still means ours submitted"
|
|
2820
|
-
);
|
|
2821
2781
|
}
|
|
2822
2782
|
|
|
2823
2783
|
#[test]
|
|
2824
|
-
fn
|
|
2825
|
-
|
|
2826
|
-
let
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
"
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
fn pasted_signal_seen_token_then_gone_is_consumed() {
|
|
2836
|
-
let marker = "[team-agent-token:msg_short]";
|
|
2837
|
-
assert_eq!(
|
|
2838
|
-
super::token_sighting(false, true),
|
|
2839
|
-
super::TokenSighting::Gone
|
|
2840
|
-
);
|
|
2841
|
-
assert_eq!(
|
|
2842
|
-
super::consumption_from_capture("❯ \n", marker, true, None),
|
|
2843
|
-
Some(true)
|
|
2844
|
-
);
|
|
2784
|
+
fn pasted_signal_token_sighting_table() {
|
|
2785
|
+
use super::TokenSighting::{Gone, NeverSeen, Visible};
|
|
2786
|
+
let cases = [
|
|
2787
|
+
("never_seen", false, false, NeverSeen),
|
|
2788
|
+
("gone", false, true, Gone),
|
|
2789
|
+
("visible", true, true, Visible),
|
|
2790
|
+
("gone_grok", false, true, Gone),
|
|
2791
|
+
];
|
|
2792
|
+
for (id, visible, seen, expected) in cases {
|
|
2793
|
+
assert_eq!(super::token_sighting(visible, seen), expected, "{id}");
|
|
2794
|
+
}
|
|
2845
2795
|
}
|
|
2846
2796
|
|
|
2847
2797
|
#[test]
|
|
2848
|
-
fn
|
|
2798
|
+
fn pasted_signal_consumption_table() {
|
|
2799
|
+
use super::PasteLatch::{GrokLineCount, HashId};
|
|
2800
|
+
// Input: capture, marker, previously seen, tracked paste. Expected is Some(bool),
|
|
2801
|
+
// not a truthiness check: None must still fail these consumption contracts.
|
|
2802
|
+
type Input<'a> = (&'a str, &'a str, bool, Option<super::PasteLatch>);
|
|
2849
2803
|
let marker = "[team-agent-token:msg_short]";
|
|
2850
2804
|
let still = format!("❯ ping {marker}\n");
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2805
|
+
let cases: &[(&str, Input<'_>, bool, &str)] = &[
|
|
2806
|
+
("folded_hash_stays",
|
|
2807
|
+
("❯ [Pasted text #1 +8 lines]\n", "[team-agent-token:msg_fold]", false, Some(HashId(1))), false,
|
|
2808
|
+
"post-fix NeverSeen + #1 still in composer must NOT be consumed"),
|
|
2809
|
+
("never_seen_empty",
|
|
2810
|
+
("", "[team-agent-token:msg_empty]", false, None), false, ""),
|
|
2811
|
+
("hash_id_gone",
|
|
2812
|
+
("assistant reply\n❯ \n", "[team-agent-token:msg_fold]", false, Some(HashId(7))), true,
|
|
2813
|
+
"NeverSeen but latched #7 left composer ⇒ consumed (positive signal)"),
|
|
2814
|
+
("hash_id_replaced",
|
|
2815
|
+
("❯ [Pasted text #2 +3 lines]\n", "[team-agent-token:msg_fold]", false, Some(HashId(1))), true,
|
|
2816
|
+
"our #1 gone, a later #2 in composer still means ours submitted"),
|
|
2817
|
+
("no_hash_latch",
|
|
2818
|
+
("❯ \n", "[team-agent-token:msg_fold]", false, None), false,
|
|
2819
|
+
"no #N latched: disappearance is unverified, not consumed"),
|
|
2820
|
+
("seen_token_gone",
|
|
2821
|
+
("❯ \n", "[team-agent-token:msg_short]", true, None), true, ""),
|
|
2822
|
+
("seen_token_visible",
|
|
2823
|
+
(&still, "[team-agent-token:msg_short]", true, None), false, ""),
|
|
2824
|
+
("grok_lines_stay",
|
|
2825
|
+
(GROK_INCIDENT_LINE, "[team-agent-token:msg_grok]", false, Some(GrokLineCount(42))), false, ""),
|
|
2826
|
+
("grok_lines_gone",
|
|
2827
|
+
("Waiting for response\n❯ \n", "[team-agent-token:msg_grok]", false, Some(GrokLineCount(42))), true, ""),
|
|
2828
|
+
("grok_lines_mismatch",
|
|
2829
|
+
("│ ❯ [Pasted: 10 lines] │", "[team-agent-token:msg_grok]", false, Some(GrokLineCount(42))), false,
|
|
2830
|
+
"different N must not claim the latched paste consumed"),
|
|
2831
|
+
// 悬案B:Gone 仍有 grok 占位符;修前 Gone 无条件 Some(true)。
|
|
2832
|
+
("gone_grok_lines_stay",
|
|
2833
|
+
("some transcript line\n> [Pasted: 27 lines]\nEnter:send Esc:cancel\n", "[team-agent-token:deadbeef]", true, Some(GrokLineCount(27))), false,
|
|
2834
|
+
"Gone must re-check PasteLatch: placeholder still in composer must not be consumed, got {got:?}"),
|
|
2835
|
+
("gone_grok_kb_stay",
|
|
2836
|
+
("│ ❯ [Pasted: 13 KB] │\n Enter:send\n", "[team-agent-token:kbform]", true, Some(GrokLineCount(13))), false,
|
|
2837
|
+
"Gone + [Pasted: 13 KB] still in composer must not be consumed, got {got:?}"),
|
|
2838
|
+
];
|
|
2839
|
+
for &(id, (text, marker, seen, tracked), expected, note) in cases {
|
|
2840
|
+
let got = super::consumption_from_capture(text, marker, seen, tracked);
|
|
2841
|
+
assert_eq!(got, Some(expected), "{id}: {note}; got={got:?}");
|
|
2842
|
+
}
|
|
2859
2843
|
}
|
|
2860
2844
|
|
|
2861
2845
|
#[test]
|
|
@@ -2874,87 +2858,115 @@ fn pasted_signal_marker_some_observation_records_composer_placeholder() {
|
|
|
2874
2858
|
}
|
|
2875
2859
|
|
|
2876
2860
|
#[test]
|
|
2877
|
-
fn
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
.
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
.expect("inject");
|
|
2889
|
-
assert_eq!(
|
|
2890
|
-
report.submit_verification,
|
|
2891
|
-
SubmitVerification::SubmitConsumptionUnverified,
|
|
2892
|
-
"folded + Enter not effective (#4 stays) must be unverified; got {:?}",
|
|
2893
|
-
report.submit_verification
|
|
2894
|
-
);
|
|
2895
|
-
}
|
|
2896
|
-
|
|
2897
|
-
#[test]
|
|
2898
|
-
fn pasted_signal_inject_folded_enter_effective_is_consumed() {
|
|
2899
|
-
let token_text = "Team Agent message from leader:\nline1\nline2\nline3\nline4\nline5\n\n[team-agent-token:msg_fold_go]";
|
|
2861
|
+
fn pasted_signal_submit_verification_table() {
|
|
2862
|
+
use SubmitVerification::{EnterSentWithoutPlaceholderCheck, SubmitConsumptionUnverified};
|
|
2863
|
+
struct Case {
|
|
2864
|
+
id: &'static str,
|
|
2865
|
+
// Payload, pre-submit capture, post-submit capture, clear-after-N-enters.
|
|
2866
|
+
// None uses FoldedPasteRunner; Some(N) uses NthEnterClearRunner.
|
|
2867
|
+
input: (String, String, String, Option<u32>),
|
|
2868
|
+
// Verification, Enter count, paste-buffer count. None preserves no assertion.
|
|
2869
|
+
expected: (SubmitVerification, Option<usize>, Option<usize>),
|
|
2870
|
+
notes: [&'static str; 3],
|
|
2871
|
+
}
|
|
2900
2872
|
let placeholder = "❯ [Pasted text #4 +6 lines]\n";
|
|
2901
|
-
|
|
2902
|
-
let
|
|
2903
|
-
let
|
|
2904
|
-
let
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
#
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2873
|
+
let short_ok = "ping [team-agent-token:msg_short_ok]";
|
|
2874
|
+
let short_stay = "ping [team-agent-token:msg_short_stay]";
|
|
2875
|
+
let marker = "[team-agent-token:msg_wrap_ok]";
|
|
2876
|
+
let wrapped_payload = format!("Team Agent message from leader:\nline1\n\n{marker}");
|
|
2877
|
+
let wrapped = wrapped_identity_with_skin(marker, "> ");
|
|
2878
|
+
let marker = "[team-agent-token:msg_cap_lock]";
|
|
2879
|
+
let cap_lock_payload = format!("Team Agent message from leader:\nline1\n\n{marker}");
|
|
2880
|
+
let cap_lock = wrapped_identity_with_skin(marker, "ready.");
|
|
2881
|
+
let marker = "[team-agent-token:msg_busy_nodup]";
|
|
2882
|
+
let busy_payload = format!("Team Agent message from leader:\nline1 composer> ❯\n\n{marker}");
|
|
2883
|
+
let busy = "STARTED\nsleep holds pty\ncomposer>\n❯\n>\n";
|
|
2884
|
+
let marker = "[team-agent-token:msg_payload_glyph]";
|
|
2885
|
+
let glyphs_payload = format!("Team Agent message from leader:\ncomposer> ❯\n\n{marker}");
|
|
2886
|
+
let glyphs = "output\ncomposer> leftover from payload\n❯ quoted\n";
|
|
2887
|
+
let mut cases = vec![
|
|
2888
|
+
Case { id: "folded_stays",
|
|
2889
|
+
input: ("Team Agent message from leader:\nline1\nline2\nline3\nline4\nline5\n\n[team-agent-token:msg_fold_stay]".into(), placeholder.into(), placeholder.into(), None),
|
|
2890
|
+
expected: (SubmitConsumptionUnverified, None, None),
|
|
2891
|
+
notes: ["folded + Enter not effective (#4 stays) must be unverified; got {:?}", "", ""] },
|
|
2892
|
+
// 只有 #4 离开 composer;不加 Working,否则 busy 升级会让半三不经正信号就绿。
|
|
2893
|
+
Case { id: "folded_gone",
|
|
2894
|
+
input: ("Team Agent message from leader:\nline1\nline2\nline3\nline4\nline5\n\n[team-agent-token:msg_fold_go]".into(), placeholder.into(), "assistant reply\n❯ \n".into(), None),
|
|
2895
|
+
expected: (EnterSentWithoutPlaceholderCheck, None, None),
|
|
2896
|
+
notes: ["folded + Enter effective (#4 left composer) must be consumed; got {:?}", "", ""] },
|
|
2897
|
+
Case { id: "short_gone",
|
|
2898
|
+
input: (short_ok.into(), short_ok.into(), "❯ \n".into(), None),
|
|
2899
|
+
expected: (EnterSentWithoutPlaceholderCheck, None, None),
|
|
2900
|
+
notes: ["short visible token then gone must stay consumed; got {:?}", "", ""] },
|
|
2901
|
+
Case { id: "short_visible",
|
|
2902
|
+
input: (short_stay.into(), short_stay.into(), short_stay.into(), None),
|
|
2903
|
+
expected: (SubmitConsumptionUnverified, None, None),
|
|
2904
|
+
notes: ["short visible token still in composer must stay unverified; got {:?}", "", ""] },
|
|
2905
|
+
Case { id: "grok_stays",
|
|
2906
|
+
input: ("Team Agent message from leader:\nline1\n\n[team-agent-token:msg_grok_stay]".into(), GROK_INCIDENT_LINE.into(), GROK_INCIDENT_LINE.into(), None),
|
|
2907
|
+
expected: (SubmitConsumptionUnverified, Some(3), None),
|
|
2908
|
+
notes: ["", "same grok N still in composer must retry Enter up to cap=3; Unverified B must not add a 4th; invert wrap-gap guard must turn this red; calls={calls:?}", ""] },
|
|
2909
|
+
Case { id: "grok_gone",
|
|
2910
|
+
input: ("Team Agent message from leader:\nline1\n\n[team-agent-token:msg_grok_go]".into(), GROK_INCIDENT_LINE.into(), "Waiting for response\n❯ \n".into(), None),
|
|
2911
|
+
expected: (EnterSentWithoutPlaceholderCheck, Some(1), None),
|
|
2912
|
+
notes: ["", "fold left composer after one Enter; no empty-composer hammer; calls={calls:?}", ""] },
|
|
2913
|
+
Case { id: "wrapped_resend_consumes",
|
|
2914
|
+
input: (wrapped_payload, wrapped, "> \n".into(), Some(2)),
|
|
2915
|
+
expected: (EnterSentWithoutPlaceholderCheck, Some(2), Some(1)),
|
|
2916
|
+
notes: ["Unverified + wrapped identity must resend one C-m then consume; got {:?}", "exactly one extra C-m after Unverified; calls={calls:?}", "must not re-paste; paste-buffer count={pastes}"] },
|
|
2917
|
+
Case { id: "identity_absent",
|
|
2918
|
+
input: (busy_payload, busy.into(), busy.into(), Some(99)),
|
|
2919
|
+
expected: (SubmitConsumptionUnverified, Some(1), None),
|
|
2920
|
+
notes: ["identity absent must stay Unverified, no extra Enter; got {:?}", "no this-paste identity ⇒ no Unverified resend; commenting the identity gate must turn this red (2+ C-m); calls={calls:?}", ""] },
|
|
2921
|
+
Case { id: "identity_resend_cap",
|
|
2922
|
+
input: (cap_lock_payload, cap_lock.clone(), cap_lock, Some(u32::MAX)),
|
|
2923
|
+
expected: (SubmitConsumptionUnverified, Some(2), Some(1)),
|
|
2924
|
+
notes: ["never-clear identity must not fake-consume; got {:?}", "cap must be exactly one extra C-m (1 inject + 1 resend); raising UNVERIFIED_COMPOSER_RESEND_MAX must turn this red; calls={calls:?}", "must not re-paste; paste-buffer count={pastes}"] },
|
|
2925
|
+
Case { id: "payload_glyphs",
|
|
2926
|
+
input: (glyphs_payload, glyphs.into(), glyphs.into(), Some(99)),
|
|
2927
|
+
expected: (SubmitConsumptionUnverified, Some(1), None),
|
|
2928
|
+
notes: ["", "glyphs in payload must not cause extra C-m when token identity is gone; calls={calls:?}", ""] },
|
|
2929
|
+
];
|
|
2930
|
+
for (id, skin) in [
|
|
2931
|
+
("skin_arrow", "❯ "),
|
|
2932
|
+
("skin_greater_than", "> "),
|
|
2933
|
+
("skin_ready", "ready."),
|
|
2934
|
+
] {
|
|
2935
|
+
let marker = format!("[team-agent-token:msg_skin_{}]", skin.chars().next().unwrap() as u32);
|
|
2936
|
+
cases.push(Case {
|
|
2937
|
+
id,
|
|
2938
|
+
input: (format!("Team Agent message from leader:\nline1\n\n{marker}"),
|
|
2939
|
+
wrapped_identity_with_skin(&marker, skin), format!("{skin}\n"), Some(2)),
|
|
2940
|
+
expected: (EnterSentWithoutPlaceholderCheck, Some(2), None),
|
|
2941
|
+
notes: ["skin {skin:?} must consume after one extra C-m", "skin {skin:?} extra C-m; got {n}", ""],
|
|
2942
|
+
});
|
|
2943
|
+
}
|
|
2944
|
+
for case in cases {
|
|
2945
|
+
let (payload, pre, post, clear_after) = case.input;
|
|
2946
|
+
let (be, rec) = match clear_after {
|
|
2947
|
+
Some(n) => backend_clears_after_n_enters(&pre, &post, n),
|
|
2948
|
+
None => backend_folded(&pre, &post),
|
|
2949
|
+
};
|
|
2950
|
+
let report = be.inject(
|
|
2951
|
+
&Target::Pane(PaneId::new("%7")), &InjectPayload::Text(payload), Key::Enter, true,
|
|
2952
|
+
).expect("inject");
|
|
2953
|
+
let (verification, enters, pastes) = case.expected;
|
|
2954
|
+
assert_eq!(report.submit_verification, verification,
|
|
2955
|
+
"{}: {}; pre={pre:?}", case.id, case.notes[0]);
|
|
2956
|
+
if enters.is_some() || pastes.is_some() {
|
|
2957
|
+
let calls = rec.lock().unwrap().clone();
|
|
2958
|
+
if let Some(enters) = enters {
|
|
2959
|
+
assert_eq!(count_submit_enters(&calls), enters,
|
|
2960
|
+
"{}: {}; calls={calls:?}", case.id, case.notes[1]);
|
|
2961
|
+
}
|
|
2962
|
+
if let Some(pastes) = pastes {
|
|
2963
|
+
let actual = calls.iter()
|
|
2964
|
+
.filter(|argv| argv.get(1).map(String::as_str) == Some("paste-buffer"))
|
|
2965
|
+
.count();
|
|
2966
|
+
assert_eq!(actual, pastes, "{}: {}; calls={calls:?}", case.id, case.notes[2]);
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2958
2970
|
}
|
|
2959
2971
|
|
|
2960
2972
|
fn count_submit_enters(calls: &[Vec<String>]) -> usize {
|
|
@@ -3415,87 +3427,16 @@ fn grok_fold_three_tui_literals_lock() {
|
|
|
3415
3427
|
assert_eq!(codex.id, Some(2));
|
|
3416
3428
|
}
|
|
3417
3429
|
|
|
3418
|
-
#[test]
|
|
3419
|
-
fn grok_fold_same_line_count_still_unconsumed() {
|
|
3420
|
-
let marker = "[team-agent-token:msg_grok]";
|
|
3421
|
-
assert_eq!(
|
|
3422
|
-
super::consumption_from_capture(
|
|
3423
|
-
GROK_INCIDENT_LINE,
|
|
3424
|
-
marker,
|
|
3425
|
-
false,
|
|
3426
|
-
Some(super::PasteLatch::GrokLineCount(42))
|
|
3427
|
-
),
|
|
3428
|
-
Some(false)
|
|
3429
|
-
);
|
|
3430
|
-
}
|
|
3431
|
-
|
|
3432
|
-
#[test]
|
|
3433
|
-
fn grok_fold_line_count_gone_is_consumed() {
|
|
3434
|
-
let marker = "[team-agent-token:msg_grok]";
|
|
3435
|
-
assert_eq!(
|
|
3436
|
-
super::consumption_from_capture(
|
|
3437
|
-
"Waiting for response\n❯ \n",
|
|
3438
|
-
marker,
|
|
3439
|
-
false,
|
|
3440
|
-
Some(super::PasteLatch::GrokLineCount(42))
|
|
3441
|
-
),
|
|
3442
|
-
Some(true)
|
|
3443
|
-
);
|
|
3444
|
-
}
|
|
3445
|
-
|
|
3446
3430
|
#[test]
|
|
3447
3431
|
fn grok_fold_different_n_is_not_same_paste() {
|
|
3448
3432
|
let marker = "[team-agent-token:msg_grok]";
|
|
3449
3433
|
let other = "│ ❯ [Pasted: 10 lines] │";
|
|
3450
|
-
assert_eq!(
|
|
3451
|
-
super::consumption_from_capture(
|
|
3452
|
-
other,
|
|
3453
|
-
marker,
|
|
3454
|
-
false,
|
|
3455
|
-
Some(super::PasteLatch::GrokLineCount(42))
|
|
3456
|
-
),
|
|
3457
|
-
Some(false),
|
|
3458
|
-
"different N must not claim the latched paste consumed"
|
|
3459
|
-
);
|
|
3460
3434
|
assert!(
|
|
3461
3435
|
!super::should_resubmit_enter(other, marker, Some(super::PasteLatch::GrokLineCount(42))),
|
|
3462
3436
|
"different N is not the same paste; do not hammer Enter"
|
|
3463
3437
|
);
|
|
3464
3438
|
}
|
|
3465
3439
|
|
|
3466
|
-
#[test]
|
|
3467
|
-
fn grok_fold_no_latch_cannot_claim_consumed() {
|
|
3468
|
-
let marker = "[team-agent-token:msg_grok]";
|
|
3469
|
-
assert_eq!(
|
|
3470
|
-
super::consumption_from_capture("❯ \n", marker, false, None),
|
|
3471
|
-
Some(false)
|
|
3472
|
-
);
|
|
3473
|
-
}
|
|
3474
|
-
|
|
3475
|
-
#[test]
|
|
3476
|
-
fn grok_fold_inject_stays_retries_while_identity_present() {
|
|
3477
|
-
let token_text = "Team Agent message from leader:\nline1\n\n[team-agent-token:msg_grok_stay]";
|
|
3478
|
-
let (be, rec) = backend_folded(GROK_INCIDENT_LINE, GROK_INCIDENT_LINE);
|
|
3479
|
-
let report = be
|
|
3480
|
-
.inject(
|
|
3481
|
-
&Target::Pane(PaneId::new("%7")),
|
|
3482
|
-
&InjectPayload::Text(token_text.to_string()),
|
|
3483
|
-
Key::Enter,
|
|
3484
|
-
true,
|
|
3485
|
-
)
|
|
3486
|
-
.expect("inject");
|
|
3487
|
-
assert_eq!(
|
|
3488
|
-
report.submit_verification,
|
|
3489
|
-
SubmitVerification::SubmitConsumptionUnverified
|
|
3490
|
-
);
|
|
3491
|
-
let calls = rec.lock().unwrap().clone();
|
|
3492
|
-
assert_eq!(
|
|
3493
|
-
count_submit_enters(&calls),
|
|
3494
|
-
3,
|
|
3495
|
-
"same grok N still in composer must retry Enter up to cap=3; Unverified B must not add a 4th; invert wrap-gap guard must turn this red; calls={calls:?}"
|
|
3496
|
-
);
|
|
3497
|
-
}
|
|
3498
|
-
|
|
3499
3440
|
/// 2026-08-21 真机屏尾:折叠占位符还在 transcript,Working 已开。
|
|
3500
3441
|
/// 非 cursor 路径会把 pasted #N 当成未消费而连按 Enter。
|
|
3501
3442
|
const CURSOR_BUSY_AFTER_SUBMIT: &str = "\
|
|
@@ -3606,30 +3547,6 @@ fn cursor_should_resubmit_false_when_busy_even_if_paste_placeholder_visible() {
|
|
|
3606
3547
|
);
|
|
3607
3548
|
}
|
|
3608
3549
|
|
|
3609
|
-
#[test]
|
|
3610
|
-
fn grok_fold_inject_leaves_consumed_one_enter() {
|
|
3611
|
-
let token_text = "Team Agent message from leader:\nline1\n\n[team-agent-token:msg_grok_go]";
|
|
3612
|
-
let (be, rec) = backend_folded(GROK_INCIDENT_LINE, "Waiting for response\n❯ \n");
|
|
3613
|
-
let report = be
|
|
3614
|
-
.inject(
|
|
3615
|
-
&Target::Pane(PaneId::new("%7")),
|
|
3616
|
-
&InjectPayload::Text(token_text.to_string()),
|
|
3617
|
-
Key::Enter,
|
|
3618
|
-
true,
|
|
3619
|
-
)
|
|
3620
|
-
.expect("inject");
|
|
3621
|
-
assert_eq!(
|
|
3622
|
-
report.submit_verification,
|
|
3623
|
-
SubmitVerification::EnterSentWithoutPlaceholderCheck
|
|
3624
|
-
);
|
|
3625
|
-
let calls = rec.lock().unwrap().clone();
|
|
3626
|
-
assert_eq!(
|
|
3627
|
-
count_submit_enters(&calls),
|
|
3628
|
-
1,
|
|
3629
|
-
"fold left composer after one Enter; no empty-composer hammer; calls={calls:?}"
|
|
3630
|
-
);
|
|
3631
|
-
}
|
|
3632
|
-
|
|
3633
3550
|
#[test]
|
|
3634
3551
|
fn grok_fold_unverified_without_identity_one_enter() {
|
|
3635
3552
|
let token_text = "Team Agent message from leader:\nhi\n\n[team-agent-token:msg_grok_empty]";
|
|
@@ -3700,57 +3617,12 @@ fn grok_fold_does_not_enter_before_fold_on_raw_tall_paste() {
|
|
|
3700
3617
|
assert_eq!(count_submit_enters(&calls), 1);
|
|
3701
3618
|
}
|
|
3702
3619
|
|
|
3703
|
-
/// 悬案B 主嫌:token 见过又消失(Gone)时 composer 仍有 grok 折叠占位符。
|
|
3704
|
-
/// 修前 Gone 无条件 Some(true)。本测试必须先红。
|
|
3705
|
-
#[test]
|
|
3706
|
-
fn gone_with_grok_placeholder_still_in_composer_must_not_be_consumed() {
|
|
3707
|
-
let cap = "some transcript line\n> [Pasted: 27 lines]\nEnter:send Esc:cancel\n";
|
|
3708
|
-
let marker = "[team-agent-token:deadbeef]";
|
|
3709
|
-
assert_eq!(
|
|
3710
|
-
super::token_sighting(false, true),
|
|
3711
|
-
super::TokenSighting::Gone
|
|
3712
|
-
);
|
|
3713
|
-
let got = super::consumption_from_capture(
|
|
3714
|
-
cap,
|
|
3715
|
-
marker,
|
|
3716
|
-
true,
|
|
3717
|
-
Some(super::PasteLatch::GrokLineCount(27)),
|
|
3718
|
-
);
|
|
3719
|
-
assert_eq!(
|
|
3720
|
-
got,
|
|
3721
|
-
Some(false),
|
|
3722
|
-
"Gone must re-check PasteLatch: placeholder still in composer must not be consumed, got {got:?}"
|
|
3723
|
-
);
|
|
3724
|
-
}
|
|
3725
|
-
|
|
3726
3620
|
#[test]
|
|
3727
|
-
fn
|
|
3621
|
+
fn grok_kb_placeholder_parser_preserves_literal_and_line_count() {
|
|
3728
3622
|
let cap = "│ ❯ [Pasted: 13 KB] │\n Enter:send\n";
|
|
3729
|
-
let marker = "[team-agent-token:kbform]";
|
|
3730
3623
|
let prompt = super::pasted_prompt_in_composer(cap, 15).expect("KB form is grok fold");
|
|
3731
3624
|
assert_eq!(prompt.literal, "pasted:");
|
|
3732
3625
|
assert_eq!(prompt.line_count, Some(13));
|
|
3733
|
-
let got = super::consumption_from_capture(
|
|
3734
|
-
cap,
|
|
3735
|
-
marker,
|
|
3736
|
-
true,
|
|
3737
|
-
Some(super::PasteLatch::GrokLineCount(13)),
|
|
3738
|
-
);
|
|
3739
|
-
assert_eq!(
|
|
3740
|
-
got,
|
|
3741
|
-
Some(false),
|
|
3742
|
-
"Gone + [Pasted: 13 KB] still in composer must not be consumed, got {got:?}"
|
|
3743
|
-
);
|
|
3744
|
-
}
|
|
3745
|
-
|
|
3746
|
-
#[test]
|
|
3747
|
-
fn gone_empty_composer_without_latch_stays_consumed_for_claude() {
|
|
3748
|
-
let marker = "[team-agent-token:msg_short]";
|
|
3749
|
-
assert_eq!(
|
|
3750
|
-
super::consumption_from_capture("❯ \n", marker, true, None),
|
|
3751
|
-
Some(true),
|
|
3752
|
-
"claude short token gone + empty composer + no latch must stay consumed"
|
|
3753
|
-
);
|
|
3754
3626
|
}
|
|
3755
3627
|
|
|
3756
3628
|
/// 样本#5 归因钉:重试只重按 Enter,不得再 load/set/paste-buffer。
|
|
@@ -3855,66 +3727,21 @@ fn provider_busy_signal_match_preserves_category_priority_and_tail_boundary() {
|
|
|
3855
3727
|
const G4_TOKEN: &str = "[team-agent-token:msg_g4]";
|
|
3856
3728
|
|
|
3857
3729
|
#[test]
|
|
3858
|
-
fn
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
}
|
|
3874
|
-
|
|
3875
|
-
#[test]
|
|
3876
|
-
fn g4_turn_cursor_unsubmitted_token_is_missing() {
|
|
3877
|
-
let text = format!("❯ {G4_TOKEN}");
|
|
3878
|
-
assert_eq!(
|
|
3879
|
-
observe_turn_from_capture(&text, Some(G4_TOKEN)),
|
|
3880
|
-
TurnVerification::LeaderNewTurnBoundaryMissing
|
|
3881
|
-
);
|
|
3882
|
-
}
|
|
3883
|
-
|
|
3884
|
-
#[test]
|
|
3885
|
-
fn g4_turn_claude_spinner_is_verified() {
|
|
3886
|
-
let text = "✶ Thinking…\nesc to interrupt";
|
|
3887
|
-
assert_eq!(
|
|
3888
|
-
observe_turn_from_capture(text, Some(G4_TOKEN)),
|
|
3889
|
-
TurnVerification::LeaderNewTurnBoundaryVerified
|
|
3890
|
-
);
|
|
3891
|
-
}
|
|
3892
|
-
|
|
3893
|
-
#[test]
|
|
3894
|
-
fn g4_turn_cursor_processing_is_verified() {
|
|
3895
|
-
let text = "processing\n❯ ";
|
|
3896
|
-
assert_eq!(
|
|
3897
|
-
observe_turn_from_capture(text, Some(G4_TOKEN)),
|
|
3898
|
-
TurnVerification::LeaderNewTurnBoundaryVerified
|
|
3899
|
-
);
|
|
3900
|
-
}
|
|
3901
|
-
|
|
3902
|
-
#[test]
|
|
3903
|
-
fn g4_turn_grok_working_is_verified() {
|
|
3904
|
-
let text = "working\n❯ ";
|
|
3905
|
-
assert_eq!(
|
|
3906
|
-
observe_turn_from_capture(text, Some(G4_TOKEN)),
|
|
3907
|
-
TurnVerification::LeaderNewTurnBoundaryVerified
|
|
3908
|
-
);
|
|
3909
|
-
}
|
|
3910
|
-
|
|
3911
|
-
#[test]
|
|
3912
|
-
fn g4_turn_empty_composer_without_busy_is_unknown() {
|
|
3913
|
-
assert_eq!(
|
|
3914
|
-
observe_turn_from_capture("❯ ", Some(G4_TOKEN)),
|
|
3915
|
-
TurnVerification::NotYetObserved,
|
|
3916
|
-
"empty composer and no busy is 不知道, never 开跑"
|
|
3917
|
-
);
|
|
3730
|
+
fn g4_turn_verification_table() {
|
|
3731
|
+
use TurnVerification::{LeaderNewTurnBoundaryMissing, LeaderNewTurnBoundaryVerified, NotYetObserved};
|
|
3732
|
+
let cursor = format!("❯ {G4_TOKEN}");
|
|
3733
|
+
let cases = [
|
|
3734
|
+
("grok_pending", "│ ❯ [Pasted: 42 lines] │", LeaderNewTurnBoundaryMissing, ""),
|
|
3735
|
+
("claude_pending", "❯ pasted text #4 +12 lines", LeaderNewTurnBoundaryMissing, ""),
|
|
3736
|
+
("cursor_pending", cursor.as_str(), LeaderNewTurnBoundaryMissing, ""),
|
|
3737
|
+
("claude_busy", "✶ Thinking…\nesc to interrupt", LeaderNewTurnBoundaryVerified, ""),
|
|
3738
|
+
("cursor_busy", "processing\n❯ ", LeaderNewTurnBoundaryVerified, ""),
|
|
3739
|
+
("grok_busy", "working\n❯ ", LeaderNewTurnBoundaryVerified, ""),
|
|
3740
|
+
("empty_unknown", "❯ ", NotYetObserved, "empty composer and no busy is 不知道, never 开跑"),
|
|
3741
|
+
];
|
|
3742
|
+
for (id, text, expected, note) in cases {
|
|
3743
|
+
assert_eq!(observe_turn_from_capture(text, Some(G4_TOKEN)), expected, "{id}: {note}");
|
|
3744
|
+
}
|
|
3918
3745
|
}
|
|
3919
3746
|
|
|
3920
3747
|
#[test]
|
|
@@ -4237,153 +4064,3 @@ fn wrap_gap_true_on_joined_token_a_cannot_see() {
|
|
|
4237
4064
|
"B must still cover the wrap gap A cannot see"
|
|
4238
4065
|
);
|
|
4239
4066
|
}
|
|
4240
|
-
|
|
4241
|
-
#[test]
|
|
4242
|
-
fn unverified_wrapped_token_resends_one_enter_then_consumes() {
|
|
4243
|
-
let marker = "[team-agent-token:msg_wrap_ok]";
|
|
4244
|
-
let token_text = format!("Team Agent message from leader:\nline1\n\n{marker}");
|
|
4245
|
-
let pending = wrapped_identity_with_skin(marker, "> ");
|
|
4246
|
-
let cleared = "> \n";
|
|
4247
|
-
let (be, rec) = backend_clears_after_n_enters(&pending, cleared, 2);
|
|
4248
|
-
let report = be
|
|
4249
|
-
.inject(
|
|
4250
|
-
&Target::Pane(PaneId::new("%7")),
|
|
4251
|
-
&InjectPayload::Text(token_text),
|
|
4252
|
-
Key::Enter,
|
|
4253
|
-
true,
|
|
4254
|
-
)
|
|
4255
|
-
.expect("inject");
|
|
4256
|
-
assert_eq!(
|
|
4257
|
-
report.submit_verification,
|
|
4258
|
-
SubmitVerification::EnterSentWithoutPlaceholderCheck,
|
|
4259
|
-
"Unverified + wrapped identity must resend one C-m then consume; got {:?}",
|
|
4260
|
-
report.submit_verification
|
|
4261
|
-
);
|
|
4262
|
-
let calls = rec.lock().unwrap().clone();
|
|
4263
|
-
assert_eq!(
|
|
4264
|
-
count_submit_enters(&calls),
|
|
4265
|
-
2,
|
|
4266
|
-
"exactly one extra C-m after Unverified; calls={calls:?}"
|
|
4267
|
-
);
|
|
4268
|
-
let pastes = calls
|
|
4269
|
-
.iter()
|
|
4270
|
-
.filter(|argv| argv.get(1).map(String::as_str) == Some("paste-buffer"))
|
|
4271
|
-
.count();
|
|
4272
|
-
assert_eq!(pastes, 1, "must not re-paste; paste-buffer count={pastes}");
|
|
4273
|
-
}
|
|
4274
|
-
|
|
4275
|
-
#[test]
|
|
4276
|
-
fn unverified_resend_skips_when_this_message_identity_absent() {
|
|
4277
|
-
let marker = "[team-agent-token:msg_busy_nodup]";
|
|
4278
|
-
let token_text = format!("Team Agent message from leader:\nline1 composer> ❯\n\n{marker}");
|
|
4279
|
-
let pending = "STARTED\nsleep holds pty\ncomposer>\n❯\n>\n";
|
|
4280
|
-
let (be, rec) = backend_clears_after_n_enters(pending, pending, 99);
|
|
4281
|
-
let report = be
|
|
4282
|
-
.inject(
|
|
4283
|
-
&Target::Pane(PaneId::new("%7")),
|
|
4284
|
-
&InjectPayload::Text(token_text),
|
|
4285
|
-
Key::Enter,
|
|
4286
|
-
true,
|
|
4287
|
-
)
|
|
4288
|
-
.expect("inject");
|
|
4289
|
-
assert_eq!(
|
|
4290
|
-
report.submit_verification,
|
|
4291
|
-
SubmitVerification::SubmitConsumptionUnverified,
|
|
4292
|
-
"identity absent must stay Unverified, no extra Enter; got {:?}",
|
|
4293
|
-
report.submit_verification
|
|
4294
|
-
);
|
|
4295
|
-
let calls = rec.lock().unwrap().clone();
|
|
4296
|
-
assert_eq!(
|
|
4297
|
-
count_submit_enters(&calls),
|
|
4298
|
-
1,
|
|
4299
|
-
"no this-paste identity ⇒ no Unverified resend; commenting the identity gate must turn this red (2+ C-m); calls={calls:?}"
|
|
4300
|
-
);
|
|
4301
|
-
}
|
|
4302
|
-
|
|
4303
|
-
#[test]
|
|
4304
|
-
fn unverified_identity_never_clears_hits_resend_cap_of_one() {
|
|
4305
|
-
let marker = "[team-agent-token:msg_cap_lock]";
|
|
4306
|
-
let token_text = format!("Team Agent message from leader:\nline1\n\n{marker}");
|
|
4307
|
-
let pending = wrapped_identity_with_skin(marker, "ready.");
|
|
4308
|
-
let (be, rec) = backend_clears_after_n_enters(&pending, &pending, u32::MAX);
|
|
4309
|
-
let report = be
|
|
4310
|
-
.inject(
|
|
4311
|
-
&Target::Pane(PaneId::new("%7")),
|
|
4312
|
-
&InjectPayload::Text(token_text),
|
|
4313
|
-
Key::Enter,
|
|
4314
|
-
true,
|
|
4315
|
-
)
|
|
4316
|
-
.expect("inject");
|
|
4317
|
-
assert_eq!(
|
|
4318
|
-
report.submit_verification,
|
|
4319
|
-
SubmitVerification::SubmitConsumptionUnverified,
|
|
4320
|
-
"never-clear identity must not fake-consume; got {:?}",
|
|
4321
|
-
report.submit_verification
|
|
4322
|
-
);
|
|
4323
|
-
let calls = rec.lock().unwrap().clone();
|
|
4324
|
-
assert_eq!(
|
|
4325
|
-
count_submit_enters(&calls),
|
|
4326
|
-
2,
|
|
4327
|
-
"cap must be exactly one extra C-m (1 inject + 1 resend); raising UNVERIFIED_COMPOSER_RESEND_MAX must turn this red; calls={calls:?}"
|
|
4328
|
-
);
|
|
4329
|
-
let pastes = calls
|
|
4330
|
-
.iter()
|
|
4331
|
-
.filter(|argv| argv.get(1).map(String::as_str) == Some("paste-buffer"))
|
|
4332
|
-
.count();
|
|
4333
|
-
assert_eq!(pastes, 1, "must not re-paste; paste-buffer count={pastes}");
|
|
4334
|
-
}
|
|
4335
|
-
|
|
4336
|
-
#[test]
|
|
4337
|
-
fn unverified_wrapped_identity_resends_on_each_of_three_skins() {
|
|
4338
|
-
for skin in ["❯ ", "> ", "ready."] {
|
|
4339
|
-
let marker = format!(
|
|
4340
|
-
"[team-agent-token:msg_skin_{}]",
|
|
4341
|
-
skin.chars().next().unwrap() as u32
|
|
4342
|
-
);
|
|
4343
|
-
let token_text = format!("Team Agent message from leader:\nline1\n\n{marker}");
|
|
4344
|
-
let pending = wrapped_identity_with_skin(&marker, skin);
|
|
4345
|
-
let cleared = format!("{skin}\n");
|
|
4346
|
-
let (be, rec) = backend_clears_after_n_enters(&pending, &cleared, 2);
|
|
4347
|
-
let report = be
|
|
4348
|
-
.inject(
|
|
4349
|
-
&Target::Pane(PaneId::new("%7")),
|
|
4350
|
-
&InjectPayload::Text(token_text),
|
|
4351
|
-
Key::Enter,
|
|
4352
|
-
true,
|
|
4353
|
-
)
|
|
4354
|
-
.expect("inject");
|
|
4355
|
-
assert_eq!(
|
|
4356
|
-
report.submit_verification,
|
|
4357
|
-
SubmitVerification::EnterSentWithoutPlaceholderCheck,
|
|
4358
|
-
"skin {skin:?} must consume after one extra C-m"
|
|
4359
|
-
);
|
|
4360
|
-
let n = count_submit_enters(&rec.lock().unwrap().clone());
|
|
4361
|
-
assert_eq!(n, 2, "skin {skin:?} extra C-m; got {n}");
|
|
4362
|
-
}
|
|
4363
|
-
}
|
|
4364
|
-
|
|
4365
|
-
#[test]
|
|
4366
|
-
fn unverified_payload_glyphs_do_not_resend_without_identity() {
|
|
4367
|
-
let marker = "[team-agent-token:msg_payload_glyph]";
|
|
4368
|
-
let token_text = format!("Team Agent message from leader:\ncomposer> ❯\n\n{marker}");
|
|
4369
|
-
let pending = "output\ncomposer> leftover from payload\n❯ quoted\n";
|
|
4370
|
-
let (be, rec) = backend_clears_after_n_enters(pending, pending, 99);
|
|
4371
|
-
let report = be
|
|
4372
|
-
.inject(
|
|
4373
|
-
&Target::Pane(PaneId::new("%7")),
|
|
4374
|
-
&InjectPayload::Text(token_text),
|
|
4375
|
-
Key::Enter,
|
|
4376
|
-
true,
|
|
4377
|
-
)
|
|
4378
|
-
.expect("inject");
|
|
4379
|
-
let calls = rec.lock().unwrap().clone();
|
|
4380
|
-
assert_eq!(
|
|
4381
|
-
count_submit_enters(&calls),
|
|
4382
|
-
1,
|
|
4383
|
-
"glyphs in payload must not cause extra C-m when token identity is gone; calls={calls:?}"
|
|
4384
|
-
);
|
|
4385
|
-
assert_eq!(
|
|
4386
|
-
report.submit_verification,
|
|
4387
|
-
SubmitVerification::SubmitConsumptionUnverified
|
|
4388
|
-
);
|
|
4389
|
-
}
|