diff --git a/apps/lightcraft-cli/src/main.rs b/apps/lightcraft-cli/src/main.rs index 63a4deb7..b6cad57e 100644 --- a/apps/lightcraft-cli/src/main.rs +++ b/apps/lightcraft-cli/src/main.rs @@ -303,10 +303,14 @@ 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(':')) { + // Optional address argument. A bare port (all digits) is taken as a port on the + // loopback default — matches the help's `--connect [ADDR]` hint alongside the + // `--control 7980` example. A non-numeric, non-`--`-prefixed token (e.g. a + // command id like `ui.inspect`) leaves the address at its default so the + // command is still consumed next. (#1178) + match args.get(i + 1).filter(|a| a.contains(':') || a.chars().all(|c| c.is_ascii_digit())) { Some(a) => { - connect = Some(a.clone()); + connect = Some(if a.contains(':') { a.clone() } else { format!("127.0.0.1:{a}") }); i += 1; } None => connect = Some(DEFAULT_ADDR.to_string()), @@ -525,9 +529,9 @@ fn run(args: &[String]) -> Result<(), String> { i += 1; break; } - "--connect" => match args.get(i + 1).filter(|a| a.contains(':') && !a.contains('=')) { + "--connect" => match args.get(i + 1).filter(|a| !a.contains('=') && (a.contains(':') || a.chars().all(|c| c.is_ascii_digit()))) { Some(a) => { - connect = Some(a.clone()); + connect = Some(if a.contains(':') { a.clone() } else { format!("127.0.0.1:{a}") }); i += 1; } None => connect = Some(DEFAULT_ADDR.to_string()), diff --git a/apps/lightcraft-cli/tests/cli.rs b/apps/lightcraft-cli/tests/cli.rs index 9aafc931..bf56b02a 100644 --- a/apps/lightcraft-cli/tests/cli.rs +++ b/apps/lightcraft-cli/tests/cli.rs @@ -476,6 +476,28 @@ fn connect_failure_hint_names_the_attempted_port() { assert!(!err.contains("--control 7980"), "{err}"); } +/// Issue #1178: `--connect 7980 ui.inspect` (after `lightcraft --control 7980`) was leaving +/// `7980` unconsumed so it parsed as a command id and produced "unknown command `7980`". +/// A bare port is now taken as `127.0.0.1:`; the same address used with `:port` still +/// works; non-numeric, non-`ADDR`-shaped tokens (e.g. a real command id) keep falling through. +#[test] +fn connect_bare_port_is_treated_as_loopback_port() { + // Bare port: the failure hint names that port. + let (ok, _lines, err) = run_cli(&["--connect", "18437", "ui.inspect"], None); + assert!(!ok); + assert!(err.contains("--control 18437"), "bare port must reach the hint: {err}"); + assert!(!err.contains("--control 7980"), "{err}"); + // `:` still works (issue #167 case). + let (ok, _lines, err) = run_cli(&["--connect", "127.0.0.1:18437", "ui.inspect"], None); + assert!(!ok); + assert!(err.contains("--control 18437"), "{err}"); + // `--connect=` already worked (the `a.starts_with("--connect=")` arm); spot-check + // the hint matches its port too. + let (ok, _lines, err) = run_cli(&["--connect=18437", "ui.inspect"], None); + assert!(!ok); + assert!(err.contains("--control 18437"), "{err}"); +} + /// The CLI logs warnings on stderr (#168): with `RUST_LOG=warn` an unknown GPU backend name is /// reported, and `RUST_LOG=off` silences it. Before, no logger was installed and nothing appeared. #[test]