diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-19 13:35:40 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-19 13:35:40 +0300 |
| commit | 70c45dbeb3a7c62a7c87fe7c52e3e6d5a3acb0d5 (patch) | |
| tree | d1427a4818e61a24021da7a11cc0b3a061fa428c | |
| parent | fe53984c4092ef00cab51b1ddd77c5b890786670 (diff) | |
fix: hide explicit client command
refs #187
| -rw-r--r-- | docs/next/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | src/main.rs | 32 | ||||
| -rw-r--r-- | tests/cli_wrapper.rs | 38 |
3 files changed, 56 insertions, 17 deletions
diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md index 02f23fad..58af43d6 100644 --- a/docs/next/CHANGELOG.md +++ b/docs/next/CHANGELOG.md @@ -7,6 +7,9 @@ - Added a Hermes Agent plugin integration for direct state reporting. - Added `ui.sidebar_min_width` and `ui.sidebar_max_width` to configure the sidebar's expanded resize bounds. Defaults remain 18 and 36 columns; existing configs are unchanged. +### Fixed +- Running the internal `herdr client` command from inside Herdr now respects the nested-launch guard, and the command is no longer advertised in root help. (#187) + ### Breaking Changes - The client/server protocol is now version 7. Stop and restart any running v0.5.10 server before attaching with this release. diff --git a/src/main.rs b/src/main.rs index 2c17e704..efdd08b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -211,6 +211,16 @@ fn random_nested_message() -> &'static str { NESTED_HERDR_MESSAGES[index] } +fn exit_if_nested_disabled(config: &config::Config) { + if should_block_nested(config) { + eprintln!("\x1b[1merror:\x1b[0m nested herdr is disabled by default."); + eprintln!("see configuration if you want to enable it."); + eprintln!(); + eprintln!("\x1b[2m\"{}\"\x1b[0m", random_nested_message()); + std::process::exit(1); + } +} + fn main() -> io::Result<()> { let raw_args: Vec<String> = std::env::args().collect(); let args = match session::configure_from_args(&raw_args) { @@ -257,8 +267,10 @@ fn main() -> io::Result<()> { return server::headless::run_server(); } - // Client mode: connect to an existing server's client socket. + // Hidden client mode: connect to an existing server's client socket. if args.get(1).map(|s| s.as_str()) == Some("client") { + let loaded_config = config::Config::load(); + exit_if_nested_disabled(&loaded_config.config); return client::run_client(); } @@ -340,15 +352,7 @@ fn main() -> io::Result<()> { } println!(); println!("Advanced commands:"); - for (command, description) in [ - ("herdr server", "Run as headless server"), - ( - "herdr client", - "Connect to a running server as a thin client", - ), - ] { - println!(" {command:<32} {description}"); - } + println!(" {:<32} Run as headless server", "herdr server"); println!(); println!("Options:"); println!(" --no-session Run monolithically (no server/client, escape hatch)"); @@ -418,13 +422,7 @@ fn main() -> io::Result<()> { } let loaded_config = config::Config::load(); - if should_block_nested(&loaded_config.config) { - eprintln!("\x1b[1merror:\x1b[0m nested herdr is disabled by default."); - eprintln!("see configuration if you want to enable it."); - eprintln!(); - eprintln!("\x1b[2m\"{}\"\x1b[0m", random_nested_message()); - std::process::exit(1); - } + exit_if_nested_disabled(&loaded_config.config); let no_session = args.iter().any(|a| a == "--no-session"); diff --git a/tests/cli_wrapper.rs b/tests/cli_wrapper.rs index affcb89a..aa06302e 100644 --- a/tests/cli_wrapper.rs +++ b/tests/cli_wrapper.rs @@ -591,6 +591,44 @@ fn help_commands_exit_successfully() { } #[test] +fn root_help_hides_explicit_client_command() { + let output = Command::new(env!("CARGO_BIN_EXE_herdr")) + .arg("--help") + .output() + .unwrap(); + + assert!(output.status.success()); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!( + !stdout.contains("herdr client"), + "root help should not advertise the internal client command: {stdout}" + ); +} + +#[test] +fn explicit_client_command_respects_nested_guard() { + let base = unique_test_dir(); + fs::create_dir_all(&base).unwrap(); + + let output = Command::new(env!("CARGO_BIN_EXE_herdr")) + .arg("client") + .env("HERDR_ENV", "1") + .env("XDG_CONFIG_HOME", &base) + .env_remove("HERDR_CONFIG_PATH") + .output() + .unwrap(); + + cleanup_test_base(&base); + + assert_eq!(output.status.code(), Some(1)); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("nested herdr is disabled by default"), + "client should fail at the nested guard before connecting: {stderr}" + ); +} + +#[test] fn removed_show_changelog_flag_fails_before_nested_guard() { let output = Command::new(env!("CARGO_BIN_EXE_herdr")) .arg("--show-changelog") |
