1use anyhow::{anyhow, Result};
2use bifrostlink::declarative::RemoteEndpoints as _;
3use bifrostlink::Remote;
4use remowt_endpoints::pty::{PtyClient, ShellId};
5use remowt_link_shared::{Address, BifConfig};
6
7use crate::forwarded::RemowtStream;
8use crate::Remowt;
9
10pub 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}
23
24#[derive(Clone)]
25pub struct RemowtShellResizer {
26 remote: Remote<BifConfig>,
27 id: ShellId,
28}
29
30impl 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}
38
39impl 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 = client
54 .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?;
58
59 Ok(RemowtShell {
60 id,
61 stream,
62 remote: self.0.rpc.remote(Address::Agent),
63 })
64 }
65}