122 lines
3.5 KiB
Go
122 lines
3.5 KiB
Go
// Package env manages the daemon-global environment for ollie.
|
|
// It owns the set of known OLLIE_* and SUPERPOWERD_* variables, provides
|
|
// defaults, and formats them for export to frontends via ollie/env.
|
|
package env
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"ollie/paths"
|
|
)
|
|
|
|
// managed is the ordered list of env vars that ollie exposes to frontends.
|
|
var managed = []string{
|
|
"OLLIE",
|
|
"OLLIE_CFG_PATH",
|
|
"OLLIE_TOOLS_PATH",
|
|
"OLLIE_AGENTS_PATH",
|
|
"OLLIE_SKILLS_PATH",
|
|
"OLLIE_PROMPTS_PATH",
|
|
"OLLIE_MEMORY_PATH",
|
|
"OLLIE_TMP_PATH",
|
|
"OLLIE_TRANSCRIPT_PATH",
|
|
"OLLIE_ELEVATE_SOCKET",
|
|
"SUPERPOWERD_SESSION_TOKEN",
|
|
"SUPERPOWERD_SOCKET_DIR",
|
|
}
|
|
|
|
// EnsureDefaults loads ~/.config/ollie/env and sets default values for any
|
|
// OLLIE_* vars not already present in the process environment.
|
|
func EnsureDefaults() {
|
|
home, _ := os.UserHomeDir()
|
|
LoadFile(filepath.Join(home, ".config", "ollie", "env"))
|
|
xdgRuntime := os.Getenv("XDG_RUNTIME_DIR")
|
|
if xdgRuntime == "" {
|
|
xdgRuntime = fmt.Sprintf("/run/user/%d", os.Getuid())
|
|
}
|
|
defaults := map[string]string{
|
|
"OLLIE": filepath.Join(home, "mnt", "ollie"),
|
|
"OLLIE_CFG_PATH": filepath.Join(home, ".config", "ollie"),
|
|
"OLLIE_TOOLS_PATH": filepath.Join(home, ".config", "ollie", "tools"),
|
|
"OLLIE_AGENTS_PATH": filepath.Join(home, ".config", "ollie", "agents"),
|
|
"OLLIE_SKILLS_PATH": filepath.Join(home, ".config", "ollie", "skills"),
|
|
"OLLIE_PROMPTS_PATH": filepath.Join(home, ".config", "ollie", "prompts"),
|
|
"OLLIE_MEMORY_PATH": filepath.Join(home, ".config", "ollie", "memory"),
|
|
"OLLIE_TMP_PATH": filepath.Join(home, ".local", "share", "ollie", "tmp"),
|
|
"OLLIE_TRANSCRIPT_PATH": filepath.Join(home, ".config", "ollie", "transcript"),
|
|
"OLLIE_ELEVATE_SOCKET": filepath.Join(xdgRuntime, "ollie", "elevate.sock"),
|
|
}
|
|
for k, v := range defaults {
|
|
if os.Getenv(k) == "" {
|
|
os.Setenv(k, v) //nolint:errcheck
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set sets a variable in the process environment.
|
|
func Set(k, v string) { os.Setenv(k, v) } //nolint:errcheck
|
|
|
|
// LoadFile reads KEY=VALUE pairs from path and sets any key not already
|
|
// present in the environment. Lines beginning with # and blank lines are
|
|
// ignored. Missing file is silently ignored.
|
|
func LoadFile(path string) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer f.Close()
|
|
|
|
sc := bufio.NewScanner(f)
|
|
for sc.Scan() {
|
|
line := strings.TrimSpace(sc.Text())
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
k, v, ok := strings.Cut(line, "=")
|
|
if !ok {
|
|
continue
|
|
}
|
|
k = strings.TrimSpace(k)
|
|
if i := strings.Index(v, " #"); i >= 0 {
|
|
v = v[:i]
|
|
}
|
|
v = strings.TrimSpace(v)
|
|
if len(v) >= 2 && (v[0] == '"' && v[len(v)-1] == '"' || v[0] == '\'' && v[len(v)-1] == '\'') {
|
|
v = v[1 : len(v)-1]
|
|
}
|
|
if k != "" && os.Getenv(k) == "" {
|
|
os.Setenv(k, paths.ExpandHome(os.ExpandEnv(v))) //nolint:errcheck
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get returns a variable from the process environment.
|
|
func Get(k string) string { return os.Getenv(k) }
|
|
|
|
// All returns the full process environment as a map.
|
|
func All() map[string]string {
|
|
pairs := os.Environ()
|
|
m := make(map[string]string, len(pairs))
|
|
for _, pair := range pairs {
|
|
k, v, _ := strings.Cut(pair, "=")
|
|
m[k] = v
|
|
}
|
|
return m
|
|
}
|
|
|
|
// Format returns the managed environment variables as NAME=VALUE lines,
|
|
// suitable for serving as ollie/env.
|
|
func Format() []byte {
|
|
var sb strings.Builder
|
|
for _, k := range managed {
|
|
if v := os.Getenv(k); v != "" {
|
|
fmt.Fprintf(&sb, "%s=%s\n", k, v)
|
|
}
|
|
}
|
|
return []byte(sb.String())
|
|
}
|