aft/list_surfaces/
bash.rs1use crate::list_envelope::{derive_wire_key, ListEnvelope, Reason, Total, Unit};
11use crate::list_surfaces::ReasonKind;
12
13pub const LIST_ID: &str = "bash.output";
15
16pub const WIRE_KEY: &str = "bash_output_list_envelope";
18
19pub const UNIT: Unit = Unit::Lines;
21
22pub const REASON: Reason = Reason::Cap;
24
25pub const REASON_KIND: ReasonKind = ReasonKind::Selecting;
27
28pub const NARROW: &[&str] = &[];
30
31#[inline]
33pub fn count_output_lines(output: &str) -> usize {
34 output.lines().count()
35}
36
37#[inline]
39pub fn wire_key() -> String {
40 derive_wire_key(LIST_ID, true)
41}
42
43pub fn build_bash_output_envelope(shown: usize, total_input_lines: usize) -> Option<ListEnvelope> {
49 if shown >= total_input_lines {
50 None
51 } else {
52 Some(ListEnvelope::new(
53 shown,
54 Total::Exact(total_input_lines),
55 UNIT,
56 vec![REASON],
57 NARROW,
58 ))
59 }
60}
61
62pub fn build_envelope_from_output(
69 agent_received_output: &str,
70 input_line_count: usize,
71) -> Option<ListEnvelope> {
72 let shown = count_output_lines(agent_received_output);
73 build_bash_output_envelope(shown, input_line_count)
74}
75
76pub fn append_envelope_trailer(
81 agent_received_output: &mut String,
82 input_line_count: usize,
83) -> Option<ListEnvelope> {
84 let body_lines = count_output_lines(agent_received_output);
85 if body_lines >= input_line_count {
86 return None;
87 }
88
89 let envelope = ListEnvelope::new(
90 body_lines.saturating_add(1),
91 Total::Exact(input_line_count),
92 UNIT,
93 vec![REASON],
94 NARROW,
95 );
96 let trailer = envelope_trailer(&envelope);
97 if !agent_received_output.is_empty() && !agent_received_output.ends_with('\n') {
98 agent_received_output.push('\n');
99 }
100 agent_received_output.push_str(&trailer);
101 Some(envelope)
102}
103
104pub fn envelope_trailer(envelope: &ListEnvelope) -> String {
109 let mut data = serde_json::Map::new();
110 data.insert(
111 derive_wire_key(LIST_ID, false),
112 serde_json::to_value(envelope).expect("ListEnvelope serialization"),
113 );
114 crate::ndjson_text::build_ndjson_text(
115 "",
116 &serde_json::Value::Object(data),
117 Some(LIST_ID),
118 false,
119 )
120}
121
122pub fn attach_bash_output_envelope(
124 data: &mut serde_json::Map<String, serde_json::Value>,
125 envelope: &Option<ListEnvelope>,
126) {
127 if let Some(env) = envelope {
128 data.insert(
129 WIRE_KEY.to_string(),
130 serde_json::to_value(env).expect("ListEnvelope serialization"),
131 );
132 }
133}
134
135pub fn produce_bash_reply_data(
137 output: String,
138 envelope: Option<ListEnvelope>,
139) -> serde_json::Map<String, serde_json::Value> {
140 let mut map = serde_json::Map::new();
141 map.insert("output".to_string(), serde_json::Value::String(output));
142 attach_bash_output_envelope(&mut map, &envelope);
143 map
144}