go/pkg/workspace/config.go
Snider f5bcef421e
fix(i18n): restore missing translation keys for health command (#65)
* fix(i18n): restore missing translation keys for health command

The locale consolidation in 39de3c2 removed keys still used by
cmd_health.go. Added back:
- cmd.dev.health.* keys (long, repos, to_push, to_pull, etc.)
- common.status.* keys (dirty, clean, synced, up_to_date)
- common.flag.registry

Also fixed workspace.LoadConfig() returning default PackagesDir
when no .core/workspace.yaml exists, which was overriding repo
paths from repos.yaml.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add nil checks for workspace.LoadConfig callers

LoadConfig now returns nil when no .core/workspace.yaml exists.
Added defensive nil checks to all callers to prevent panics.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: align workspace.LoadConfig error handling

Both call sites now gracefully ignore errors and fall back to defaults,
since workspace config is optional for setup commands.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:55:01 +00:00

97 lines
2.5 KiB
Go

package workspace
import (
"fmt"
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
// WorkspaceConfig holds workspace-level configuration from .core/workspace.yaml.
type WorkspaceConfig struct {
Version int `yaml:"version"`
Active string `yaml:"active"` // Active package name
DefaultOnly []string `yaml:"default_only"` // Default types for setup
PackagesDir string `yaml:"packages_dir"` // Where packages are cloned
}
// DefaultConfig returns a config with default values.
func DefaultConfig() *WorkspaceConfig {
return &WorkspaceConfig{
Version: 1,
PackagesDir: "./packages",
}
}
// LoadConfig tries to load workspace.yaml from the given directory's .core subfolder.
// Returns nil if no config file exists (caller should check for nil).
func LoadConfig(dir string) (*WorkspaceConfig, error) {
path := filepath.Join(dir, ".core", "workspace.yaml")
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
// Try parent directory
parent := filepath.Dir(dir)
if parent != dir {
return LoadConfig(parent)
}
// No workspace.yaml found anywhere - return nil to indicate no config
return nil, nil
}
return nil, fmt.Errorf("failed to read workspace config: %w", err)
}
config := DefaultConfig()
if err := yaml.Unmarshal(data, config); err != nil {
return nil, fmt.Errorf("failed to parse workspace config: %w", err)
}
if config.Version != 1 {
return nil, fmt.Errorf("unsupported workspace config version: %d", config.Version)
}
return config, nil
}
// SaveConfig saves the configuration to the given directory's .core/workspace.yaml.
func SaveConfig(dir string, config *WorkspaceConfig) error {
coreDir := filepath.Join(dir, ".core")
if err := os.MkdirAll(coreDir, 0755); err != nil {
return fmt.Errorf("failed to create .core directory: %w", err)
}
path := filepath.Join(coreDir, "workspace.yaml")
data, err := yaml.Marshal(config)
if err != nil {
return fmt.Errorf("failed to marshal workspace config: %w", err)
}
if err := os.WriteFile(path, data, 0644); err != nil {
return fmt.Errorf("failed to write workspace config: %w", err)
}
return nil
}
// FindWorkspaceRoot searches for the root directory containing .core/workspace.yaml.
func FindWorkspaceRoot() (string, error) {
dir, err := os.Getwd()
if err != nil {
return "", err
}
for {
if _, err := os.Stat(filepath.Join(dir, ".core", "workspace.yaml")); err == nil {
return dir, nil
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
return "", fmt.Errorf("not in a workspace")
}