aboutsummaryrefslogtreecommitdiff
path: root/src/app/api/panes.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-17 23:55:08 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-17 23:59:56 +0300
commite0758c32118f2aa006db3d8fa4b41833fe6e7ead (patch)
tree2b29dd61ebf870db8d0ac95cc0b4515178c834c4 /src/app/api/panes.rs
parent040956531f673c8fb7720037494ed4e61b123c6c (diff)
feat: harden named agent cli workflows
refs #1525
Diffstat (limited to 'src/app/api/panes.rs')
-rw-r--r--src/app/api/panes.rs51
1 files changed, 36 insertions, 15 deletions
diff --git a/src/app/api/panes.rs b/src/app/api/panes.rs
index 17569682..6a5b41fe 100644
--- a/src/app/api/panes.rs
+++ b/src/app/api/panes.rs
@@ -20,9 +20,8 @@ use crate::app::Mode;
use crate::layout::{find_in_direction, NavDirection, PaneId};
use super::super::api_helpers::{
- detect_state_from_api, encode_api_keys, encode_api_text, normalize_metadata_source,
- normalize_metadata_tokens, normalize_metadata_ttl, normalize_reported_agent_label,
- MAX_METADATA_TOKEN_KEYS_PER_RESOURCE,
+ detect_state_from_api, encode_api_keys, normalize_metadata_source, normalize_metadata_tokens,
+ normalize_metadata_ttl, normalize_reported_agent_label, MAX_METADATA_TOKEN_KEYS_PER_RESOURCE,
};
#[cfg(test)]
use super::super::api_helpers::{METADATA_SOURCE_MAX_CHARS, METADATA_TTL_MAX_MS};
@@ -1499,20 +1498,16 @@ impl App {
let Some(runtime) = self.lookup_runtime_sender(ws_idx, pane_id) else {
return pane_not_found(id, &params.pane_id);
};
- let encoded_keys = match encode_api_keys(runtime, &params.keys) {
- Ok(encoded_keys) => encoded_keys,
+ let bytes = match super::super::api_helpers::encode_api_input(
+ runtime,
+ &params.text,
+ &params.keys,
+ ) {
+ Ok(bytes) => bytes,
Err(key) => return encode_error(id, "invalid_key", format!("unsupported key {key}")),
};
- if !params.text.is_empty() {
- let text_bytes = encode_api_text(runtime, &params.text);
- if let Err(err) = runtime.try_send_bytes(Bytes::from(text_bytes)) {
- return encode_error(id, "pane_send_failed", err.to_string());
- }
- }
- for bytes in encoded_keys {
- if let Err(err) = runtime.try_send_bytes(Bytes::from(bytes)) {
- return encode_error(id, "pane_send_failed", err.to_string());
- }
+ if let Err(err) = runtime.try_send_bytes(Bytes::from(bytes)) {
+ return encode_error(id, "pane_send_failed", err.to_string());
}
encode_success(id, ResponseResult::Ok {})
@@ -2072,6 +2067,32 @@ mod tests {
}
#[tokio::test]
+ async fn api_pane_send_input_brackets_text_and_enter_atomically() {
+ let (mut app, pane_id, mut rx) = app_with_send_key_runtime(1);
+ let internal_pane_id = app.state.workspaces[0].tabs[0].root_pane;
+ app.lookup_runtime_sender(0, internal_pane_id)
+ .unwrap()
+ .test_process_pty_bytes(b"\x1b[?2004h");
+
+ let response = app.handle_api_request(crate::api::schema::Request {
+ id: "req".into(),
+ method: crate::api::schema::Method::PaneSendInput(PaneSendInputParams {
+ pane_id,
+ text: "A != B".into(),
+ keys: vec!["Enter".into()],
+ }),
+ });
+
+ let success: SuccessResponse = serde_json::from_str(&response).unwrap();
+ assert_eq!(success.result, ResponseResult::Ok {});
+ assert_eq!(
+ rx.try_recv().unwrap(),
+ bytes::Bytes::from_static(b"\x1b[200~A != B\x1b[201~\r")
+ );
+ assert!(rx.try_recv().is_err());
+ }
+
+ #[tokio::test]
async fn api_pane_send_input_keys_accept_key_combo_chords() {
let (mut app, pane_id, mut rx) = app_with_send_key_runtime(1);