fix(ax): unify home-path resolution

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 18:52:15 +00:00 committed by Snider
parent be78c27561
commit faf6b8b6fb
12 changed files with 81 additions and 23 deletions

View file

@ -6,6 +6,7 @@ import (
"bytes"
"flag"
"dappco.re/go/agent/pkg/agentic"
"dappco.re/go/core"
)
@ -95,7 +96,7 @@ func (commands appCommandSet) version(_ core.Options) core.Result {
core.Print(nil, "core-agent %s", commands.core.App().Version)
core.Print(nil, " go: %s", core.Env("GO"))
core.Print(nil, " os: %s/%s", core.Env("OS"), core.Env("ARCH"))
core.Print(nil, " home: %s", core.Env("DIR_HOME"))
core.Print(nil, " home: %s", agentic.HomeDir())
core.Print(nil, " hostname: %s", core.Env("HOSTNAME"))
core.Print(nil, " pid: %s", core.Env("PID"))
core.Print(nil, " channel: %s", updateChannel())
@ -108,14 +109,14 @@ func (commands appCommandSet) check(_ core.Options) core.Result {
core.Print(nil, "")
core.Print(nil, " binary: core-agent")
agentsPath := core.Path("Code", ".core", "agents.yaml")
agentsPath := core.JoinPath(agentic.CoreRoot(), "agents.yaml")
if fs.IsFile(agentsPath) {
core.Print(nil, " agents: %s (ok)", agentsPath)
} else {
core.Print(nil, " agents: %s (MISSING)", agentsPath)
}
wsRoot := core.Path("Code", ".core", "workspace")
wsRoot := agentic.WorkspaceRoot()
if fs.IsDir(wsRoot) {
entries := core.PathGlob(core.JoinPath(wsRoot, "*"))
core.Print(nil, " workspace: %s (%d entries)", wsRoot, len(entries))

View file

@ -184,7 +184,7 @@ func (s *PrepSubsystem) cmdPrompt(opts core.Options) core.Result {
task = "Review and report findings"
}
repoPath := core.JoinPath(core.Env("DIR_HOME"), "Code", org, repo)
repoPath := core.JoinPath(HomeDir(), "Code", org, repo)
input := PrepInput{
Repo: repo,
@ -209,7 +209,7 @@ func (s *PrepSubsystem) cmdExtract(opts core.Options) core.Result {
}
target := opts.String("target")
if target == "" {
target = core.Path("Code", ".core", "workspace", "test-extract")
target = core.JoinPath(WorkspaceRoot(), "test-extract")
}
data := &lib.WorkspaceData{

View file

@ -172,7 +172,7 @@ func containerCommand(agentType, command string, args []string, repoDir, metaDir
image = defaultDockerImage
}
home := core.Env("DIR_HOME")
home := HomeDir()
dockerArgs := []string{
"run", "--rm",

View file

@ -9,10 +9,7 @@ import (
)
func agentHomeDir() string {
if home := core.Env("HOME"); home != "" {
return home
}
return core.Env("DIR_HOME")
return HomeDir()
}
// ingestFindings reads the agent output log and creates issues via the API

View file

@ -58,7 +58,7 @@ func (s *PrepSubsystem) mirror(ctx context.Context, _ *mcp.CallToolRequest, inpu
basePath := s.codePath
if basePath == "" {
basePath = core.JoinPath(core.Env("DIR_HOME"), "Code", "core")
basePath = core.JoinPath(HomeDir(), "Code", "core")
} else {
basePath = core.JoinPath(basePath, "core")
}

View file

@ -22,7 +22,7 @@ var fs = (&core.Fs{}).NewUnrestricted()
func LocalFs() *core.Fs { return fs }
// WorkspaceRoot returns the root directory for agent workspaces.
// Checks CORE_WORKSPACE env var first, falls back to ~/Code/.core/workspace.
// Checks CORE_WORKSPACE env var first, falls back to HomeDir()/Code/.core/workspace.
//
// wsDir := core.JoinPath(agentic.WorkspaceRoot(), "core", "go-io", "task-42")
func WorkspaceRoot() string {
@ -58,14 +58,27 @@ func WorkspaceName(wsDir string) string {
}
// CoreRoot returns the root directory for core ecosystem files.
// Checks CORE_WORKSPACE env var first, falls back to ~/Code/.core.
// Checks CORE_WORKSPACE env var first, falls back to HomeDir()/Code/.core.
//
// root := agentic.CoreRoot()
func CoreRoot() string {
if root := core.Env("CORE_WORKSPACE"); root != "" {
return root
}
return core.JoinPath(core.Env("DIR_HOME"), "Code", ".core")
return core.JoinPath(HomeDir(), "Code", ".core")
}
// HomeDir returns the user home directory used by agentic path helpers.
//
// home := agentic.HomeDir()
func HomeDir() string {
if home := core.Env("CORE_HOME"); home != "" {
return home
}
if home := core.Env("HOME"); home != "" {
return home
}
return core.Env("DIR_HOME")
}
func workspaceStatusPaths(wsRoot string) []string {

View file

@ -18,6 +18,12 @@ func ExampleCoreRoot() {
// Output: true
}
func ExampleHomeDir() {
home := HomeDir()
core.Println(home != "")
// Output: true
}
func ExamplePlansRoot() {
root := PlansRoot()
core.Println(core.HasSuffix(root, "plans"))

View file

@ -19,10 +19,30 @@ func TestPaths_CoreRoot_Good_EnvVar(t *testing.T) {
func TestPaths_CoreRoot_Good_Fallback(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "")
home := core.Env("DIR_HOME")
home := HomeDir()
assert.Equal(t, home+"/Code/.core", CoreRoot())
}
func TestPaths_CoreRoot_Good_CoreHome(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "")
t.Setenv("CORE_HOME", "/tmp/core-home")
assert.Equal(t, "/tmp/core-home/Code/.core", CoreRoot())
}
func TestPaths_HomeDir_Good_CoreHome(t *testing.T) {
t.Setenv("CORE_HOME", "/tmp/core-home")
t.Setenv("HOME", "/tmp/home")
t.Setenv("DIR_HOME", "/tmp/dir-home")
assert.Equal(t, "/tmp/core-home", HomeDir())
}
func TestPaths_HomeDir_Good_HomeFallback(t *testing.T) {
t.Setenv("CORE_HOME", "")
t.Setenv("HOME", "/tmp/home")
t.Setenv("DIR_HOME", "/tmp/dir-home")
assert.Equal(t, "/tmp/home", HomeDir())
}
func TestPaths_WorkspaceRoot_Good(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "/tmp/test-core")
assert.Equal(t, "/tmp/test-core/workspace", WorkspaceRoot())
@ -131,7 +151,7 @@ func TestPaths_LocalFs_Ugly_EmptyPath(t *testing.T) {
func TestPaths_WorkspaceRoot_Bad_EmptyEnv(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "")
home := core.Env("DIR_HOME")
home := HomeDir()
// Should fall back to ~/Code/.core/workspace
assert.Equal(t, home+"/Code/.core/workspace", WorkspaceRoot())
}
@ -196,7 +216,7 @@ func TestPaths_CoreRoot_Ugly_UnicodeEnv(t *testing.T) {
func TestPaths_PlansRoot_Bad_EmptyEnv(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "")
home := core.Env("DIR_HOME")
home := HomeDir()
assert.Equal(t, home+"/Code/.core/plans", PlansRoot())
}

View file

@ -52,7 +52,7 @@ var _ coremcp.Subsystem = (*PrepSubsystem)(nil)
// sub := agentic.NewPrep()
// sub.SetCompletionNotifier(monitor)
func NewPrep() *PrepSubsystem {
home := core.Env("DIR_HOME")
home := HomeDir()
forgeToken := core.Env("FORGE_TOKEN")
if forgeToken == "" {

View file

@ -178,6 +178,23 @@ func TestPrep_NewPrep_Good_EnvOverrides(t *testing.T) {
assert.Equal(t, "/custom/code", s.codePath)
}
func TestPrep_NewPrep_Good_CoreHomeOverride(t *testing.T) {
tmpHome := t.TempDir()
claudeDir := core.JoinPath(tmpHome, ".claude")
require.True(t, fs.EnsureDir(claudeDir).OK)
require.True(t, fs.Write(core.JoinPath(claudeDir, "brain.key"), "core-home-key").OK)
t.Setenv("CORE_HOME", tmpHome)
t.Setenv("HOME", "/ignored-home")
t.Setenv("DIR_HOME", "/ignored-dir")
t.Setenv("CORE_BRAIN_KEY", "")
t.Setenv("CODE_PATH", "")
s := NewPrep()
assert.Equal(t, core.JoinPath(tmpHome, "Code"), s.codePath)
assert.Equal(t, "core-home-key", s.brainKey)
}
func TestPrep_NewPrep_Good_GiteaTokenFallback(t *testing.T) {
t.Setenv("FORGE_TOKEN", "")
t.Setenv("GITEA_TOKEN", "gitea-fallback-token")

View file

@ -207,7 +207,7 @@ func remoteToken(host string) string {
}
// Try reading from file
home := core.Env("DIR_HOME")
home := HomeDir()
tokenFiles := []string{
core.Sprintf("%s/.core/tokens/%s.token", home, core.Lower(host)),
core.Sprintf("%s/.core/agent-token", home),

View file

@ -76,7 +76,11 @@ func (s *PrepSubsystem) reviewQueue(ctx context.Context, _ *mcp.CallToolRequest,
limit = 4
}
basePath := core.JoinPath(s.codePath, "core")
basePath := s.codePath
if basePath == "" {
basePath = core.JoinPath(HomeDir(), "Code")
}
basePath = core.JoinPath(basePath, "core")
// Find repos with draft PRs (ahead of GitHub)
candidates := s.findReviewCandidates(basePath)
@ -335,7 +339,7 @@ func (s *PrepSubsystem) buildReviewCommand(repoDir, reviewer string) (string, []
// storeReviewOutput saves raw review output for training data collection.
func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string) {
dataDir := core.JoinPath(core.Env("DIR_HOME"), ".core", "training", "reviews")
dataDir := core.JoinPath(HomeDir(), ".core", "training", "reviews")
fs.EnsureDir(dataDir)
timestamp := time.Now().Format("2006-01-02T15-04-05")
@ -367,13 +371,13 @@ func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string
// saveRateLimitState persists rate limit info for cross-run awareness.
func (s *PrepSubsystem) saveRateLimitState(info *RateLimitInfo) {
path := core.JoinPath(core.Env("DIR_HOME"), ".core", "coderabbit-ratelimit.json")
path := core.JoinPath(HomeDir(), ".core", "coderabbit-ratelimit.json")
fs.WriteAtomic(path, core.JSONMarshalString(info))
}
// loadRateLimitState reads persisted rate limit info.
func (s *PrepSubsystem) loadRateLimitState() *RateLimitInfo {
path := core.JoinPath(core.Env("DIR_HOME"), ".core", "coderabbit-ratelimit.json")
path := core.JoinPath(HomeDir(), ".core", "coderabbit-ratelimit.json")
r := fs.Read(path)
if !r.OK {
return nil