From 9fd08711e681b3578f1966092cd06aa32e31cb72 Mon Sep 17 00:00:00 2001 From: gram Date: Thu, 18 Sep 2025 19:25:00 +0200 Subject: [PATCH 1/2] add runtime launch command --- src/args.rs | 11 +++++++++++ src/cli.rs | 1 + src/commands/mod.rs | 2 +- src/commands/runtime.rs | 16 +++++++++++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/args.rs b/src/args.rs index 6cdfe7f..7a10f47 100644 --- a/src/args.rs +++ b/src/args.rs @@ -322,6 +322,10 @@ pub enum RuntimeCommands { #[clap(alias("shot"), alias("snap"), alias("photo"))] Screenshot, + /// Launch the given app. + #[clap(alias("start"), alias("execute"), alias("open"))] + Launch(LaunchArgs), + /// Restart the running app. #[clap(alias("reload"))] Restart, @@ -334,6 +338,13 @@ pub enum RuntimeCommands { Id, } +#[derive(Debug, Parser)] +pub struct LaunchArgs { + /// The app ID to launch. For example, "lux.snek". + #[arg()] + pub id: String, +} + #[derive(Debug, Parser)] pub struct ReplArgs { /// Path to the project root. diff --git a/src/cli.rs b/src/cli.rs index d3a8bb8..96bd420 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -33,6 +33,7 @@ pub fn run_command(vfs: PathBuf, command: &Commands) -> anyhow::Result<()> { NameCommands::Generate => cmd_name_generate(&vfs), }, Runtime(root_args) => match &root_args.command { + RuntimeCommands::Launch(args) => cmd_launch(root_args, args), RuntimeCommands::Restart => cmd_restart(root_args), RuntimeCommands::Exit => cmd_exit(root_args), RuntimeCommands::Id => cmd_id(root_args), diff --git a/src/commands/mod.rs b/src/commands/mod.rs index cac4d46..5f7860f 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -32,6 +32,6 @@ pub use monitor::cmd_monitor; pub use name::{cmd_name_generate, cmd_name_get, cmd_name_set}; pub use new::cmd_new; pub use repl::cmd_repl; -pub use runtime::{cmd_exit, cmd_id, cmd_restart, cmd_screenshot}; +pub use runtime::{cmd_exit, cmd_id, cmd_launch, cmd_restart, cmd_screenshot}; pub use shots::cmd_shots_download; pub use vfs::cmd_vfs; diff --git a/src/commands/runtime.rs b/src/commands/runtime.rs index 5bd50c1..a4f0a21 100644 --- a/src/commands/runtime.rs +++ b/src/commands/runtime.rs @@ -1,4 +1,4 @@ -use crate::args::RuntimeArgs; +use crate::args::{LaunchArgs, RuntimeArgs}; use crate::net::{connect, Stream}; use anyhow::{bail, Context, Result}; use firefly_types::serial; @@ -26,6 +26,20 @@ pub fn cmd_restart(root_args: &RuntimeArgs) -> Result<()> { wait_for_ok(stream) } +pub fn cmd_launch(root_args: &RuntimeArgs, args: &LaunchArgs) -> Result<()> { + println!("⏳️ connecting..."); + let mut stream = connect(root_args)?; + stream.set_timeout(2); + let Some((author_id, app_id)) = args.id.split_once('.') else { + bail!("the ID must contain a dot"); + }; + println!("⌛ launching {}...", args.id); + let id = (author_id.to_string(), app_id.to_string()); + let req = serial::Request::Launch(id); + stream.send(&req).context("send request")?; + wait_for_ok(stream) +} + pub fn cmd_id(root_args: &RuntimeArgs) -> Result<()> { eprintln!("⏳️ connecting..."); let mut stream = connect(root_args)?; From 41a48720a537f20f53a77df48b6f6e18a29af1c9 Mon Sep 17 00:00:00 2001 From: gram Date: Thu, 18 Sep 2025 19:48:43 +0200 Subject: [PATCH 2/2] validate ID, show logs --- src/commands/runtime.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/commands/runtime.rs b/src/commands/runtime.rs index a4f0a21..e0af7ff 100644 --- a/src/commands/runtime.rs +++ b/src/commands/runtime.rs @@ -30,9 +30,20 @@ pub fn cmd_launch(root_args: &RuntimeArgs, args: &LaunchArgs) -> Result<()> { println!("⏳️ connecting..."); let mut stream = connect(root_args)?; stream.set_timeout(2); + + if args.id == "sys.connector" || args.id == "sys.disconnector" { + bail!("cannot connect or disconnect through CLI yet"); + } let Some((author_id, app_id)) = args.id.split_once('.') else { bail!("the ID must contain a dot"); }; + if let Err(err) = firefly_types::validate_id(author_id) { + bail!("invalid author ID: {err}"); + } + if let Err(err) = firefly_types::validate_id(app_id) { + bail!("invalid app ID: {err}"); + } + println!("⌛ launching {}...", args.id); let id = (author_id.to_string(), app_id.to_string()); let req = serial::Request::Launch(id); @@ -79,9 +90,15 @@ fn wait_for_ok(stream: Box) -> Result<()> { let mut stream = stream; for _ in 0..5 { let resp = stream.next()?; - if matches!(resp, serial::Response::Ok) { - println!("✅ done"); - return Ok(()); + match resp { + serial::Response::Ok => { + println!("✅ done"); + return Ok(()); + } + serial::Response::Log(log) => { + println!("🪵 {log}"); + } + _ => {} } } bail!("timed out waiting for response")