diff --git a/pkg/agentic/auto_pr_test.go b/pkg/agentic/auto_pr_test.go index 02383cd..a7d9f84 100644 --- a/pkg/agentic/auto_pr_test.go +++ b/pkg/agentic/auto_pr_test.go @@ -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{}), diff --git a/pkg/agentic/commands_test.go b/pkg/agentic/commands_test.go index 767c1e0..d4efc3c 100644 --- a/pkg/agentic/commands_test.go +++ b/pkg/agentic/commands_test.go @@ -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) diff --git a/pkg/agentic/commands_workspace_test.go b/pkg/agentic/commands_workspace_test.go index cc38ae8..405cbc6 100644 --- a/pkg/agentic/commands_workspace_test.go +++ b/pkg/agentic/commands_workspace_test.go @@ -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) } } diff --git a/pkg/agentic/dispatch_test.go b/pkg/agentic/dispatch_test.go index 32cb6f5..00300e3 100644 --- a/pkg/agentic/dispatch_test.go +++ b/pkg/agentic/dispatch_test.go @@ -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, diff --git a/pkg/agentic/handlers_test.go b/pkg/agentic/handlers_test.go index 6e42fc3..07e2e68 100644 --- a/pkg/agentic/handlers_test.go +++ b/pkg/agentic/handlers_test.go @@ -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{ diff --git a/pkg/agentic/ingest_test.go b/pkg/agentic/ingest_test.go index fec745f..25ba485 100644 --- a/pkg/agentic/ingest_test.go +++ b/pkg/agentic/ingest_test.go @@ -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{}), diff --git a/pkg/agentic/logic_test.go b/pkg/agentic/logic_test.go index e4d938b..7388bf5 100644 --- a/pkg/agentic/logic_test.go +++ b/pkg/agentic/logic_test.go @@ -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") diff --git a/pkg/agentic/mirror_test.go b/pkg/agentic/mirror_test.go index ecc4a79..d40f5b5 100644 --- a/pkg/agentic/mirror_test.go +++ b/pkg/agentic/mirror_test.go @@ -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) diff --git a/pkg/agentic/plan_logic_test.go b/pkg/agentic/plan_logic_test.go index 6a2dbd1..4276801 100644 --- a/pkg/agentic/plan_logic_test.go +++ b/pkg/agentic/plan_logic_test.go @@ -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) diff --git a/pkg/agentic/plan_test.go b/pkg/agentic/plan_test.go index 9f574c1..db9d5eb 100644 --- a/pkg/agentic/plan_test.go +++ b/pkg/agentic/plan_test.go @@ -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) diff --git a/pkg/agentic/pr_test.go b/pkg/agentic/pr_test.go index bd2bd7d..6405613 100644 --- a/pkg/agentic/pr_test.go +++ b/pkg/agentic/pr_test.go @@ -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()) diff --git a/pkg/agentic/prep_extra_test.go b/pkg/agentic/prep_extra_test.go index 119f8a2..b3509b0 100644 --- a/pkg/agentic/prep_extra_test.go +++ b/pkg/agentic/prep_extra_test.go @@ -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{}), diff --git a/pkg/agentic/prep_test.go b/pkg/agentic/prep_test.go index 77a8a79..5b9132c 100644 --- a/pkg/agentic/prep_test.go +++ b/pkg/agentic/prep_test.go @@ -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), } diff --git a/pkg/agentic/queue_extra_test.go b/pkg/agentic/queue_extra_test.go index 4062d53..785dd75 100644 --- a/pkg/agentic/queue_extra_test.go +++ b/pkg/agentic/queue_extra_test.go @@ -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{}), diff --git a/pkg/agentic/queue_logic_test.go b/pkg/agentic/queue_logic_test.go index ff4e337..d0d0f35 100644 --- a/pkg/agentic/queue_logic_test.go +++ b/pkg/agentic/queue_logic_test.go @@ -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() diff --git a/pkg/agentic/queue_test.go b/pkg/agentic/queue_test.go index 49dc9c5..9743a2c 100644 --- a/pkg/agentic/queue_test.go +++ b/pkg/agentic/queue_test.go @@ -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", diff --git a/pkg/agentic/resume_test.go b/pkg/agentic/resume_test.go index 78273e0..713fb19 100644 --- a/pkg/agentic/resume_test.go +++ b/pkg/agentic/resume_test.go @@ -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) diff --git a/pkg/agentic/review_queue_extra_test.go b/pkg/agentic/review_queue_extra_test.go index 5842073..a25bebf 100644 --- a/pkg/agentic/review_queue_extra_test.go +++ b/pkg/agentic/review_queue_extra_test.go @@ -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)) diff --git a/pkg/agentic/status_extra_test.go b/pkg/agentic/status_extra_test.go index 0cc661c..b4b851b 100644 --- a/pkg/agentic/status_extra_test.go +++ b/pkg/agentic/status_extra_test.go @@ -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", diff --git a/pkg/agentic/status_logic_test.go b/pkg/agentic/status_logic_test.go index 0faf7d5..87e05b4 100644 --- a/pkg/agentic/status_logic_test.go +++ b/pkg/agentic/status_logic_test.go @@ -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) diff --git a/pkg/agentic/status_test.go b/pkg/agentic/status_test.go index f72e4f9..91ec18a 100644 --- a/pkg/agentic/status_test.go +++ b/pkg/agentic/status_test.go @@ -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", diff --git a/pkg/agentic/verify_extra_test.go b/pkg/agentic/verify_extra_test.go index d5cb6b3..1e1061d 100644 --- a/pkg/agentic/verify_extra_test.go +++ b/pkg/agentic/verify_extra_test.go @@ -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{}), diff --git a/pkg/agentic/verify_test.go b/pkg/agentic/verify_test.go index 084ed67..97d1c13 100644 --- a/pkg/agentic/verify_test.go +++ b/pkg/agentic/verify_test.go @@ -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{}), diff --git a/pkg/agentic/watch_test.go b/pkg/agentic/watch_test.go index 9d08a61..7405250 100644 --- a/pkg/agentic/watch_test.go +++ b/pkg/agentic/watch_test.go @@ -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)) }) } diff --git a/pkg/brain/direct_test.go b/pkg/brain/direct_test.go index 4c9194b..6c0c755 100644 --- a/pkg/brain/direct_test.go +++ b/pkg/brain/direct_test.go @@ -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) diff --git a/pkg/monitor/harvest_test.go b/pkg/monitor/harvest_test.go index ade3251..32be621 100644 --- a/pkg/monitor/harvest_test.go +++ b/pkg/monitor/harvest_test.go @@ -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"]) diff --git a/pkg/monitor/logic_test.go b/pkg/monitor/logic_test.go index 18188db..4ea312a 100644 --- a/pkg/monitor/logic_test.go +++ b/pkg/monitor/logic_test.go @@ -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) diff --git a/pkg/monitor/monitor_test.go b/pkg/monitor/monitor_test.go index e09b4c9..0a99752 100644 --- a/pkg/monitor/monitor_test.go +++ b/pkg/monitor/monitor_test.go @@ -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") diff --git a/pkg/setup/setup_test.go b/pkg/setup/setup_test.go index 1696d42..55176e0 100644 --- a/pkg/setup/setup_test.go +++ b/pkg/setup/setup_test.go @@ -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.") }