refactor: centralize environment variable key constants (#1730)
* refactor: centralize environment variable key constants * refactor: update environment variable constants and usage in gateway
This commit is contained in:
parent
affd77f989
commit
c07f5c948f
13 changed files with 83 additions and 21 deletions
|
|
@ -12,7 +12,7 @@ const Logo = "🦞"
|
||||||
// GetPicoclawHome returns the picoclaw home directory.
|
// GetPicoclawHome returns the picoclaw home directory.
|
||||||
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
||||||
func GetPicoclawHome() string {
|
func GetPicoclawHome() string {
|
||||||
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
|
if home := os.Getenv(config.EnvHome); home != "" {
|
||||||
return home
|
return home
|
||||||
}
|
}
|
||||||
home, _ := os.UserHomeDir()
|
home, _ := os.UserHomeDir()
|
||||||
|
|
@ -20,7 +20,7 @@ func GetPicoclawHome() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfigPath() string {
|
func GetConfigPath() string {
|
||||||
if configPath := os.Getenv("PICOCLAW_CONFIG"); configPath != "" {
|
if configPath := os.Getenv(config.EnvConfig); configPath != "" {
|
||||||
return configPath
|
return configPath
|
||||||
}
|
}
|
||||||
return filepath.Join(GetPicoclawHome(), "config.json")
|
return filepath.Join(GetPicoclawHome(), "config.json")
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (cb *ContextBuilder) WithToolDiscovery(useBM25, useRegex bool) *ContextBuil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGlobalConfigDir() string {
|
func getGlobalConfigDir() string {
|
||||||
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
|
if home := os.Getenv(config.EnvHome); home != "" {
|
||||||
return home
|
return home
|
||||||
}
|
}
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
|
|
@ -65,7 +65,7 @@ func getGlobalConfigDir() string {
|
||||||
func NewContextBuilder(workspace string) *ContextBuilder {
|
func NewContextBuilder(workspace string) *ContextBuilder {
|
||||||
// builtin skills: skills directory in current project
|
// builtin skills: skills directory in current project
|
||||||
// Use the skills/ directory under the current working directory
|
// Use the skills/ directory under the current working directory
|
||||||
builtinSkillsDir := strings.TrimSpace(os.Getenv("PICOCLAW_BUILTIN_SKILLS"))
|
builtinSkillsDir := strings.TrimSpace(os.Getenv(config.EnvBuiltinSkills))
|
||||||
if builtinSkillsDir == "" {
|
if builtinSkillsDir == "" {
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
builtinSkillsDir = filepath.Join(wd, "skills")
|
builtinSkillsDir = filepath.Join(wd, "skills")
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
"github.com/sipeed/picoclaw/pkg/fileutil"
|
"github.com/sipeed/picoclaw/pkg/fileutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ func (c *AuthCredential) NeedsRefresh() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func authFilePath() string {
|
func authFilePath() string {
|
||||||
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
|
if home := os.Getenv(config.EnvHome); home != "" {
|
||||||
return filepath.Join(home, "auth.json")
|
return filepath.Join(home, "auth.json")
|
||||||
}
|
}
|
||||||
home, _ := os.UserHomeDir()
|
home, _ := os.UserHomeDir()
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ func DefaultConfig() *Config {
|
||||||
// Determine the base path for the workspace.
|
// Determine the base path for the workspace.
|
||||||
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
||||||
var homePath string
|
var homePath string
|
||||||
if picoclawHome := os.Getenv("PICOCLAW_HOME"); picoclawHome != "" {
|
if picoclawHome := os.Getenv(EnvHome); picoclawHome != "" {
|
||||||
homePath = picoclawHome
|
homePath = picoclawHome
|
||||||
} else {
|
} else {
|
||||||
userHome, _ := os.UserHomeDir()
|
userHome, _ := os.UserHomeDir()
|
||||||
|
|
|
||||||
37
pkg/config/envkeys.go
Normal file
37
pkg/config/envkeys.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
// PicoClaw - Ultra-lightweight personal AI agent
|
||||||
|
// License: MIT
|
||||||
|
//
|
||||||
|
// Copyright (c) 2026 PicoClaw contributors
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
// Runtime environment variable keys for the picoclaw process.
|
||||||
|
// These control the location of files and binaries at runtime and are read
|
||||||
|
// directly via os.Getenv / os.LookupEnv. All picoclaw-specific keys use the
|
||||||
|
// PICOCLAW_ prefix. Reference these constants instead of inline string
|
||||||
|
// literals to keep all supported knobs visible in one place and to prevent
|
||||||
|
// typos.
|
||||||
|
const (
|
||||||
|
// EnvHome overrides the base directory for all picoclaw data
|
||||||
|
// (config, workspace, skills, auth store, …).
|
||||||
|
// Default: ~/.picoclaw
|
||||||
|
EnvHome = "PICOCLAW_HOME"
|
||||||
|
|
||||||
|
// EnvConfig overrides the full path to the JSON config file.
|
||||||
|
// Default: $PICOCLAW_HOME/config.json
|
||||||
|
EnvConfig = "PICOCLAW_CONFIG"
|
||||||
|
|
||||||
|
// EnvBuiltinSkills overrides the directory from which built-in
|
||||||
|
// skills are loaded.
|
||||||
|
// Default: <cwd>/skills
|
||||||
|
EnvBuiltinSkills = "PICOCLAW_BUILTIN_SKILLS"
|
||||||
|
|
||||||
|
// EnvBinary overrides the path to the picoclaw executable.
|
||||||
|
// Used by the web launcher when spawning the gateway subprocess.
|
||||||
|
// Default: resolved from the same directory as the current executable.
|
||||||
|
EnvBinary = "PICOCLAW_BINARY"
|
||||||
|
|
||||||
|
// EnvGatewayHost overrides the host address for the gateway server.
|
||||||
|
// Default: "127.0.0.1"
|
||||||
|
EnvGatewayHost = "PICOCLAW_GATEWAY_HOST"
|
||||||
|
)
|
||||||
|
|
@ -66,6 +66,14 @@ var ErrPassphraseRequired = errors.New("credential: enc:// passphrase required")
|
||||||
// indicating a wrong passphrase or SSH key. Callers can detect this with errors.Is.
|
// indicating a wrong passphrase or SSH key. Callers can detect this with errors.Is.
|
||||||
var ErrDecryptionFailed = errors.New("credential: enc:// decryption failed (wrong passphrase or SSH key?)")
|
var ErrDecryptionFailed = errors.New("credential: enc:// decryption failed (wrong passphrase or SSH key?)")
|
||||||
|
|
||||||
|
// SSHKeyPathEnvVar is the environment variable that specifies the path to the
|
||||||
|
// SSH private key used for enc:// credential encryption and decryption.
|
||||||
|
const SSHKeyPathEnvVar = "PICOCLAW_SSH_KEY_PATH"
|
||||||
|
|
||||||
|
// picoclawHome is a package-local copy of config.EnvHome. It is kept here to
|
||||||
|
// avoid a circular import between pkg/credential and pkg/config.
|
||||||
|
const picoclawHome = "PICOCLAW_HOME"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fileScheme = "file://"
|
fileScheme = "file://"
|
||||||
encScheme = "enc://"
|
encScheme = "enc://"
|
||||||
|
|
@ -73,7 +81,6 @@ const (
|
||||||
saltLen = 16
|
saltLen = 16
|
||||||
nonceLen = 12
|
nonceLen = 12
|
||||||
keyLen = 32
|
keyLen = 32
|
||||||
sshKeyEnv = "PICOCLAW_SSH_KEY_PATH"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver resolves raw credential strings for model_list api_key fields.
|
// Resolver resolves raw credential strings for model_list api_key fields.
|
||||||
|
|
@ -248,14 +255,14 @@ func allowedSSHKeyPath(path string) bool {
|
||||||
clean := filepath.Clean(path)
|
clean := filepath.Clean(path)
|
||||||
|
|
||||||
// Exact match with PICOCLAW_SSH_KEY_PATH.
|
// Exact match with PICOCLAW_SSH_KEY_PATH.
|
||||||
if envPath, ok := os.LookupEnv(sshKeyEnv); ok && envPath != "" {
|
if envPath, ok := os.LookupEnv(SSHKeyPathEnvVar); ok && envPath != "" {
|
||||||
if clean == filepath.Clean(envPath) {
|
if clean == filepath.Clean(envPath) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Within PICOCLAW_HOME.
|
// Within PICOCLAW_HOME.
|
||||||
if picoHome := os.Getenv("PICOCLAW_HOME"); picoHome != "" {
|
if picoHome := os.Getenv(picoclawHome); picoHome != "" {
|
||||||
if isWithinDir(clean, picoHome) {
|
if isWithinDir(clean, picoHome) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -316,7 +323,7 @@ func pickSSHKeyPath(override string) string {
|
||||||
if override != "" {
|
if override != "" {
|
||||||
return override
|
return override
|
||||||
}
|
}
|
||||||
if p, ok := os.LookupEnv(sshKeyEnv); ok {
|
if p, ok := os.LookupEnv(SSHKeyPathEnvVar); ok {
|
||||||
return p // respect explicit setting, even if ""
|
return p // respect explicit setting, even if ""
|
||||||
}
|
}
|
||||||
return findDefaultSSHKey()
|
return findDefaultSSHKey()
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ResolveTargetHome(override string) (string, error) {
|
func ResolveTargetHome(override string) (string, error) {
|
||||||
if override != "" {
|
if override != "" {
|
||||||
return ExpandHome(override), nil
|
return ExpandHome(override), nil
|
||||||
}
|
}
|
||||||
if envHome := os.Getenv("PICOCLAW_HOME"); envHome != "" {
|
if envHome := os.Getenv(config.EnvHome); envHome != "" {
|
||||||
return ExpandHome(envHome), nil
|
return ExpandHome(envHome), nil
|
||||||
}
|
}
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ import (
|
||||||
"github.com/sipeed/picoclaw/pkg/migrate/internal"
|
"github.com/sipeed/picoclaw/pkg/migrate/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OpenclawHomeEnvVar is the environment variable that overrides the source
|
||||||
|
// openclaw home directory when migrating from openclaw to picoclaw.
|
||||||
|
// Default: ~/.openclaw
|
||||||
|
const OpenclawHomeEnvVar = "OPENCLAW_HOME"
|
||||||
|
|
||||||
var providerMapping = map[string]string{
|
var providerMapping = map[string]string{
|
||||||
"anthropic": "anthropic",
|
"anthropic": "anthropic",
|
||||||
"claude": "anthropic",
|
"claude": "anthropic",
|
||||||
|
|
@ -112,7 +117,7 @@ func resolveSourceHome(override string) (string, error) {
|
||||||
if override != "" {
|
if override != "" {
|
||||||
return internal.ExpandHome(override), nil
|
return internal.ExpandHome(override), nil
|
||||||
}
|
}
|
||||||
if envHome := os.Getenv("OPENCLAW_HOME"); envHome != "" {
|
if envHome := os.Getenv(OpenclawHomeEnvVar); envHome != "" {
|
||||||
return internal.ExpandHome(envHome), nil
|
return internal.ExpandHome(envHome), nil
|
||||||
}
|
}
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CodexHomeEnvVar is the environment variable that overrides the Codex CLI
|
||||||
|
// home directory when resolving the codex auth.json credentials file.
|
||||||
|
// Default: ~/.codex
|
||||||
|
const CodexHomeEnvVar = "CODEX_HOME"
|
||||||
|
|
||||||
// CodexCliAuth represents the ~/.codex/auth.json file structure.
|
// CodexCliAuth represents the ~/.codex/auth.json file structure.
|
||||||
type CodexCliAuth struct {
|
type CodexCliAuth struct {
|
||||||
Tokens struct {
|
Tokens struct {
|
||||||
|
|
@ -69,7 +74,7 @@ func CreateCodexCliTokenSource() func() (string, string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveCodexAuthPath() (string, error) {
|
func resolveCodexAuthPath() (string, error) {
|
||||||
codexHome := os.Getenv("CODEX_HOME")
|
codexHome := os.Getenv(CodexHomeEnvVar)
|
||||||
if codexHome == "" {
|
if codexHome == "" {
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -387,10 +387,10 @@ func (h *Handler) startGatewayLocked(initialStatus string, existingPid int) (int
|
||||||
// GetConfigPath() already reads, so the gateway sub-process uses the same
|
// GetConfigPath() already reads, so the gateway sub-process uses the same
|
||||||
// config file without requiring a --config flag on the gateway subcommand.
|
// config file without requiring a --config flag on the gateway subcommand.
|
||||||
if h.configPath != "" {
|
if h.configPath != "" {
|
||||||
cmd.Env = append(cmd.Env, "PICOCLAW_CONFIG="+h.configPath)
|
cmd.Env = append(cmd.Env, config.EnvConfig+"="+h.configPath)
|
||||||
}
|
}
|
||||||
if host := h.gatewayHostOverride(); host != "" {
|
if host := h.gatewayHostOverride(); host != "" {
|
||||||
cmd.Env = append(cmd.Env, "PICOCLAW_GATEWAY_HOST="+host)
|
cmd.Env = append(cmd.Env, config.EnvGatewayHost+"="+host)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
stdoutPipe, err := cmd.StdoutPipe()
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,7 @@ func loadSkillContent(path string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func globalConfigDir() string {
|
func globalConfigDir() string {
|
||||||
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
|
if home := os.Getenv(config.EnvHome); home != "" {
|
||||||
return home
|
return home
|
||||||
}
|
}
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
|
|
@ -320,7 +320,7 @@ func globalConfigDir() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func builtinSkillsDir() string {
|
func builtinSkillsDir() string {
|
||||||
if path := os.Getenv("PICOCLAW_BUILTIN_SKILLS"); path != "" {
|
if path := os.Getenv(config.EnvBuiltinSkills); path != "" {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
var execCommand = exec.Command
|
var execCommand = exec.Command
|
||||||
|
|
@ -19,7 +21,7 @@ func EnsureOnboarded(configPath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := execCommand(FindPicoclawBinary(), "onboard")
|
cmd := execCommand(FindPicoclawBinary(), "onboard")
|
||||||
cmd.Env = append(os.Environ(), "PICOCLAW_CONFIG="+configPath)
|
cmd.Env = append(os.Environ(), config.EnvConfig+"="+configPath)
|
||||||
cmd.Stdin = strings.NewReader("n\n")
|
cmd.Stdin = strings.NewReader("n\n")
|
||||||
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,23 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetPicoclawHome returns the picoclaw home directory.
|
// GetPicoclawHome returns the picoclaw home directory.
|
||||||
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
||||||
func GetPicoclawHome() string {
|
func GetPicoclawHome() string {
|
||||||
if home := os.Getenv("PICOCLAW_HOME"); home != "" {
|
if home := os.Getenv(config.EnvHome); home != "" {
|
||||||
return home
|
return home
|
||||||
}
|
}
|
||||||
home, _ := os.UserHomeDir()
|
home, _ := os.UserHomeDir()
|
||||||
return filepath.Join(home, ".picoclaw")
|
return filepath.Join(home, ".picoclaw")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDefaultConfigPath returns the default path to the picoclaw config file.
|
||||||
func GetDefaultConfigPath() string {
|
func GetDefaultConfigPath() string {
|
||||||
if configPath := os.Getenv("PICOCLAW_CONFIG"); configPath != "" {
|
if configPath := os.Getenv(config.EnvConfig); configPath != "" {
|
||||||
return configPath
|
return configPath
|
||||||
}
|
}
|
||||||
return filepath.Join(GetPicoclawHome(), "config.json")
|
return filepath.Join(GetPicoclawHome(), "config.json")
|
||||||
|
|
@ -37,7 +40,7 @@ func FindPicoclawBinary() string {
|
||||||
binaryName = "picoclaw.exe"
|
binaryName = "picoclaw.exe"
|
||||||
}
|
}
|
||||||
|
|
||||||
if p := os.Getenv("PICOCLAW_BINARY"); p != "" {
|
if p := os.Getenv(config.EnvBinary); p != "" {
|
||||||
if info, _ := os.Stat(p); info != nil && !info.IsDir() {
|
if info, _ := os.Stat(p); info != nil && !info.IsDir() {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue