From fbfa87d6141b9752f5f7c525a22721583bf46e8c Mon Sep 17 00:00:00 2001 From: Vikram Bhaskaran Date: Tue, 13 Oct 2026 01:24:02 +1100 Subject: [PATCH] Treat a numeric --connect value as a loopback port. --- apps/lightcraft-cli/src/main.rs | 55 +++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/apps/lightcraft-cli/src/main.rs b/apps/lightcraft-cli/src/main.rs index 63a4deb76..e9d8575f6 100644 --- a/apps/lightcraft-cli/src/main.rs +++ b/apps/lightcraft-cli/src/main.rs @@ -303,16 +303,16 @@ fn mcp(args: &[String]) -> Result<(), String> { while i < args.len() { match args[i].as_str() { "--connect" => { - // Optional address argument. - match args.get(i + 1).filter(|a| !a.starts_with("--") && a.contains(':')) { - Some(a) => { - connect = Some(a.clone()); - i += 1; - } - None => connect = Some(DEFAULT_ADDR.to_string()), + let (addr, took) = connect_value(args.get(i + 1).map(String::as_str)); + connect = Some(addr); + if took { + i += 1; } } - a if a.starts_with("--connect=") => connect = Some(a["--connect=".len()..].to_string()), + a if a.starts_with("--connect=") => { + let (addr, _) = connect_value(Some(&a["--connect=".len()..])); + connect = Some(addr); + } "--headless" => connect = None, "--demo" => demo = true, "--compact" => compact = true, @@ -525,14 +525,17 @@ fn run(args: &[String]) -> Result<(), String> { i += 1; break; } - "--connect" => match args.get(i + 1).filter(|a| a.contains(':') && !a.contains('=')) { - Some(a) => { - connect = Some(a.clone()); + "--connect" => { + let (addr, took) = connect_value(args.get(i + 1).map(String::as_str)); + connect = Some(addr); + if took { i += 1; } - None => connect = Some(DEFAULT_ADDR.to_string()), }, - a if a.starts_with("--connect=") => connect = Some(a["--connect=".len()..].to_string()), + a if a.starts_with("--connect=") => { + let (addr, _) = connect_value(Some(&a["--connect=".len()..])); + connect = Some(addr); + } "--demo" => demo = true, "--library" => library = Some(take_value(args, &mut i, "--library")?.to_string()), "--import" => imports.push(take_value(args, &mut i, "--import")?.to_string()), @@ -627,6 +630,18 @@ fn take_value<'a>(args: &'a [String], i: &mut usize, flag: &str) -> Result<&'a s /// The port an `--connect` address names, for the recovery hint. The whole address when it has /// no port, so a hint is never built from a guess. +/// `--connect` takes an address, or a bare port (`7980` → `127.0.0.1:7980`). A following +/// command id is left alone (#1178). +fn connect_value(next: Option<&str>) -> (String, bool) { + match next { + Some(a) if !a.starts_with('-') && a.contains(':') && !a.contains('=') => (a.to_string(), true), + Some(a) if !a.is_empty() && a.bytes().all(|c| c.is_ascii_digit()) && a.parse::().ok().is_some_and(|p| p > 0) => { + (format!("127.0.0.1:{a}"), true) + } + _ => (DEFAULT_ADDR.to_string(), false), + } +} + fn connect_port(addr: &str) -> &str { addr.rsplit_once(':').map_or(addr, |(_, port)| port) } @@ -965,6 +980,20 @@ fn denoise_serve(args: &[String]) -> Result<(), String> { serve(listener, s.model, s.tile, s.device, s.run, opts, std::sync::Arc::new(|m: &str| eprintln!("lightcraft-cli denoise-serve: {m}"))) } +#[cfg(test)] +mod connect_tests { + use super::connect_value; + + #[test] + fn a_bare_port_is_loopback_and_a_command_is_not_consumed() { + assert_eq!(connect_value(Some("7980")), ("127.0.0.1:7980".into(), true)); + assert_eq!(connect_value(Some("127.0.0.1:7980")), ("127.0.0.1:7980".into(), true)); + assert_eq!(connect_value(Some("photo.rate")), ("127.0.0.1:7980".into(), false)); + assert_eq!(connect_value(Some("0")), ("127.0.0.1:7980".into(), false)); + assert_eq!(connect_value(None), ("127.0.0.1:7980".into(), false)); + } +} + #[cfg(not(feature = "denoise"))] fn denoise_serve(_: &[String]) -> Result<(), String> { Err("denoise-serve: this build has no denoise support (build with the `denoise` feature)".into())