diff --git a/src/dippy/dippy.py b/src/dippy/dippy.py index dc76408..eb069da 100644 --- a/src/dippy/dippy.py +++ b/src/dippy/dippy.py @@ -271,6 +271,39 @@ def main(): """Main entry point for the hook.""" global MODE + # Early exit flags — checked before reading stdin + if "--help" in sys.argv or "-h" in sys.argv: + from dippy import __version__ + + print(f"Dippy v{__version__} — approval autopilot for AI coding assistants") + print() + print("Usage: dippy [--claude|--gemini|--cursor]") + print() + print("Reads JSON hook payload from stdin. Outputs a JSON decision.") + print() + print("Modes:") + print(" --claude Force Claude Code mode") + print(" --gemini Force Gemini CLI mode") + print(" --cursor Force Cursor mode") + print(" (auto-detected from input if not specified)") + print() + print("Flags:") + print(" --help, -h Show this help") + print(" --version, -V Show version") + raise SystemExit(0) + + if "--version" in sys.argv or "-V" in sys.argv: + from dippy import __version__ + + print(f"dippy {__version__}") + raise SystemExit(0) + + # If stdin is a TTY, no input is being piped — show help instead of hanging + if sys.stdin.isatty(): + print("dippy: no input (expected JSON on stdin)") + print("Run 'dippy --help' for usage.") + raise SystemExit(0) + setup_logging() try: diff --git a/tests/test_dippy.py b/tests/test_dippy.py index 42edb4b..db17bde 100644 --- a/tests/test_dippy.py +++ b/tests/test_dippy.py @@ -3966,6 +3966,69 @@ def test_command(check, cmd, expected_safe): assert needs_confirmation(result), f"Expected confirmation for: {cmd}" +class TestCLI: + """Test CLI flags (--help, --version) and TTY detection.""" + + def test_help_flag(self, capsys): + import sys + from unittest.mock import patch + + with patch.object(sys, "argv", ["dippy", "--help"]): + from dippy.dippy import main + + with pytest.raises(SystemExit) as exc_info: + main() + assert exc_info.value.code == 0 + captured = capsys.readouterr() + assert "Usage:" in captured.out + assert "--claude" in captured.out + + def test_help_flag_short(self, capsys): + import sys + from unittest.mock import patch + + with patch.object(sys, "argv", ["dippy", "-h"]): + from dippy.dippy import main + + with pytest.raises(SystemExit) as exc_info: + main() + assert exc_info.value.code == 0 + captured = capsys.readouterr() + assert "Usage:" in captured.out + + def test_version_flag(self, capsys): + import sys + from unittest.mock import patch + + with patch.object(sys, "argv", ["dippy", "--version"]): + from dippy.dippy import main + + with pytest.raises(SystemExit) as exc_info: + main() + assert exc_info.value.code == 0 + captured = capsys.readouterr() + from dippy import __version__ + + assert __version__ in captured.out + + def test_tty_shows_help(self, capsys): + """When stdin is a TTY (no piped input), show help instead of hanging.""" + import sys + from unittest.mock import patch + + with patch.object(sys, "argv", ["dippy"]), patch.object( + sys.stdin, "isatty", return_value=True + ): + from dippy.dippy import main + + with pytest.raises(SystemExit) as exc_info: + main() + assert exc_info.value.code == 0 + captured = capsys.readouterr() + assert "no input" in captured.out + assert "--help" in captured.out + + class TestPostToolUse: """Test PostToolUse hook handling."""