"""Tests for standalone myclaude / mykimi / mycodex / myhermes entrypoints.""" from pathlib import Path from unittest.mock import MagicMock, patch from click.testing import CliRunner from myagents.entrypoints import build_xiaohe_cli, claude_cli, codex_cli, hermes_cli, kimi_cli class TestXiaoheProvider: """``xiaohe switch provider`` subcommand registration.""" def test_help_lists_switch(self) -> None: runner = CliRunner() result = runner.invoke(build_xiaohe_cli(), ["--help"]) assert result.exit_code == 0 assert "switch" in result.output def test_help_lists_info(self) -> None: runner = CliRunner() result = runner.invoke(build_xiaohe_cli(), ["--help"]) assert result.exit_code == 0 assert "info" in result.output class TestMyclaudeEntrypoint: """``myclaude`` standalone entrypoint.""" def test_runs_claude(self) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/claude"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(claude_cli, []) assert result.exit_code == 0 assert mock_run.call_args[0][0] == [ "/usr/bin/claude", "--dangerously-skip-permissions", ] def test_version_shows_myclaude(self) -> None: runner = CliRunner() result = runner.invoke(claude_cli, ["--version"]) assert result.exit_code == 0 assert "myclaude" in result.output def test_passthrough(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/claude"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(claude_cli, ["--cwd", str(tmp_path), "--resume"]) assert result.exit_code == 0 assert "--resume" in mock_run.call_args[0][0] class TestMykimiEntrypoint: """``mykimi`` standalone entrypoint.""" def test_runs_kimi(self) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/kimi"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(kimi_cli, []) assert result.exit_code == 0 assert mock_run.call_args[0][0] == ["/usr/bin/kimi"] def test_version_shows_mykimi(self) -> None: runner = CliRunner() result = runner.invoke(kimi_cli, ["--version"]) assert result.exit_code == 0 assert "mykimi" in result.output def test_passthrough(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/kimi"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(kimi_cli, ["--cwd", str(tmp_path), "--resume"]) assert result.exit_code == 0 assert "--resume" in mock_run.call_args[0][0] class TestMycodexEntrypoint: """``mycodex`` standalone entrypoint.""" def test_runs_codex(self) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/codex"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(codex_cli, []) assert result.exit_code == 0 assert mock_run.call_args[0][0] == ["/usr/bin/codex", "--dangerously-bypass-approvals-and-sandbox"] def test_version_shows_mycodex(self) -> None: runner = CliRunner() result = runner.invoke(codex_cli, ["--version"]) assert result.exit_code == 0 assert "mycodex" in result.output def test_passthrough(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/codex"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(codex_cli, ["--cwd", str(tmp_path), "-r", "abc123"]) assert result.exit_code == 0 assert mock_run.call_args[0][0] == ["/usr/bin/codex", "--dangerously-bypass-approvals-and-sandbox", "resume", "abc123"] class TestMyhermesEntrypoint: """``myhermes`` standalone entrypoint.""" def test_runs_hermes(self) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/hermes"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(hermes_cli, []) assert result.exit_code == 0 assert mock_run.call_args[0][0] == ["/usr/bin/hermes", "--yolo"] def test_version_shows_myhermes(self) -> None: runner = CliRunner() result = runner.invoke(hermes_cli, ["--version"]) assert result.exit_code == 0 assert "myhermes" in result.output def test_passthrough(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", return_value="/usr/bin/hermes"), patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke( hermes_cli, ["--cwd", str(tmp_path), "--resume", "abc123"] ) assert result.exit_code == 0 assert mock_run.call_args[0][0][-3:] == [ "--resume", "abc123", "--no-restore-cwd", ] class TestTmuxOption: """``--tmux`` / ``-t`` wraps the backend in an attachable tmux session.""" def _which(self, name: str) -> str: return f"/usr/bin/{name}" def test_tmux_wraps_command(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", side_effect=self._which), patch("myagents.launcher.subprocess.run") as mock_run, patch.dict("os.environ", {}, clear=False) as env, ): env.pop("TMUX", None) mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(claude_cli, ["--cwd", str(tmp_path), "--tmux"]) assert result.exit_code == 0 argv = mock_run.call_args[0][0] assert argv[:3] == ["/usr/bin/tmux", "new-session", "-A"] assert "-c" in argv and str(tmp_path) in argv assert argv[-1] == "/usr/bin/claude --dangerously-skip-permissions" def test_tmux_session_name_deterministic(self, tmp_path: Path) -> None: from myagents.launcher import _tmux_session_name first = _tmux_session_name("claude", tmp_path) second = _tmux_session_name("claude", tmp_path) other = _tmux_session_name("kimi", tmp_path) assert first == second assert first != other assert first.startswith("myclaude-") def test_tmux_with_passthrough(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", side_effect=self._which), patch("myagents.launcher.subprocess.run") as mock_run, patch.dict("os.environ", {}, clear=False) as env, ): env.pop("TMUX", None) mock_run.return_value = MagicMock(returncode=0) result = runner.invoke( claude_cli, ["--cwd", str(tmp_path), "-t", "-r", "sess-1"] ) assert result.exit_code == 0 argv = mock_run.call_args[0][0] assert argv[0] == "/usr/bin/tmux" assert argv[-1].endswith("-r sess-1") def test_tmux_skipped_when_already_inside(self, tmp_path: Path) -> None: runner = CliRunner() with ( patch("myagents.launcher.shutil.which", side_effect=self._which), patch("myagents.launcher.subprocess.run") as mock_run, patch.dict("os.environ", {"TMUX": "/tmp/tmux-501/default,1,0"}), ): mock_run.return_value = MagicMock(returncode=0) result = runner.invoke(claude_cli, ["--cwd", str(tmp_path), "-t"]) assert result.exit_code == 0 argv = mock_run.call_args[0][0] assert argv[0] == "/usr/bin/claude" def test_tmux_missing_binary(self, tmp_path: Path) -> None: runner = CliRunner() def _which(name: str) -> str | None: return None if name == "tmux" else f"/usr/bin/{name}" with ( patch("myagents.launcher.shutil.which", side_effect=_which), patch.dict("os.environ", {}, clear=False) as env, ): env.pop("TMUX", None) result = runner.invoke(claude_cli, ["--cwd", str(tmp_path), "-t"]) assert result.exit_code == 127