mirror of
https://github.com/robcholz/vibebox.git
synced 2026-05-22 07:06:48 +02:00
refactor: remove old cli.
This commit is contained in:
+1
-1
@@ -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
@@ -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");
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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>>,
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user