agentmux_srv/backend/blockcontroller/shell/
ssh_pane.rs1use std::path::Path;
13use std::sync::Arc;
14
15use portable_pty::CommandBuilder;
16
17use super::file_ops::handle_append_block_file;
18use crate::backend::mps::Broker;
19use crate::backend::remote::conn::SshDest;
20use crate::backend::remote::{askpass, link, ssh};
21use crate::backend::storage::filestore::FileStore;
22
23pub(super) fn command(
29 ssh_path: &Path,
30 dest: &SshDest,
31 (cmd, cmd_args, cwd): (&str, &[String], &str),
32 askpass_secret: Option<&str>,
33 auth_key: &str,
34 block_id: &str,
35) -> CommandBuilder {
36 let mut args = ssh::launch(dest, cmd, cmd_args, cwd, ssh::shared_control_dir().as_deref());
37 ssh::set_pane_env(&mut args, block_id);
38 tracing::info!(dest = %dest.destination, args = ?args, "ssh spawn path");
39 let mut c = CommandBuilder::new(ssh_path);
40 c.args(args.iter().map(String::as_str));
41 c.env("TERM", "xterm-256color");
42 c.env("COLORTERM", "truecolor");
43 crate::backend::pane_env::sanitize_pty_command(&mut c);
46 if let (Some(secret), Some(program)) = (askpass_secret, askpass::program()) {
47 let local_url = std::env::var("AGENTMUX_LOCAL_URL").unwrap_or_default();
48 for (k, v) in askpass::ssh_env(secret, &program, &local_url, auth_key) {
49 c.env(k, v);
50 }
51 }
52 c
53}
54
55pub(super) fn ended(conn: &str, dest: &str, raw_exit_code: Option<u32>, stopped_by_srv: bool) -> Option<String> {
61 let lost = ssh::pane_lost_connection(raw_exit_code, stopped_by_srv);
62 let note = lost.then(|| {
63 if link::held(conn) {
64 link::disconnected_note(conn)
65 } else {
66 ssh::lost_note(conn)
67 }
68 });
69 link::pane_ended(conn, lost.then(|| ssh::lost_message(dest)).as_deref());
70 note
71}
72
73pub(super) async fn write_note(broker: Arc<Broker>, filestore: Option<Arc<FileStore>>, block_id: String, text: String) {
76 let _ = tokio::task::spawn_blocking(move || {
77 let note = super::super::pane_note(&text);
78 handle_append_block_file(&broker, &block_id, "term", ¬e, filestore.as_ref(), None)
79 })
80 .await;
81}