aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/next/CHANGELOG.md3
-rw-r--r--src/main.rs32
-rw-r--r--tests/cli_wrapper.rs38
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")