refactor(agentic): adopt core.Env() + core.Path() across package

Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.

10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.

Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.

Bumps dappco.re/go/core to v0.6.0.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-22 10:15:15 +00:00
parent 3022f05fb8
commit 6393bfe4da
12 changed files with 42 additions and 53 deletions

4
go.mod
View file

@ -3,13 +3,13 @@ module dappco.re/go/agent
go 1.26.0
require (
dappco.re/go/core v0.5.0
dappco.re/go/core v0.6.0
dappco.re/go/core/api v0.2.0
dappco.re/go/core/process v0.3.0
dappco.re/go/core/ws v0.3.0
forge.lthn.ai/core/api v0.1.6
forge.lthn.ai/core/cli v0.3.7
forge.lthn.ai/core/mcp v0.4.4
forge.lthn.ai/core/mcp v0.4.8
github.com/gin-gonic/gin v1.12.0
github.com/gorilla/websocket v1.5.3
github.com/modelcontextprotocol/go-sdk v1.4.1

11
go.sum
View file

@ -1,13 +1,18 @@
dappco.re/go/core v0.5.0 h1:P5DJoaCiK5Q+af5UiTdWqUIW4W4qYKzpgGK50thm21U=
dappco.re/go/core v0.5.0/go.mod h1:f2/tBZ3+3IqDrg2F5F598llv0nmb/4gJVCFzM5geE4A=
dappco.re/go/core v0.6.0 h1:0wmuO/UmCWXxJkxQ6XvVLnqkAuWitbd49PhxjCsplyk=
dappco.re/go/core v0.6.0/go.mod h1:f2/tBZ3+3IqDrg2F5F598llv0nmb/4gJVCFzM5geE4A=
dappco.re/go/core/api v0.2.0 h1:5OcN9nawpp18Jp6dB1OwI2CBfs0Tacb0y0zqxFB6TJ0=
dappco.re/go/core/api v0.2.0/go.mod h1:AtgNAx8lDY+qhVObFdNQOjSUQrHX1BeiDdMuA6RIfzo=
dappco.re/go/core/i18n v0.2.0/go.mod h1:9eSVJXr3OpIGWQvDynfhqcp27xnLMwlYLgsByU+p7ok=
dappco.re/go/core/io v0.2.0 h1:zuudgIiTsQQ5ipVt97saWdGLROovbEB/zdVyy9/l+I4=
dappco.re/go/core/io v0.2.0/go.mod h1:1QnQV6X9LNgFKfm8SkOtR9LLaj3bDcsOIeJOOyjbL5E=
dappco.re/go/core/log v0.1.0 h1:pa71Vq2TD2aoEUQWFKwNcaJ3GBY8HbaNGqtE688Unyc=
dappco.re/go/core/log v0.1.0/go.mod h1:Nkqb8gsXhZAO8VLpx7B8i1iAmohhzqA20b9Zr8VUcJs=
dappco.re/go/core/process v0.3.0 h1:BPF9R79+8ZWe34qCIy/sZy+P4HwbaO95js2oPJL7IqM=
dappco.re/go/core/process v0.3.0/go.mod h1:qwx8kt6x+J9gn7fu8lavuess72Ye9jPBODqDZQ9K0as=
dappco.re/go/core/scm v0.4.0/go.mod h1:ufb7si6HBkaT6zC8L67kLm8zzBaD1aQoTn4OsVAM1aI=
dappco.re/go/core/store v0.2.0/go.mod h1:QQGJiruayjna3nywbf0N2gcO502q/oEkPoSpBpSKbLM=
dappco.re/go/core/ws v0.3.0 h1:ZxR8y5pfrWvnCHVN7qExXz7fdP5a063uNqyqE0Ab8pQ=
dappco.re/go/core/ws v0.3.0/go.mod h1:aLyXrJnbCOGL0SW9rC1EHAAIS83w3djO374gHIz4Nic=
forge.lthn.ai/core/api v0.1.5 h1:NwZrcOyBjaiz5/cn0n0tnlMUodi8Or6FHMx59C7Kv2o=
@ -42,6 +47,12 @@ forge.lthn.ai/core/mcp v0.4.0 h1:t4HMTI6CpoGB/VmE1aTklSEM8EI4Z/uKWyjGHxa1f4M=
forge.lthn.ai/core/mcp v0.4.0/go.mod h1:eU35WT/8Mc0oJDVWdKaXEtNp27+Hc8KvnTKPf4DAqXE=
forge.lthn.ai/core/mcp v0.4.4 h1:VTCOA1Dj/L7S8JCRg9BfYw7KfowW/Vvrp39bxc0dYyw=
forge.lthn.ai/core/mcp v0.4.4/go.mod h1:eU35WT/8Mc0oJDVWdKaXEtNp27+Hc8KvnTKPf4DAqXE=
forge.lthn.ai/core/mcp v0.4.6 h1:jZY72sfPiCppKU4YyX7Gwy7ynbgVzUto+3S6oAj5Qs4=
forge.lthn.ai/core/mcp v0.4.6/go.mod h1:eU35WT/8Mc0oJDVWdKaXEtNp27+Hc8KvnTKPf4DAqXE=
forge.lthn.ai/core/mcp v0.4.7 h1:Iy/83laUpkaH8W2EoDlVMJbyv60xJ4aMgQe6sOcwL7k=
forge.lthn.ai/core/mcp v0.4.7/go.mod h1:eU35WT/8Mc0oJDVWdKaXEtNp27+Hc8KvnTKPf4DAqXE=
forge.lthn.ai/core/mcp v0.4.8 h1:nd1x3AL8AkUfl0kziltoJUX96Nx1BeFWEbgHmfrkKz8=
forge.lthn.ai/core/mcp v0.4.8/go.mod h1:eU35WT/8Mc0oJDVWdKaXEtNp27+Hc8KvnTKPf4DAqXE=
github.com/99designs/gqlgen v0.17.88 h1:neMQDgehMwT1vYIOx/w5ZYPUU/iMNAJzRO44I5Intoc=
github.com/99designs/gqlgen v0.17.88/go.mod h1:qeqYFEgOeSKqWedOjogPizimp2iu4E23bdPvl4jTYic=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=

View file

@ -4,8 +4,6 @@ package agentic
import (
"context"
"os"
"path/filepath"
"syscall"
"time"
@ -101,8 +99,7 @@ func agentCommand(agent, prompt string) (string, []string, error) {
}
return "coderabbit", args, nil
case "local":
home, _ := os.UserHomeDir()
script := core.JoinPath(home, "Code", "core", "agent", "scripts", "local-agent.sh")
script := core.JoinPath(core.Env("DIR_HOME"), "Code", "core", "agent", "scripts", "local-agent.sh")
return "bash", []string{script, prompt}, nil
default:
return "", nil, core.E("agentCommand", "unknown agent: "+agent, nil)
@ -191,7 +188,7 @@ func (s *PrepSubsystem) spawnAgent(agent, prompt, wsDir, srcDir string) (int, st
}
// Emit completion event with actual status
emitCompletionEvent(agent, filepath.Base(wsDir), finalStatus)
emitCompletionEvent(agent, core.PathBase(wsDir), finalStatus)
// Notify monitor immediately (push to connected clients)
if s.onComplete != nil {

View file

@ -6,8 +6,6 @@ import (
"bytes"
"encoding/json"
"net/http"
"os"
"path/filepath"
core "dappco.re/go/core"
)
@ -21,7 +19,7 @@ func (s *PrepSubsystem) ingestFindings(wsDir string) {
}
// Read the log file
logFiles, _ := filepath.Glob(core.JoinPath(wsDir, "agent-*.log"))
logFiles := core.PathGlob(core.JoinPath(wsDir, "agent-*.log"))
if len(logFiles) == 0 {
return
}
@ -92,8 +90,7 @@ func (s *PrepSubsystem) createIssueViaAPI(repo, title, description, issueType, p
}
// Read the agent API key from file
home, _ := os.UserHomeDir()
r := fs.Read(core.JoinPath(home, ".claude", "agent-api.key"))
r := fs.Read(core.JoinPath(core.Env("DIR_HOME"), ".claude", "agent-api.key"))
if !r.OK {
return
}

View file

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

View file

@ -3,7 +3,6 @@
package agentic
import (
"os"
"os/exec"
"strconv"
"unsafe"
@ -45,11 +44,10 @@ func WorkspaceRoot() string {
//
// root := agentic.CoreRoot()
func CoreRoot() string {
if root := os.Getenv("CORE_WORKSPACE"); root != "" {
if root := core.Env("CORE_WORKSPACE"); root != "" {
return root
}
home, _ := os.UserHomeDir()
return core.JoinPath(home, "Code", ".core")
return core.JoinPath(core.Env("DIR_HOME"), "Code", ".core")
}
// PlansRoot returns the root directory for agent plans.
@ -64,11 +62,10 @@ func PlansRoot() string {
//
// name := agentic.AgentName() // "cladius" on Snider's Mac, "charon" elsewhere
func AgentName() string {
if name := os.Getenv("AGENT_NAME"); name != "" {
if name := core.Env("AGENT_NAME"); name != "" {
return name
}
hostname, _ := os.Hostname()
h := core.Lower(hostname)
h := core.Lower(core.Env("HOSTNAME"))
if core.Contains(h, "snider") || core.Contains(h, "studio") || core.Contains(h, "mac") {
return "cladius"
}
@ -102,7 +99,7 @@ func DefaultBranch(repoDir string) string {
//
// org := agentic.GitHubOrg() // "dAppCore"
func GitHubOrg() string {
if org := os.Getenv("GITHUB_ORG"); org != "" {
if org := core.Env("GITHUB_ORG"); org != "" {
return org
}
return "dAppCore"

View file

@ -8,7 +8,6 @@ import (
"encoding/hex"
"encoding/json"
"os"
"path/filepath"
"strings"
"time"
@ -341,7 +340,7 @@ func (s *PrepSubsystem) planList(_ context.Context, _ *mcp.CallToolRequest, inpu
func planPath(dir, id string) string {
// Sanitise ID to prevent path traversal
safe := filepath.Base(id)
safe := core.PathBase(id)
if safe == "." || safe == ".." || safe == "" {
safe = "invalid"
}

View file

@ -10,9 +10,7 @@ import (
"encoding/json"
goio "io"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"time"
@ -56,14 +54,14 @@ var _ coremcp.Subsystem = (*PrepSubsystem)(nil)
// sub.SetCompletionNotifier(monitor)
// sub.RegisterTools(server)
func NewPrep() *PrepSubsystem {
home, _ := os.UserHomeDir()
home := core.Env("DIR_HOME")
forgeToken := os.Getenv("FORGE_TOKEN")
forgeToken := core.Env("FORGE_TOKEN")
if forgeToken == "" {
forgeToken = os.Getenv("GITEA_TOKEN")
forgeToken = core.Env("GITEA_TOKEN")
}
brainKey := os.Getenv("CORE_BRAIN_KEY")
brainKey := core.Env("CORE_BRAIN_KEY")
if brainKey == "" {
if r := fs.Read(core.JoinPath(home, ".claude", "brain.key")); r.OK {
brainKey = core.Trim(r.Value.(string))
@ -89,7 +87,7 @@ func (s *PrepSubsystem) SetCompletionNotifier(n CompletionNotifier) {
}
func envOr(key, fallback string) string {
if v := os.Getenv(key); v != "" {
if v := core.Env(key); v != "" {
return v
}
return fallback
@ -192,7 +190,7 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques
out := PrepOutput{WorkspaceDir: wsDir}
// Source repo path — sanitise to prevent path traversal
repoName := filepath.Base(input.Repo) // strips ../ and absolute paths
repoName := core.PathBase(input.Repo) // strips ../ and absolute paths
if repoName == "." || repoName == ".." || repoName == "" {
return nil, PrepOutput{}, core.E("prep", "invalid repo name: "+input.Repo, nil)
}
@ -573,7 +571,7 @@ func (s *PrepSubsystem) findConsumers(repo, wsDir string) int {
}
modData := mr.Value.(string)
if core.Contains(modData, modulePath) && !core.HasPrefix(modData, "module "+modulePath) {
consumers = append(consumers, filepath.Base(dir))
consumers = append(consumers, core.PathBase(dir))
}
}

View file

@ -6,7 +6,6 @@ import (
"context"
"encoding/json"
"net/http"
"os"
"time"
core "dappco.re/go/core"
@ -180,17 +179,17 @@ func resolveHost(host string) string {
func remoteToken(host string) string {
// Check environment first
envKey := core.Sprintf("AGENT_TOKEN_%s", core.Upper(host))
if token := os.Getenv(envKey); token != "" {
if token := core.Env(envKey); token != "" {
return token
}
// Fallback to shared agent token
if token := os.Getenv("MCP_AUTH_TOKEN"); token != "" {
if token := core.Env("MCP_AUTH_TOKEN"); token != "" {
return token
}
// Try reading from file
home, _ := os.UserHomeDir()
home := core.Env("DIR_HOME")
tokenFiles := []string{
core.Sprintf("%s/.core/tokens/%s.token", home, core.Lower(host)),
core.Sprintf("%s/.core/agent-token", home),

View file

@ -339,8 +339,7 @@ func (s *PrepSubsystem) buildReviewCommand(ctx context.Context, repoDir, reviewe
// storeReviewOutput saves raw review output for training data collection.
func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string) {
home, _ := os.UserHomeDir()
dataDir := core.JoinPath(home, ".core", "training", "reviews")
dataDir := core.JoinPath(core.Env("DIR_HOME"), ".core", "training", "reviews")
fs.EnsureDir(dataDir)
timestamp := time.Now().Format("2006-01-02T15-04-05")
@ -374,16 +373,14 @@ func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string
// saveRateLimitState persists rate limit info for cross-run awareness.
func (s *PrepSubsystem) saveRateLimitState(info *RateLimitInfo) {
home, _ := os.UserHomeDir()
path := core.JoinPath(home, ".core", "coderabbit-ratelimit.json")
path := core.JoinPath(core.Env("DIR_HOME"), ".core", "coderabbit-ratelimit.json")
data, _ := json.Marshal(info)
fs.Write(path, string(data))
}
// loadRateLimitState reads persisted rate limit info.
func (s *PrepSubsystem) loadRateLimitState() *RateLimitInfo {
home, _ := os.UserHomeDir()
path := core.JoinPath(home, ".core", "coderabbit-ratelimit.json")
path := core.JoinPath(core.Env("DIR_HOME"), ".core", "coderabbit-ratelimit.json")
r := fs.Read(path)
if !r.OK {
return nil

View file

@ -9,7 +9,6 @@ import (
"net/http"
"os"
"os/exec"
"path/filepath"
"time"
core "dappco.re/go/core"
@ -130,7 +129,7 @@ func (s *PrepSubsystem) rebaseBranch(srcDir, branch string) bool {
}
// Force-push the rebased branch to Forge (origin is local clone)
st, _ := readStatus(filepath.Dir(srcDir))
st, _ := readStatus(core.PathDir(srcDir))
org := "core"
repo := ""
if st != nil {

View file

@ -4,7 +4,6 @@ package agentic
import (
"context"
"path/filepath"
"time"
core "dappco.re/go/core"
@ -192,20 +191,17 @@ func (s *PrepSubsystem) watch(ctx context.Context, req *mcp.CallToolRequest, inp
// findActiveWorkspaces returns workspace names that are running or queued.
func (s *PrepSubsystem) findActiveWorkspaces() []string {
wsRoot := WorkspaceRoot()
entries, err := filepath.Glob(core.JoinPath(wsRoot, "*/status.json"))
if err != nil {
return nil
}
entries := core.PathGlob(core.JoinPath(wsRoot, "*/status.json"))
var active []string
for _, entry := range entries {
wsDir := filepath.Dir(entry)
wsDir := core.PathDir(entry)
st, err := readStatus(wsDir)
if err != nil {
continue
}
if st.Status == "running" || st.Status == "queued" {
active = append(active, filepath.Base(wsDir))
active = append(active, core.PathBase(wsDir))
}
}
return active
@ -213,7 +209,7 @@ func (s *PrepSubsystem) findActiveWorkspaces() []string {
// resolveWorkspaceDir converts a workspace name to full path.
func (s *PrepSubsystem) resolveWorkspaceDir(name string) string {
if filepath.IsAbs(name) {
if core.PathIsAbs(name) {
return name
}
return core.JoinPath(WorkspaceRoot(), name)