feat(v0.3): add seed dir and project root resolvers in config
ResolveSeedDir, ResolveProjectSeedDir, and ResolveProjectRoot read the v0.3 environment variables (CTASK_SEED_DIR, CTASK_SEED_PROJECT_DIR, CTASK_PROJECT_ROOT) and fall back to platform defaults under %APPDATA%\ctask or ~/.config/ctask. The expandPath helper handles tilde expansion + abs-path resolution once for all resolvers.
This commit is contained in:
+60
-10
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -14,16 +15,7 @@ func ResolveRoot() string {
|
||||
home, _ := os.UserHomeDir()
|
||||
return filepath.Join(home, "ai-workspaces")
|
||||
}
|
||||
// Expand leading tilde
|
||||
if strings.HasPrefix(root, "~/") || root == "~" {
|
||||
home, _ := os.UserHomeDir()
|
||||
root = filepath.Join(home, root[2:])
|
||||
}
|
||||
abs, err := filepath.Abs(root)
|
||||
if err != nil {
|
||||
return root
|
||||
}
|
||||
return abs
|
||||
return expandPath(root)
|
||||
}
|
||||
|
||||
// ResolveAgent returns the agent command.
|
||||
@@ -36,6 +28,37 @@ func ResolveAgent() string {
|
||||
return agent
|
||||
}
|
||||
|
||||
// ResolveSeedDir returns the user general seed directory.
|
||||
// Reads CTASK_SEED_DIR; falls back to %APPDATA%\ctask\seed on Windows or
|
||||
// ~/.config/ctask/seed on Unix.
|
||||
func ResolveSeedDir() string {
|
||||
if v := os.Getenv("CTASK_SEED_DIR"); v != "" {
|
||||
return expandPath(v)
|
||||
}
|
||||
return defaultSeedDir("seed")
|
||||
}
|
||||
|
||||
// ResolveProjectSeedDir returns the user project seed directory.
|
||||
// Reads CTASK_SEED_PROJECT_DIR; falls back to %APPDATA%\ctask\seed-project on Windows
|
||||
// or ~/.config/ctask/seed-project on Unix.
|
||||
func ResolveProjectSeedDir() string {
|
||||
if v := os.Getenv("CTASK_SEED_PROJECT_DIR"); v != "" {
|
||||
return expandPath(v)
|
||||
}
|
||||
return defaultSeedDir("seed-project")
|
||||
}
|
||||
|
||||
// ResolveProjectRoot returns the project workspace root override.
|
||||
// Returns empty string if CTASK_PROJECT_ROOT is not set; callers should fall back
|
||||
// to ResolveRoot() in that case.
|
||||
func ResolveProjectRoot() string {
|
||||
v := os.Getenv("CTASK_PROJECT_ROOT")
|
||||
if v == "" {
|
||||
return ""
|
||||
}
|
||||
return expandPath(v)
|
||||
}
|
||||
|
||||
// EnvVars returns the environment variables to export into child sessions.
|
||||
func EnvVars(slug, mode, root, workspace, category string) map[string]string {
|
||||
return map[string]string{
|
||||
@@ -46,3 +69,30 @@ func EnvVars(slug, mode, root, workspace, category string) map[string]string {
|
||||
"CTASK_CATEGORY": category,
|
||||
}
|
||||
}
|
||||
|
||||
// defaultSeedDir returns the platform-default location for a seed directory leaf.
|
||||
func defaultSeedDir(leaf string) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
appData := os.Getenv("APPDATA")
|
||||
if appData == "" {
|
||||
home, _ := os.UserHomeDir()
|
||||
return filepath.Join(home, "AppData", "Roaming", "ctask", leaf)
|
||||
}
|
||||
return filepath.Join(appData, "ctask", leaf)
|
||||
}
|
||||
home, _ := os.UserHomeDir()
|
||||
return filepath.Join(home, ".config", "ctask", leaf)
|
||||
}
|
||||
|
||||
// expandPath expands a leading ~/ and resolves to an absolute path when possible.
|
||||
func expandPath(p string) string {
|
||||
if strings.HasPrefix(p, "~/") || p == "~" {
|
||||
home, _ := os.UserHomeDir()
|
||||
p = filepath.Join(home, p[1:])
|
||||
}
|
||||
abs, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
return p
|
||||
}
|
||||
return abs
|
||||
}
|
||||
|
||||
@@ -68,6 +68,82 @@ func TestRootResolvesTilde(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveSeedDirDefault(t *testing.T) {
|
||||
os.Unsetenv("CTASK_SEED_DIR")
|
||||
got := ResolveSeedDir()
|
||||
home, _ := os.UserHomeDir()
|
||||
var want string
|
||||
if runtime.GOOS == "windows" {
|
||||
appData := os.Getenv("APPDATA")
|
||||
if appData == "" {
|
||||
t.Skip("APPDATA not set on this Windows host")
|
||||
}
|
||||
want = filepath.Join(appData, "ctask", "seed")
|
||||
} else {
|
||||
want = filepath.Join(home, ".config", "ctask", "seed")
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("ResolveSeedDir default: got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveSeedDirOverride(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
os.Setenv("CTASK_SEED_DIR", dir)
|
||||
defer os.Unsetenv("CTASK_SEED_DIR")
|
||||
got := ResolveSeedDir()
|
||||
if got != dir {
|
||||
t.Errorf("ResolveSeedDir override: got %q, want %q", got, dir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveProjectSeedDirDefault(t *testing.T) {
|
||||
os.Unsetenv("CTASK_SEED_PROJECT_DIR")
|
||||
got := ResolveProjectSeedDir()
|
||||
home, _ := os.UserHomeDir()
|
||||
var want string
|
||||
if runtime.GOOS == "windows" {
|
||||
appData := os.Getenv("APPDATA")
|
||||
if appData == "" {
|
||||
t.Skip("APPDATA not set on this Windows host")
|
||||
}
|
||||
want = filepath.Join(appData, "ctask", "seed-project")
|
||||
} else {
|
||||
want = filepath.Join(home, ".config", "ctask", "seed-project")
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("ResolveProjectSeedDir default: got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveProjectSeedDirOverride(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
os.Setenv("CTASK_SEED_PROJECT_DIR", dir)
|
||||
defer os.Unsetenv("CTASK_SEED_PROJECT_DIR")
|
||||
got := ResolveProjectSeedDir()
|
||||
if got != dir {
|
||||
t.Errorf("ResolveProjectSeedDir override: got %q, want %q", got, dir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveProjectRootEmptyWhenUnset(t *testing.T) {
|
||||
os.Unsetenv("CTASK_PROJECT_ROOT")
|
||||
got := ResolveProjectRoot()
|
||||
if got != "" {
|
||||
t.Errorf("ResolveProjectRoot with no override should return empty, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveProjectRootOverride(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
os.Setenv("CTASK_PROJECT_ROOT", dir)
|
||||
defer os.Unsetenv("CTASK_PROJECT_ROOT")
|
||||
got := ResolveProjectRoot()
|
||||
if got != dir {
|
||||
t.Errorf("ResolveProjectRoot override: got %q, want %q", got, dir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvVars(t *testing.T) {
|
||||
vars := EnvVars("my-slug", "local", "/abs/root", "/abs/root/cat/ws", "general")
|
||||
expected := map[string]string{
|
||||
|
||||
Reference in New Issue
Block a user