Skip to content

Commit 9197a94

Browse files
committed
chore: commit all modified and untracked files
Includes changes to: - code_assistant_manager/configs/tools/__init__.py - code_assistant_manager/tools/goose.py - code_assistant_manager/configs/tools/opencode.py
1 parent 2d97965 commit 9197a94

3 files changed

Lines changed: 100 additions & 1 deletion

File tree

code_assistant_manager/configs/tools/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .neovate import NeovateConfig
1717
from .qoder import QoderConfig
1818
from .zed import ZedConfig
19+
from .opencode import OpenCodeConfig
1920

2021
# Registry
2122
_CONFIG_CLASSES: Dict[str, Type[BaseToolConfig]] = {
@@ -32,6 +33,7 @@
3233
"neovate": NeovateConfig,
3334
"qodercli": QoderConfig,
3435
"zed": ZedConfig,
36+
"opencode": OpenCodeConfig,
3537
}
3638

3739

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from pathlib import Path
2+
from typing import Dict, List
3+
from ..base import BaseToolConfig
4+
5+
6+
class OpenCodeConfig(BaseToolConfig):
7+
def __init__(self):
8+
super().__init__("opencode")
9+
10+
def get_scope_paths(self) -> Dict[str, List[Path]]:
11+
return {
12+
"user": [self.home / ".config" / "opencode" / "opencode.json"],
13+
"project": [self.cwd / ".config" / "opencode" / "opencode.json"],
14+
}
15+
16+
def set_value(self, key_path: str, value: str, scope: str) -> Path:
17+
"""Override set_value to handle plugin array specially."""
18+
config_data = self.load_config(scope)
19+
20+
# Parse key path
21+
parts = self._parse_key_path(key_path)
22+
23+
# Special handling for plugin key - treat as array
24+
if len(parts) == 1 and parts[0] == "plugin":
25+
# Handle plugin array
26+
if "plugin" not in config_data:
27+
config_data["plugin"] = []
28+
29+
if not isinstance(config_data["plugin"], list):
30+
# Convert existing value to array
31+
existing_value = config_data["plugin"]
32+
config_data["plugin"] = [existing_value]
33+
34+
# Append new value if not already present
35+
if value not in config_data["plugin"]:
36+
config_data["plugin"].append(value)
37+
else:
38+
# Use default behavior for other keys
39+
self._set_nested_value(config_data, parts, value)
40+
41+
return self.save_config(config_data, scope)

code_assistant_manager/tools/goose.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,46 @@ def _get_filtered_endpoints(self) -> List[str]:
123123
if self.endpoint_manager._is_client_supported(ep, "goose")
124124
]
125125

126+
def _validate_and_fix_config(self) -> None:
127+
"""Validate that config.yaml references valid custom providers.
128+
129+
If config references a provider that doesn't exist, try to use an available one.
130+
"""
131+
config_file = Path.home() / ".config" / "goose" / "config.yaml"
132+
if not config_file.exists():
133+
return
134+
135+
try:
136+
with open(config_file, "r", encoding="utf-8") as f:
137+
config_data = yaml.safe_load(f) or {}
138+
except Exception:
139+
return
140+
141+
provider_name = config_data.get("GOOSE_PROVIDER")
142+
model_name = config_data.get("GOOSE_MODEL")
143+
144+
# Check if current provider exists
145+
custom_providers = self._get_custom_providers()
146+
147+
if provider_name and provider_name in custom_providers:
148+
# Provider exists, verify model exists
149+
if model_name and model_name in custom_providers[provider_name]:
150+
# Everything is valid
151+
return
152+
else:
153+
# Provider exists but model doesn't; use first available model
154+
if custom_providers[provider_name]:
155+
first_model = custom_providers[provider_name][0]
156+
self._write_default_to_config(provider_name, first_model)
157+
print(f"Fixed: Updated model to '{first_model}'")
158+
else:
159+
# Provider doesn't exist; use first available provider and model
160+
if custom_providers:
161+
first_provider = next(iter(custom_providers.keys()))
162+
first_model = custom_providers[first_provider][0]
163+
self._write_default_to_config(first_provider, first_model)
164+
print(f"Fixed: Updated provider to '{first_provider}' and model to '{first_model}'")
165+
126166
def _get_custom_providers(self) -> Dict[str, List[str]]:
127167
"""Read existing custom providers from ~/.config/goose/custom_providers/.
128168
@@ -387,10 +427,23 @@ def _show_and_select_model(
387427

388428

389429
def _write_default_to_config(self, provider_name: str, model_name: str) -> None:
390-
"""Write provider and model to goose config.yaml."""
430+
"""Write provider and model to goose config.yaml.
431+
432+
Validates that the provider and model exist in custom providers before writing.
433+
"""
391434
config_file = Path.home() / ".config" / "goose" / "config.yaml"
392435
config_file.parent.mkdir(parents=True, exist_ok=True)
393436

437+
# Validate that the provider and model exist
438+
custom_providers = self._get_custom_providers()
439+
if provider_name not in custom_providers:
440+
print(f"Warning: Provider '{provider_name}' not found in custom providers. Skipping config update.")
441+
return
442+
443+
if model_name not in custom_providers[provider_name]:
444+
print(f"Warning: Model '{model_name}' not found in provider '{provider_name}'. Skipping config update.")
445+
return
446+
394447
config_data = {}
395448
if config_file.exists():
396449
try:
@@ -417,6 +470,9 @@ def run(self, args: List[str] = None) -> int:
417470
# Load environment variables first
418471
self._load_environment()
419472

473+
# Validate and fix config if needed
474+
self._validate_and_fix_config()
475+
420476
# Check if Goose is installed
421477
if not self._ensure_tool_installed(
422478
self.command_name, self.tool_key, self.install_description

0 commit comments

Comments
 (0)