diff --git a/crates/bashkit-cli/Cargo.toml b/crates/bashkit-cli/Cargo.toml new file mode 100644 index 00000000..00f012ce --- /dev/null +++ b/crates/bashkit-cli/Cargo.toml @@ -0,0 +1,21 @@ +# BashKit CLI - Command line interface for bashkit +# Run bash scripts in a sandboxed environment + +[package] +name = "bashkit-cli" +version.workspace = true +edition.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true +description = "Command line interface for BashKit sandboxed bash interpreter" + +[[bin]] +name = "bashkit" +path = "src/main.rs" + +[dependencies] +bashkit = { path = "../bashkit" } +tokio.workspace = true +clap.workspace = true +anyhow.workspace = true diff --git a/crates/bashkit-cli/src/main.rs b/crates/bashkit-cli/src/main.rs new file mode 100644 index 00000000..7cb39a99 --- /dev/null +++ b/crates/bashkit-cli/src/main.rs @@ -0,0 +1,66 @@ +//! BashKit CLI - Command line interface for sandboxed bash execution +//! +//! Usage: +//! bashkit -c 'echo hello' # Execute a command string +//! bashkit script.sh # Execute a script file +//! bashkit # Interactive REPL (not yet implemented) + +use anyhow::{Context, Result}; +use clap::Parser; +use std::path::PathBuf; + +/// BashKit - Sandboxed bash interpreter +#[derive(Parser, Debug)] +#[command(name = "bashkit")] +#[command(author, version, about, long_about = None)] +struct Args { + /// Execute the given command string + #[arg(short = 'c')] + command: Option, + + /// Script file to execute + #[arg()] + script: Option, + + /// Arguments to pass to the script + #[arg(trailing_var_arg = true)] + args: Vec, +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Args::parse(); + + let mut bash = bashkit::Bash::new(); + + // Execute command string if provided + if let Some(cmd) = args.command { + let result = bash.exec(&cmd).await.context("Failed to execute command")?; + print!("{}", result.stdout); + if !result.stderr.is_empty() { + eprint!("{}", result.stderr); + } + std::process::exit(result.exit_code); + } + + // Execute script file if provided + if let Some(script_path) = args.script { + let script = std::fs::read_to_string(&script_path) + .with_context(|| format!("Failed to read script: {}", script_path.display()))?; + + let result = bash + .exec(&script) + .await + .context("Failed to execute script")?; + print!("{}", result.stdout); + if !result.stderr.is_empty() { + eprint!("{}", result.stderr); + } + std::process::exit(result.exit_code); + } + + // Interactive REPL (not yet implemented) + eprintln!("bashkit: interactive mode not yet implemented"); + eprintln!("Usage: bashkit -c 'command' or bashkit script.sh"); + std::process::exit(1); +}