1use anyhow::{anyhow, Result};2use bifrostlink::declarative::RemoteEndpoints as _;3use bifrostlink::Remote;4use remowt_endpoints::pty::{PtyClient, ShellId};5use remowt_link_shared::{Address, BifConfig};67use crate::forwarded::RemowtStream;8use crate::Remowt;910pub struct RemowtShell {11 pub id: ShellId,12 pub stream: RemowtStream,13 remote: Remote<BifConfig>,14}15impl RemowtShell {16 pub fn resizer(&self) -> RemowtShellResizer {17 RemowtShellResizer {18 remote: self.remote.clone(),19 id: self.id,20 }21 }22}2324#[derive(Clone)]25pub struct RemowtShellResizer {26 remote: Remote<BifConfig>,27 id: ShellId,28}2930impl RemowtShellResizer {31 pub async fn resize(&self, cols: u16, rows: u16) -> Result<()> {32 PtyClient::wrap(self.remote.clone())33 .resize(self.id, cols, rows)34 .await?35 .map_err(|e| anyhow!("failed to resize remote shell: {e}"))36 }37}3839impl Remowt {40 pub async fn open_shell(41 &self,42 term: &str,43 cols: u16,44 rows: u16,45 escalate: bool,46 ) -> Result<RemowtShell> {47 let (forwarded, path) = self.bind_runtime_unix("shell").await?;48 let client: PtyClient<BifConfig> = if escalate {49 self.run0_endpoints().await?50 } else {51 self.endpoints()52 };53 let id = client54 .open_shell(path, term.to_owned(), cols, rows)55 .await?56 .map_err(|e| anyhow!("agent failed to open shell: {e}"))?;57 let stream = forwarded.accept().await?;5859 Ok(RemowtShell {60 id,61 stream,62 remote: self.0.rpc.remote(Address::Agent),63 })64 }65}