refactor: remove old cli.

This commit is contained in:
robcholz
2026-02-07 15:10:05 -05:00
parent 0d7c4a7c7f
commit 8c816c38b7
6 changed files with 47 additions and 198 deletions
+1 -1
View File
@@ -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.
+17 -14
View File
@@ -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::<u64>().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");
+7 -1
View File
@@ -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::<u64>().ok())
-2
View File
@@ -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<Mutex<AppState>>,
config: Arc<Mutex<InstanceConfig>>,
+18 -176
View File
@@ -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<F>(args: CliArgs, io_handler: F) -> Result<(), Box<dyn std::error::Error>>
pub struct VmArg {
pub cpu_count: usize,
pub ram_bytes: u64,
pub no_default_mounts: bool,
pub mounts: Vec<String>,
}
pub fn run_with_args<F>(args: VmArg, io_handler: F) -> Result<(), Box<dyn std::error::Error>>
where
F: FnOnce(Arc<OutputMonitor>, OwnedFd, OwnedFd) -> IoContext,
{
@@ -129,7 +132,7 @@ where
}
pub(crate) fn run_with_args_and_extras<F>(
args: CliArgs,
args: VmArg,
io_handler: F,
extra_login_actions: Vec<LoginAction>,
extra_directory_shares: Vec<DirectoryShare>,
@@ -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 <count> Number of virtual CPUs (default {DEFAULT_CPU_COUNT}).
--ram <megabytes> RAM size in megabytes (default {DEFAULT_RAM_MB}).
--script <path/to/script.sh> Run script in VM.
--send <some-command> Type `some-command` followed by newline into the VM.
--expect <string> [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<PathBuf>,
version: bool,
help: bool,
no_default_mounts: bool,
mounts: Vec<String>,
login_actions: Vec<LoginAction>,
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<CliArgs, Box<dyn std::error::Error>> {
parse_cli_from(env::args_os())
}
pub fn parse_cli_from<I>(args: I) -> Result<CliArgs, Box<dyn std::error::Error>>
where
I: IntoIterator<Item = OsString>,
{
fn os_to_string(value: OsString, flag: &str) -> Result<String, Box<dyn std::error::Error>> {
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,
+4 -4
View File
@@ -91,7 +91,7 @@ pub fn ensure_manager(
}
pub fn run_manager(
args: vm::CliArgs,
args: vm::VmArg,
auto_shutdown_ms: u64,
) -> Result<(), Box<dyn std::error::Error>> {
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<LoginAction>,
extra_shares: Vec<DirectoryShare>,
config: Arc<Mutex<InstanceConfig>>,
@@ -406,7 +406,7 @@ struct RealVmExecutor;
impl VmExecutor for RealVmExecutor {
fn run_vm(
&self,
args: vm::CliArgs,
args: vm::VmArg,
extra_login_actions: Vec<LoginAction>,
extra_shares: Vec<DirectoryShare>,
config: Arc<Mutex<InstanceConfig>>,
@@ -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,