use std::io::Write;
use anyhow::{Result, anyhow};
use clap::Subcommand;
use crate::mcp::BasemindServer;
use crate::mcp::params::*;
use super::render::{Emit, emit};
use super::run_tool;
#[derive(Subcommand, Debug)]
pub enum ShellCmd {
Spawn {
command: String,
#[arg(long)]
cwd: Option<String>,
#[arg(long = "env", value_name = "KEY=VALUE")]
env: Vec<String>,
#[arg(long)]
title: Option<String>,
},
Send {
session_id: String,
text: String,
#[arg(long)]
no_enter: bool,
},
Capture {
session_id: String,
#[arg(long)]
lines: Option<usize>,
},
Kill {
session_id: String,
},
List,
Broadcast {
text: String,
#[arg(long = "session", value_name = "SESSION_ID", required = true)]
session_ids: Vec<String>,
#[arg(long)]
no_enter: bool,
},
}
fn parse_env(raw: &str) -> Result<ShellEnv> {
let (key, value) = raw
.split_once('=')
.ok_or_else(|| anyhow!("invalid --env {raw:?}: expected KEY=VALUE"))?;
Ok(ShellEnv {
key: key.to_string(),
value: value.to_string(),
})
}
pub async fn run(server: &BasemindServer, cmd: ShellCmd, opts: &Emit, out: &mut impl Write) -> Result<()> {
let p = match cmd {
ShellCmd::Spawn {
command,
cwd,
env,
title,
} => {
let env = if env.is_empty() {
None
} else {
Some(env.iter().map(|e| parse_env(e)).collect::<Result<_>>()?)
};
ShellParams {
command: Some(command),
cwd: cwd.map(|c| c.as_str().into()),
env,
title,
..ShellParams::new(ShellMode::Spawn)
}
}
ShellCmd::Send {
session_id,
text,
no_enter,
} => ShellParams {
session_id: Some(session_id),
text: Some(text),
enter: Some(!no_enter),
..ShellParams::new(ShellMode::Send)
},
ShellCmd::Capture { session_id, lines } => ShellParams {
session_id: Some(session_id),
lines,
..ShellParams::new(ShellMode::Capture)
},
ShellCmd::Kill { session_id } => ShellParams {
session_id: Some(session_id),
..ShellParams::new(ShellMode::Kill)
},
ShellCmd::List => ShellParams::new(ShellMode::List),
ShellCmd::Broadcast {
text,
session_ids,
no_enter,
} => ShellParams {
session_ids: Some(session_ids),
text: Some(text),
enter: Some(!no_enter),
..ShellParams::new(ShellMode::Broadcast)
},
};
let key = p.mode.telemetry_key();
let r = run_tool(key, server.shell(Parameters(Lenient(p))).await)?;
emit(key, &r, opts, out)
}