fix: eliminate path/filepath from all test files

29 test files migrated: filepath.Join→core.JoinPath,
filepath.Dir→core.PathDir, filepath.Base→core.PathBase,
filepath.IsAbs→core.PathIsAbs. Test dogfooding complete for filepath.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-26 01:39:41 +00:00
parent aafa63818f
commit 23bb62a116
29 changed files with 447 additions and 471 deletions

View file

@ -6,7 +6,6 @@ import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
@ -30,14 +29,14 @@ func TestAutoPR_AutoCreatePR_Bad(t *testing.T) {
}
// No status file → early return (no panic)
wsNoStatus := filepath.Join(root, "ws-no-status")
wsNoStatus := core.JoinPath(root, "ws-no-status")
require.NoError(t, os.MkdirAll(wsNoStatus, 0o755))
assert.NotPanics(t, func() {
s.autoCreatePR(wsNoStatus)
})
// Empty branch → early return
wsNoBranch := filepath.Join(root, "ws-no-branch")
wsNoBranch := core.JoinPath(root, "ws-no-branch")
require.NoError(t, os.MkdirAll(wsNoBranch, 0o755))
st := &WorkspaceStatus{
Status: "completed",
@ -47,13 +46,13 @@ func TestAutoPR_AutoCreatePR_Bad(t *testing.T) {
}
data, err := json.MarshalIndent(st, "", " ")
require.NoError(t, err)
require.NoError(t, os.WriteFile(filepath.Join(wsNoBranch, "status.json"), data, 0o644))
require.NoError(t, os.WriteFile(core.JoinPath(wsNoBranch, "status.json"), data, 0o644))
assert.NotPanics(t, func() {
s.autoCreatePR(wsNoBranch)
})
// Empty repo → early return
wsNoRepo := filepath.Join(root, "ws-no-repo")
wsNoRepo := core.JoinPath(root, "ws-no-repo")
require.NoError(t, os.MkdirAll(wsNoRepo, 0o755))
st2 := &WorkspaceStatus{
Status: "completed",
@ -63,7 +62,7 @@ func TestAutoPR_AutoCreatePR_Bad(t *testing.T) {
}
data2, err := json.MarshalIndent(st2, "", " ")
require.NoError(t, err)
require.NoError(t, os.WriteFile(filepath.Join(wsNoRepo, "status.json"), data2, 0o644))
require.NoError(t, os.WriteFile(core.JoinPath(wsNoRepo, "status.json"), data2, 0o644))
assert.NotPanics(t, func() {
s.autoCreatePR(wsNoRepo)
})
@ -74,8 +73,8 @@ func TestAutoPR_AutoCreatePR_Ugly(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Set up a real git repo with no commits ahead of origin/dev
wsDir := filepath.Join(root, "ws-no-ahead")
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(root, "ws-no-ahead")
repoDir := core.JoinPath(wsDir, "repo")
require.NoError(t, os.MkdirAll(repoDir, 0o755))
// Init the repo
@ -86,7 +85,7 @@ func TestAutoPR_AutoCreatePR_Ugly(t *testing.T) {
cmd = exec.Command("git", "-C", repoDir, "config", "user.email", "test@test.com")
require.NoError(t, cmd.Run())
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("# test"), 0o644))
require.NoError(t, os.WriteFile(core.JoinPath(repoDir, "README.md"), []byte("# test"), 0o644))
cmd = exec.Command("git", "-C", repoDir, "add", ".")
require.NoError(t, cmd.Run())
cmd = exec.Command("git", "-C", repoDir, "commit", "-m", "init")
@ -102,7 +101,7 @@ func TestAutoPR_AutoCreatePR_Ugly(t *testing.T) {
}
data, err := json.MarshalIndent(st, "", " ")
require.NoError(t, err)
require.NoError(t, os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644))
require.NoError(t, os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644))
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),

View file

