diff --git a/docs/usage/FEATURES.md b/docs/usage/FEATURES.md index 8afaa62022..d4d3cbec1b 100644 --- a/docs/usage/FEATURES.md +++ b/docs/usage/FEATURES.md @@ -1175,12 +1175,18 @@ rtk init -g --uninstall # Desinstaller ### `rtk rewrite` -- Recriture de commande -Commande interne utilisee par le hook. Imprime la commande reecrite sur stdout (exit 0) ou sort avec exit 1 si aucun equivalent RTK n'existe. +Commande interne utilisee par le hook. Le code de sortie preserve la decision de permission : + +- `0` : imprime une commande reecrite explicitement autorisee +- `1` : aucun equivalent RTK, sans sortie +- `2` : une regle de refus correspond, sans sortie +- `3` : imprime une commande reecrite qui necessite encore une confirmation (regle ask ou comportement par defaut) + +Les integrations doivent donc lire stdout pour les codes `0` et `3`, tout en conservant la demande de confirmation pour le code `3`. ```bash -rtk rewrite "git status" # -> "rtk git status" (exit 0) -rtk rewrite "terraform plan" # -> (exit 1, pas de recriture) -rtk rewrite "rtk git status" # -> "rtk git status" (exit 0, inchange) +rtk rewrite "git status" # -> "rtk git status" (exit 3 par defaut) +rtk rewrite "echo hello" # -> (exit 1, pas de recriture) ``` ### `rtk verify` -- Verification d'integrite diff --git a/src/main.rs b/src/main.rs index 30ba275b38..0f96dc5719 100644 --- a/src/main.rs +++ b/src/main.rs @@ -837,11 +837,13 @@ enum Commands { /// Rewrite a raw command to its RTK equivalent (single source of truth for hooks) /// - /// Exits 0 and prints the rewritten command if supported. - /// Exits 1 with no output if the command has no RTK equivalent. + /// Exit 0: prints a rewrite that an explicit allow rule matched. + /// Exit 1: no RTK equivalent; prints nothing. + /// Exit 2: a deny rule matched; prints nothing. + /// Exit 3: prints a rewrite that still requires user approval (ask or default). /// - /// Used by Claude Code, Gemini CLI, and other LLM hooks: - /// REWRITTEN=$(rtk rewrite "$CMD") || exit 0 + /// Integrators should consume stdout for exits 0 and 3, while preserving the + /// approval requirement for exit 3. Other exits should pass through unchanged. Rewrite { /// Raw command to rewrite (e.g. "git status", "cargo test && git push") /// Accepts multiple args: `rtk rewrite ls -al` is equivalent to `rtk rewrite "ls -al"` @@ -3386,6 +3388,27 @@ mod tests { } } + #[test] + fn test_rewrite_help_documents_exit_code_contract() { + use clap::CommandFactory; + + let mut command = Cli::command(); + let help = command + .find_subcommand_mut("rewrite") + .expect("rewrite subcommand should exist") + .render_long_help() + .to_string(); + + for exit_code in 0..=3 { + assert!( + help.contains(&format!("Exit {exit_code}:")), + "rewrite help should document exit {exit_code}:\n{help}" + ); + } + assert!(help.contains("consume stdout for exits 0 and 3")); + assert!(!help.contains("|| exit 0")); + } + #[test] fn test_merge_filters_with_no_args() { let filters = vec![];