aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli/spec.rs42
-rw-r--r--src/main.rs13
2 files changed, 52 insertions, 3 deletions
diff --git a/src/cli/spec.rs b/src/cli/spec.rs
index f3d0d271..1f2e85a4 100644
--- a/src/cli/spec.rs
+++ b/src/cli/spec.rs
@@ -18,6 +18,7 @@ pub(super) fn command() -> Command {
)
.arg(flag("handoff").help("Opt into live handoff for update or remote attach"))
.arg(flag("default-config").help("Print default configuration and exit"))
+ .arg(flag("skill").help("Print the agent skill file and exit"))
.arg(
Arg::new("version")
.short('V')
@@ -426,7 +427,7 @@ fn agent_command() -> Command {
.last(true),
)
.after_help(
- "The pane must be at its interactive shell prompt. Success means the expected agent was detected in the same terminal and is ready for input.",
+ "The pane must be at its interactive shell prompt. Success means the expected agent was detected in the same terminal and is ready for input.\n\nnext: herdr agent prompt <TARGET> <TEXT> --wait",
),
)
.subcommand(
@@ -568,7 +569,10 @@ fn pane_command() -> Command {
Command::new("send-text")
.about("Send literal text to a pane")
.arg(required("pane_id", "PANE_ID"))
- .arg(required("text", "TEXT")),
+ .arg(required("text", "TEXT"))
+ .after_help(
+ "next: herdr pane run <PANE_ID> <COMMAND> sends text and Enter in one call",
+ ),
)
.subcommand(
Command::new("send-keys")
@@ -1269,6 +1273,40 @@ mod tests {
.any(|arg| arg.get_id() == "agent_args"));
}
+ fn long_help(path: &[&str]) -> String {
+ let mut args = vec!["herdr".to_string()];
+ args.extend(path.iter().map(|segment| segment.to_string()));
+ args.push("--help".to_string());
+ let mut output = Vec::new();
+ assert!(
+ super::write_requested_help(&args, &mut output).unwrap(),
+ "help was not handled for herdr {}",
+ path.join(" ")
+ );
+ String::from_utf8(output).unwrap()
+ }
+
+ #[test]
+ fn next_step_hints_render_without_replacing_existing_after_help() {
+ let agent_start = long_help(&["agent", "start"]);
+ assert!(
+ agent_start.contains("The pane must be at its interactive shell prompt."),
+ "agent start dropped its existing after_help: {agent_start}"
+ );
+ assert!(
+ agent_start.contains("next: herdr agent prompt <TARGET> <TEXT> --wait"),
+ "agent start is missing its next-step hint: {agent_start}"
+ );
+
+ let pane_send_text = long_help(&["pane", "send-text"]);
+ assert!(
+ pane_send_text.contains(
+ "next: herdr pane run <PANE_ID> <COMMAND> sends text and Enter in one call"
+ ),
+ "pane send-text is missing its next-step hint: {pane_send_text}"
+ );
+ }
+
#[test]
fn completion_generation_succeeds_for_every_supported_shell() {
for shell in [
diff --git a/src/main.rs b/src/main.rs
index 3f1f7930..65dc7c11 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -424,6 +424,9 @@ pane_history = false
# scrollback_limit_bytes = 10000000
"##;
+// Bundled at build time so the printed skill always matches this binary's release.
+const SKILL: &str = include_str!("../SKILL.md");
+
fn should_block_nested(config: &config::Config) -> bool {
should_block_nested_for_env(config, std::env::var(HERDR_ENV_VAR).ok().as_deref())
}
@@ -477,7 +480,7 @@ fn main() -> io::Result<()> {
&& !args.iter().any(|a| {
matches!(
a.as_str(),
- "--help" | "-h" | "--version" | "-V" | "--default-config"
+ "--help" | "-h" | "--version" | "-V" | "--default-config" | "--skill"
)
})
{
@@ -637,6 +640,7 @@ fn main() -> io::Result<()> {
println!(" Keybindings for --remote app attach (default: local)");
println!(" --handoff Opt into live handoff for update or remote attach");
println!(" --default-config Print default configuration and exit");
+ println!(" --skill Print the agent skill file and exit");
println!(" --version, -V Print version and exit");
println!(" --help, -h Show this help");
println!();
@@ -644,6 +648,7 @@ fn main() -> io::Result<()> {
println!("Logs: {}", logging::help_log_paths_summary());
println!("Env: HERDR_CONFIG_PATH overrides config file path");
println!("Home: https://herdr.dev");
+ println!("Skill: herdr --skill prints agent instructions for driving herdr from a pane");
return Ok(());
}
@@ -657,6 +662,11 @@ fn main() -> io::Result<()> {
return Ok(());
}
+ if args.iter().any(|a| a == "--skill") {
+ print!("{SKILL}");
+ return Ok(());
+ }
+
// Reject unknown flags
let known_flags = [
"--no-session",
@@ -666,6 +676,7 @@ fn main() -> io::Result<()> {
"--version",
"-V",
"--default-config",
+ "--skill",
"--help",
"-h",
];