diff --git a/docs/tasks.md b/docs/tasks.md index 19f1257..ac33a5a 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -44,7 +44,7 @@ 7. [x] setup vibebox commands 8. [ ] setup cli commands. 1. [x] Organize all the params. - 2. [ ] Remove old cli. + 2. [x] Remove old cli. 3. [ ] add an actual config file. 4. [ ] set up the cli. 9. [ ] fix ui overlap, and consistency issue. diff --git a/src/bin/vibebox-cli.rs b/src/bin/vibebox-cli.rs index 6e35e3c..9044830 100644 --- a/src/bin/vibebox-cli.rs +++ b/src/bin/vibebox-cli.rs @@ -21,7 +21,13 @@ fn main() -> Result<()> { if env::var("VIBEBOX_VM_MANAGER").as_deref() == Ok("1") { tracing::info!("starting vm manager mode"); - let args = vm::parse_cli().map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?; + // TODO: wire CLI args into VmArg once we reintroduce CLI parsing. + let args = vm::VmArg { + cpu_count: 2, + ram_bytes: 2048 * 1024 * 1024, + no_default_mounts: false, + mounts: Vec::new(), + }; let auto_shutdown_ms = env::var("VIBEBOX_AUTO_SHUTDOWN_MS") .ok() .and_then(|value| value.parse::().ok()) @@ -34,23 +40,20 @@ fn main() -> Result<()> { return Ok(()); } - let args = vm::parse_cli().map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?; - tracing::debug!("parsed cli args"); - if args.version() { - vm::print_version(); - return Ok(()); - } - if args.help() { - vm::print_help(); - return Ok(()); - } - vm::ensure_signed(); + // TODO: wire CLI args into VmArg once we reintroduce CLI parsing. + let vm_args = vm::VmArg { + cpu_count: 2, + ram_bytes: 2048 * 1024 * 1024, + no_default_mounts: false, + mounts: Vec::new(), + }; + let vm_info = VmInfo { version: env!("CARGO_PKG_VERSION").to_string(), - max_memory_mb: args.ram_mb(), - cpu_cores: args.cpu_count(), + max_memory_mb: vm_args.ram_bytes / (1024 * 1024), + cpu_cores: vm_args.cpu_count, }; let cwd = env::current_dir().map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?; tracing::info!(cwd = %cwd.display(), "starting vibebox cli"); diff --git a/src/bin/vibebox-supervisor.rs b/src/bin/vibebox-supervisor.rs index 1665315..584fa5f 100644 --- a/src/bin/vibebox-supervisor.rs +++ b/src/bin/vibebox-supervisor.rs @@ -19,7 +19,13 @@ fn main() -> Result<()> { let instance_dir = instance::ensure_instance_dir(&cwd) .map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?; let _ = instance::touch_last_active(&instance_dir); - let args = vm::parse_cli().map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?; + // TODO: wire CLI args into VmArg once we reintroduce CLI parsing. + let args = vm::VmArg { + cpu_count: 2, + ram_bytes: 2048 * 1024 * 1024, + no_default_mounts: false, + mounts: Vec::new(), + }; let auto_shutdown_ms = env::var("VIBEBOX_AUTO_SHUTDOWN_MS") .ok() .and_then(|value| value.parse::().ok()) diff --git a/src/instance.rs b/src/instance.rs index cdc3a4f..c31ba9c 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -26,7 +26,6 @@ use crate::{ }; const SSH_KEY_NAME: &str = "ssh_key"; -#[allow(dead_code)] pub(crate) const SERIAL_LOG_NAME: &str = "serial.log"; const DEFAULT_SSH_USER: &str = "vibecoder"; const SSH_CONNECT_RETRIES: usize = 30; @@ -353,7 +352,6 @@ pub(crate) fn build_ssh_login_actions( vec![LoginAction::Send(setup)] } -#[allow(dead_code)] fn spawn_ssh_io( app: Arc>, config: Arc>, diff --git a/src/vm.rs b/src/vm.rs index 67680ac..d8d4361 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,8 +1,6 @@ use crate::session_manager::{GLOBAL_CACHE_DIR_NAME, INSTANCE_DIR_NAME}; use std::{ - env, - ffi::OsString, - fs, + env, fs, io::{self, Write}, os::{ fd::RawFd, @@ -25,7 +23,6 @@ use std::{ use block2::RcBlock; use dispatch2::DispatchQueue; -use lexopt::prelude::*; use objc2::{AnyThread, rc::Retained, runtime::ProtocolObject}; use objc2_foundation::*; use objc2_virtualization::*; @@ -40,7 +37,6 @@ const DEFAULT_CPU_COUNT: usize = 2; const DEFAULT_RAM_MB: u64 = 2048; const DEFAULT_RAM_BYTES: u64 = DEFAULT_RAM_MB * BYTES_PER_MB; const START_TIMEOUT: Duration = Duration::from_secs(60); -const DEFAULT_EXPECT_TIMEOUT: Duration = Duration::from_secs(30); const LOGIN_EXPECT_TIMEOUT: Duration = Duration::from_secs(120); const PROVISION_SCRIPT: &str = include_str!("provision.sh"); const PROVISION_SCRIPT_NAME: &str = "provision.sh"; @@ -121,7 +117,14 @@ impl DirectoryShare { } } -pub fn run_with_args(args: CliArgs, io_handler: F) -> Result<(), Box> +pub struct VmArg { + pub cpu_count: usize, + pub ram_bytes: u64, + pub no_default_mounts: bool, + pub mounts: Vec, +} + +pub fn run_with_args(args: VmArg, io_handler: F) -> Result<(), Box> where F: FnOnce(Arc, OwnedFd, OwnedFd) -> IoContext, { @@ -129,7 +132,7 @@ where } pub(crate) fn run_with_args_and_extras( - args: CliArgs, + args: VmArg, io_handler: F, extra_login_actions: Vec, extra_directory_shares: Vec, @@ -172,22 +175,14 @@ where let mise_directory_share = DirectoryShare::new(guest_mise_cache, "/root/.local/share/mise".into(), false)?; - let disk_path = if let Some(path) = args.disk { - if !path.exists() { - return Err(format!("Disk image does not exist: {}", path.display()).into()); - } - path - } else { - ensure_default_image( - &base_raw, - &base_compressed, - &default_raw, - std::slice::from_ref(&mise_directory_share), - )?; - ensure_instance_disk(&instance_raw, &default_raw)?; - - instance_raw - }; + ensure_default_image( + &base_raw, + &base_compressed, + &default_raw, + std::slice::from_ref(&mise_directory_share), + )?; + ensure_instance_disk(&instance_raw, &default_raw)?; + let disk_path = instance_raw; let mut login_actions = Vec::new(); let mut directory_shares = Vec::new(); @@ -236,9 +231,6 @@ where login_actions.extend(extra_login_actions); - // Any user-provided login actions must come after our system ones - login_actions.extend(args.login_actions); - run_vm_with_io( &disk_path, &login_actions, @@ -249,156 +241,6 @@ where ) } -pub fn print_help() { - println!( - "Vibe is a quick way to spin up a Linux virtual machine on Mac to sandbox LLM agents. - -vibe [OPTIONS] [disk-image.raw] - -Options - - --help Print this help message. - --version Print the version (commit SHA). - --no-default-mounts Disable all default mounts. - --mount host-path:guest-path[:read-only | :read-write] Mount `host-path` inside VM at `guest-path`. - Defaults to read-write. - Errors if host-path does not exist. - --cpus Number of virtual CPUs (default {DEFAULT_CPU_COUNT}). - --ram RAM size in megabytes (default {DEFAULT_RAM_MB}). - --script Run script in VM. - --send Type `some-command` followed by newline into the VM. - --expect [timeout-seconds] Wait for `string` to appear in console output before executing next `--script` or `--send`. - If `string` does not appear within timeout (default 30 seconds), shutdown VM with error. -" - ); -} - -pub fn print_version() { - println!("Vibe"); - println!("https://github.com/lynaghk/vibe/"); - println!("Git SHA: {}", env!("GIT_SHA")); -} - -pub struct CliArgs { - disk: Option, - version: bool, - help: bool, - no_default_mounts: bool, - mounts: Vec, - login_actions: Vec, - cpu_count: usize, - ram_bytes: u64, -} - -impl CliArgs { - pub fn version(&self) -> bool { - self.version - } - - pub fn help(&self) -> bool { - self.help - } - - pub fn cpu_count(&self) -> usize { - self.cpu_count - } - - pub fn ram_bytes(&self) -> u64 { - self.ram_bytes - } - - pub fn ram_mb(&self) -> u64 { - self.ram_bytes / BYTES_PER_MB - } -} - -pub fn parse_cli() -> Result> { - parse_cli_from(env::args_os()) -} - -pub fn parse_cli_from(args: I) -> Result> -where - I: IntoIterator, -{ - fn os_to_string(value: OsString, flag: &str) -> Result> { - value - .into_string() - .map_err(|_| format!("{flag} expects valid UTF-8").into()) - } - - let mut parser = lexopt::Parser::from_iter(args); - let mut disk = None; - let mut version = false; - let mut help = false; - let mut no_default_mounts = false; - let mut mounts = Vec::new(); - let mut login_actions = Vec::new(); - let mut script_index = 0; - let mut cpu_count = DEFAULT_CPU_COUNT; - let mut ram_bytes = DEFAULT_RAM_BYTES; - - while let Some(arg) = parser.next()? { - match arg { - Long("version") => version = true, - Long("help") | Short('h') => help = true, - Long("no-default-mounts") => no_default_mounts = true, - Long("cpus") => { - let value = os_to_string(parser.value()?, "--cpus")?.parse()?; - if value == 0 { - return Err("--cpus must be >= 1".into()); - } - cpu_count = value; - } - Long("ram") => { - let value: u64 = os_to_string(parser.value()?, "--ram")?.parse()?; - if value == 0 { - return Err("--ram must be >= 1".into()); - } - ram_bytes = value * BYTES_PER_MB; - } - Long("mount") => { - mounts.push(os_to_string(parser.value()?, "--mount")?); - } - Long("script") => { - login_actions.push(Script { - path: os_to_string(parser.value()?, "--script")?.into(), - index: script_index, - }); - script_index += 1; - } - Long("send") => { - login_actions.push(Send(os_to_string(parser.value()?, "--send")?)); - } - Long("expect") => { - let text = os_to_string(parser.value()?, "--expect")?; - let timeout = match parser.optional_value() { - Some(value) => Duration::from_secs(os_to_string(value, "--expect")?.parse()?), - None => DEFAULT_EXPECT_TIMEOUT, - }; - login_actions.push(Expect { text, timeout }); - } - Value(value) => { - if disk.is_some() { - return Err("Only one disk path may be provided".into()); - } - disk = Some(PathBuf::from(value)); - } - _ => return Err(arg.unexpected().into()), - } - } - - Ok(CliArgs { - disk, - version, - help, - no_default_mounts, - mounts, - login_actions, - cpu_count, - ram_bytes, - }) -} - fn script_command_from_path( path: &Path, index: usize, diff --git a/src/vm_manager.rs b/src/vm_manager.rs index 8745679..ebbe423 100644 --- a/src/vm_manager.rs +++ b/src/vm_manager.rs @@ -91,7 +91,7 @@ pub fn ensure_manager( } pub fn run_manager( - args: vm::CliArgs, + args: vm::VmArg, auto_shutdown_ms: u64, ) -> Result<(), Box> { let project_root = env::current_dir()?; @@ -392,7 +392,7 @@ struct ManagerOptions { trait VmExecutor { fn run_vm( &self, - args: vm::CliArgs, + args: vm::VmArg, extra_login_actions: Vec, extra_shares: Vec, config: Arc>, @@ -406,7 +406,7 @@ struct RealVmExecutor; impl VmExecutor for RealVmExecutor { fn run_vm( &self, - args: vm::CliArgs, + args: vm::VmArg, extra_login_actions: Vec, extra_shares: Vec, config: Arc>, @@ -435,7 +435,7 @@ impl VmExecutor for RealVmExecutor { fn run_manager_with( project_root: &Path, - args: vm::CliArgs, + args: vm::VmArg, auto_shutdown_ms: u64, executor: &dyn VmExecutor, options: ManagerOptions,