feat: honor PICOCLAW_HOME env var for config, auth, and workspace paths

This commit is contained in:
Keith Patrick 2026-03-05 22:08:37 +00:00
parent 3e5b849984
commit 51e8479f99
5 changed files with 41 additions and 4 deletions

View file

@ -18,12 +18,21 @@ var (
goVersion string goVersion string
) )
// GetPicoclawHome returns the picoclaw home directory.
// Priority: $PICOCLAW_HOME > ~/.picoclaw
func GetPicoclawHome() string {
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
return home
}
home, _ := os.UserHomeDir()
return filepath.Join(home, ".picoclaw")
}
func GetConfigPath() string { func GetConfigPath() string {
if configPath := os.Getenv("PICOCLAW_CONFIG"); configPath != "" { if configPath := os.Getenv("PICOCLAW_CONFIG"); configPath != "" {
return configPath return configPath
} }
home, _ := os.UserHomeDir() return filepath.Join(GetPicoclawHome(), "config.json")
return filepath.Join(home, ".picoclaw", "config.json")
} }
func LoadConfig() (*config.Config, error) { func LoadConfig() (*config.Config, error) {

View file

@ -19,6 +19,27 @@ func TestGetConfigPath(t *testing.T) {
assert.Equal(t, want, got) assert.Equal(t, want, got)
} }
func TestGetConfigPath_WithPICOCLAW_HOME(t *testing.T) {
t.Setenv("PICOCLAW_HOME", "/custom/picoclaw")
t.Setenv("HOME", "/tmp/home")
got := GetConfigPath()
want := filepath.Join("/custom/picoclaw", "config.json")
assert.Equal(t, want, got)
}
func TestGetConfigPath_WithPICOCLAW_CONFIG(t *testing.T) {
t.Setenv("PICOCLAW_CONFIG", "/custom/config.json")
t.Setenv("PICOCLAW_HOME", "/custom/picoclaw")
t.Setenv("HOME", "/tmp/home")
got := GetConfigPath()
want := "/custom/config.json"
assert.Equal(t, want, got)
}
func TestFormatVersion_NoGitCommit(t *testing.T) { func TestFormatVersion_NoGitCommit(t *testing.T) {
oldVersion, oldGit := version, gitCommit oldVersion, oldGit := version, gitCommit
t.Cleanup(func() { version, gitCommit = oldVersion, oldGit }) t.Cleanup(func() { version, gitCommit = oldVersion, oldGit })

View file

@ -42,6 +42,9 @@ type ContextBuilder struct {
} }
func getGlobalConfigDir() string { func getGlobalConfigDir() string {
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
return home
}
home, err := os.UserHomeDir() home, err := os.UserHomeDir()
if err != nil { if err != nil {
return "" return ""

View file

@ -187,12 +187,13 @@ func resolveAgentWorkspace(agentCfg *config.AgentConfig, defaults *config.AgentD
if agentCfg != nil && strings.TrimSpace(agentCfg.Workspace) != "" { if agentCfg != nil && strings.TrimSpace(agentCfg.Workspace) != "" {
return expandHome(strings.TrimSpace(agentCfg.Workspace)) return expandHome(strings.TrimSpace(agentCfg.Workspace))
} }
// Use the configured default workspace (respects PICOCLAW_HOME)
if agentCfg == nil || agentCfg.Default || agentCfg.ID == "" || routing.NormalizeAgentID(agentCfg.ID) == "main" { if agentCfg == nil || agentCfg.Default || agentCfg.ID == "" || routing.NormalizeAgentID(agentCfg.ID) == "main" {
return expandHome(defaults.Workspace) return expandHome(defaults.Workspace)
} }
home, _ := os.UserHomeDir() // For named agents without explicit workspace, use default workspace with agent ID suffix
id := routing.NormalizeAgentID(agentCfg.ID) id := routing.NormalizeAgentID(agentCfg.ID)
return filepath.Join(home, ".picoclaw", "workspace-"+id) return filepath.Join(expandHome(defaults.Workspace), "..", "workspace-"+id)
} }
// resolveAgentModel resolves the primary model for an agent. // resolveAgentModel resolves the primary model for an agent.

View file

@ -39,6 +39,9 @@ func (c *AuthCredential) NeedsRefresh() bool {
} }
func authFilePath() string { func authFilePath() string {
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
return filepath.Join(home, "auth.json")
}
home, _ := os.UserHomeDir() home, _ := os.UserHomeDir()
return filepath.Join(home, ".picoclaw", "auth.json") return filepath.Join(home, ".picoclaw", "auth.json")
} }