@ -8,7 +8,6 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
@ -460,10 +459,10 @@ func TestCommandsWorkspace_CmdWorkspaceList_Good_WithEntries(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
ws := filepath.Join(wsRoot, "ws-1")
ws := core.JoinPath(wsRoot, "ws-1")
os.MkdirAll(ws, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
r := s.cmdWorkspaceList(core.NewOptions())
assert.True(t, r.OK)
@ -479,10 +478,10 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Good_RemovesCompleted(t *testing.T)
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
ws := filepath.Join(wsRoot, "ws-done")
ws := core.JoinPath(wsRoot, "ws-done")
os.MkdirAll(ws, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: "completed", Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
r := s.cmdWorkspaceClean(core.NewOptions())
assert.True(t, r.OK)
@ -499,18 +498,18 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Good_FilterFailed(t *testing.T) {
{"ws-ok", "completed"},
{"ws-bad", "failed"},
} {
d := filepath.Join(wsRoot, ws.name)
d := core.JoinPath(wsRoot, ws.name)
os.MkdirAll(d, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: ws.status, Repo: "test", Agent: "codex"})
os.WriteFile(filepath.Join(d, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(d, "status.json"), data, 0o644)
}
r := s.cmdWorkspaceClean(core.NewOptions(core.Option{Key: "_arg", Value: "failed"}))
assert.True(t, r.OK)
_, err1 := os.Stat(filepath.Join(wsRoot, "ws-bad"))
_, err1 := os.Stat(core.JoinPath(wsRoot, "ws-bad"))
assert.True(t, os.IsNotExist(err1))
_, err2 := os.Stat(filepath.Join(wsRoot, "ws-ok"))
_, err2 := os.Stat(core.JoinPath(wsRoot, "ws-ok"))
assert.NoError(t, err2)
}
@ -518,10 +517,10 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Good_FilterBlocked(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
d := filepath.Join(wsRoot, "ws-stuck")
d := core.JoinPath(wsRoot, "ws-stuck")
os.MkdirAll(d, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: "blocked", Repo: "test", Agent: "codex"})
os.WriteFile(filepath.Join(d, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(d, "status.json"), data, 0o644)
r := s.cmdWorkspaceClean(core.NewOptions(core.Option{Key: "_arg", Value: "blocked"}))
assert.True(t, r.OK)
@ -567,10 +566,10 @@ func TestCommands_CmdStatus_Good_WithWorkspaces(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
ws := filepath.Join(wsRoot, "ws-1")
ws := core.JoinPath(wsRoot, "ws-1")
os.MkdirAll(ws, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: "completed", Repo: "test", Agent: "codex"})
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
r := s.cmdStatus(core.NewOptions())
assert.True(t, r.OK)
@ -590,7 +589,7 @@ func TestCommands_CmdPrompt_Good_DefaultTask(t *testing.T) {
func TestCommands_CmdExtract_Good(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
target := filepath.Join(t.TempDir(), "extract-test")
target := core.JoinPath(t.TempDir(), "extract-test")
r := s.cmdExtract(core.NewOptions(
core.Option{Key: "_arg", Value: "default"},
core.Option{Key: "target", Value: target},
@ -651,9 +650,9 @@ func TestCommands_RegisterCommands_Good_AllRegistered(t *testing.T) {
func TestCommands_CmdExtract_Bad_TargetDirAlreadyHasFiles(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
target := filepath.Join(t.TempDir(), "extract-existing")
target := core.JoinPath(t.TempDir(), "extract-existing")
os.MkdirAll(target, 0o755)
os.WriteFile(filepath.Join(target, "existing.txt"), []byte("data"), 0o644)
os.WriteFile(core.JoinPath(target, "existing.txt"), []byte("data"), 0o644)
// Missing template arg uses "default", target already has files — still succeeds (overwrites)
r := s.cmdExtract(core.NewOptions(
@ -664,7 +663,7 @@ func TestCommands_CmdExtract_Bad_TargetDirAlreadyHasFiles(t *testing.T) {
func TestCommands_CmdExtract_Ugly_TargetIsFile(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
target := filepath.Join(t.TempDir(), "not-a-dir")
target := core.JoinPath(t.TempDir(), "not-a-dir")
os.WriteFile(target, []byte("I am a file"), 0o644)
r := s.cmdExtract(core.NewOptions(
@ -840,13 +839,13 @@ func TestCommands_CmdStatus_Ugly_NonDirEntries(t *testing.T) {
os.MkdirAll(wsRoot, 0o755)
// Create a file (not a dir) inside workspace root
os.WriteFile(filepath.Join(wsRoot, "not-a-workspace.txt"), []byte("junk"), 0o644)
os.WriteFile(core.JoinPath(wsRoot, "not-a-workspace.txt"), []byte("junk"), 0o644)
// Also create a proper workspace
ws := filepath.Join(wsRoot, "ws-valid")
ws := core.JoinPath(wsRoot, "ws-valid")
os.MkdirAll(ws, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: "running", Repo: "test", Agent: "codex"})
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
r := s.cmdStatus(core.NewOptions())
assert.True(t, r.OK)

View file

@ -5,7 +5,6 @@ package agentic
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
@ -89,22 +88,22 @@ func TestCommandsWorkspace_CmdWorkspaceList_Bad_NoWorkspaceRootDir(t *testing.T)
func TestCommandsWorkspace_CmdWorkspaceList_Ugly_NonDirAndCorruptStatus(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
os.MkdirAll(wsRoot, 0o755)
// Non-directory entry in workspace root
os.WriteFile(filepath.Join(wsRoot, "stray-file.txt"), []byte("not a workspace"), 0o644)
os.WriteFile(core.JoinPath(wsRoot, "stray-file.txt"), []byte("not a workspace"), 0o644)
// Workspace with corrupt status.json
wsCorrupt := filepath.Join(wsRoot, "ws-corrupt")
wsCorrupt := core.JoinPath(wsRoot, "ws-corrupt")
os.MkdirAll(wsCorrupt, 0o755)
os.WriteFile(filepath.Join(wsCorrupt, "status.json"), []byte("{broken json!!!"), 0o644)
os.WriteFile(core.JoinPath(wsCorrupt, "status.json"), []byte("{broken json!!!"), 0o644)
// Valid workspace
wsGood := filepath.Join(wsRoot, "ws-good")
wsGood := core.JoinPath(wsRoot, "ws-good")
os.MkdirAll(wsGood, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(wsGood, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsGood, "status.json"), data, 0o644)
c := core.New()
s := &PrepSubsystem{
@ -122,7 +121,7 @@ func TestCommandsWorkspace_CmdWorkspaceList_Ugly_NonDirAndCorruptStatus(t *testi
func TestCommandsWorkspace_CmdWorkspaceClean_Bad_UnknownFilterLeavesEverything(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspaces with various statuses
for _, ws := range []struct{ name, status string }{
@ -130,10 +129,10 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Bad_UnknownFilterLeavesEverything(t
{"ws-fail", "failed"},
{"ws-run", "running"},
} {
d := filepath.Join(wsRoot, ws.name)
d := core.JoinPath(wsRoot, ws.name)
os.MkdirAll(d, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: ws.status, Repo: "test", Agent: "codex"})
os.WriteFile(filepath.Join(d, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(d, "status.json"), data, 0o644)
}
c := core.New()
@ -149,7 +148,7 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Bad_UnknownFilterLeavesEverything(t
// All workspaces should still exist
for _, name := range []string{"ws-done", "ws-fail", "ws-run"} {
_, err := os.Stat(filepath.Join(wsRoot, name))
_, err := os.Stat(core.JoinPath(wsRoot, name))
assert.NoError(t, err, "workspace %s should still exist", name)
}
}
@ -157,7 +156,7 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Bad_UnknownFilterLeavesEverything(t
func TestCommandsWorkspace_CmdWorkspaceClean_Ugly_MixedStatuses(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspaces with statuses including merged and ready-for-review
for _, ws := range []struct{ name, status string }{
@ -167,10 +166,10 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Ugly_MixedStatuses(t *testing.T) {
{"ws-queued", "queued"},
{"ws-blocked", "blocked"},
} {
d := filepath.Join(wsRoot, ws.name)
d := core.JoinPath(wsRoot, ws.name)
os.MkdirAll(d, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Status: ws.status, Repo: "test", Agent: "codex"})
os.WriteFile(filepath.Join(d, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(d, "status.json"), data, 0o644)
}
c := core.New()
@ -186,12 +185,12 @@ func TestCommandsWorkspace_CmdWorkspaceClean_Ugly_MixedStatuses(t *testing.T) {
// merged, ready-for-review, blocked should be removed
for _, name := range []string{"ws-merged", "ws-review", "ws-blocked"} {
_, err := os.Stat(filepath.Join(wsRoot, name))
_, err := os.Stat(core.JoinPath(wsRoot, name))
assert.True(t, os.IsNotExist(err), "workspace %s should be removed", name)
}
// running and queued should remain
for _, name := range []string{"ws-running", "ws-queued"} {
_, err := os.Stat(filepath.Join(wsRoot, name))
_, err := os.Stat(core.JoinPath(wsRoot, name))
assert.NoError(t, err, "workspace %s should still exist", name)
}
}

View file

@ -9,7 +9,6 @@ import (
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
@ -81,12 +80,12 @@ func TestDispatch_DetectFinalStatus_Ugly(t *testing.T) {
dir := t.TempDir()
// BLOCKED.md exists but is whitespace only — NOT blocked
os.WriteFile(filepath.Join(dir, "BLOCKED.md"), []byte(" \n "), 0o644)
os.WriteFile(core.JoinPath(dir, "BLOCKED.md"), []byte(" \n "), 0o644)
status, _ := detectFinalStatus(dir, 0, "completed")
assert.Equal(t, "completed", status)
// BLOCKED.md takes precedence over non-zero exit
os.WriteFile(filepath.Join(dir, "BLOCKED.md"), []byte("Need credentials"), 0o644)
os.WriteFile(core.JoinPath(dir, "BLOCKED.md"), []byte("Need credentials"), 0o644)
status2, question2 := detectFinalStatus(dir, 1, "failed")
assert.Equal(t, "blocked", status2)
assert.Equal(t, "Need credentials", question2)
@ -136,7 +135,7 @@ func TestDispatch_StartIssueTracking_Good(t *testing.T) {
dir := t.TempDir()
st := &WorkspaceStatus{Status: "running", Repo: "go-io", Org: "core", Issue: 15}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(dir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(dir, "status.json"), data, 0o644)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), forge: forge.NewForge(srv.URL, "tok"), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
s.startIssueTracking(dir)
@ -157,7 +156,7 @@ func TestDispatch_StartIssueTracking_Ugly(t *testing.T) {
dir := t.TempDir()
st := &WorkspaceStatus{Status: "running", Repo: "test"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(dir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(dir, "status.json"), data, 0o644)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), forge: forge.NewForge("http://invalid", "tok"), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
s.startIssueTracking(dir) // no issue → skips API call
@ -174,7 +173,7 @@ func TestDispatch_StopIssueTracking_Good(t *testing.T) {
dir := t.TempDir()
st := &WorkspaceStatus{Status: "completed", Repo: "go-io", Issue: 10}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(dir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(dir, "status.json"), data, 0o644)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), forge: forge.NewForge(srv.URL, "tok"), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
s.stopIssueTracking(dir)
@ -190,7 +189,7 @@ func TestDispatch_StopIssueTracking_Ugly(t *testing.T) {
dir := t.TempDir()
st := &WorkspaceStatus{Status: "completed", Repo: "test"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(dir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(dir, "status.json"), data, 0o644)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), forge: forge.NewForge("http://invalid", "tok"), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
s.stopIssueTracking(dir)
@ -202,10 +201,10 @@ func TestDispatch_BroadcastStart_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "ws-test")
wsDir := core.JoinPath(root, "workspace", "ws-test")
os.MkdirAll(wsDir, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
c := core.New()
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(c, AgentOptions{}), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
@ -231,10 +230,10 @@ func TestDispatch_BroadcastComplete_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "ws-test")
wsDir := core.JoinPath(root, "workspace", "ws-test")
os.MkdirAll(wsDir, 0o755)
data, _ := json.Marshal(WorkspaceStatus{Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
c := core.New()
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(c, AgentOptions{}), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
@ -259,18 +258,18 @@ func TestDispatch_OnAgentComplete_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "ws-test")
repoDir := filepath.Join(wsDir, "repo")
metaDir := filepath.Join(wsDir, ".meta")
wsDir := core.JoinPath(root, "ws-test")
repoDir := core.JoinPath(wsDir, "repo")
metaDir := core.JoinPath(wsDir, ".meta")
os.MkdirAll(repoDir, 0o755)
os.MkdirAll(metaDir, 0o755)
st := &WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex", StartedAt: time.Now()}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
s := newPrepWithProcess()
outputFile := filepath.Join(metaDir, "agent-codex.log")
outputFile := core.JoinPath(metaDir, "agent-codex.log")
s.onAgentComplete("codex", wsDir, outputFile, 0, "completed", "test output")
updated, err := ReadStatus(wsDir)
@ -286,18 +285,18 @@ func TestDispatch_OnAgentComplete_Bad(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "ws-fail")
repoDir := filepath.Join(wsDir, "repo")
metaDir := filepath.Join(wsDir, ".meta")
wsDir := core.JoinPath(root, "ws-fail")
repoDir := core.JoinPath(wsDir, "repo")
metaDir := core.JoinPath(wsDir, ".meta")
os.MkdirAll(repoDir, 0o755)
os.MkdirAll(metaDir, 0o755)
st := &WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex", StartedAt: time.Now()}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
s := newPrepWithProcess()
s.onAgentComplete("codex", wsDir, filepath.Join(metaDir, "agent-codex.log"), 1, "failed", "error")
s.onAgentComplete("codex", wsDir, core.JoinPath(metaDir, "agent-codex.log"), 1, "failed", "error")
updated, _ := ReadStatus(wsDir)
assert.Equal(t, "failed", updated.Status)
@ -308,26 +307,26 @@ func TestDispatch_OnAgentComplete_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "ws-blocked")
repoDir := filepath.Join(wsDir, "repo")
metaDir := filepath.Join(wsDir, ".meta")
wsDir := core.JoinPath(root, "ws-blocked")
repoDir := core.JoinPath(wsDir, "repo")
metaDir := core.JoinPath(wsDir, ".meta")
os.MkdirAll(repoDir, 0o755)
os.MkdirAll(metaDir, 0o755)
os.WriteFile(filepath.Join(repoDir, "BLOCKED.md"), []byte("Need credentials"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "BLOCKED.md"), []byte("Need credentials"), 0o644)
st := &WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex", StartedAt: time.Now()}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
s := newPrepWithProcess()
s.onAgentComplete("codex", wsDir, filepath.Join(metaDir, "agent-codex.log"), 0, "completed", "")
s.onAgentComplete("codex", wsDir, core.JoinPath(metaDir, "agent-codex.log"), 0, "completed", "")
updated, _ := ReadStatus(wsDir)
assert.Equal(t, "blocked", updated.Status)
assert.Equal(t, "Need credentials", updated.Question)
// Empty output should NOT create log file
_, err := os.Stat(filepath.Join(metaDir, "agent-codex.log"))
_, err := os.Stat(core.JoinPath(metaDir, "agent-codex.log"))
assert.True(t, os.IsNotExist(err))
}
@ -335,10 +334,10 @@ func TestDispatch_OnAgentComplete_Ugly(t *testing.T) {
func TestDispatch_RunQA_Good(t *testing.T) {
wsDir := t.TempDir()
repoDir := filepath.Join(wsDir, "repo")
repoDir := core.JoinPath(wsDir, "repo")
os.MkdirAll(repoDir, 0o755)
os.WriteFile(filepath.Join(repoDir, "go.mod"), []byte("module testmod\n\ngo 1.22\n"), 0o644)
os.WriteFile(filepath.Join(repoDir, "main.go"), []byte("package main\nfunc main() {}\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "go.mod"), []byte("module testmod\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "main.go"), []byte("package main\nfunc main() {}\n"), 0o644)
s := newPrepWithProcess()
assert.True(t, s.runQA(wsDir))
@ -346,21 +345,21 @@ func TestDispatch_RunQA_Good(t *testing.T) {
func TestDispatch_RunQA_Bad(t *testing.T) {
wsDir := t.TempDir()
repoDir := filepath.Join(wsDir, "repo")
repoDir := core.JoinPath(wsDir, "repo")
os.MkdirAll(repoDir, 0o755)
// Broken Go code
os.WriteFile(filepath.Join(repoDir, "go.mod"), []byte("module testmod\n\ngo 1.22\n"), 0o644)
os.WriteFile(filepath.Join(repoDir, "main.go"), []byte("package main\nfunc main( {\n}\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "go.mod"), []byte("module testmod\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "main.go"), []byte("package main\nfunc main( {\n}\n"), 0o644)
s := newPrepWithProcess()
assert.False(t, s.runQA(wsDir))
// PHP project — composer not available
wsDir2 := t.TempDir()
repoDir2 := filepath.Join(wsDir2, "repo")
repoDir2 := core.JoinPath(wsDir2, "repo")
os.MkdirAll(repoDir2, 0o755)
os.WriteFile(filepath.Join(repoDir2, "composer.json"), []byte(`{"name":"test"}`), 0o644)
os.WriteFile(core.JoinPath(repoDir2, "composer.json"), []byte(`{"name":"test"}`), 0o644)
assert.False(t, s.runQA(wsDir2))
}
@ -368,24 +367,24 @@ func TestDispatch_RunQA_Bad(t *testing.T) {
func TestDispatch_RunQA_Ugly(t *testing.T) {
// Unknown language — passes QA (no checks)
wsDir := t.TempDir()
os.MkdirAll(filepath.Join(wsDir, "repo"), 0o755)
os.MkdirAll(core.JoinPath(wsDir, "repo"), 0o755)
s := newPrepWithProcess()
assert.True(t, s.runQA(wsDir))
// Go vet failure (compiles but bad printf)
wsDir2 := t.TempDir()
repoDir2 := filepath.Join(wsDir2, "repo")
repoDir2 := core.JoinPath(wsDir2, "repo")
os.MkdirAll(repoDir2, 0o755)
os.WriteFile(filepath.Join(repoDir2, "go.mod"), []byte("module testmod\n\ngo 1.22\n"), 0o644)
os.WriteFile(filepath.Join(repoDir2, "main.go"), []byte("package main\nimport \"fmt\"\nfunc main() { fmt.Printf(\"%d\", \"x\") }\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir2, "go.mod"), []byte("module testmod\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir2, "main.go"), []byte("package main\nimport \"fmt\"\nfunc main() { fmt.Printf(\"%d\", \"x\") }\n"), 0o644)
assert.False(t, s.runQA(wsDir2))
// Node project — npm install likely fails
wsDir3 := t.TempDir()
repoDir3 := filepath.Join(wsDir3, "repo")
repoDir3 := core.JoinPath(wsDir3, "repo")
os.MkdirAll(repoDir3, 0o755)
os.WriteFile(filepath.Join(repoDir3, "package.json"), []byte(`{"name":"test","scripts":{"test":"echo ok"}}`), 0o644)
os.WriteFile(core.JoinPath(repoDir3, "package.json"), []byte(`{"name":"test","scripts":{"test":"echo ok"}}`), 0o644)
_ = s.runQA(wsDir3) // exercises the node path
}
@ -400,17 +399,17 @@ func TestDispatch_Dispatch_Good(t *testing.T) {
}))
t.Cleanup(forgeSrv.Close)
srcRepo := filepath.Join(t.TempDir(), "core", "go-io")
srcRepo := core.JoinPath(t.TempDir(), "core", "go-io")
exec.Command("git", "init", "-b", "main", srcRepo).Run()
exec.Command("git", "-C", srcRepo, "config", "user.name", "T").Run()
exec.Command("git", "-C", srcRepo, "config", "user.email", "t@t.com").Run()
os.WriteFile(filepath.Join(srcRepo, "go.mod"), []byte("module test\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(srcRepo, "go.mod"), []byte("module test\ngo 1.22\n"), 0o644)
exec.Command("git", "-C", srcRepo, "add", ".").Run()
exec.Command("git", "-C", srcRepo, "commit", "-m", "init").Run()
s := newPrepWithProcess()
s.forge = forge.NewForge(forgeSrv.URL, "tok")
s.codePath = filepath.Dir(filepath.Dir(srcRepo))
s.codePath = core.PathDir(core.PathDir(srcRepo))
_, out, err := s.dispatch(context.Background(), nil, DispatchInput{
Repo: "go-io", Task: "Fix stuff", Issue: 42, DryRun: true,

View file

@ -5,7 +5,6 @@ package agentic
import (
"context"
"os"
"path/filepath"
"testing"
"time"
@ -72,13 +71,13 @@ func TestHandlers_RegisterHandlers_Good_QAFailsUpdatesStatus(t *testing.T) {
root := WorkspaceRoot()
wsName := "core/test/task-1"
wsDir := filepath.Join(root, wsName)
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(root, wsName)
repoDir := core.JoinPath(wsDir, "repo")
os.MkdirAll(repoDir, 0o755)
// Create a Go project that will fail vet/build
os.WriteFile(filepath.Join(repoDir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
os.WriteFile(filepath.Join(repoDir, "main.go"), []byte("package main\nimport \"fmt\"\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(repoDir, "main.go"), []byte("package main\nimport \"fmt\"\n"), 0o644)
st := &WorkspaceStatus{
Status: "completed",
@ -108,8 +107,8 @@ func TestHandlers_RegisterHandlers_Good_IngestOnCompletion(t *testing.T) {
root := WorkspaceRoot()
wsName := "core/test/task-2"
wsDir := filepath.Join(root, wsName)
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(root, wsName)
repoDir := core.JoinPath(wsDir, "repo")
os.MkdirAll(repoDir, 0o755)
st := &WorkspaceStatus{

View file

@ -6,7 +6,6 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"time"
@ -47,13 +46,13 @@ func TestIngest_IngestFindings_Good_WithFindings(t *testing.T) {
"- `pkg/core/service.go:100` has a missing error check\n" +
"- `pkg/core/config.go:25` needs documentation\n" +
"This is padding to get past the 100 char minimum length requirement for the log file content parsing."
require.True(t, fs.Write(filepath.Join(wsDir, "agent-codex.log"), logContent).OK)
require.True(t, fs.Write(core.JoinPath(wsDir, "agent-codex.log"), logContent).OK)
// Set up HOME for the agent-api.key read
home := t.TempDir()
t.Setenv("DIR_HOME", home)
require.True(t, fs.EnsureDir(filepath.Join(home, ".claude")).OK)
require.True(t, fs.Write(filepath.Join(home, ".claude", "agent-api.key"), "test-api-key").OK)
require.True(t, fs.EnsureDir(core.JoinPath(home, ".claude")).OK)
require.True(t, fs.Write(core.JoinPath(home, ".claude", "agent-api.key"), "test-api-key").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -114,7 +113,7 @@ func TestIngest_IngestFindings_Bad_TooFewFindings(t *testing.T) {
// Only 1 finding (need >= 2 to ingest)
logContent := "Found: `main.go:1` has an issue. This padding makes the content long enough to pass the 100 char minimum check."
require.True(t, fs.Write(filepath.Join(wsDir, "agent-codex.log"), logContent).OK)
require.True(t, fs.Write(core.JoinPath(wsDir, "agent-codex.log"), logContent).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -136,7 +135,7 @@ func TestIngest_IngestFindings_Bad_QuotaExhausted(t *testing.T) {
// Log contains quota error — should skip
logContent := "QUOTA_EXHAUSTED: Rate limit exceeded. `main.go:1` `other.go:2` padding to ensure we pass length check and get past the threshold."
require.True(t, fs.Write(filepath.Join(wsDir, "agent-codex.log"), logContent).OK)
require.True(t, fs.Write(core.JoinPath(wsDir, "agent-codex.log"), logContent).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -171,7 +170,7 @@ func TestIngest_IngestFindings_Bad_ShortLogFile(t *testing.T) {
}))
// Log content is less than 100 bytes — should skip
require.True(t, fs.Write(filepath.Join(wsDir, "agent-codex.log"), "short").OK)
require.True(t, fs.Write(core.JoinPath(wsDir, "agent-codex.log"), "short").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -258,8 +257,8 @@ func TestIngest_CreateIssueViaAPI_Bad_ServerError(t *testing.T) {
home := t.TempDir()
t.Setenv("DIR_HOME", home)
require.True(t, fs.EnsureDir(filepath.Join(home, ".claude")).OK)
require.True(t, fs.Write(filepath.Join(home, ".claude", "agent-api.key"), "test-key").OK)
require.True(t, fs.EnsureDir(core.JoinPath(home, ".claude")).OK)
require.True(t, fs.Write(core.JoinPath(home, ".claude", "agent-api.key"), "test-key").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -326,8 +325,8 @@ func TestIngest_CreateIssueViaAPI_Ugly(t *testing.T) {
home := t.TempDir()
t.Setenv("DIR_HOME", home)
require.True(t, fs.EnsureDir(filepath.Join(home, ".claude")).OK)
require.True(t, fs.Write(filepath.Join(home, ".claude", "agent-api.key"), "test-key").OK)
require.True(t, fs.EnsureDir(core.JoinPath(home, ".claude")).OK)
require.True(t, fs.Write(core.JoinPath(home, ".claude", "agent-api.key"), "test-key").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),

View file

@ -6,7 +6,6 @@ import (
"bufio"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
@ -268,11 +267,11 @@ func TestAutoPr_BuildAutoPRBody_Ugly_ZeroCommits(t *testing.T) {
func TestEvents_EmitEvent_Good_WritesJSONL(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitEvent("agent_completed", "codex", "core/go-io/task-5", "completed")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK, "events.jsonl should exist after emitEvent")
@ -286,11 +285,11 @@ func TestEvents_EmitEvent_Good_WritesJSONL(t *testing.T) {
func TestEvents_EmitEvent_Good_ValidJSON(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitEvent("agent_started", "claude", "core/agent/task-1", "running")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
f, err := os.Open(eventsFile)
require.NoError(t, err)
defer f.Close()
@ -310,12 +309,12 @@ func TestEvents_EmitEvent_Good_ValidJSON(t *testing.T) {
func TestEvents_EmitEvent_Good_Appends(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitEvent("agent_started", "codex", "core/go-io/task-1", "running")
emitEvent("agent_completed", "codex", "core/go-io/task-1", "completed")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
@ -331,11 +330,11 @@ func TestEvents_EmitEvent_Good_Appends(t *testing.T) {
func TestEvents_EmitEvent_Good_StartHelper(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitStartEvent("gemini", "core/go-log/task-3")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "agent_started")
@ -345,11 +344,11 @@ func TestEvents_EmitEvent_Good_StartHelper(t *testing.T) {
func TestEvents_EmitEvent_Good_CompletionHelper(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitCompletionEvent("claude", "core/agent/task-7", "failed")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "agent_completed")
@ -370,7 +369,7 @@ func TestEvents_EmitEvent_Bad_NoWorkspaceDir(t *testing.T) {
func TestEvents_EmitEvent_Ugly_EmptyFields(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
// Should not panic with all empty fields
assert.NotPanics(t, func() {
@ -383,11 +382,11 @@ func TestEvents_EmitEvent_Ugly_EmptyFields(t *testing.T) {
func TestEvents_EmitStartEvent_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitStartEvent("codex", "core/go-io/task-10")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
content := r.Value.(string)
@ -400,13 +399,13 @@ func TestEvents_EmitStartEvent_Bad(t *testing.T) {
// Empty agent name
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
assert.NotPanics(t, func() {
emitStartEvent("", "core/go-io/task-10")
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
content := r.Value.(string)
@ -417,14 +416,14 @@ func TestEvents_EmitStartEvent_Ugly(t *testing.T) {
// Very long workspace name
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
longName := strings.Repeat("very-long-workspace-name-", 50)
assert.NotPanics(t, func() {
emitStartEvent("claude", longName)
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "agent_started")
@ -433,11 +432,11 @@ func TestEvents_EmitStartEvent_Ugly(t *testing.T) {
func TestEvents_EmitCompletionEvent_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
emitCompletionEvent("gemini", "core/go-log/task-5", "completed")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
content := r.Value.(string)
@ -450,13 +449,13 @@ func TestEvents_EmitCompletionEvent_Bad(t *testing.T) {
// Empty status
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
assert.NotPanics(t, func() {
emitCompletionEvent("claude", "core/agent/task-1", "")
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "agent_completed")
@ -466,13 +465,13 @@ func TestEvents_EmitCompletionEvent_Ugly(t *testing.T) {
// Unicode in agent name
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
assert.NotPanics(t, func() {
emitCompletionEvent("\u00e9nchantr\u00efx-\u2603", "core/agent/task-1", "completed")
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
eventsFile := core.JoinPath(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "\u00e9nchantr\u00efx")
@ -597,7 +596,7 @@ func TestHandlers_ResolveWorkspace_Good_ExistingDir(t *testing.T) {
// Create the workspace directory structure
wsName := "core/go-io/task-5"
wsDir := filepath.Join(root, "workspace", wsName)
wsDir := core.JoinPath(root, "workspace", wsName)
require.True(t, fs.EnsureDir(wsDir).OK)
result := resolveWorkspace(wsName)
@ -609,7 +608,7 @@ func TestHandlers_ResolveWorkspace_Good_NestedPath(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
wsName := "core/agent/pr-42"
wsDir := filepath.Join(root, "workspace", wsName)
wsDir := core.JoinPath(root, "workspace", wsName)
require.True(t, fs.EnsureDir(wsDir).OK)
result := resolveWorkspace(wsName)
@ -651,7 +650,7 @@ func TestHandlers_FindWorkspaceByPR_Good_MatchesFlatLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "task-10")
wsDir := core.JoinPath(root, "workspace", "task-10")
require.True(t, fs.EnsureDir(wsDir).OK)
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -667,7 +666,7 @@ func TestHandlers_FindWorkspaceByPR_Good_MatchesDeepLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "core", "go-io", "task-15")
wsDir := core.JoinPath(root, "workspace", "core", "go-io", "task-15")
require.True(t, fs.EnsureDir(wsDir).OK)
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "running",
@ -683,7 +682,7 @@ func TestHandlers_FindWorkspaceByPR_Bad_NoMatch(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "task-99")
wsDir := core.JoinPath(root, "workspace", "task-99")
require.True(t, fs.EnsureDir(wsDir).OK)
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -707,7 +706,7 @@ func TestHandlers_FindWorkspaceByPR_Bad_RepoDiffers(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "task-5")
wsDir := core.JoinPath(root, "workspace", "task-5")
require.True(t, fs.EnsureDir(wsDir).OK)
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -724,9 +723,9 @@ func TestHandlers_FindWorkspaceByPR_Ugly_CorruptStatusFile(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "corrupt-ws")
wsDir := core.JoinPath(root, "workspace", "corrupt-ws")
require.True(t, fs.EnsureDir(wsDir).OK)
require.True(t, fs.Write(filepath.Join(wsDir, "status.json"), "not-valid-json{").OK)
require.True(t, fs.Write(core.JoinPath(wsDir, "status.json"), "not-valid-json{").OK)
// Should skip corrupt entries, not panic
result := findWorkspaceByPR("go-io", "agent/any")

View file

@ -4,7 +4,6 @@ package agentic
import (
"os/exec"
"path/filepath"
"testing"
core "dappco.re/go/core"
@ -34,7 +33,7 @@ func initBareRepo(t *testing.T) string {
run("git", "config", "user.email", "test@test.com")
// Create a file and commit
require.True(t, fs.Write(filepath.Join(dir, "README.md"), "# Test").OK)
require.True(t, fs.Write(core.JoinPath(dir, "README.md"), "# Test").OK)
run("git", "add", "README.md")
run("git", "commit", "-m", "initial commit")
return dir
@ -102,7 +101,7 @@ func TestMirror_CommitsAhead_Good_OneAhead(t *testing.T) {
run("git", "branch", "base")
// Add a commit on main
require.True(t, fs.Write(filepath.Join(dir, "new.txt"), "data").OK)
require.True(t, fs.Write(core.JoinPath(dir, "new.txt"), "data").OK)
run("git", "add", "new.txt")
run("git", "commit", "-m", "second commit")
@ -129,7 +128,7 @@ func TestMirror_CommitsAhead_Good_ThreeAhead(t *testing.T) {
run("git", "branch", "base")
for i := 0; i < 3; i++ {
name := filepath.Join(dir, "file"+string(rune('a'+i))+".txt")
name := core.JoinPath(dir, "file"+string(rune('a'+i))+".txt")
require.True(t, fs.Write(name, "content").OK)
run("git", "add", ".")
run("git", "commit", "-m", "commit "+string(rune('0'+i)))
@ -182,7 +181,7 @@ func TestMirror_FilesChanged_Good_OneFile(t *testing.T) {
run("git", "branch", "base")
require.True(t, fs.Write(filepath.Join(dir, "changed.txt"), "new").OK)
require.True(t, fs.Write(core.JoinPath(dir, "changed.txt"), "new").OK)
run("git", "add", "changed.txt")
run("git", "commit", "-m", "add file")
@ -209,7 +208,7 @@ func TestMirror_FilesChanged_Good_MultipleFiles(t *testing.T) {
run("git", "branch", "base")
for _, name := range []string{"a.go", "b.go", "c.go"} {
require.True(t, fs.Write(filepath.Join(dir, name), "package main").OK)
require.True(t, fs.Write(core.JoinPath(dir, name), "package main").OK)
}
run("git", "add", ".")
run("git", "commit", "-m", "add three files")
@ -317,13 +316,13 @@ func TestMirror_ListLocalRepos_Good_FindsRepos(t *testing.T) {
// Create two git repos under base
for _, name := range []string{"repo-a", "repo-b"} {
repoDir := filepath.Join(base, name)
repoDir := core.JoinPath(base, name)
cmd := exec.Command("git", "init", repoDir)
require.NoError(t, cmd.Run())
}
// Create a non-repo directory
require.True(t, fs.EnsureDir(filepath.Join(base, "not-a-repo")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(base, "not-a-repo")).OK)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{})}
repos := s.listLocalRepos(base)
@ -364,18 +363,18 @@ func TestMirror_ListLocalRepos_Ugly(t *testing.T) {
// Create two git repos
for _, name := range []string{"real-repo-a", "real-repo-b"} {
repoDir := filepath.Join(base, name)
repoDir := core.JoinPath(base, name)
cmd := exec.Command("git", "init", repoDir)
require.NoError(t, cmd.Run())
}
// Create non-git directories (no .git inside)
for _, name := range []string{"plain-dir", "another-dir"} {
require.True(t, fs.EnsureDir(filepath.Join(base, name)).OK)
require.True(t, fs.EnsureDir(core.JoinPath(base, name)).OK)
}
// Create a regular file (not a directory)
require.True(t, fs.Write(filepath.Join(base, "some-file.txt"), "hello").OK)
require.True(t, fs.Write(core.JoinPath(base, "some-file.txt"), "hello").OK)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{})}
repos := s.listLocalRepos(base)

View file

@ -3,10 +3,10 @@
package agentic
import (
"path/filepath"
"testing"
"time"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -68,7 +68,7 @@ func TestReadWritePlan_Good_BasicRoundtrip(t *testing.T) {
path, err := writePlan(dir, plan)
require.NoError(t, err)
assert.Equal(t, filepath.Join(dir, "basic-plan-abc.json"), path)
assert.Equal(t, core.JoinPath(dir, "basic-plan-abc.json"), path)
read, err := readPlan(dir, "basic-plan-abc")
require.NoError(t, err)
@ -120,7 +120,7 @@ func TestPlan_ReadPlan_Bad_MissingFile(t *testing.T) {
func TestPlan_ReadPlan_Bad_CorruptJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "bad.json"), `{broken`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "bad.json"), `{broken`).OK)
_, err := readPlan(dir, "bad")
assert.Error(t, err)
@ -128,7 +128,7 @@ func TestPlan_ReadPlan_Bad_CorruptJSON(t *testing.T) {
func TestPlan_WritePlan_Good_CreatesNestedDir(t *testing.T) {
base := t.TempDir()
nested := filepath.Join(base, "deep", "nested", "plans")
nested := core.JoinPath(base, "deep", "nested", "plans")
plan := &Plan{
ID: "deep-plan-xyz",
@ -139,7 +139,7 @@ func TestPlan_WritePlan_Good_CreatesNestedDir(t *testing.T) {
path, err := writePlan(nested, plan)
require.NoError(t, err)
assert.Equal(t, filepath.Join(nested, "deep-plan-xyz.json"), path)
assert.Equal(t, core.JoinPath(nested, "deep-plan-xyz.json"), path)
assert.True(t, fs.IsFile(path))
}
@ -168,7 +168,7 @@ func TestPlan_WritePlan_Good_OverwriteExistingLogic(t *testing.T) {
func TestPlan_ReadPlan_Ugly_EmptyFileLogic(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "empty.json"), "").OK)
require.True(t, fs.Write(core.JoinPath(dir, "empty.json"), "").OK)
_, err := readPlan(dir, "empty")
assert.Error(t, err)

View file

@ -3,10 +3,10 @@
package agentic
import (
"path/filepath"
"strings"
"testing"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -27,7 +27,7 @@ func TestPlan_WritePlan_Good(t *testing.T) {
path, err := writePlan(dir, plan)
require.NoError(t, err)
assert.Equal(t, filepath.Join(dir, "test-plan-abc123.json"), path)
assert.Equal(t, core.JoinPath(dir, "test-plan-abc123.json"), path)
// Verify file exists
assert.True(t, fs.IsFile(path))
@ -35,7 +35,7 @@ func TestPlan_WritePlan_Good(t *testing.T) {
func TestPlan_WritePlan_Good_CreatesDirectory(t *testing.T) {
base := t.TempDir()
dir := filepath.Join(base, "nested", "plans")
dir := core.JoinPath(base, "nested", "plans")
plan := &Plan{
ID: "nested-plan-abc123",
@ -95,7 +95,7 @@ func TestPlan_ReadPlan_Bad_NotFound(t *testing.T) {
func TestPlan_ReadPlan_Bad_InvalidJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "bad-json.json"), "{broken").OK)
require.True(t, fs.Write(core.JoinPath(dir, "bad-json.json"), "{broken").OK)
_, err := readPlan(dir, "bad-json")
assert.Error(t, err)
@ -204,7 +204,7 @@ func TestPlan_WritePlan_Good_OverwriteExisting(t *testing.T) {
func TestPlan_ReadPlan_Ugly_EmptyFile(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "empty.json"), "").OK)
require.True(t, fs.Write(core.JoinPath(dir, "empty.json"), "").OK)
_, err := readPlan(dir, "empty")
assert.Error(t, err)

View file

@ -9,7 +9,6 @@ import (
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
@ -162,8 +161,8 @@ func TestPr_CreatePR_Good_DryRun(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Create workspace with repo/.git
wsDir := filepath.Join(root, "workspace", "test-ws")
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(root, "workspace", "test-ws")
repoDir := core.JoinPath(wsDir, "repo")
require.NoError(t, exec.Command("git", "init", "-b", "main", repoDir).Run())
gitCmd := exec.Command("git", "config", "user.name", "Test")
gitCmd.Dir = repoDir
@ -201,8 +200,8 @@ func TestPr_CreatePR_Good_CustomTitle(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "test-ws-2")
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(root, "workspace", "test-ws-2")
repoDir := core.JoinPath(wsDir, "repo")
require.NoError(t, exec.Command("git", "init", "-b", "main", repoDir).Run())
gitCmd := exec.Command("git", "config", "user.name", "Test")
gitCmd.Dir = repoDir
@ -375,8 +374,8 @@ func TestPr_CreatePR_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "test-ws-ugly")
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(root, "workspace", "test-ws-ugly")
repoDir := core.JoinPath(wsDir, "repo")
require.NoError(t, exec.Command("git", "init", "-b", "main", repoDir).Run())
gitCmd := exec.Command("git", "config", "user.name", "Test")
gitCmd.Dir = repoDir
@ -386,7 +385,7 @@ func TestPr_CreatePR_Ugly(t *testing.T) {
gitCmd.Run()
// Need an initial commit so HEAD exists for branch detection
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("# Test"), 0o644))
require.NoError(t, os.WriteFile(core.JoinPath(repoDir, "README.md"), []byte("# Test"), 0o644))
addCmd := exec.Command("git", "add", ".")
addCmd.Dir = repoDir
require.NoError(t, addCmd.Run())

View file

@ -9,7 +9,6 @@ import (
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
@ -50,7 +49,7 @@ use (
./core/agent
./core/mcp
)`
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
os.WriteFile(core.JoinPath(dir, "go.work"), []byte(goWork), 0o644)
// Create module dirs with go.mod
for _, mod := range []struct {
@ -61,9 +60,9 @@ use (
{"core/agent", "module forge.lthn.ai/core/agent\n\nrequire forge.lthn.ai/core/go v0.7.0\n"},
{"core/mcp", "module forge.lthn.ai/core/mcp\n\nrequire forge.lthn.ai/core/go v0.7.0\n"},
} {
modDir := filepath.Join(dir, mod.path)
modDir := core.JoinPath(dir, mod.path)
os.MkdirAll(modDir, 0o755)
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte(mod.content), 0o644)
os.WriteFile(core.JoinPath(modDir, "go.mod"), []byte(mod.content), 0o644)
}
s := &PrepSubsystem{
@ -88,11 +87,11 @@ func TestPrep_FindConsumersList_Good_NoConsumers(t *testing.T) {
use (
./core/go
)`
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
os.WriteFile(core.JoinPath(dir, "go.work"), []byte(goWork), 0o644)
modDir := filepath.Join(dir, "core", "go")
modDir := core.JoinPath(dir, "core", "go")
os.MkdirAll(modDir, 0o755)
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
os.WriteFile(core.JoinPath(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -222,7 +221,7 @@ func TestPrep_GetIssueBody_Bad_NotFound(t *testing.T) {
func TestPrep_BuildPrompt_Good_BasicFields(t *testing.T) {
dir := t.TempDir()
// Create go.mod to detect language
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -282,7 +281,7 @@ func TestPrep_BuildPrompt_Good_WithIssue(t *testing.T) {
func TestPrep_BuildPrompt_Good(t *testing.T) {
dir := t.TempDir()
// Create go.mod to detect language as "go"
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -330,7 +329,7 @@ func TestPrep_BuildPrompt_Bad(t *testing.T) {
func TestPrep_BuildPrompt_Ugly(t *testing.T) {
dir := t.TempDir()
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
@ -368,7 +367,7 @@ func TestPrep_BuildPrompt_Ugly(t *testing.T) {
func TestPrep_BuildPrompt_Ugly_WithGitLog(t *testing.T) {
dir := t.TempDir()
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
os.WriteFile(core.JoinPath(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
// Init a real git repo with commits so git log path is covered
exec.Command("git", "init", "-b", "main", dir).Run()
@ -396,10 +395,10 @@ func TestPrep_BuildPrompt_Ugly_WithGitLog(t *testing.T) {
func TestDispatch_RunQA_Good_PHPNoComposer(t *testing.T) {
dir := t.TempDir()
repoDir := filepath.Join(dir, "repo")
repoDir := core.JoinPath(dir, "repo")
os.MkdirAll(repoDir, 0o755)
// composer.json present but no composer binary
os.WriteFile(filepath.Join(repoDir, "composer.json"), []byte(`{"name":"test"}`), 0o644)
os.WriteFile(core.JoinPath(repoDir, "composer.json"), []byte(`{"name":"test"}`), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -546,15 +545,15 @@ func TestPrep_FindConsumersList_Ugly(t *testing.T) {
dir := t.TempDir()
goWork := "go 1.22\n\nuse (\n\t./core/go\n\t./core/missing\n)"
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
os.WriteFile(core.JoinPath(dir, "go.work"), []byte(goWork), 0o644)
// Create only the first module dir with go.mod
modDir := filepath.Join(dir, "core", "go")
modDir := core.JoinPath(dir, "core", "go")
os.MkdirAll(modDir, 0o755)
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
os.WriteFile(core.JoinPath(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
// core/missing has no go.mod
os.MkdirAll(filepath.Join(dir, "core", "missing"), 0o755)
os.MkdirAll(core.JoinPath(dir, "core", "missing"), 0o755)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),

View file

@ -8,7 +8,6 @@ import (
"net/http"
"net/http/httptest"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
@ -36,43 +35,43 @@ func TestPrep_EnvOr_Good_UnsetUsesFallback(t *testing.T) {
func TestPrep_DetectLanguage_Good_Go(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test").OK)
assert.Equal(t, "go", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Good_PHP(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "composer.json"), "{}").OK)
require.True(t, fs.Write(core.JoinPath(dir, "composer.json"), "{}").OK)
assert.Equal(t, "php", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Good_TypeScript(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "package.json"), "{}").OK)
require.True(t, fs.Write(core.JoinPath(dir, "package.json"), "{}").OK)
assert.Equal(t, "ts", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Good_Rust(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "Cargo.toml"), "[package]").OK)
require.True(t, fs.Write(core.JoinPath(dir, "Cargo.toml"), "[package]").OK)
assert.Equal(t, "rust", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Good_Python(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "requirements.txt"), "flask").OK)
require.True(t, fs.Write(core.JoinPath(dir, "requirements.txt"), "flask").OK)
assert.Equal(t, "py", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Good_Cpp(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "CMakeLists.txt"), "cmake_minimum_required").OK)
require.True(t, fs.Write(core.JoinPath(dir, "CMakeLists.txt"), "cmake_minimum_required").OK)
assert.Equal(t, "cpp", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Good_Docker(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "Dockerfile"), "FROM alpine").OK)
require.True(t, fs.Write(core.JoinPath(dir, "Dockerfile"), "FROM alpine").OK)
assert.Equal(t, "docker", detectLanguage(dir))
}
@ -98,7 +97,7 @@ func TestPrep_DetectBuildCmd_Good(t *testing.T) {
for _, tt := range tests {
t.Run(tt.file, func(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, tt.file), tt.content).OK)
require.True(t, fs.Write(core.JoinPath(dir, tt.file), tt.content).OK)
assert.Equal(t, tt.expected, detectBuildCmd(dir))
})
}
@ -126,7 +125,7 @@ func TestPrep_DetectTestCmd_Good(t *testing.T) {
for _, tt := range tests {
t.Run(tt.file, func(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, tt.file), tt.content).OK)
require.True(t, fs.Write(core.JoinPath(dir, tt.file), tt.content).OK)
assert.Equal(t, tt.expected, detectTestCmd(dir))
})
}
@ -500,8 +499,8 @@ func TestPrep_DetectLanguage_Bad(t *testing.T) {
func TestPrep_DetectLanguage_Ugly(t *testing.T) {
// Dir with multiple project files (go.mod + package.json) — go wins (first match)
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
require.True(t, fs.Write(filepath.Join(dir, "package.json"), "{}").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test").OK)
require.True(t, fs.Write(core.JoinPath(dir, "package.json"), "{}").OK)
assert.Equal(t, "go", detectLanguage(dir), "go.mod checked first, so go wins")
}
@ -580,7 +579,7 @@ func TestPrep_TestPrepWorkspace_Ugly(t *testing.T) {
func TestPrep_TestBuildPrompt_Good(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -689,7 +688,7 @@ func TestPrep_GetGitLog_Good(t *testing.T) {
run("git", "init", "-b", "main")
run("git", "config", "user.name", "Test")
run("git", "config", "user.email", "test@test.com")
require.True(t, fs.Write(filepath.Join(dir, "README.md"), "# Test").OK)
require.True(t, fs.Write(core.JoinPath(dir, "README.md"), "# Test").OK)
run("git", "add", "README.md")
run("git", "commit", "-m", "initial commit")
@ -748,7 +747,7 @@ func TestPrep_PrepWorkspace_Good(t *testing.T) {
t.Cleanup(srv.Close)
// Create a source repo to clone from
srcRepo := filepath.Join(root, "src", "core", "test-repo")
srcRepo := core.JoinPath(root, "src", "core", "test-repo")
run := func(dir string, args ...string) {
t.Helper()
cmd := exec.Command(args[0], args[1:]...)
@ -766,14 +765,14 @@ func TestPrep_PrepWorkspace_Good(t *testing.T) {
run(srcRepo, "git", "init", "-b", "main")
run(srcRepo, "git", "config", "user.name", "Test")
run(srcRepo, "git", "config", "user.email", "test@test.com")
require.True(t, fs.Write(filepath.Join(srcRepo, "README.md"), "# Test").OK)
require.True(t, fs.Write(core.JoinPath(srcRepo, "README.md"), "# Test").OK)
run(srcRepo, "git", "add", "README.md")
run(srcRepo, "git", "commit", "-m", "initial commit")
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
forge: forge.NewForge(srv.URL, "test-token"),
codePath: filepath.Join(root, "src"),
codePath: core.JoinPath(root, "src"),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}

View file

@ -5,7 +5,6 @@ package agentic
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
@ -91,7 +90,7 @@ rates:
sustained_delay: 120
burst_window: 2
burst_delay: 15`
os.WriteFile(filepath.Join(root, "agents.yaml"), []byte(cfg), 0o644)
os.WriteFile(core.JoinPath(root, "agents.yaml"), []byte(cfg), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -110,7 +109,7 @@ rates:
func TestQueue_CountRunningByModel_Good_NoWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
os.MkdirAll(core.JoinPath(root, "workspace"), 0o755)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -125,7 +124,7 @@ func TestQueue_CountRunningByModel_Good_NoWorkspaces(t *testing.T) {
func TestQueue_DrainQueue_Good_NoCoreFallsBackToMutex(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
os.MkdirAll(core.JoinPath(root, "workspace"), 0o755)
s := &PrepSubsystem{
ServiceRuntime: nil,
@ -139,7 +138,7 @@ func TestQueue_DrainQueue_Good_NoCoreFallsBackToMutex(t *testing.T) {
func TestQueue_DrainOne_Good_NoWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
os.MkdirAll(core.JoinPath(root, "workspace"), 0o755)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -153,13 +152,13 @@ func TestQueue_DrainOne_Good_NoWorkspaces(t *testing.T) {
func TestQueue_DrainOne_Good_SkipsNonQueued(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
ws := filepath.Join(wsRoot, "ws-done")
ws := core.JoinPath(wsRoot, "ws-done")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{Status: "completed", Agent: "codex", Repo: "test"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -173,13 +172,13 @@ func TestQueue_DrainOne_Good_SkipsNonQueued(t *testing.T) {
func TestQueue_DrainOne_Good_SkipsBackedOffPool(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
ws := filepath.Join(wsRoot, "ws-queued")
ws := core.JoinPath(wsRoot, "ws-queued")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{Status: "queued", Agent: "codex", Repo: "test", Task: "do it"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -197,7 +196,7 @@ func TestQueue_DrainOne_Good_SkipsBackedOffPool(t *testing.T) {
func TestQueue_CanDispatchAgent_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
os.MkdirAll(core.JoinPath(root, "workspace"), 0o755)
c := core.New()
// Set concurrency on Core.Config() — same path that Register() uses
@ -224,7 +223,7 @@ func TestQueue_CanDispatchAgent_Ugly(t *testing.T) {
func TestQueue_DrainQueue_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
os.MkdirAll(core.JoinPath(root, "workspace"), 0o755)
c := core.New()
s := &PrepSubsystem{
@ -243,10 +242,10 @@ func TestQueue_DrainQueue_Ugly(t *testing.T) {
func TestQueue_CanDispatchAgent_Bad_AgentAtLimit(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a running workspace with a valid-looking PID (use our own PID)
ws := filepath.Join(wsRoot, "ws-running")
ws := core.JoinPath(wsRoot, "ws-running")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{
Status: "running",
@ -255,7 +254,7 @@ func TestQueue_CanDispatchAgent_Bad_AgentAtLimit(t *testing.T) {
PID: os.Getpid(), // Our own PID so Kill(pid, 0) succeeds
}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
c := core.New()
c.Config().Set("agents.concurrency", map[string]ConcurrencyLimit{
@ -277,10 +276,10 @@ func TestQueue_CanDispatchAgent_Bad_AgentAtLimit(t *testing.T) {
func TestQueue_CountRunningByAgent_Bad_WrongAgentType(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a running workspace for a different agent type
ws := filepath.Join(wsRoot, "ws-gemini")
ws := core.JoinPath(wsRoot, "ws-gemini")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{
Status: "running",
@ -289,7 +288,7 @@ func TestQueue_CountRunningByAgent_Bad_WrongAgentType(t *testing.T) {
PID: os.Getpid(),
}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -304,12 +303,12 @@ func TestQueue_CountRunningByAgent_Bad_WrongAgentType(t *testing.T) {
func TestQueue_CountRunningByAgent_Ugly_CorruptStatusJSON(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a workspace with corrupt status.json
ws := filepath.Join(wsRoot, "ws-corrupt")
ws := core.JoinPath(wsRoot, "ws-corrupt")
os.MkdirAll(ws, 0o755)
os.WriteFile(filepath.Join(ws, "status.json"), []byte("{not valid json!!!"), 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), []byte("{not valid json!!!"), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -326,9 +325,9 @@ func TestQueue_CountRunningByAgent_Ugly_CorruptStatusJSON(t *testing.T) {
func TestQueue_CountRunningByModel_Bad_NoMatchingModel(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
ws := filepath.Join(wsRoot, "ws-1")
ws := core.JoinPath(wsRoot, "ws-1")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{
Status: "running",
@ -337,7 +336,7 @@ func TestQueue_CountRunningByModel_Bad_NoMatchingModel(t *testing.T) {
PID: os.Getpid(),
}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -352,7 +351,7 @@ func TestQueue_CountRunningByModel_Bad_NoMatchingModel(t *testing.T) {
func TestQueue_CountRunningByModel_Ugly_ModelMismatch(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Two workspaces, different models of same agent
for _, ws := range []struct {
@ -361,11 +360,11 @@ func TestQueue_CountRunningByModel_Ugly_ModelMismatch(t *testing.T) {
{"ws-a", "codex:gpt-5.4"},
{"ws-b", "codex:gpt-5.3-codex-spark"},
} {
d := filepath.Join(wsRoot, ws.name)
d := core.JoinPath(wsRoot, ws.name)
os.MkdirAll(d, 0o755)
st := &WorkspaceStatus{Status: "running", Agent: ws.agent, Repo: "test", PID: os.Getpid()}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(d, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(d, "status.json"), data, 0o644)
}
s := &PrepSubsystem{
@ -393,7 +392,7 @@ rates:
sustained_delay: 0
burst_window: 0
burst_delay: 0`
os.WriteFile(filepath.Join(root, "agents.yaml"), []byte(cfg), 0o644)
os.WriteFile(core.JoinPath(root, "agents.yaml"), []byte(cfg), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -418,7 +417,7 @@ rates:
sustained_delay: 60
burst_window: 2
burst_delay: 10`
os.WriteFile(filepath.Join(root, "agents.yaml"), []byte(cfg), 0o644)
os.WriteFile(core.JoinPath(root, "agents.yaml"), []byte(cfg), 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -439,10 +438,10 @@ rates:
func TestQueue_DrainOne_Bad_QueuedButAtConcurrencyLimit(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a running workspace that uses our PID
wsRunning := filepath.Join(wsRoot, "ws-running")
wsRunning := core.JoinPath(wsRoot, "ws-running")
os.MkdirAll(wsRunning, 0o755)
stRunning := &WorkspaceStatus{
Status: "running",
@ -451,14 +450,14 @@ func TestQueue_DrainOne_Bad_QueuedButAtConcurrencyLimit(t *testing.T) {
PID: os.Getpid(),
}
dataRunning, _ := json.Marshal(stRunning)
os.WriteFile(filepath.Join(wsRunning, "status.json"), dataRunning, 0o644)
os.WriteFile(core.JoinPath(wsRunning, "status.json"), dataRunning, 0o644)
// Create a queued workspace
wsQueued := filepath.Join(wsRoot, "ws-queued")
wsQueued := core.JoinPath(wsRoot, "ws-queued")
os.MkdirAll(wsQueued, 0o755)
stQueued := &WorkspaceStatus{Status: "queued", Agent: "claude", Repo: "go-log", Task: "do it"}
dataQueued, _ := json.Marshal(stQueued)
os.WriteFile(filepath.Join(wsQueued, "status.json"), dataQueued, 0o644)
os.WriteFile(core.JoinPath(wsQueued, "status.json"), dataQueued, 0o644)
c := core.New()
c.Config().Set("agents.concurrency", map[string]ConcurrencyLimit{
@ -479,14 +478,14 @@ func TestQueue_DrainOne_Bad_QueuedButAtConcurrencyLimit(t *testing.T) {
func TestQueue_DrainOne_Ugly_QueuedButInBackoffWindow(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a queued workspace
ws := filepath.Join(wsRoot, "ws-queued")
ws := core.JoinPath(wsRoot, "ws-queued")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{Status: "queued", Agent: "codex", Repo: "go-io", Task: "fix it"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -609,14 +608,14 @@ func TestQueue_LoadAgentsConfig_Ugly(t *testing.T) {
func TestQueue_DrainQueue_Bad_FrozenQueueDoesNothing(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a queued workspace that would normally be drained
ws := filepath.Join(wsRoot, "ws-queued")
ws := core.JoinPath(wsRoot, "ws-queued")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{Status: "queued", Agent: "codex", Repo: "go-io", Task: "fix it"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),

View file

@ -4,7 +4,6 @@ package agentic
import (
"os/exec"
"path/filepath"
"testing"
"time"
@ -28,7 +27,7 @@ func TestQueue_CountRunningByModel_Good_SkipsNonRunning(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Completed workspace — must not be counted
ws := filepath.Join(root, "workspace", "test-ws")
ws := core.JoinPath(root, "workspace", "test-ws")
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "completed",
@ -44,7 +43,7 @@ func TestQueue_CountRunningByModel_Good_SkipsMismatchedModel(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
ws := filepath.Join(root, "workspace", "model-ws")
ws := core.JoinPath(root, "workspace", "model-ws")
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "running",
@ -62,7 +61,7 @@ func TestQueue_CountRunningByModel_Good_DeepLayout(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Deep layout: workspace/org/repo/task-N/status.json
ws := filepath.Join(root, "workspace", "core", "go-io", "task-1")
ws := core.JoinPath(root, "workspace", "core", "go-io", "task-1")
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "completed",
@ -242,7 +241,7 @@ func TestPaths_LocalFs_Good_NonNil(t *testing.T) {
func TestPaths_LocalFs_Good_CanRead(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "hello.txt")
path := core.JoinPath(dir, "hello.txt")
require.True(t, fs.Write(path, "hello").OK)
f := LocalFs()

View file

@ -6,7 +6,6 @@ import (
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"path/filepath"
"testing"
)
@ -35,7 +34,7 @@ func TestQueue_CanDispatchAgent_Good_NoConfig(t *testing.T) {
// With no running workspaces and default config, should be able to dispatch
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), codePath: t.TempDir()}
assert.True(t, s.canDispatchAgent("gemini"))
@ -45,7 +44,7 @@ func TestQueue_CanDispatchAgent_Good_UnknownAgent(t *testing.T) {
// Unknown agent has no limit, so always allowed
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), codePath: t.TempDir()}
assert.True(t, s.canDispatchAgent("unknown-agent"))
@ -54,7 +53,7 @@ func TestQueue_CanDispatchAgent_Good_UnknownAgent(t *testing.T) {
func TestQueue_CountRunningByAgent_Good_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{})}
assert.Equal(t, 0, s.countRunningByAgent("gemini"))
@ -66,7 +65,7 @@ func TestQueue_CountRunningByAgent_Good_NoRunning(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Create a workspace with completed status under workspace/
ws := filepath.Join(root, "workspace", "test-ws")
ws := core.JoinPath(root, "workspace", "test-ws")
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "completed",

View file

@ -7,7 +7,6 @@ import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
@ -23,14 +22,14 @@ func TestResume_Resume_Good(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
wsRoot := WorkspaceRoot()
ws := filepath.Join(wsRoot, "ws-blocked")
repoDir := filepath.Join(ws, "repo")
ws := core.JoinPath(wsRoot, "ws-blocked")
repoDir := core.JoinPath(ws, "repo")
os.MkdirAll(repoDir, 0o755)
exec.Command("git", "init", repoDir).Run()
st := &WorkspaceStatus{Status: "blocked", Repo: "go-io", Agent: "codex", Task: "Fix the tests"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
_, out, err := s.resume(context.Background(), nil, ResumeInput{
@ -43,7 +42,7 @@ func TestResume_Resume_Good(t *testing.T) {
assert.Contains(t, out.Prompt, "Fix the tests")
assert.Contains(t, out.Prompt, "Use the new Core API")
answerContent, _ := os.ReadFile(filepath.Join(repoDir, "ANSWER.md"))
answerContent, _ := os.ReadFile(core.JoinPath(repoDir, "ANSWER.md"))
assert.Contains(t, string(answerContent), "Use the new Core API")
// Agent override
@ -53,12 +52,12 @@ func TestResume_Resume_Good(t *testing.T) {
assert.Equal(t, "claude:opus", out2.Agent)
// Completed workspace is resumable too
ws2 := filepath.Join(wsRoot, "ws-done")
os.MkdirAll(filepath.Join(ws2, "repo"), 0o755)
exec.Command("git", "init", filepath.Join(ws2, "repo")).Run()
ws2 := core.JoinPath(wsRoot, "ws-done")
os.MkdirAll(core.JoinPath(ws2, "repo"), 0o755)
exec.Command("git", "init", core.JoinPath(ws2, "repo")).Run()
st2 := &WorkspaceStatus{Status: "completed", Repo: "go-io", Agent: "codex", Task: "Review code"}
data2, _ := json.Marshal(st2)
os.WriteFile(filepath.Join(ws2, "status.json"), data2, 0o644)
os.WriteFile(core.JoinPath(ws2, "status.json"), data2, 0o644)
_, out3, err3 := s.resume(context.Background(), nil, ResumeInput{Workspace: "ws-done", DryRun: true})
require.NoError(t, err3)
@ -82,12 +81,12 @@ func TestResume_Resume_Bad(t *testing.T) {
assert.Contains(t, err.Error(), "workspace not found")
// Not resumable (running)
ws := filepath.Join(WorkspaceRoot(), "ws-running")
os.MkdirAll(filepath.Join(ws, "repo"), 0o755)
exec.Command("git", "init", filepath.Join(ws, "repo")).Run()
ws := core.JoinPath(WorkspaceRoot(), "ws-running")
os.MkdirAll(core.JoinPath(ws, "repo"), 0o755)
exec.Command("git", "init", core.JoinPath(ws, "repo")).Run()
st := &WorkspaceStatus{Status: "running", Repo: "test", Agent: "codex"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
_, _, err = s.resume(context.Background(), nil, ResumeInput{Workspace: "ws-running"})
assert.Error(t, err)
@ -99,9 +98,9 @@ func TestResume_Resume_Ugly(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Workspace exists but no status.json
ws := filepath.Join(WorkspaceRoot(), "ws-nostatus")
os.MkdirAll(filepath.Join(ws, "repo"), 0o755)
exec.Command("git", "init", filepath.Join(ws, "repo")).Run()
ws := core.JoinPath(WorkspaceRoot(), "ws-nostatus")
os.MkdirAll(core.JoinPath(ws, "repo"), 0o755)
exec.Command("git", "init", core.JoinPath(ws, "repo")).Run()
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}), backoff: make(map[string]time.Time), failCount: make(map[string]int)}
_, _, err := s.resume(context.Background(), nil, ResumeInput{Workspace: "ws-nostatus"})
@ -109,12 +108,12 @@ func TestResume_Resume_Ugly(t *testing.T) {
assert.Contains(t, err.Error(), "no status.json")
// No answer provided — prompt has no ANSWER section
ws2 := filepath.Join(WorkspaceRoot(), "ws-noanswer")
os.MkdirAll(filepath.Join(ws2, "repo"), 0o755)
exec.Command("git", "init", filepath.Join(ws2, "repo")).Run()
ws2 := core.JoinPath(WorkspaceRoot(), "ws-noanswer")
os.MkdirAll(core.JoinPath(ws2, "repo"), 0o755)
exec.Command("git", "init", core.JoinPath(ws2, "repo")).Run()
st := &WorkspaceStatus{Status: "blocked", Repo: "test", Agent: "codex", Task: "Fix"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws2, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws2, "status.json"), data, 0o644)
_, out, err := s.resume(context.Background(), nil, ResumeInput{Workspace: "ws-noanswer", DryRun: true})
require.NoError(t, err)

View file

@ -6,7 +6,6 @@ import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
@ -49,7 +48,7 @@ func TestSaveLoadRateLimitState_Good_Roundtrip(t *testing.T) {
t.Setenv("CORE_WORKSPACE", dir)
// Ensure .core dir exists
os.MkdirAll(filepath.Join(dir, ".core"), 0o755)
os.MkdirAll(core.JoinPath(dir, ".core"), 0o755)
// Note: saveRateLimitState uses core.Env("DIR_HOME") which is pre-populated.
// We need to work around this by using CORE_WORKSPACE for the load,
@ -97,7 +96,7 @@ func TestReviewQueue_Good_NoCandidates(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Create an empty core dir (no repos)
coreDir := filepath.Join(root, "core")
coreDir := core.JoinPath(root, "core")
os.MkdirAll(coreDir, 0o755)
s := &PrepSubsystem{
@ -118,7 +117,7 @@ func TestReviewQueue_Good_NoCandidates(t *testing.T) {
func TestStatus_Good_FilteredByStatus(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspaces with different statuses
for _, ws := range []struct {
@ -130,11 +129,11 @@ func TestStatus_Good_FilteredByStatus(t *testing.T) {
{"ws-3", "completed"},
{"ws-4", "queued"},
} {
wsDir := filepath.Join(wsRoot, ws.name)
wsDir := core.JoinPath(wsRoot, ws.name)
os.MkdirAll(wsDir, 0o755)
st := &WorkspaceStatus{Status: ws.status, Repo: "test", Agent: "codex"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
}
s := &PrepSubsystem{
@ -156,10 +155,10 @@ func TestStatus_Good_FilteredByStatus(t *testing.T) {
func TestHandlers_ResolveWorkspace_Good_Exists(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspace dir
ws := filepath.Join(wsRoot, "core", "go-io", "task-15")
ws := core.JoinPath(wsRoot, "core", "go-io", "task-15")
os.MkdirAll(ws, 0o755)
result := resolveWorkspace("core/go-io/task-15")
@ -177,13 +176,13 @@ func TestHandlers_ResolveWorkspace_Bad_NotExists(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Good_Match(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
ws := filepath.Join(wsRoot, "ws-test")
ws := core.JoinPath(wsRoot, "ws-test")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{Repo: "go-io", Branch: "agent/fix", Status: "completed"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
result := findWorkspaceByPR("go-io", "agent/fix")
assert.Equal(t, ws, result)
@ -192,14 +191,14 @@ func TestHandlers_FindWorkspaceByPR_Good_Match(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Good_DeepLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Deep layout: org/repo/task
ws := filepath.Join(wsRoot, "core", "agent", "task-5")
ws := core.JoinPath(wsRoot, "core", "agent", "task-5")
os.MkdirAll(ws, 0o755)
st := &WorkspaceStatus{Repo: "agent", Branch: "agent/tests", Status: "completed"}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(ws, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(ws, "status.json"), data, 0o644)
result := findWorkspaceByPR("agent", "agent/tests")
assert.Equal(t, ws, result)
@ -210,14 +209,14 @@ func TestHandlers_FindWorkspaceByPR_Good_DeepLayout(t *testing.T) {
func TestReviewQueue_LoadRateLimitState_Ugly(t *testing.T) {
// core.Env("DIR_HOME") is cached at init, so we must write to the real path.
// Save original content, write corrupt JSON, test, then restore.
ratePath := filepath.Join(core.Env("DIR_HOME"), ".core", "coderabbit-ratelimit.json")
ratePath := core.JoinPath(core.Env("DIR_HOME"), ".core", "coderabbit-ratelimit.json")
// Save original content (may or may not exist)
original, readErr := os.ReadFile(ratePath)
hadFile := readErr == nil
// Ensure parent dir exists
os.MkdirAll(filepath.Dir(ratePath), 0o755)
os.MkdirAll(core.PathDir(ratePath), 0o755)
// Write corrupt JSON
require.NoError(t, os.WriteFile(ratePath, []byte("not-valid-json{{{"), 0o644))

View file

@ -7,7 +7,6 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"time"
@ -22,7 +21,7 @@ import (
func TestStatus_Good_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -40,10 +39,10 @@ func TestStatus_Good_EmptyWorkspace(t *testing.T) {
func TestStatus_Good_MixedWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create completed workspace (old layout)
ws1 := filepath.Join(wsRoot, "task-1")
ws1 := core.JoinPath(wsRoot, "task-1")
require.True(t, fs.EnsureDir(ws1).OK)
require.NoError(t, writeStatus(ws1, &WorkspaceStatus{
Status: "completed",
@ -52,7 +51,7 @@ func TestStatus_Good_MixedWorkspaces(t *testing.T) {
}))
// Create failed workspace (old layout)
ws2 := filepath.Join(wsRoot, "task-2")
ws2 := core.JoinPath(wsRoot, "task-2")
require.True(t, fs.EnsureDir(ws2).OK)
require.NoError(t, writeStatus(ws2, &WorkspaceStatus{
Status: "failed",
@ -61,7 +60,7 @@ func TestStatus_Good_MixedWorkspaces(t *testing.T) {
}))
// Create blocked workspace (old layout)
ws3 := filepath.Join(wsRoot, "task-3")
ws3 := core.JoinPath(wsRoot, "task-3")
require.True(t, fs.EnsureDir(ws3).OK)
require.NoError(t, writeStatus(ws3, &WorkspaceStatus{
Status: "blocked",
@ -71,7 +70,7 @@ func TestStatus_Good_MixedWorkspaces(t *testing.T) {
}))
// Create queued workspace (old layout)
ws4 := filepath.Join(wsRoot, "task-4")
ws4 := core.JoinPath(wsRoot, "task-4")
require.True(t, fs.EnsureDir(ws4).OK)
require.NoError(t, writeStatus(ws4, &WorkspaceStatus{
Status: "queued",
@ -99,10 +98,10 @@ func TestStatus_Good_MixedWorkspaces(t *testing.T) {
func TestStatus_Good_DeepLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspace in deep layout (org/repo/task)
ws := filepath.Join(wsRoot, "core", "go-io", "task-15")
ws := core.JoinPath(wsRoot, "core", "go-io", "task-15")
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "completed",
@ -125,11 +124,11 @@ func TestStatus_Good_DeepLayout(t *testing.T) {
func TestStatus_Good_CorruptStatusFile(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
ws := filepath.Join(wsRoot, "corrupt-ws")
ws := core.JoinPath(wsRoot, "corrupt-ws")
require.True(t, fs.EnsureDir(ws).OK)
require.True(t, fs.Write(filepath.Join(ws, "status.json"), "invalid-json{{{").OK)
require.True(t, fs.Write(core.JoinPath(ws, "status.json"), "invalid-json{{{").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -182,7 +181,7 @@ func TestShutdown_ShutdownGraceful_Good(t *testing.T) {
func TestShutdown_ShutdownNow_Good_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
require.True(t, fs.EnsureDir(core.JoinPath(root, "workspace")).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -201,11 +200,11 @@ func TestShutdown_ShutdownNow_Good_EmptyWorkspace(t *testing.T) {
func TestShutdown_ShutdownNow_Good_ClearsQueued(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create queued workspaces
for i := 1; i <= 3; i++ {
ws := filepath.Join(wsRoot, "task-"+itoa(i))
ws := core.JoinPath(wsRoot, "task-"+itoa(i))
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "queued",
@ -226,7 +225,7 @@ func TestShutdown_ShutdownNow_Good_ClearsQueued(t *testing.T) {
// Verify queued workspaces are now failed
for i := 1; i <= 3; i++ {
ws := filepath.Join(wsRoot, "task-"+itoa(i))
ws := core.JoinPath(wsRoot, "task-"+itoa(i))
st, err := ReadStatus(ws)
require.NoError(t, err)
assert.Equal(t, "failed", st.Status)
@ -557,10 +556,10 @@ func TestQueue_DrainQueue_Good_FrozenDoesNothing(t *testing.T) {
func TestPrep_Shutdown_ShutdownNow_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspace in deep layout (org/repo/task)
ws := filepath.Join(wsRoot, "core", "go-io", "task-5")
ws := core.JoinPath(wsRoot, "core", "go-io", "task-5")
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "queued",
@ -646,11 +645,11 @@ func TestShutdown_ShutdownGraceful_Bad_AlreadyFrozen(t *testing.T) {
func TestShutdown_ShutdownGraceful_Ugly_WithWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspaces with various statuses
for _, name := range []string{"ws-completed", "ws-failed", "ws-blocked"} {
ws := filepath.Join(wsRoot, name)
ws := core.JoinPath(wsRoot, name)
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "completed",
@ -679,11 +678,11 @@ func TestShutdown_ShutdownGraceful_Ugly_WithWorkspaces(t *testing.T) {
func TestShutdown_ShutdownNow_Bad_NoRunningPIDs(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create completed workspaces only (no running PIDs to kill)
for i := 1; i <= 2; i++ {
ws := filepath.Join(wsRoot, "task-"+itoa(i))
ws := core.JoinPath(wsRoot, "task-"+itoa(i))
require.True(t, fs.EnsureDir(ws).OK)
require.NoError(t, writeStatus(ws, &WorkspaceStatus{
Status: "completed",

View file

@ -4,10 +4,10 @@ package agentic
import (
"encoding/json"
"path/filepath"
"testing"
"time"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -35,7 +35,7 @@ func TestStatus_ReadStatus_Good_AllFields(t *testing.T) {
}
data, err := json.MarshalIndent(original, "", " ")
require.NoError(t, err)
require.True(t, fs.Write(filepath.Join(dir, "status.json"), string(data)).OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), string(data)).OK)
st, err := ReadStatus(dir)
require.NoError(t, err)
@ -59,7 +59,7 @@ func TestStatus_ReadStatus_Bad_MissingFile(t *testing.T) {
func TestStatus_ReadStatus_Bad_CorruptJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), `{"status": "running", broken`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), `{"status": "running", broken`).OK)
_, err := ReadStatus(dir)
assert.Error(t, err, "corrupt JSON must return an error")
@ -67,7 +67,7 @@ func TestStatus_ReadStatus_Bad_CorruptJSON(t *testing.T) {
func TestStatus_ReadStatus_Bad_NullJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), "null").OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "null").OK)
// null is valid JSON — ReadStatus returns a zero-value struct, not an error
st, err := ReadStatus(dir)

View file

@ -5,7 +5,6 @@ package agentic
import (
"context"
"encoding/json"
"path/filepath"
"testing"
"time"
@ -30,7 +29,7 @@ func TestStatus_WriteStatus_Good(t *testing.T) {
require.NoError(t, err)
// Verify file was written via core.Fs
r := fs.Read(filepath.Join(dir, "status.json"))
r := fs.Read(core.JoinPath(dir, "status.json"))
require.True(t, r.OK)
var read WorkspaceStatus
@ -78,7 +77,7 @@ func TestStatus_ReadStatus_Good(t *testing.T) {
data, err := json.MarshalIndent(status, "", " ")
require.NoError(t, err)
require.True(t, fs.Write(filepath.Join(dir, "status.json"), string(data)).OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), string(data)).OK)
read, err := ReadStatus(dir)
require.NoError(t, err)
@ -100,7 +99,7 @@ func TestStatus_ReadStatus_Bad_NoFile(t *testing.T) {
func TestStatus_ReadStatus_Bad_InvalidJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), "not json{").OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "not json{").OK)
_, err := ReadStatus(dir)
assert.Error(t, err)
@ -118,7 +117,7 @@ func TestStatus_ReadStatus_Good_BlockedWithQuestion(t *testing.T) {
data, err := json.MarshalIndent(status, "", " ")
require.NoError(t, err)
require.True(t, fs.Write(filepath.Join(dir, "status.json"), string(data)).OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), string(data)).OK)
read, err := ReadStatus(dir)
require.NoError(t, err)
@ -178,7 +177,7 @@ func TestStatus_WriteStatus_Good_OverwriteExisting(t *testing.T) {
func TestStatus_ReadStatus_Ugly_EmptyFile(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), "").OK)
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "").OK)
_, err := ReadStatus(dir)
assert.Error(t, err)
@ -189,33 +188,33 @@ func TestStatus_ReadStatus_Ugly_EmptyFile(t *testing.T) {
func TestStatus_Status_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Case 1: running + dead PID + BLOCKED.md → should detect as blocked
ws1 := filepath.Join(wsRoot, "dead-blocked")
require.True(t, fs.EnsureDir(filepath.Join(ws1, "repo")).OK)
ws1 := core.JoinPath(wsRoot, "dead-blocked")
require.True(t, fs.EnsureDir(core.JoinPath(ws1, "repo")).OK)
require.NoError(t, writeStatus(ws1, &WorkspaceStatus{
Status: "running",
Repo: "go-io",
Agent: "codex",
PID: 999999,
}))
require.True(t, fs.Write(filepath.Join(ws1, "repo", "BLOCKED.md"), "Need API credentials").OK)
require.True(t, fs.Write(core.JoinPath(ws1, "repo", "BLOCKED.md"), "Need API credentials").OK)
// Case 2: running + dead PID + agent log → completed
ws2 := filepath.Join(wsRoot, "dead-completed")
require.True(t, fs.EnsureDir(filepath.Join(ws2, "repo")).OK)
ws2 := core.JoinPath(wsRoot, "dead-completed")
require.True(t, fs.EnsureDir(core.JoinPath(ws2, "repo")).OK)
require.NoError(t, writeStatus(ws2, &WorkspaceStatus{
Status: "running",
Repo: "go-log",
Agent: "claude",
PID: 999999,
}))
require.True(t, fs.Write(filepath.Join(ws2, "agent-claude.log"), "agent finished ok").OK)
require.True(t, fs.Write(core.JoinPath(ws2, "agent-claude.log"), "agent finished ok").OK)
// Case 3: running + dead PID + no log + no BLOCKED.md → failed
ws3 := filepath.Join(wsRoot, "dead-failed")
require.True(t, fs.EnsureDir(filepath.Join(ws3, "repo")).OK)
ws3 := core.JoinPath(wsRoot, "dead-failed")
require.True(t, fs.EnsureDir(core.JoinPath(ws3, "repo")).OK)
require.NoError(t, writeStatus(ws3, &WorkspaceStatus{
Status: "running",
Repo: "agent",
@ -318,11 +317,11 @@ func TestStatus_WriteStatus_Bad_ReadOnlyPath(t *testing.T) {
func TestStatus_Status_Good_PopulatedWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create a running workspace with a live PID (our own PID)
ws1 := filepath.Join(wsRoot, "task-running")
require.True(t, fs.EnsureDir(filepath.Join(ws1, "repo")).OK)
ws1 := core.JoinPath(wsRoot, "task-running")
require.True(t, fs.EnsureDir(core.JoinPath(ws1, "repo")).OK)
require.NoError(t, writeStatus(ws1, &WorkspaceStatus{
Status: "completed",
Repo: "go-io",
@ -331,8 +330,8 @@ func TestStatus_Status_Good_PopulatedWorkspaces(t *testing.T) {
}))
// Create a blocked workspace
ws2 := filepath.Join(wsRoot, "task-blocked")
require.True(t, fs.EnsureDir(filepath.Join(ws2, "repo")).OK)
ws2 := core.JoinPath(wsRoot, "task-blocked")
require.True(t, fs.EnsureDir(core.JoinPath(ws2, "repo")).OK)
require.NoError(t, writeStatus(ws2, &WorkspaceStatus{
Status: "blocked",
Repo: "go-log",

View file

@ -8,7 +8,6 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
@ -66,8 +65,8 @@ func TestVerify_AutoVerifyAndMerge_Good_FullPipeline(t *testing.T) {
t.Cleanup(srv.Close)
dir := t.TempDir()
wsDir := filepath.Join(dir, "ws")
repoDir := filepath.Join(wsDir, "repo")
wsDir := core.JoinPath(dir, "ws")
repoDir := core.JoinPath(wsDir, "repo")
os.MkdirAll(repoDir, 0o755)
// No go.mod, composer.json, or package.json = no test runner = passes
@ -79,7 +78,7 @@ func TestVerify_AutoVerifyAndMerge_Good_FullPipeline(t *testing.T) {
PRURL: "https://forge.lthn.ai/core/test-repo/pulls/5",
}
data, _ := json.Marshal(st)
os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0o644)
os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),

View file

@ -8,7 +8,6 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
@ -269,7 +268,7 @@ func TestVerify_RunVerification_Good_NoProjectFile(t *testing.T) {
func TestVerify_RunVerification_Good_GoProject(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -284,7 +283,7 @@ func TestVerify_RunVerification_Good_GoProject(t *testing.T) {
func TestVerify_RunVerification_Good_PHPProject(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "composer.json"), `{"require":{}}`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "composer.json"), `{"require":{}}`).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -299,7 +298,7 @@ func TestVerify_RunVerification_Good_PHPProject(t *testing.T) {
func TestVerify_RunVerification_Good_NodeProject(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "package.json"), `{"scripts":{"test":"echo ok"}}`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "package.json"), `{"scripts":{"test":"echo ok"}}`).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -313,7 +312,7 @@ func TestVerify_RunVerification_Good_NodeProject(t *testing.T) {
func TestVerify_RunVerification_Good_NodeNoTestScript(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "package.json"), `{"scripts":{}}`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "package.json"), `{"scripts":{}}`).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -330,7 +329,7 @@ func TestVerify_RunVerification_Good_NodeNoTestScript(t *testing.T) {
func TestVerify_FileExists_Good_Exists(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "test.txt")
path := core.JoinPath(dir, "test.txt")
require.True(t, fs.Write(path, "hello").OK)
assert.True(t, fileExists(path))
@ -566,9 +565,9 @@ func TestVerify_AttemptVerifyAndMerge_Ugly(t *testing.T) {
dir := t.TempDir()
// Write a go.mod so runVerification detects Go and runs "go test ./..."
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module broken-test\n\ngo 1.22").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module broken-test\n\ngo 1.22").OK)
// Write invalid Go code to force test failure
require.True(t, fs.Write(filepath.Join(dir, "broken.go"), "package broken\n\nfunc Bad() { undeclared() }").OK)
require.True(t, fs.Write(core.JoinPath(dir, "broken.go"), "package broken\n\nfunc Bad() { undeclared() }").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -666,7 +665,7 @@ func TestVerify_ForgeMergePR_Ugly_EmptyBody200(t *testing.T) {
func TestVerify_FileExists_Ugly_PathIsDirectory(t *testing.T) {
dir := t.TempDir()
sub := filepath.Join(dir, "subdir")
sub := core.JoinPath(dir, "subdir")
require.NoError(t, os.MkdirAll(sub, 0o755))
// A directory is not a file — fileExists should return false
@ -728,7 +727,7 @@ func TestVerify_FlagForReview_Ugly_LabelNotFoundZeroID(t *testing.T) {
func TestVerify_RunVerification_Bad_GoModButNoGoFiles(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test\n\ngo 1.22").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test\n\ngo 1.22").OK)
// go.mod exists but no .go files — go test should fail
s := &PrepSubsystem{
@ -746,8 +745,8 @@ func TestVerify_RunVerification_Bad_GoModButNoGoFiles(t *testing.T) {
func TestVerify_RunVerification_Ugly_MultipleProjectFiles(t *testing.T) {
dir := t.TempDir()
// Both go.mod and package.json exist — Go takes priority
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test\n\ngo 1.22").OK)
require.True(t, fs.Write(filepath.Join(dir, "package.json"), `{"scripts":{"test":"echo ok"}}`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test\n\ngo 1.22").OK)
require.True(t, fs.Write(core.JoinPath(dir, "package.json"), `{"scripts":{"test":"echo ok"}}`).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -764,8 +763,8 @@ func TestVerify_RunVerification_Ugly_MultipleProjectFiles(t *testing.T) {
func TestVerify_RunVerification_Ugly_GoAndPHPProjectFiles(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test\n\ngo 1.22").OK)
require.True(t, fs.Write(filepath.Join(dir, "composer.json"), `{"require":{}}`).OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module test\n\ngo 1.22").OK)
require.True(t, fs.Write(core.JoinPath(dir, "composer.json"), `{"require":{}}`).OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -782,9 +781,9 @@ func TestVerify_RunVerification_Ugly_GoAndPHPProjectFiles(t *testing.T) {
func TestVerify_RunGoTests_Good(t *testing.T) {
dir := t.TempDir()
// Create a valid Go project with a passing test
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module testproj\n\ngo 1.22\n").OK)
require.True(t, fs.Write(filepath.Join(dir, "main.go"), "package testproj\n\nfunc Add(a, b int) int { return a + b }\n").OK)
require.True(t, fs.Write(filepath.Join(dir, "main_test.go"), `package testproj
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module testproj\n\ngo 1.22\n").OK)
require.True(t, fs.Write(core.JoinPath(dir, "main.go"), "package testproj\n\nfunc Add(a, b int) int { return a + b }\n").OK)
require.True(t, fs.Write(core.JoinPath(dir, "main_test.go"), `package testproj
import "testing"
@ -810,8 +809,8 @@ func TestAdd(t *testing.T) {
func TestVerify_RunGoTests_Bad(t *testing.T) {
dir := t.TempDir()
// Create a broken Go project — compilation error
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module broken\n\ngo 1.22\n").OK)
require.True(t, fs.Write(filepath.Join(dir, "broken.go"), "package broken\n\nfunc Bad() { undeclared() }\n").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module broken\n\ngo 1.22\n").OK)
require.True(t, fs.Write(core.JoinPath(dir, "broken.go"), "package broken\n\nfunc Bad() { undeclared() }\n").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -828,8 +827,8 @@ func TestVerify_RunGoTests_Bad(t *testing.T) {
func TestVerify_RunGoTests_Ugly(t *testing.T) {
dir := t.TempDir()
// go.mod but no test files — Go considers this a pass
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module empty\n\ngo 1.22\n").OK)
require.True(t, fs.Write(filepath.Join(dir, "main.go"), "package empty\n").OK)
require.True(t, fs.Write(core.JoinPath(dir, "go.mod"), "module empty\n\ngo 1.22\n").OK)
require.True(t, fs.Write(core.JoinPath(dir, "main.go"), "package empty\n").OK)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),

View file

@ -5,7 +5,6 @@ package agentic
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
@ -23,7 +22,7 @@ func TestWatch_ResolveWorkspaceDir_Good_RelativeName(t *testing.T) {
}
dir := s.resolveWorkspaceDir("go-io-abc123")
assert.Contains(t, dir, "go-io-abc123")
assert.True(t, filepath.IsAbs(dir))
assert.True(t, core.PathIsAbs(dir))
}
func TestWatch_ResolveWorkspaceDir_Good_AbsolutePath(t *testing.T) {
@ -42,25 +41,25 @@ func TestWatch_FindActiveWorkspaces_Good_WithActive(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create running workspace
ws1 := filepath.Join(wsRoot, "ws-running")
ws1 := core.JoinPath(wsRoot, "ws-running")
os.MkdirAll(ws1, 0o755)
st1, _ := json.Marshal(WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(ws1, "status.json"), st1, 0o644)
os.WriteFile(core.JoinPath(ws1, "status.json"), st1, 0o644)
// Create completed workspace (should not be in active list)
ws2 := filepath.Join(wsRoot, "ws-done")
ws2 := core.JoinPath(wsRoot, "ws-done")
os.MkdirAll(ws2, 0o755)
st2, _ := json.Marshal(WorkspaceStatus{Status: "completed", Repo: "go-crypt", Agent: "codex"})
os.WriteFile(filepath.Join(ws2, "status.json"), st2, 0o644)
os.WriteFile(core.JoinPath(ws2, "status.json"), st2, 0o644)
// Create queued workspace
ws3 := filepath.Join(wsRoot, "ws-queued")
ws3 := core.JoinPath(wsRoot, "ws-queued")
os.MkdirAll(ws3, 0o755)
st3, _ := json.Marshal(WorkspaceStatus{Status: "queued", Repo: "go-log", Agent: "gemini"})
os.WriteFile(filepath.Join(ws3, "status.json"), st3, 0o644)
os.WriteFile(core.JoinPath(ws3, "status.json"), st3, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -78,7 +77,7 @@ func TestWatch_FindActiveWorkspaces_Good_Empty(t *testing.T) {
t.Setenv("CORE_WORKSPACE", root)
// Ensure workspace dir exists but is empty
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
os.MkdirAll(core.JoinPath(root, "workspace"), 0o755)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -94,7 +93,7 @@ func TestWatch_FindActiveWorkspaces_Good_Empty(t *testing.T) {
func TestWatch_FindActiveWorkspaces_Bad(t *testing.T) {
// Workspace dir doesn't exist
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", filepath.Join(root, "nonexistent"))
t.Setenv("CORE_WORKSPACE", core.JoinPath(root, "nonexistent"))
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -111,18 +110,18 @@ func TestWatch_FindActiveWorkspaces_Ugly(t *testing.T) {
// Workspaces with corrupt status.json
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
wsRoot := core.JoinPath(root, "workspace")
// Create workspace with corrupt status.json
ws1 := filepath.Join(wsRoot, "ws-corrupt")
ws1 := core.JoinPath(wsRoot, "ws-corrupt")
os.MkdirAll(ws1, 0o755)
os.WriteFile(filepath.Join(ws1, "status.json"), []byte("not-valid-json{{{"), 0o644)
os.WriteFile(core.JoinPath(ws1, "status.json"), []byte("not-valid-json{{{"), 0o644)
// Create valid running workspace
ws2 := filepath.Join(wsRoot, "ws-valid")
ws2 := core.JoinPath(wsRoot, "ws-valid")
os.MkdirAll(ws2, 0o755)
st, _ := json.Marshal(WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(ws2, "status.json"), st, 0o644)
os.WriteFile(core.JoinPath(ws2, "status.json"), st, 0o644)
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
@ -147,7 +146,7 @@ func TestWatch_ResolveWorkspaceDir_Bad(t *testing.T) {
}
dir := s.resolveWorkspaceDir("")
assert.NotEmpty(t, dir, "empty name should still resolve to workspace root")
assert.True(t, filepath.IsAbs(dir))
assert.True(t, core.PathIsAbs(dir))
}
func TestWatch_ResolveWorkspaceDir_Ugly(t *testing.T) {
@ -160,6 +159,6 @@ func TestWatch_ResolveWorkspaceDir_Ugly(t *testing.T) {
assert.NotPanics(t, func() {
dir := s.resolveWorkspaceDir("../..")
// JoinPath handles traversal; result should be absolute
assert.True(t, filepath.IsAbs(dir))
assert.True(t, core.PathIsAbs(dir))
})
}

View file

@ -5,12 +5,13 @@ package brain
import (
"context"
"encoding/json"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newTestDirect returns a DirectSubsystem wired to the given test server.
@ -60,9 +61,9 @@ func TestNewDirect_Good_KeyFromFile(t *testing.T) {
tmpHome := t.TempDir()
t.Setenv("CORE_HOME", tmpHome)
keyDir := filepath.Join(tmpHome, ".claude")
keyDir := core.JoinPath(tmpHome, ".claude")
require.True(t, fs.EnsureDir(keyDir).OK)
require.True(t, fs.Write(filepath.Join(keyDir, "brain.key"), " file-key-456 \n").OK)
require.True(t, fs.Write(core.JoinPath(keyDir, "brain.key"), " file-key-456 \n").OK)
sub := NewDirect()
assert.Equal(t, "file-key-456", sub.apiKey)

View file

@ -7,7 +7,6 @@ import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"testing"
"dappco.re/go/agent/pkg/messages"
@ -22,23 +21,23 @@ func initTestRepo(t *testing.T) (sourceDir, wsDir string) {
t.Helper()
// Create bare "source" repo
sourceDir = filepath.Join(t.TempDir(), "source")
sourceDir = core.JoinPath(t.TempDir(), "source")
require.NoError(t, os.MkdirAll(sourceDir, 0755))
run(t, sourceDir, "git", "init")
run(t, sourceDir, "git", "checkout", "-b", "main")
os.WriteFile(filepath.Join(sourceDir, "README.md"), []byte("# test"), 0644)
os.WriteFile(core.JoinPath(sourceDir, "README.md"), []byte("# test"), 0644)
run(t, sourceDir, "git", "add", ".")
run(t, sourceDir, "git", "commit", "-m", "init")
// Create workspace dir with src/ clone
wsDir = filepath.Join(t.TempDir(), "workspace")
srcDir := filepath.Join(wsDir, "src")
wsDir = core.JoinPath(t.TempDir(), "workspace")
srcDir := core.JoinPath(wsDir, "src")
require.NoError(t, os.MkdirAll(wsDir, 0755))
run(t, wsDir, "git", "clone", sourceDir, "src")
// Create agent branch with a commit
run(t, srcDir, "git", "checkout", "-b", "agent/test-task")
os.WriteFile(filepath.Join(srcDir, "new.go"), []byte("package main\n"), 0644)
os.WriteFile(core.JoinPath(srcDir, "new.go"), []byte("package main\n"), 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "agent work")
@ -62,14 +61,14 @@ func writeStatus(t *testing.T, wsDir, status, repo, branch string) {
"branch": branch,
}
data, _ := json.MarshalIndent(st, "", " ")
require.NoError(t, os.WriteFile(filepath.Join(wsDir, "status.json"), data, 0644))
require.NoError(t, os.WriteFile(core.JoinPath(wsDir, "status.json"), data, 0644))
}
// --- Tests ---
func TestHarvest_DetectBranch_Good(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
branch := testMon.detectBranch(srcDir)
assert.Equal(t, "agent/test-task", branch)
@ -82,7 +81,7 @@ func TestHarvest_DetectBranch_Bad_NoRepo(t *testing.T) {
func TestHarvest_CountUnpushed_Good(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
count := testMon.countUnpushed(srcDir, "agent/test-task")
assert.Equal(t, 1, count)
@ -90,7 +89,7 @@ func TestHarvest_CountUnpushed_Good(t *testing.T) {
func TestHarvest_CountChangedFiles_Good(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
count := testMon.countChangedFiles(srcDir)
assert.Equal(t, 1, count)
@ -98,7 +97,7 @@ func TestHarvest_CountChangedFiles_Good(t *testing.T) {
func TestHarvest_CheckSafety_Good_CleanWorkspace(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
reason := testMon.checkSafety(srcDir)
assert.Equal(t, "", reason)
@ -106,10 +105,10 @@ func TestHarvest_CheckSafety_Good_CleanWorkspace(t *testing.T) {
func TestHarvest_CheckSafety_Bad_BinaryFile(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
// Add a binary file
os.WriteFile(filepath.Join(srcDir, "app.exe"), []byte("binary"), 0644)
os.WriteFile(core.JoinPath(srcDir, "app.exe"), []byte("binary"), 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "add binary")
@ -120,11 +119,11 @@ func TestHarvest_CheckSafety_Bad_BinaryFile(t *testing.T) {
func TestHarvest_CheckSafety_Bad_LargeFile(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
// Add a file > 1MB
bigData := make([]byte, 1024*1024+1)
os.WriteFile(filepath.Join(srcDir, "huge.txt"), bigData, 0644)
os.WriteFile(core.JoinPath(srcDir, "huge.txt"), bigData, 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "add large file")
@ -148,7 +147,7 @@ func TestHarvest_HarvestWorkspace_Good(t *testing.T) {
assert.Equal(t, "", result.rejected)
// Verify status updated
data, err := os.ReadFile(filepath.Join(wsDir, "status.json"))
data, err := os.ReadFile(core.JoinPath(wsDir, "status.json"))
require.NoError(t, err)
var st map[string]any
json.Unmarshal(data, &st)
@ -169,7 +168,7 @@ func TestHarvest_HarvestWorkspace_Bad_MainBranch(t *testing.T) {
_, wsDir := initTestRepo(t)
// Switch back to main
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
run(t, srcDir, "git", "checkout", "main")
writeStatus(t, wsDir, "completed", "test-repo", "main")
@ -182,10 +181,10 @@ func TestHarvest_HarvestWorkspace_Bad_MainBranch(t *testing.T) {
func TestHarvest_HarvestWorkspace_Bad_BinaryRejected(t *testing.T) {
_, wsDir := initTestRepo(t)
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
// Add binary
os.WriteFile(filepath.Join(srcDir, "build.so"), []byte("elf"), 0644)
os.WriteFile(core.JoinPath(srcDir, "build.so"), []byte("elf"), 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "add binary")
@ -199,7 +198,7 @@ func TestHarvest_HarvestWorkspace_Bad_BinaryRejected(t *testing.T) {
assert.Contains(t, result.rejected, "binary file added")
// Verify status set to rejected
data, _ := os.ReadFile(filepath.Join(wsDir, "status.json"))
data, _ := os.ReadFile(core.JoinPath(wsDir, "status.json"))
var st map[string]any
json.Unmarshal(data, &st)
assert.Equal(t, "rejected", st["status"])
@ -241,11 +240,11 @@ func TestHarvest_UpdateStatus_Good(t *testing.T) {
dir := t.TempDir()
initial := map[string]any{"status": "completed", "repo": "test"}
data, _ := json.MarshalIndent(initial, "", " ")
os.WriteFile(filepath.Join(dir, "status.json"), data, 0644)
os.WriteFile(core.JoinPath(dir, "status.json"), data, 0644)
updateStatus(dir, "ready-for-review", "")
out, _ := os.ReadFile(filepath.Join(dir, "status.json"))
out, _ := os.ReadFile(core.JoinPath(dir, "status.json"))
var st map[string]any
json.Unmarshal(out, &st)
assert.Equal(t, "ready-for-review", st["status"])
@ -255,11 +254,11 @@ func TestHarvest_UpdateStatus_Good_WithQuestion(t *testing.T) {
dir := t.TempDir()
initial := map[string]any{"status": "completed", "repo": "test"}
data, _ := json.MarshalIndent(initial, "", " ")
os.WriteFile(filepath.Join(dir, "status.json"), data, 0644)
os.WriteFile(core.JoinPath(dir, "status.json"), data, 0644)
updateStatus(dir, "rejected", "binary file: app.exe")
out, _ := os.ReadFile(filepath.Join(dir, "status.json"))
out, _ := os.ReadFile(core.JoinPath(dir, "status.json"))
var st map[string]any
json.Unmarshal(out, &st)
assert.Equal(t, "rejected", st["status"])

View file

@ -5,7 +5,6 @@ package monitor
import (
"context"
"os"
"path/filepath"
"testing"
"time"
@ -43,7 +42,7 @@ func TestLogic_HandleAgentStarted_Bad_EmptyWorkspace(t *testing.T) {
func TestLogic_HandleAgentCompleted_Good_NilRuntime(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
// ServiceRuntime is nil — must not panic, must record completion and poke.
@ -58,7 +57,7 @@ func TestLogic_HandleAgentCompleted_Good_NilRuntime(t *testing.T) {
func TestLogic_HandleAgentCompleted_Good_WithCore(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
// Use Register so IPC handlers are wired
c := core.New(core.WithService(Register))
@ -76,7 +75,7 @@ func TestLogic_HandleAgentCompleted_Good_WithCore(t *testing.T) {
func TestLogic_HandleAgentCompleted_Bad_EmptyFields(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
@ -94,7 +93,7 @@ func TestLogic_HandleAgentCompleted_Bad_EmptyFields(t *testing.T) {
func TestLogic_CheckIdleAfterDelay_Bad_NilRuntime(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New() // ServiceRuntime is nil
@ -120,7 +119,7 @@ func TestLogic_CheckIdleAfterDelay_Bad_NilRuntime(t *testing.T) {
func TestLogic_CheckIdleAfterDelay_Good_EmptyWorkspace(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
// Create a Core with an IPC handler to capture QueueDrained messages
var captured []messages.QueueDrained
@ -153,7 +152,7 @@ func TestLogic_CheckIdleAfterDelay_Good_EmptyWorkspace(t *testing.T) {
func TestLogic_CountLiveWorkspaces_Good_EmptyWorkspace(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
running, queued := mon.countLiveWorkspaces()
@ -256,7 +255,7 @@ func TestLogic_SetCore_Good_RegistersIPCHandler(t *testing.T) {
func TestLogic_SetCore_Good_IPCHandlerFires(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
// IPC handlers are registered via Register, not SetCore
c := core.New(core.WithService(Register))
@ -275,7 +274,7 @@ func TestLogic_SetCore_Good_IPCHandlerFires(t *testing.T) {
func TestLogic_SetCore_Good_CompletedIPCHandler(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
// IPC handlers are registered via Register, not SetCore
c := core.New(core.WithService(Register))
@ -296,7 +295,7 @@ func TestLogic_SetCore_Good_CompletedIPCHandler(t *testing.T) {
func TestLogic_OnStartup_Good_StartsLoop(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
home := t.TempDir()
t.Setenv("HOME", home)
@ -316,7 +315,7 @@ func TestLogic_OnStartup_Good_StartsLoop(t *testing.T) {
func TestLogic_OnStartup_Good_NoError(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New(Options{Interval: 1 * time.Hour})
assert.True(t, mon.OnStartup(context.Background()).OK)
@ -331,7 +330,7 @@ func TestLogic_OnShutdown_Good_NoError(t *testing.T) {
func TestLogic_OnShutdown_Good_StopsLoop(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
home := t.TempDir()
t.Setenv("HOME", home)
@ -394,7 +393,7 @@ func TestLogic_Register_Good_CoreWired(t *testing.T) {
func TestLogic_Register_Good_IPCHandlerActive(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
c := core.New(core.WithService(Register))
require.NotNil(t, c)

View file

@ -9,7 +9,6 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
@ -26,9 +25,9 @@ func setupBrainKey(t *testing.T, key string) {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
claudeDir := filepath.Join(home, ".claude")
claudeDir := core.JoinPath(home, ".claude")
require.NoError(t, os.MkdirAll(claudeDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(claudeDir, "brain.key"), []byte(key), 0644))
require.NoError(t, os.WriteFile(core.JoinPath(claudeDir, "brain.key"), []byte(key), 0644))
}
// setupAPIEnv sets up brain key, CORE_API_URL, and AGENT_NAME for API tests.
@ -43,10 +42,10 @@ func setupAPIEnv(t *testing.T, apiURL string) {
// under the given root. Returns the workspace directory path.
func writeWorkspaceStatus(t *testing.T, wsRoot, name string, fields map[string]any) string {
t.Helper()
dir := filepath.Join(wsRoot, "workspace", name)
dir := core.JoinPath(wsRoot, "workspace", name)
require.NoError(t, os.MkdirAll(dir, 0755))
data, _ := json.Marshal(fields)
require.NoError(t, os.WriteFile(filepath.Join(dir, "status.json"), data, 0644))
require.NoError(t, os.WriteFile(core.JoinPath(dir, "status.json"), data, 0644))
return dir
}
@ -130,7 +129,7 @@ func TestMonitor_CheckCompletions_Good_NewCompletions(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
// Create Core with IPC handler to capture QueueDrained messages
var drainEvents []messages.QueueDrained
@ -166,7 +165,7 @@ func TestMonitor_CheckCompletions_Good_MixedStatuses(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
assert.Equal(t, "", mon.checkCompletions())
@ -203,7 +202,7 @@ func TestMonitor_CheckCompletions_Good_NoNewCompletions(t *testing.T) {
func TestMonitor_CheckCompletions_Good_EmptyWorkspace(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
msg := mon.checkCompletions()
@ -214,9 +213,9 @@ func TestMonitor_CheckCompletions_Bad_InvalidJSON(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
dir := filepath.Join(wsRoot, "workspace", "ws-bad")
dir := core.JoinPath(wsRoot, "workspace", "ws-bad")
require.NoError(t, os.MkdirAll(dir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "status.json"), []byte("not json"), 0644))
require.NoError(t, os.WriteFile(core.JoinPath(dir, "status.json"), []byte("not json"), 0644))
mon := New()
msg := mon.checkCompletions()
@ -227,7 +226,7 @@ func TestMonitor_CheckCompletions_Good_NilRuntime(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
assert.Equal(t, "", mon.checkCompletions())
@ -424,7 +423,7 @@ func TestMonitor_Check_Good_CombinesMessages(t *testing.T) {
func TestMonitor_Check_Good_NoMessages(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
home := t.TempDir()
t.Setenv("HOME", home)
@ -445,7 +444,7 @@ func TestMonitor_Notify_Good_NilServer(t *testing.T) {
func TestMonitor_Loop_Good_ImmediateCancel(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
home := t.TempDir()
t.Setenv("HOME", home)
@ -470,7 +469,7 @@ func TestMonitor_Loop_Good_ImmediateCancel(t *testing.T) {
func TestMonitor_Loop_Good_PokeTriggersCheck(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
home := t.TempDir()
t.Setenv("HOME", home)
@ -613,7 +612,7 @@ func TestMonitor_AgentStatusResource_Good(t *testing.T) {
func TestMonitor_AgentStatusResource_Good_Empty(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
result, err := mon.agentStatusResource(context.Background(), &mcp.ReadResourceRequest{})
@ -626,9 +625,9 @@ func TestMonitor_AgentStatusResource_Bad_InvalidJSON(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
dir := filepath.Join(wsRoot, "workspace", "ws-bad")
dir := core.JoinPath(wsRoot, "workspace", "ws-bad")
require.NoError(t, os.MkdirAll(dir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "status.json"), []byte("bad"), 0644))
require.NoError(t, os.WriteFile(core.JoinPath(dir, "status.json"), []byte("bad"), 0644))
mon := New()
result, err := mon.agentStatusResource(context.Background(), &mcp.ReadResourceRequest{})
@ -639,25 +638,25 @@ func TestMonitor_AgentStatusResource_Bad_InvalidJSON(t *testing.T) {
// --- syncRepos (git pull path) ---
func TestMonitor_SyncRepos_Good_PullsChangedRepo(t *testing.T) {
remoteDir := filepath.Join(t.TempDir(), "remote")
remoteDir := core.JoinPath(t.TempDir(), "remote")
require.NoError(t, os.MkdirAll(remoteDir, 0755))
run(t, remoteDir, "git", "init", "--bare")
codeDir := t.TempDir()
repoDir := filepath.Join(codeDir, "test-repo")
repoDir := core.JoinPath(codeDir, "test-repo")
run(t, codeDir, "git", "clone", remoteDir, "test-repo")
run(t, repoDir, "git", "checkout", "-b", "main")
os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("# test"), 0644)
os.WriteFile(core.JoinPath(repoDir, "README.md"), []byte("# test"), 0644)
run(t, repoDir, "git", "add", ".")
run(t, repoDir, "git", "commit", "-m", "init")
run(t, repoDir, "git", "push", "-u", "origin", "main")
// Simulate another agent pushing work via a second clone
clone2Parent := t.TempDir()
tmpClone := filepath.Join(clone2Parent, "clone2")
tmpClone := core.JoinPath(clone2Parent, "clone2")
run(t, clone2Parent, "git", "clone", remoteDir, "clone2")
run(t, tmpClone, "git", "checkout", "main")
os.WriteFile(filepath.Join(tmpClone, "new.go"), []byte("package main\n"), 0644)
os.WriteFile(core.JoinPath(tmpClone, "new.go"), []byte("package main\n"), 0644)
run(t, tmpClone, "git", "add", ".")
run(t, tmpClone, "git", "commit", "-m", "agent work")
run(t, tmpClone, "git", "push", "origin", "main")
@ -683,21 +682,21 @@ func TestMonitor_SyncRepos_Good_PullsChangedRepo(t *testing.T) {
}
func TestMonitor_SyncRepos_Good_SkipsDirtyRepo(t *testing.T) {
remoteDir := filepath.Join(t.TempDir(), "remote")
remoteDir := core.JoinPath(t.TempDir(), "remote")
require.NoError(t, os.MkdirAll(remoteDir, 0755))
run(t, remoteDir, "git", "init", "--bare")
codeDir := t.TempDir()
repoDir := filepath.Join(codeDir, "dirty-repo")
repoDir := core.JoinPath(codeDir, "dirty-repo")
run(t, codeDir, "git", "clone", remoteDir, "dirty-repo")
run(t, repoDir, "git", "checkout", "-b", "main")
os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("# test"), 0644)
os.WriteFile(core.JoinPath(repoDir, "README.md"), []byte("# test"), 0644)
run(t, repoDir, "git", "add", ".")
run(t, repoDir, "git", "commit", "-m", "init")
run(t, repoDir, "git", "push", "-u", "origin", "main")
// Make the repo dirty
os.WriteFile(filepath.Join(repoDir, "dirty.txt"), []byte("uncommitted"), 0644)
os.WriteFile(core.JoinPath(repoDir, "dirty.txt"), []byte("uncommitted"), 0644)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := CheckinResponse{
@ -719,15 +718,15 @@ func TestMonitor_SyncRepos_Good_SkipsDirtyRepo(t *testing.T) {
}
func TestMonitor_SyncRepos_Good_SkipsNonMainBranch(t *testing.T) {
remoteDir := filepath.Join(t.TempDir(), "remote")
remoteDir := core.JoinPath(t.TempDir(), "remote")
require.NoError(t, os.MkdirAll(remoteDir, 0755))
run(t, remoteDir, "git", "init", "--bare")
codeDir := t.TempDir()
repoDir := filepath.Join(codeDir, "feature-repo")
repoDir := core.JoinPath(codeDir, "feature-repo")
run(t, codeDir, "git", "clone", remoteDir, "feature-repo")
run(t, repoDir, "git", "checkout", "-b", "main")
os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("# test"), 0644)
os.WriteFile(core.JoinPath(repoDir, "README.md"), []byte("# test"), 0644)
run(t, repoDir, "git", "add", ".")
run(t, repoDir, "git", "commit", "-m", "init")
run(t, repoDir, "git", "push", "-u", "origin", "main")
@ -800,21 +799,21 @@ func TestMonitor_HarvestCompleted_Good_MultipleWorkspaces(t *testing.T) {
for i := 0; i < 2; i++ {
name := fmt.Sprintf("ws-%d", i)
wsDir := filepath.Join(wsRoot, "workspace", name)
wsDir := core.JoinPath(wsRoot, "workspace", name)
sourceDir := filepath.Join(wsRoot, fmt.Sprintf("source-%d", i))
sourceDir := core.JoinPath(wsRoot, fmt.Sprintf("source-%d", i))
require.NoError(t, os.MkdirAll(sourceDir, 0755))
run(t, sourceDir, "git", "init")
run(t, sourceDir, "git", "checkout", "-b", "main")
os.WriteFile(filepath.Join(sourceDir, "README.md"), []byte("# test"), 0644)
os.WriteFile(core.JoinPath(sourceDir, "README.md"), []byte("# test"), 0644)
run(t, sourceDir, "git", "add", ".")
run(t, sourceDir, "git", "commit", "-m", "init")
require.NoError(t, os.MkdirAll(wsDir, 0755))
run(t, wsDir, "git", "clone", sourceDir, "src")
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
run(t, srcDir, "git", "checkout", "-b", "agent/test-task")
os.WriteFile(filepath.Join(srcDir, "new.go"), []byte("package main\n"), 0644)
os.WriteFile(core.JoinPath(srcDir, "new.go"), []byte("package main\n"), 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "agent work")
@ -846,7 +845,7 @@ func TestMonitor_HarvestCompleted_Good_MultipleWorkspaces(t *testing.T) {
func TestMonitor_HarvestCompleted_Good_Empty(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
require.NoError(t, os.MkdirAll(filepath.Join(wsRoot, "workspace"), 0755))
require.NoError(t, os.MkdirAll(core.JoinPath(wsRoot, "workspace"), 0755))
mon := New()
mon.ServiceRuntime = testMon.ServiceRuntime
@ -858,25 +857,25 @@ func TestMonitor_HarvestCompleted_Good_RejectedWorkspace(t *testing.T) {
wsRoot := t.TempDir()
t.Setenv("CORE_WORKSPACE", wsRoot)
sourceDir := filepath.Join(wsRoot, "source-rej")
sourceDir := core.JoinPath(wsRoot, "source-rej")
require.NoError(t, os.MkdirAll(sourceDir, 0755))
run(t, sourceDir, "git", "init")
run(t, sourceDir, "git", "checkout", "-b", "main")
os.WriteFile(filepath.Join(sourceDir, "README.md"), []byte("# test"), 0644)
os.WriteFile(core.JoinPath(sourceDir, "README.md"), []byte("# test"), 0644)
run(t, sourceDir, "git", "add", ".")
run(t, sourceDir, "git", "commit", "-m", "init")
wsDir := filepath.Join(wsRoot, "workspace", "ws-rej")
wsDir := core.JoinPath(wsRoot, "workspace", "ws-rej")
require.NoError(t, os.MkdirAll(wsDir, 0755))
run(t, wsDir, "git", "clone", sourceDir, "src")
srcDir := filepath.Join(wsDir, "src")
srcDir := core.JoinPath(wsDir, "src")
run(t, srcDir, "git", "checkout", "-b", "agent/test-task")
os.WriteFile(filepath.Join(srcDir, "new.go"), []byte("package main\n"), 0644)
os.WriteFile(core.JoinPath(srcDir, "new.go"), []byte("package main\n"), 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "agent work")
// Add binary to trigger rejection
os.WriteFile(filepath.Join(srcDir, "app.exe"), []byte("binary"), 0644)
os.WriteFile(core.JoinPath(srcDir, "app.exe"), []byte("binary"), 0644)
run(t, srcDir, "git", "add", ".")
run(t, srcDir, "git", "commit", "-m", "add binary")

View file

@ -3,7 +3,6 @@
package setup
import (
"path/filepath"
"testing"
core "dappco.re/go/core"
@ -19,7 +18,7 @@ func testSvc() *Service {
func TestDetect_Good(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.WriteMode(filepath.Join(dir, "go.mod"), "module example.com/test\n", 0644).OK)
require.True(t, fs.WriteMode(core.JoinPath(dir, "go.mod"), "module example.com/test\n", 0644).OK)
assert.Equal(t, TypeGo, Detect(dir))
assert.Equal(t, []ProjectType{TypeGo}, DetectAll(dir))
@ -59,28 +58,28 @@ func TestParseGitRemote_Bad(t *testing.T) {
func TestRun_Good(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.WriteMode(filepath.Join(dir, "go.mod"), "module example.com/test\n", 0644).OK)
require.True(t, fs.WriteMode(core.JoinPath(dir, "go.mod"), "module example.com/test\n", 0644).OK)
err := testSvc().Run(Options{Path: dir})
require.NoError(t, err)
build := fs.Read(filepath.Join(dir, ".core", "build.yaml"))
build := fs.Read(core.JoinPath(dir, ".core", "build.yaml"))
require.True(t, build.OK)
assert.Contains(t, build.Value.(string), "type: go")
test := fs.Read(filepath.Join(dir, ".core", "test.yaml"))
test := fs.Read(core.JoinPath(dir, ".core", "test.yaml"))
require.True(t, test.OK)
assert.Contains(t, test.Value.(string), "go test ./...")
}
func TestRun_TemplateAlias_Good(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.WriteMode(filepath.Join(dir, "go.mod"), "module example.com/test\n", 0644).OK)
require.True(t, fs.WriteMode(core.JoinPath(dir, "go.mod"), "module example.com/test\n", 0644).OK)
err := testSvc().Run(Options{Path: dir, Template: "agent"})
require.NoError(t, err)
prompt := fs.Read(filepath.Join(dir, "PROMPT.md"))
prompt := fs.Read(core.JoinPath(dir, "PROMPT.md"))
require.True(t, prompt.OK)
assert.Contains(t, prompt.Value.(string), "This workspace was scaffolded by pkg/setup.")
}