100 lines
3.3 KiB
Python
100 lines
3.3 KiB
Python
import json
|
|
|
|
from laya_router.clients.base import read_json
|
|
from laya_router.clients.claude import ClaudeClient
|
|
from laya_router.clients.codex import CodexClient, hooks_feature_enabled
|
|
from laya_router.config import Settings
|
|
|
|
|
|
def _settings(tmp_path) -> Settings:
|
|
return Settings(home=tmp_path)
|
|
|
|
|
|
def test_claude_merge_is_idempotent_and_keeps_existing_hooks(tmp_path):
|
|
path = tmp_path / "settings.json"
|
|
path.write_text(
|
|
json.dumps(
|
|
{
|
|
"env": {"ANTHROPIC_AUTH_TOKEN": "secret-token"},
|
|
"hooks": {
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [{"type": "command", "command": "rtk hook claude"}],
|
|
}
|
|
]
|
|
},
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
client = ClaudeClient(path)
|
|
settings = _settings(tmp_path / "runtime")
|
|
|
|
assert client.install(settings) is True
|
|
assert client.install(settings) is False
|
|
|
|
saved = read_json(path)
|
|
assert saved["env"]["ANTHROPIC_AUTH_TOKEN"] == "secret-token"
|
|
assert saved["hooks"]["PreToolUse"][0]["matcher"] == "Bash"
|
|
commands = [
|
|
item["command"]
|
|
for group in saved["hooks"]["UserPromptSubmit"]
|
|
for item in group["hooks"]
|
|
]
|
|
assert commands == [f'"{tmp_path / "runtime" / ".venv" / "bin" / "laya-hook"}" --client claude']
|
|
assert list(path.parent.glob("settings.json.bak-*"))
|
|
|
|
assert client.uninstall() is True
|
|
removed = read_json(path)
|
|
assert "UserPromptSubmit" not in removed["hooks"]
|
|
assert removed["hooks"]["PreToolUse"][0]["hooks"][0]["command"] == "rtk hook claude"
|
|
assert removed["env"]["ANTHROPIC_AUTH_TOKEN"] == "secret-token"
|
|
|
|
|
|
def test_codex_uninstall_drops_file_when_it_only_contains_our_hook(tmp_path):
|
|
codex_dir = tmp_path / ".codex"
|
|
client = CodexClient(codex_dir)
|
|
settings = _settings(tmp_path / "runtime")
|
|
assert client.install(settings) is True
|
|
assert client.install(settings) is False
|
|
saved = read_json(client.hooks_path)
|
|
assert saved["hooks"]["UserPromptSubmit"][0]["hooks"][0]["statusMessage"] == "Laya routing"
|
|
assert client.uninstall() is True
|
|
assert not client.hooks_path.exists()
|
|
|
|
|
|
def test_codex_uninstall_keeps_foreign_hooks(tmp_path):
|
|
codex_dir = tmp_path / ".codex"
|
|
hooks = codex_dir / "hooks.json"
|
|
hooks.parent.mkdir()
|
|
hooks.write_text(
|
|
json.dumps(
|
|
{
|
|
"hooks": {
|
|
"UserPromptSubmit": [
|
|
{"hooks": [{"type": "command", "command": "other-hook"}]}
|
|
]
|
|
}
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
client = CodexClient(codex_dir)
|
|
client.install(_settings(tmp_path / "runtime"))
|
|
client.uninstall()
|
|
saved = read_json(hooks)
|
|
commands = [
|
|
item["command"]
|
|
for group in saved["hooks"]["UserPromptSubmit"]
|
|
for item in group["hooks"]
|
|
]
|
|
assert commands == ["other-hook"]
|
|
|
|
|
|
def test_hooks_feature_parser():
|
|
listing = "hooks stable true\nplugin_hooks removed false\n"
|
|
assert hooks_feature_enabled(listing) is True
|
|
assert hooks_feature_enabled("hooks experimental false") is False
|
|
assert hooks_feature_enabled("no hooks here") is None
|