diff --git a/headroom/install/paths.py b/headroom/install/paths.py index 985f705eb..bcca00b0e 100644 --- a/headroom/install/paths.py +++ b/headroom/install/paths.py @@ -125,13 +125,20 @@ def opencode_config_path() -> Path: """Return the OpenCode config path. Resolves ``~/.config/opencode/opencode.json`` when ``OPENCODE_CONFIG`` - is unset; otherwise the value of that environment variable. + is unset; otherwise the value of that environment variable. Checks for + ``opencode.jsonc`` as well. """ env_path = os.environ.get("OPENCODE_CONFIG", "").strip() if env_path: return Path(env_path).expanduser() - return Path.home() / ".config" / "opencode" / "opencode.json" + base_dir = Path.home() / ".config" / "opencode" + jsonc_path = base_dir / "opencode.jsonc" + + if jsonc_path.exists(): + return jsonc_path + + return base_dir / "opencode.json" def zcode_config_dir() -> Path: diff --git a/headroom/providers/opencode/config.py b/headroom/providers/opencode/config.py index d0f321ef1..6c64544fe 100644 --- a/headroom/providers/opencode/config.py +++ b/headroom/providers/opencode/config.py @@ -81,7 +81,7 @@ def _opencode_home_dir() -> Path: def opencode_config_paths() -> tuple[Path, Path]: """Return ``(config_file, backup_file)`` for OpenCode.""" config_file = opencode_config_path() - backup_file = config_file.with_suffix(".json.headroom-backup") + backup_file = config_file.with_name(config_file.name + ".headroom-backup") return config_file, backup_file diff --git a/tests/test_cli/test_wrap_opencode.py b/tests/test_cli/test_wrap_opencode.py index 95f4e0ecc..b74a7d936 100644 --- a/tests/test_cli/test_wrap_opencode.py +++ b/tests/test_cli/test_wrap_opencode.py @@ -346,7 +346,7 @@ def test_unwrap_opencode_restores_from_backup( _set_test_home(monkeypatch, tmp_path) config_file = tmp_path / ".config" / "opencode" / "opencode.json" - backup_file = config_file.with_suffix(".json.headroom-backup") + backup_file = config_file.with_name("opencode.json.headroom-backup") config_file.parent.mkdir(parents=True, exist_ok=True) original = '{"model": "openai/gpt-4o"}' config_file.write_text(original) @@ -361,6 +361,31 @@ def test_unwrap_opencode_restores_from_backup( assert config_file.read_text(encoding="utf-8") == original +def test_unwrap_opencode_restores_from_backup_jsonc( + runner: CliRunner, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Unwrap restores the pre-wrap backup and removes it for jsonc files.""" + monkeypatch.chdir(tmp_path) + _set_test_home(monkeypatch, tmp_path) + + config_file = tmp_path / ".config" / "opencode" / "opencode.jsonc" + backup_file = config_file.with_name("opencode.jsonc.headroom-backup") + config_file.parent.mkdir(parents=True, exist_ok=True) + original = '{\n // User comment\n "model": "openai/gpt-4o"\n}' + config_file.write_text(original) + backup_file.write_text(original) + + with patch.object(wrap_mod, "_stop_local_proxy_for_unwrap", return_value="stopped"): + result = runner.invoke(main, ["unwrap", "opencode"]) + + assert result.exit_code == 0, result.output + assert "Restored prior" in result.output + assert not backup_file.exists() + assert config_file.read_text(encoding="utf-8") == original + + def test_unwrap_opencode_strips_blocks_when_no_backup( runner: CliRunner, tmp_path: Path, diff --git a/tests/test_providers_opencode_config.py b/tests/test_providers_opencode_config.py index ef1d142fe..658ba1ea4 100644 --- a/tests/test_providers_opencode_config.py +++ b/tests/test_providers_opencode_config.py @@ -49,6 +49,39 @@ def test_opencode_config_paths_from_env(tmp_path: Path, monkeypatch: pytest.Monk assert backup_file == tmp_path / "custom" / "opencode.json.headroom-backup" +def test_opencode_config_paths_default_jsonc( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """Default config path resolves to opencode.jsonc when it exists.""" + _set_test_home(monkeypatch, tmp_path) + base_dir = tmp_path / ".config" / "opencode" + base_dir.mkdir(parents=True, exist_ok=True) + jsonc_path = base_dir / "opencode.jsonc" + jsonc_path.write_text("{}") + + config_file, backup_file = opencode_config_paths() + assert config_file == jsonc_path + assert backup_file == base_dir / "opencode.jsonc.headroom-backup" + + +def test_opencode_config_paths_env_overrides_jsonc( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """OPENCODE_CONFIG takes precedence even if opencode.jsonc exists.""" + _set_test_home(monkeypatch, tmp_path) + base_dir = tmp_path / ".config" / "opencode" + base_dir.mkdir(parents=True, exist_ok=True) + jsonc_path = base_dir / "opencode.jsonc" + jsonc_path.write_text("{}") + + custom_path = tmp_path / "custom" / "opencode.json" + monkeypatch.setenv("OPENCODE_CONFIG", str(custom_path)) + + config_file, backup_file = opencode_config_paths() + assert config_file == custom_path + assert backup_file == tmp_path / "custom" / "opencode.json.headroom-backup" + + # --------------------------------------------------------------------------- # Snapshot # ---------------------------------------------------------------------------