feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
// System information registry for the Core framework.
|
|
|
|
|
// Read-only key-value store of environment facts, populated once at init.
|
|
|
|
|
// Env is environment. Config is ours.
|
|
|
|
|
//
|
|
|
|
|
// System keys:
|
|
|
|
|
//
|
|
|
|
|
// core.Env("OS") // "darwin"
|
|
|
|
|
// core.Env("ARCH") // "arm64"
|
|
|
|
|
// core.Env("GO") // "go1.26"
|
|
|
|
|
// core.Env("DS") // "/" (directory separator)
|
|
|
|
|
// core.Env("PS") // ":" (path list separator)
|
|
|
|
|
// core.Env("HOSTNAME") // "cladius"
|
|
|
|
|
// core.Env("USER") // "snider"
|
|
|
|
|
// core.Env("PID") // "12345"
|
|
|
|
|
// core.Env("NUM_CPU") // "10"
|
|
|
|
|
//
|
|
|
|
|
// Directory keys:
|
|
|
|
|
//
|
|
|
|
|
// core.Env("DIR_HOME") // "/Users/snider"
|
|
|
|
|
// core.Env("DIR_CONFIG") // "~/Library/Application Support"
|
|
|
|
|
// core.Env("DIR_CACHE") // "~/Library/Caches"
|
|
|
|
|
// core.Env("DIR_DATA") // "~/Library" (platform-specific)
|
|
|
|
|
// core.Env("DIR_TMP") // "/tmp"
|
|
|
|
|
// core.Env("DIR_CWD") // current working directory
|
|
|
|
|
// core.Env("DIR_DOWNLOADS") // "~/Downloads"
|
|
|
|
|
// core.Env("DIR_CODE") // "~/Code"
|
|
|
|
|
//
|
|
|
|
|
// Timestamp keys:
|
|
|
|
|
//
|
|
|
|
|
// core.Env("CORE_START") // "2026-03-22T14:30:00Z"
|
|
|
|
|
package core
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"os"
|
|
|
|
|
"runtime"
|
|
|
|
|
"strconv"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// SysInfo holds read-only system information, populated once at init.
|
|
|
|
|
type SysInfo struct {
|
|
|
|
|
values map[string]string
|
|
|
|
|
}
|
|
|
|
|
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
// systemInfo is declared empty — populated in init() so Path() can be used
|
|
|
|
|
// without creating an init cycle.
|
|
|
|
|
var systemInfo = &SysInfo{values: make(map[string]string)}
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
func init() {
|
|
|
|
|
i := systemInfo
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
|
|
|
|
|
// System
|
|
|
|
|
i.values["OS"] = runtime.GOOS
|
|
|
|
|
i.values["ARCH"] = runtime.GOARCH
|
|
|
|
|
i.values["GO"] = runtime.Version()
|
|
|
|
|
i.values["DS"] = string(os.PathSeparator)
|
|
|
|
|
i.values["PS"] = string(os.PathListSeparator)
|
|
|
|
|
i.values["PID"] = strconv.Itoa(os.Getpid())
|
|
|
|
|
i.values["NUM_CPU"] = strconv.Itoa(runtime.NumCPU())
|
|
|
|
|
i.values["USER"] = Username()
|
|
|
|
|
|
|
|
|
|
if h, err := os.Hostname(); err == nil {
|
|
|
|
|
i.values["HOSTNAME"] = h
|
|
|
|
|
}
|
|
|
|
|
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
// Directories — DS and DIR_HOME set first so Path() can use them.
|
|
|
|
|
// CORE_HOME overrides os.UserHomeDir() (e.g., agent workspaces).
|
|
|
|
|
if d := os.Getenv("CORE_HOME"); d != "" {
|
|
|
|
|
i.values["DIR_HOME"] = d
|
|
|
|
|
} else if d, err := os.UserHomeDir(); err == nil {
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
i.values["DIR_HOME"] = d
|
|
|
|
|
}
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
|
|
|
|
|
// Derived directories via Path() — single point of responsibility
|
|
|
|
|
i.values["DIR_DOWNLOADS"] = Path("Downloads")
|
|
|
|
|
i.values["DIR_CODE"] = Path("Code")
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
if d, err := os.UserConfigDir(); err == nil {
|
|
|
|
|
i.values["DIR_CONFIG"] = d
|
|
|
|
|
}
|
|
|
|
|
if d, err := os.UserCacheDir(); err == nil {
|
|
|
|
|
i.values["DIR_CACHE"] = d
|
|
|
|
|
}
|
|
|
|
|
i.values["DIR_TMP"] = os.TempDir()
|
|
|
|
|
if d, err := os.Getwd(); err == nil {
|
|
|
|
|
i.values["DIR_CWD"] = d
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Platform-specific data directory
|
|
|
|
|
switch runtime.GOOS {
|
|
|
|
|
case "darwin":
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
i.values["DIR_DATA"] = Path(Env("DIR_HOME"), "Library")
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
case "windows":
|
|
|
|
|
if d := os.Getenv("LOCALAPPDATA"); d != "" {
|
|
|
|
|
i.values["DIR_DATA"] = d
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
if xdg := os.Getenv("XDG_DATA_HOME"); xdg != "" {
|
|
|
|
|
i.values["DIR_DATA"] = xdg
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
} else if Env("DIR_HOME") != "" {
|
|
|
|
|
i.values["DIR_DATA"] = Path(Env("DIR_HOME"), ".local", "share")
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Timestamps
|
|
|
|
|
i.values["CORE_START"] = time.Now().UTC().Format(time.RFC3339)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Env returns a system information value by key.
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
// Core keys (OS, DIR_HOME, DS, etc.) are pre-populated at init.
|
|
|
|
|
// Unknown keys fall through to os.Getenv — making Env a universal
|
|
|
|
|
// replacement for os.Getenv.
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
//
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
// core.Env("OS") // "darwin" (pre-populated)
|
|
|
|
|
// core.Env("DIR_HOME") // "/Users/snider" (pre-populated)
|
|
|
|
|
// core.Env("FORGE_TOKEN") // falls through to os.Getenv
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
func Env(key string) string {
|
feat: add core.Path() + core.Env() fallthrough + PathGlob/PathIsAbs/CleanPath
Path() builds OS-aware absolute paths using Env("DS") — single point
of responsibility for filesystem paths. Relative paths anchor to
DIR_HOME. cleanPath resolves .. and double separators.
Env() now falls through to os.Getenv for unknown keys — universal
replacement for os.Getenv. Core keys (OS, DIR_HOME, etc.) take
precedence, arbitrary env vars pass through.
New exports: Path, PathBase, PathDir, PathExt, PathIsAbs, PathGlob,
CleanPath. Info init moved to init() so Path() can be used during
population without init cycle. DIR_HOME respects CORE_HOME env var
override for agent workspace sandboxing.
13 path tests, 17 env tests — all passing.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:50:50 +00:00
|
|
|
if v := systemInfo.values[key]; v != "" {
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
return os.Getenv(key)
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EnvKeys returns all available environment keys.
|
|
|
|
|
//
|
|
|
|
|
// keys := core.EnvKeys()
|
|
|
|
|
func EnvKeys() []string {
|
|
|
|
|
keys := make([]string, 0, len(systemInfo.values))
|
|
|
|
|
for k := range systemInfo.values {
|
|
|
|
|
keys = append(keys, k)
|
|
|
|
|
}
|
|
|
|
|
return keys
|
|
|
|
|
}
|