opencode-cursor-agent/internal/config/config.go

89 lines
2.4 KiB
Go
Raw Normal View History

2026-04-18 14:08:01 +00:00
package config
import (
"fmt"
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
type Config struct {
Port int `yaml:"port"`
CursorCLIPath string `yaml:"cursor_cli_path"`
DefaultModel string `yaml:"default_model"`
Timeout int `yaml:"timeout"`
MaxConcurrent int `yaml:"max_concurrent"`
UseACP bool `yaml:"use_acp"`
ChatOnlyWorkspace bool `yaml:"chat_only_workspace"`
LogLevel string `yaml:"log_level"`
AvailableModels []string `yaml:"available_models,omitempty"`
}
// Defaults returns a Config populated with default values.
//
// ChatOnlyWorkspace defaults to true. This is the cursor-api-proxy posture:
// every Cursor CLI / ACP child is spawned in an empty temp directory with
// HOME / CURSOR_CONFIG_DIR overridden so it cannot see the host user's real
// project files or global ~/.cursor rules. Set to false only if you really
// want the Cursor agent to have access to the cwd where cursor-adapter
// started.
func Defaults() Config {
return Config{
Port: 8976,
CursorCLIPath: "agent",
DefaultModel: "auto",
Timeout: 300,
MaxConcurrent: 5,
UseACP: false,
ChatOnlyWorkspace: true,
LogLevel: "INFO",
}
}
// Load reads a YAML config file from path. If path is empty it defaults to
// ~/.cursor-adapter/config.yaml. When the file does not exist, a config with
// default values is returned without an error.
func Load(path string) (*Config, error) {
if path == "" {
home, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("resolving home directory: %w", err)
}
path = filepath.Join(home, ".cursor-adapter", "config.yaml")
}
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
c := Defaults()
return &c, nil
}
return nil, fmt.Errorf("reading config file %s: %w", path, err)
}
cfg := Defaults()
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing config file %s: %w", path, err)
}
if err := cfg.validate(); err != nil {
return nil, fmt.Errorf("validating config: %w", err)
}
return &cfg, nil
}
func (c *Config) validate() error {
if c.Port <= 0 {
return fmt.Errorf("port must be > 0, got %d", c.Port)
}
if c.CursorCLIPath == "" {
return fmt.Errorf("cursor_cli_path must not be empty")
}
if c.Timeout <= 0 {
return fmt.Errorf("timeout must be > 0, got %d", c.Timeout)
}
return nil
}