Files
superwork/tui/internal/config/config.go
T
2026-06-23 05:02:15 +08:00

115 lines
2.8 KiB
Go

package config
import (
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/BurntSushi/toml"
)
const DefaultWebhookPort = 17421
type Settings struct {
WebhookPort int `toml:"webhook_port"`
BrainstormPrompt string `toml:"brainstorm_prompt"`
BrainstormContinuePrompt string `toml:"brainstorm_continue_prompt"`
ImplementPlanPrompt string `toml:"implement_plan_prompt"`
ReviewPrompt string `toml:"review_prompt"`
AutoReview bool `toml:"auto_review"`
DevBranch string `toml:"dev_branch"`
AutoBuildBranch string `toml:"auto_build_branch"`
WorktreePostCreateScript string `toml:"worktree_post_create_script"`
WorktreePreRemoveScript string `toml:"worktree_pre_remove_script"`
ImplTabPreCreateScript string `toml:"impl_tab_pre_create_script"`
ImplTabPostCloseScript string `toml:"impl_tab_post_close_script"`
ProfilesDir string `toml:"profiles_dir"`
SystemPromptCommand string `toml:"system_prompt_command"`
}
func DefaultSettings() *Settings {
return &Settings{
WebhookPort: DefaultWebhookPort,
AutoReview: true,
DevBranch: "main",
}
}
// configFilePath returns the path to the config file. It's a variable so tests can override it.
var configFilePath = func() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("resolve home dir: %w", err)
}
return filepath.Join(home, ".config", "superwork", "config.toml"), nil
}
func Load() (*Settings, error) {
return LoadFrom("")
}
func LoadFrom(path string) (*Settings, error) {
if path == "" {
var err error
path, err = configFilePath()
if err != nil {
return nil, err
}
}
s := DefaultSettings()
_, err := toml.DecodeFile(path, s)
if errors.Is(err, fs.ErrNotExist) {
return s, nil
}
if err != nil {
return nil, fmt.Errorf("decode config %s: %w", path, err)
}
return s, nil
}
func Save(s *Settings) error {
return SaveTo("", s)
}
func SaveTo(path string, s *Settings) error {
if path == "" {
var err error
path, err = configFilePath()
if err != nil {
return err
}
}
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("create config dir: %w", err)
}
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("create config file: %w", err)
}
defer f.Close()
if err := toml.NewEncoder(f).Encode(s); err != nil {
return fmt.Errorf("encode config: %w", err)
}
return nil
}
func WorkspaceRoot() (string, error) {
out, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
if err != nil {
cwd, cerr := os.Getwd()
if cerr != nil {
return "", fmt.Errorf("get cwd: %w", cerr)
}
return cwd, nil
}
return strings.TrimSpace(string(out)), nil
}
func SpxDir(workspaceRoot string) string {
return filepath.Join(workspaceRoot, ".spx")
}