mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-10 05:01:28 -10:00
On macOS, DefaultUserConfigPath used Go's os.UserConfigDir which returns ~/Library/Application Support, while users (and Claude Code) place config at ~/.config/zero/config.json. The user config was never read, leaving activeProvider empty and the launch failing with `active provider "" not found` on a fresh `go run cmd/zero setup`. - Add config.UserConfigDir(): on darwin, resolve to ~/.config (honoring XDG_CONFIG_HOME), matching Linux and Claude Code. DefaultUserConfigPath, the TUI user-commands dir, and specialist manifests all route through it. - Add config.ErrNoActiveProvider sentinel; the interactive TUI now drops into the setup wizard when resolve fails solely due to a missing/ unresolvable active provider, instead of exiting fatally. Other resolve errors (malformed JSON, directory conflicts) remain fatal. Note: `zero setup`/`zero auth` already MkdirAll the config dir before writing, so the directory is auto-created on first write. Co-authored-by: smallnest <smallnest@gmail>
76 lines
2.1 KiB
Go
76 lines
2.1 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// DefaultResolveOptions builds config resolution inputs from the local process
|
|
// environment and workspace.
|
|
func DefaultResolveOptions(workspaceRoot string) (ResolveOptions, error) {
|
|
userConfigPath, err := DefaultUserConfigPath()
|
|
if err != nil {
|
|
return ResolveOptions{}, err
|
|
}
|
|
|
|
userConfigPath, err = existingConfigFile(userConfigPath)
|
|
if err != nil {
|
|
return ResolveOptions{}, err
|
|
}
|
|
|
|
projectConfigPath, err := existingConfigFile(filepath.Join(workspaceRoot, ".zero", "config.json"))
|
|
if err != nil {
|
|
return ResolveOptions{}, err
|
|
}
|
|
|
|
return ResolveOptions{
|
|
UserConfigPath: userConfigPath,
|
|
ProjectConfigPath: projectConfigPath,
|
|
ProviderCommand: strings.TrimSpace(os.Getenv("ZERO_PROVIDER_COMMAND")),
|
|
}, nil
|
|
}
|
|
|
|
func DefaultUserConfigPath() (string, error) {
|
|
userConfigDir, err := UserConfigDir()
|
|
if err != nil {
|
|
return "", fmt.Errorf("resolve user config directory: %w", err)
|
|
}
|
|
return filepath.Join(userConfigDir, "zero", "config.json"), nil
|
|
}
|
|
|
|
// UserConfigDir returns the base directory Zero stores per-user config under.
|
|
// It mirrors os.UserConfigDir everywhere except macOS: there Go defaults to
|
|
// ~/Library/Application Support, but Zero deliberately uses ~/.config (XDG-style,
|
|
// matching Linux and Claude Code) so a single config path works cross-platform.
|
|
// $XDG_CONFIG_HOME still wins on macOS when set.
|
|
func UserConfigDir() (string, error) {
|
|
if runtime.GOOS == "darwin" {
|
|
if xdg := strings.TrimSpace(os.Getenv("XDG_CONFIG_HOME")); xdg != "" {
|
|
return xdg, nil
|
|
}
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return "", fmt.Errorf("resolve home directory: %w", err)
|
|
}
|
|
return filepath.Join(home, ".config"), nil
|
|
}
|
|
return os.UserConfigDir()
|
|
}
|
|
|
|
func existingConfigFile(path string) (string, error) {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return "", nil
|
|
}
|
|
return "", fmt.Errorf("inspect config %s: %w", path, err)
|
|
}
|
|
if info.IsDir() {
|
|
return "", fmt.Errorf("config path %s is a directory, want a file", path)
|
|
}
|
|
return path, nil
|
|
}
|