refactor(agentic): route file I/O through core.Fs
Replace raw os.* file operations with Core Fs equivalents: - os.Stat → fs.Exists/fs.IsFile/fs.IsDir (resume, pr, plan, mirror, prep) - os.ReadDir → fs.List (queue, status, plan, mirror, review_queue) - os.Remove → fs.Delete (dispatch) - os.OpenFile(append) → fs.Append (events, review_queue) - strings.Replace → core.Replace (scan) Eliminates os import from resume.go, pr.go. Eliminates strings import from scan.go. Trades os for io in events.go. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
ede5d6f561
commit
3022f05fb8
11 changed files with 61 additions and 46 deletions
|
|
@ -125,7 +125,7 @@ func (s *PrepSubsystem) spawnAgent(agent, prompt, wsDir, srcDir string) (int, st
|
|||
|
||||
// Clean up stale BLOCKED.md from previous runs so it doesn't
|
||||
// prevent this run from completing
|
||||
os.Remove(core.JoinPath(srcDir, "BLOCKED.md"))
|
||||
fs.Delete(core.JoinPath(srcDir, "BLOCKED.md"))
|
||||
|
||||
proc, err := process.StartWithOptions(context.Background(), process.RunOptions{
|
||||
Command: command,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package agentic
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
|
|
@ -42,10 +42,11 @@ func emitCompletionEvent(agent, workspace, status string) {
|
|||
}
|
||||
|
||||
// Append to events log
|
||||
f, err := os.OpenFile(eventsFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
r := fs.Append(eventsFile)
|
||||
if !r.OK {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
f.Write(append(data, '\n'))
|
||||
wc := r.Value.(io.WriteCloser)
|
||||
defer wc.Close()
|
||||
wc.Write(append(data, '\n'))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,17 +246,18 @@ func filesChanged(repoDir, base, head string) int {
|
|||
|
||||
// listLocalRepos returns repo names that exist as directories in basePath.
|
||||
func (s *PrepSubsystem) listLocalRepos(basePath string) []string {
|
||||
entries, err := os.ReadDir(basePath)
|
||||
if err != nil {
|
||||
r := fs.List(basePath)
|
||||
if !r.OK {
|
||||
return nil
|
||||
}
|
||||
entries := r.Value.([]os.DirEntry)
|
||||
var repos []string
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
// Must have a .git directory
|
||||
if _, err := os.Stat(core.JoinPath(basePath, e.Name(), ".git")); err == nil {
|
||||
if fs.IsDir(core.JoinPath(basePath, e.Name(), ".git")) {
|
||||
repos = append(repos, e.Name())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ func (s *PrepSubsystem) planDelete(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
|
||||
path := planPath(PlansRoot(), input.ID)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if !fs.Exists(path) {
|
||||
return nil, PlanDeleteOutput{}, core.E("planDelete", "plan not found: "+input.ID, nil)
|
||||
}
|
||||
|
||||
|
|
@ -301,10 +301,11 @@ func (s *PrepSubsystem) planList(_ context.Context, _ *mcp.CallToolRequest, inpu
|
|||
return nil, PlanListOutput{}, core.E("planList", "failed to access plans directory", err)
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, PlanListOutput{}, core.E("planList", "failed to read plans directory", err)
|
||||
r := fs.List(dir)
|
||||
if !r.OK {
|
||||
return nil, PlanListOutput{}, nil
|
||||
}
|
||||
entries := r.Value.([]os.DirEntry)
|
||||
|
||||
var plans []Plan
|
||||
for _, entry := range entries {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
|
|
@ -58,7 +57,7 @@ func (s *PrepSubsystem) createPR(ctx context.Context, _ *mcp.CallToolRequest, in
|
|||
wsDir := core.JoinPath(WorkspaceRoot(), input.Workspace)
|
||||
srcDir := core.JoinPath(wsDir, "src")
|
||||
|
||||
if _, err := os.Stat(srcDir); err != nil {
|
||||
if !fs.IsDir(srcDir) {
|
||||
return nil, CreatePROutput{}, core.E("createPR", "workspace not found: "+input.Workspace, nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -250,12 +250,20 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques
|
|||
wsTmpl = "review"
|
||||
}
|
||||
|
||||
promptContent, _ := lib.Prompt(input.Template)
|
||||
promptContent := ""
|
||||
if r := lib.Prompt(input.Template); r.OK {
|
||||
promptContent = r.Value.(string)
|
||||
}
|
||||
personaContent := ""
|
||||
if input.Persona != "" {
|
||||
personaContent, _ = lib.Persona(input.Persona)
|
||||
if r := lib.Persona(input.Persona); r.OK {
|
||||
personaContent = r.Value.(string)
|
||||
}
|
||||
}
|
||||
flowContent := ""
|
||||
if r := lib.Flow(detectLanguage(repoPath)); r.OK {
|
||||
flowContent = r.Value.(string)
|
||||
}
|
||||
flowContent, _ := lib.Flow(detectLanguage(repoPath))
|
||||
|
||||
wsData := &lib.WorkspaceData{
|
||||
Repo: input.Repo,
|
||||
|
|
@ -319,13 +327,13 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques
|
|||
// --- Prompt templates ---
|
||||
|
||||
func (s *PrepSubsystem) writePromptTemplate(template, wsDir string) {
|
||||
prompt, err := lib.Template(template)
|
||||
if err != nil {
|
||||
// Fallback to default template
|
||||
prompt, _ = lib.Template("default")
|
||||
if prompt == "" {
|
||||
prompt = "Read TODO.md and complete the task. Work in src/.\n"
|
||||
}
|
||||
r := lib.Template(template)
|
||||
if !r.OK {
|
||||
r = lib.Template("default")
|
||||
}
|
||||
prompt := "Read TODO.md and complete the task. Work in src/.\n"
|
||||
if r.OK {
|
||||
prompt = r.Value.(string)
|
||||
}
|
||||
|
||||
fs.Write(core.JoinPath(wsDir, "src", "PROMPT.md"), prompt)
|
||||
|
|
@ -337,12 +345,12 @@ func (s *PrepSubsystem) writePromptTemplate(template, wsDir string) {
|
|||
// and writes PLAN.md into the workspace src/ directory.
|
||||
func (s *PrepSubsystem) writePlanFromTemplate(templateSlug string, variables map[string]string, task string, wsDir string) {
|
||||
// Load template from embedded prompts package
|
||||
data, err := lib.Template(templateSlug)
|
||||
if err != nil {
|
||||
r := lib.Template(templateSlug)
|
||||
if !r.OK {
|
||||
return // Template not found, skip silently
|
||||
}
|
||||
|
||||
content := data
|
||||
content := r.Value.(string)
|
||||
|
||||
// Substitute variables ({{variable_name}} → value)
|
||||
for key, value := range variables {
|
||||
|
|
@ -649,7 +657,7 @@ func detectLanguage(repoPath string) string {
|
|||
{"Dockerfile", "docker"},
|
||||
}
|
||||
for _, c := range checks {
|
||||
if _, err := os.Stat(core.JoinPath(repoPath, c.file)); err == nil {
|
||||
if fs.IsFile(core.JoinPath(repoPath, c.file)) {
|
||||
return c.lang
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,10 +119,11 @@ func (s *PrepSubsystem) delayForAgent(agent string) time.Duration {
|
|||
func (s *PrepSubsystem) countRunningByAgent(agent string) int {
|
||||
wsRoot := WorkspaceRoot()
|
||||
|
||||
entries, err := os.ReadDir(wsRoot)
|
||||
if err != nil {
|
||||
r := fs.List(wsRoot)
|
||||
if !r.OK {
|
||||
return 0
|
||||
}
|
||||
entries := r.Value.([]os.DirEntry)
|
||||
|
||||
count := 0
|
||||
for _, entry := range entries {
|
||||
|
|
@ -171,10 +172,11 @@ func (s *PrepSubsystem) drainQueue() {
|
|||
|
||||
wsRoot := WorkspaceRoot()
|
||||
|
||||
entries, err := os.ReadDir(wsRoot)
|
||||
if err != nil {
|
||||
r := fs.List(wsRoot)
|
||||
if !r.OK {
|
||||
return
|
||||
}
|
||||
entries := r.Value.([]os.DirEntry)
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ package agentic
|
|||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
|
@ -48,7 +47,7 @@ func (s *PrepSubsystem) resume(ctx context.Context, _ *mcp.CallToolRequest, inpu
|
|||
srcDir := core.JoinPath(wsDir, "src")
|
||||
|
||||
// Verify workspace exists
|
||||
if _, err := os.Stat(srcDir); err != nil {
|
||||
if !fs.IsDir(srcDir) {
|
||||
return nil, ResumeOutput{}, core.E("resume", "workspace not found: "+input.Workspace, nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ package agentic
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
|
|
@ -134,10 +135,11 @@ func (s *PrepSubsystem) reviewQueue(ctx context.Context, _ *mcp.CallToolRequest,
|
|||
|
||||
// findReviewCandidates returns repos that are ahead of GitHub main.
|
||||
func (s *PrepSubsystem) findReviewCandidates(basePath string) []string {
|
||||
entries, err := os.ReadDir(basePath)
|
||||
if err != nil {
|
||||
r := fs.List(basePath)
|
||||
if !r.OK {
|
||||
return nil
|
||||
}
|
||||
entries := r.Value.([]os.DirEntry)
|
||||
|
||||
var candidates []string
|
||||
for _, e := range entries {
|
||||
|
|
@ -361,11 +363,13 @@ func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string
|
|||
jsonLine, _ := json.Marshal(entry)
|
||||
|
||||
jsonlPath := core.JoinPath(dataDir, "reviews.jsonl")
|
||||
f, err := os.OpenFile(jsonlPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
f.Write(append(jsonLine, '\n'))
|
||||
r := fs.Append(jsonlPath)
|
||||
if !r.OK {
|
||||
return
|
||||
}
|
||||
wc := r.Value.(io.WriteCloser)
|
||||
defer wc.Close()
|
||||
wc.Write(append(jsonLine, '\n'))
|
||||
}
|
||||
|
||||
// saveRateLimitState persists rate limit info for cross-run awareness.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
|
@ -197,7 +196,7 @@ func (s *PrepSubsystem) listRepoIssues(ctx context.Context, org, repo, label str
|
|||
Title: issue.Title,
|
||||
Labels: labels,
|
||||
Assignee: assignee,
|
||||
URL: strings.Replace(issue.HTMLURL, "https://forge.lthn.ai", s.forgeURL, 1),
|
||||
URL: core.Replace(issue.HTMLURL, "https://forge.lthn.ai", s.forgeURL),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,10 +113,11 @@ func (s *PrepSubsystem) registerStatusTool(server *mcp.Server) {
|
|||
func (s *PrepSubsystem) status(ctx context.Context, _ *mcp.CallToolRequest, input StatusInput) (*mcp.CallToolResult, StatusOutput, error) {
|
||||
wsRoot := WorkspaceRoot()
|
||||
|
||||
entries, err := os.ReadDir(wsRoot)
|
||||
if err != nil {
|
||||
return nil, StatusOutput{}, core.E("status", "no workspaces found", err)
|
||||
r := fs.List(wsRoot)
|
||||
if !r.OK {
|
||||
return nil, StatusOutput{}, core.E("status", "no workspaces found", nil)
|
||||
}
|
||||
entries := r.Value.([]os.DirEntry)
|
||||
|
||||
var workspaces []WorkspaceInfo
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue