fix(ax): align code comments with AX principles

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 22:54:19 +00:00
parent 877de43257
commit bd12c0a31a
26 changed files with 239 additions and 537 deletions

View file

@ -17,14 +17,12 @@ import (
core "dappco.re/go/core"
)
// --- Dispatch & Workspace ---
// handleDispatch dispatches a subagent to work on a repo task.
// result := c.Action("agentic.dispatch").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.dispatch").Run(ctx, core.NewOptions(
// core.Option{Key: "repo", Value: "go-io"},
// core.Option{Key: "task", Value: "Fix tests"},
// ))
// core.Option{Key: "repo", Value: "go-io"},
// core.Option{Key: "task", Value: "Fix tests"},
//
// ))
func (s *PrepSubsystem) handleDispatch(ctx context.Context, options core.Options) core.Result {
input := DispatchInput{
Repo: options.String("repo"),
@ -39,12 +37,12 @@ func (s *PrepSubsystem) handleDispatch(ctx context.Context, options core.Options
return core.Result{Value: out, OK: true}
}
// handlePrep prepares a workspace without dispatching an agent.
// result := c.Action("agentic.prep").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.prep").Run(ctx, core.NewOptions(
// core.Option{Key: "repo", Value: "go-io"},
// core.Option{Key: "issue", Value: 42},
// ))
// core.Option{Key: "repo", Value: "go-io"},
// core.Option{Key: "issue", Value: 42},
//
// ))
func (s *PrepSubsystem) handlePrep(ctx context.Context, options core.Options) core.Result {
input := PrepInput{
Repo: options.String("repo"),
@ -58,9 +56,7 @@ func (s *PrepSubsystem) handlePrep(ctx context.Context, options core.Options) co
return core.Result{Value: out, OK: true}
}
// handleStatus lists workspace statuses.
//
// result := c.Action("agentic.status").Run(ctx, core.NewOptions())
// result := c.Action("agentic.status").Run(ctx, core.NewOptions())
func (s *PrepSubsystem) handleStatus(ctx context.Context, options core.Options) core.Result {
input := StatusInput{
Workspace: options.String("workspace"),
@ -74,11 +70,11 @@ func (s *PrepSubsystem) handleStatus(ctx context.Context, options core.Options)
return core.Result{Value: out, OK: true}
}
// handleResume resumes a blocked workspace.
// result := c.Action("agentic.resume").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.resume").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "core/go-io/task-5"},
// ))
// core.Option{Key: "workspace", Value: "core/go-io/task-5"},
//
// ))
func (s *PrepSubsystem) handleResume(ctx context.Context, options core.Options) core.Result {
input := ResumeInput{
Workspace: options.String("workspace"),
@ -91,9 +87,7 @@ func (s *PrepSubsystem) handleResume(ctx context.Context, options core.Options)
return core.Result{Value: out, OK: true}
}
// handleScan scans forge repos for actionable issues.
//
// result := c.Action("agentic.scan").Run(ctx, core.NewOptions())
// result := c.Action("agentic.scan").Run(ctx, core.NewOptions())
func (s *PrepSubsystem) handleScan(ctx context.Context, options core.Options) core.Result {
input := ScanInput{
Org: options.String("org"),
@ -106,11 +100,11 @@ func (s *PrepSubsystem) handleScan(ctx context.Context, options core.Options) co
return core.Result{Value: out, OK: true}
}
// handleWatch watches a workspace for completion.
// result := c.Action("agentic.watch").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.watch").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "core/go-io/task-5"},
// ))
// core.Option{Key: "workspace", Value: "core/go-io/task-5"},
//
// ))
func (s *PrepSubsystem) handleWatch(ctx context.Context, options core.Options) core.Result {
input := WatchInput{
PollInterval: options.Int("poll_interval"),
@ -126,58 +120,56 @@ func (s *PrepSubsystem) handleWatch(ctx context.Context, options core.Options) c
return core.Result{Value: out, OK: true}
}
// handlePrompt reads an embedded prompt by slug.
// result := c.Action("agentic.prompt").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.prompt").Run(ctx, core.NewOptions(
// core.Option{Key: "slug", Value: "coding"},
// ))
// core.Option{Key: "slug", Value: "coding"},
//
// ))
func (s *PrepSubsystem) handlePrompt(_ context.Context, options core.Options) core.Result {
return lib.Prompt(options.String("slug"))
}
// handleTask reads an embedded task plan by slug.
// result := c.Action("agentic.task").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.task").Run(ctx, core.NewOptions(
// core.Option{Key: "slug", Value: "bug-fix"},
// ))
// core.Option{Key: "slug", Value: "bug-fix"},
//
// ))
func (s *PrepSubsystem) handleTask(_ context.Context, options core.Options) core.Result {
return lib.Task(options.String("slug"))
}
// handleFlow reads an embedded flow by slug.
// result := c.Action("agentic.flow").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.flow").Run(ctx, core.NewOptions(
// core.Option{Key: "slug", Value: "go"},
// ))
// core.Option{Key: "slug", Value: "go"},
//
// ))
func (s *PrepSubsystem) handleFlow(_ context.Context, options core.Options) core.Result {
return lib.Flow(options.String("slug"))
}
// handlePersona reads an embedded persona by path.
// result := c.Action("agentic.persona").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.persona").Run(ctx, core.NewOptions(
// core.Option{Key: "path", Value: "code/backend-architect"},
// ))
// core.Option{Key: "path", Value: "code/backend-architect"},
//
// ))
func (s *PrepSubsystem) handlePersona(_ context.Context, options core.Options) core.Result {
return lib.Persona(options.String("path"))
}
// --- Pipeline ---
// handleComplete runs the named completion task.
// result := c.Action("agentic.complete").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.complete").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "/srv/.core/workspace/core/go-io/task-42"},
// ))
// core.Option{Key: "workspace", Value: "/srv/.core/workspace/core/go-io/task-42"},
//
// ))
func (s *PrepSubsystem) handleComplete(ctx context.Context, options core.Options) core.Result {
return s.Core().Task("agent.completion").Run(ctx, s.Core(), options)
}
// handleQA runs build+test on a completed workspace.
// result := c.Action("agentic.qa").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.qa").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
// ))
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
//
// ))
func (s *PrepSubsystem) handleQA(ctx context.Context, options core.Options) core.Result {
// Feature flag gate — skip QA if disabled
if s.ServiceRuntime != nil && !s.Config().Enabled("auto-qa") {
@ -215,11 +207,11 @@ func (s *PrepSubsystem) handleQA(ctx context.Context, options core.Options) core
return core.Result{Value: passed, OK: passed}
}
// handleAutoPR creates a PR for a completed workspace.
// result := c.Action("agentic.auto-pr").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.auto-pr").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
// ))
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
//
// ))
func (s *PrepSubsystem) handleAutoPR(ctx context.Context, options core.Options) core.Result {
if s.ServiceRuntime != nil && !s.Config().Enabled("auto-pr") {
return core.Result{OK: true}
@ -246,11 +238,11 @@ func (s *PrepSubsystem) handleAutoPR(ctx context.Context, options core.Options)
return core.Result{OK: true}
}
// handleVerify verifies and auto-merges a PR.
// result := c.Action("agentic.verify").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.verify").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
// ))
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
//
// ))
func (s *PrepSubsystem) handleVerify(ctx context.Context, options core.Options) core.Result {
if s.ServiceRuntime != nil && !s.Config().Enabled("auto-merge") {
return core.Result{OK: true}
@ -285,11 +277,11 @@ func (s *PrepSubsystem) handleVerify(ctx context.Context, options core.Options)
return core.Result{OK: true}
}
// handleIngest creates issues from agent findings.
// result := c.Action("agentic.ingest").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.ingest").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
// ))
// core.Option{Key: "workspace", Value: "/path/to/workspace"},
//
// ))
func (s *PrepSubsystem) handleIngest(ctx context.Context, options core.Options) core.Result {
workspaceDir := options.String("workspace")
if workspaceDir == "" {
@ -307,11 +299,11 @@ func (s *PrepSubsystem) handlePoke(ctx context.Context, _ core.Options) core.Res
return core.Result{OK: true}
}
// handleMirror mirrors agent branches to GitHub.
// result := c.Action("agentic.mirror").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.mirror").Run(ctx, core.NewOptions(
// core.Option{Key: "repo", Value: "go-io"},
// ))
// core.Option{Key: "repo", Value: "go-io"},
//
// ))
func (s *PrepSubsystem) handleMirror(ctx context.Context, options core.Options) core.Result {
input := MirrorInput{
Repo: options.String("repo"),
@ -323,8 +315,6 @@ func (s *PrepSubsystem) handleMirror(ctx context.Context, options core.Options)
return core.Result{Value: out, OK: true}
}
// --- Forge ---
// handleIssueGet retrieves a forge issue.
//
// result := c.Action("agentic.issue.get").Run(ctx, core.NewOptions(
@ -335,21 +325,21 @@ func (s *PrepSubsystem) handleIssueGet(ctx context.Context, options core.Options
return s.cmdIssueGet(options)
}
// handleIssueList lists forge issues.
// result := c.Action("agentic.issue.list").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.issue.list").Run(ctx, core.NewOptions(
// core.Option{Key: "_arg", Value: "go-io"},
// ))
// core.Option{Key: "_arg", Value: "go-io"},
//
// ))
func (s *PrepSubsystem) handleIssueList(ctx context.Context, options core.Options) core.Result {
return s.cmdIssueList(options)
}
// handleIssueCreate creates a forge issue.
// result := c.Action("agentic.issue.create").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.issue.create").Run(ctx, core.NewOptions(
// core.Option{Key: "_arg", Value: "go-io"},
// core.Option{Key: "title", Value: "Bug report"},
// ))
// core.Option{Key: "_arg", Value: "go-io"},
// core.Option{Key: "title", Value: "Bug report"},
//
// ))
func (s *PrepSubsystem) handleIssueCreate(ctx context.Context, options core.Options) core.Result {
return s.cmdIssueCreate(options)
}
@ -364,11 +354,11 @@ func (s *PrepSubsystem) handlePRGet(ctx context.Context, options core.Options) c
return s.cmdPRGet(options)
}
// handlePRList lists forge PRs.
// result := c.Action("agentic.pr.list").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.pr.list").Run(ctx, core.NewOptions(
// core.Option{Key: "_arg", Value: "go-io"},
// ))
// core.Option{Key: "_arg", Value: "go-io"},
//
// ))
func (s *PrepSubsystem) handlePRList(ctx context.Context, options core.Options) core.Result {
return s.cmdPRList(options)
}
@ -383,13 +373,11 @@ func (s *PrepSubsystem) handlePRMerge(ctx context.Context, options core.Options)
return s.cmdPRMerge(options)
}
// --- Review ---
// handleReviewQueue runs CodeRabbit review on a workspace.
// result := c.Action("agentic.review-queue").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.review-queue").Run(ctx, core.NewOptions(
// core.Option{Key: "workspace", Value: "core/go-io/task-5"},
// ))
// core.Option{Key: "workspace", Value: "core/go-io/task-5"},
//
// ))
func (s *PrepSubsystem) handleReviewQueue(ctx context.Context, options core.Options) core.Result {
input := ReviewQueueInput{
Limit: options.Int("limit"),
@ -403,13 +391,11 @@ func (s *PrepSubsystem) handleReviewQueue(ctx context.Context, options core.Opti
return core.Result{Value: out, OK: true}
}
// --- Epic ---
// handleEpic creates an epic (multi-repo task breakdown).
// result := c.Action("agentic.epic").Run(ctx, core.NewOptions(
//
// result := c.Action("agentic.epic").Run(ctx, core.NewOptions(
// core.Option{Key: "task", Value: "Update all repos to v0.8.0"},
// ))
// core.Option{Key: "task", Value: "Update all repos to v0.8.0"},
//
// ))
func (s *PrepSubsystem) handleEpic(ctx context.Context, options core.Options) core.Result {
input := EpicInput{
Repo: options.String("repo"),

View file

@ -9,8 +9,7 @@ import (
core "dappco.re/go/core"
)
// autoCreatePR pushes the agent's branch and creates a PR on Forge
// if the agent made any commits beyond the initial clone.
// s.autoCreatePR("/srv/.core/workspace/core/go-io/task-5")
func (s *PrepSubsystem) autoCreatePR(workspaceDir string) {
result := ReadStatusResult(workspaceDir)
workspaceStatus, ok := workspaceStatusValue(result)

View file

@ -71,7 +71,13 @@ func pullRequestAuthor(pr pullRequestView) string {
return pr.User.Login
}
// parseForgeArgs extracts org and repo from options.
// org, repo, num := parseForgeArgs(core.NewOptions(
//
// core.Option{Key: "org", Value: "core"},
// core.Option{Key: "_arg", Value: "go-io"},
// core.Option{Key: "number", Value: "42"},
//
// ))
func parseForgeArgs(options core.Options) (org, repo string, num int64) {
org = options.String("org")
if org == "" {

View file

@ -13,11 +13,7 @@ import (
core "dappco.re/go/core"
)
// cloneWorkspaceDeps clones Core ecosystem dependencies into the workspace.
// After this, the workspace go.work includes ./repo and all ./dep-* dirs,
// giving the agent everything needed to build and test.
//
// s.cloneWorkspaceDeps(ctx, workspaceDir, repoDir, "core")
// s.cloneWorkspaceDeps(ctx, workspaceDir, repoDir, "core")
func (s *PrepSubsystem) cloneWorkspaceDeps(ctx context.Context, workspaceDir, repoDir, org string) {
goModPath := core.JoinPath(repoDir, "go.mod")
r := fs.Read(goModPath)
@ -80,11 +76,8 @@ type coreDep struct {
dir string // e.g. "core-go" (workspace subdir)
}
// parseCoreDeps extracts direct Core ecosystem dependencies from go.mod content.
// Skips indirect deps — only clones what the repo directly imports.
//
// deps := parseCoreDeps(goMod)
// if len(deps) > 0 { core.Println(deps[0].repo) }
// deps := parseCoreDeps(goMod)
// if len(deps) > 0 { core.Println(deps[0].repo) }
func parseCoreDeps(gomod string) []coreDep {
var deps []coreDep
seen := make(map[string]bool)

View file

@ -226,16 +226,13 @@ func containerCommand(command string, args []string, repoDir, metaDir string) (s
return "docker", dockerArgs
}
// --- spawnAgent: decomposed into testable steps ---
// agentOutputFile returns the log file path for an agent's output.
// outputFile := agentOutputFile(workspaceDir, "codex")
func agentOutputFile(workspaceDir, agent string) string {
agentBase := core.SplitN(agent, ":", 2)[0]
return core.JoinPath(WorkspaceMetaDir(workspaceDir), core.Sprintf("agent-%s.log", agentBase))
}
// detectFinalStatus reads workspace state after agent exit to determine outcome.
// Returns (status, question) — "completed", "blocked", or "failed".
// status, question := detectFinalStatus(repoDir, 0, "completed")
func detectFinalStatus(repoDir string, exitCode int, processStatus string) (string, string) {
blockedPath := core.JoinPath(repoDir, "BLOCKED.md")
if blockedResult := fs.Read(blockedPath); blockedResult.OK && core.Trim(blockedResult.Value.(string)) != "" {
@ -342,8 +339,6 @@ func (s *PrepSubsystem) broadcastComplete(agent, workspaceDir, finalStatus strin
}
}
// onAgentComplete handles all post-completion logic for a spawned agent.
// Called from the monitoring goroutine after the process exits.
func (s *PrepSubsystem) onAgentComplete(agent, workspaceDir, outputFile string, exitCode int, processStatus, output string) {
// Save output
if output != "" {
@ -384,9 +379,7 @@ func (s *PrepSubsystem) onAgentComplete(agent, workspaceDir, outputFile string,
}
}
// spawnAgent launches an agent inside a Docker container.
// The repo/ directory is mounted at /workspace, agent runs sandboxed.
// Output is captured and written to .meta/agent-{agent}.log on completion.
// pid, processID, outputFile, err := s.spawnAgent(agent, prompt, workspaceDir)
func (s *PrepSubsystem) spawnAgent(agent, prompt, workspaceDir string) (int, string, string, error) {
command, args, err := agentCommand(agent, prompt)
if err != nil {
@ -472,8 +465,7 @@ func (m *agentCompletionMonitor) run(_ context.Context, _ core.Options) core.Res
return core.Result{OK: true}
}
// runQA runs build + test checks on the repo after agent completion.
// Returns true if QA passes, false if build or tests fail.
// passed := s.runQA(workspaceDir)
func (s *PrepSubsystem) runQA(workspaceDir string) bool {
ctx := context.Background()
repoDir := WorkspaceRepoDir(workspaceDir)

View file

@ -9,11 +9,7 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- agentic_create_epic ---
// EpicInput is the input for agentic_create_epic.
//
// input := agentic.EpicInput{Repo: "go-scm", Title: "Port agentic plans", Tasks: []string{"Read PHP flow", "Implement Go MCP tools"}}
// input := agentic.EpicInput{Repo: "go-scm", Title: "Port agentic plans", Tasks: []string{"Read PHP flow", "Implement Go MCP tools"}}
type EpicInput struct {
Repo string `json:"repo"` // Target repo (e.g. "go-scm")
Org string `json:"org,omitempty"` // Forge org (default "core")
@ -26,9 +22,7 @@ type EpicInput struct {
Template string `json:"template,omitempty"` // Prompt template for dispatch (default "coding")
}
// EpicOutput is the output for agentic_create_epic.
//
// out := agentic.EpicOutput{Success: true, EpicNumber: 42, EpicURL: "https://forge.example/core/go-scm/issues/42"}
// out := agentic.EpicOutput{Success: true, EpicNumber: 42, EpicURL: "https://forge.example/core/go-scm/issues/42"}
type EpicOutput struct {
Success bool `json:"success"`
EpicNumber int `json:"epic_number"`
@ -37,9 +31,7 @@ type EpicOutput struct {
Dispatched int `json:"dispatched,omitempty"`
}
// ChildRef references a child issue.
//
// child := agentic.ChildRef{Number: 43, Title: "Implement plan list", URL: "https://forge.example/core/go-scm/issues/43"}
// child := agentic.ChildRef{Number: 43, Title: "Implement plan list", URL: "https://forge.example/core/go-scm/issues/43"}
type ChildRef struct {
Number int `json:"number"`
Title string `json:"title"`
@ -144,7 +136,7 @@ func (s *PrepSubsystem) createEpic(ctx context.Context, callRequest *mcp.CallToo
return nil, out, nil
}
// createIssue creates a single issue on Forge and returns its reference.
// child, err := s.createIssue(ctx, "core", "go-scm", "Port agentic plans", "", nil)
func (s *PrepSubsystem) createIssue(ctx context.Context, org, repo, title, body string, labelIDs []int64) (ChildRef, error) {
payload := map[string]any{
"title": title,
@ -176,7 +168,7 @@ func (s *PrepSubsystem) createIssue(ctx context.Context, org, repo, title, body
}, nil
}
// resolveLabelIDs looks up label IDs by name, creating labels that don't exist.
// labelIDs := s.resolveLabelIDs(ctx, "core", "go-scm", []string{"agentic", "epic"})
func (s *PrepSubsystem) resolveLabelIDs(ctx context.Context, org, repo string, names []string) []int64 {
if len(names) == 0 {
return nil
@ -216,7 +208,7 @@ func (s *PrepSubsystem) resolveLabelIDs(ctx context.Context, org, repo string, n
return ids
}
// createLabel creates a label on Forge and returns its ID.
// id := s.createLabel(ctx, "core", "go-scm", "agentic")
func (s *PrepSubsystem) createLabel(ctx context.Context, org, repo, name string) int64 {
colours := map[string]string{
"agentic": "#7c3aed",

View file

@ -9,20 +9,14 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- agentic_mirror tool ---
// MirrorInput is the input for agentic_mirror.
//
// input := agentic.MirrorInput{Repo: "go-io", DryRun: true, MaxFiles: 50}
// input := agentic.MirrorInput{Repo: "go-io", DryRun: true, MaxFiles: 50}
type MirrorInput struct {
Repo string `json:"repo,omitempty"` // Specific repo, or empty for all
DryRun bool `json:"dry_run,omitempty"` // Preview without pushing
MaxFiles int `json:"max_files,omitempty"` // Max files per PR (default 50, CodeRabbit limit)
}
// MirrorOutput is the output for agentic_mirror.
//
// out := agentic.MirrorOutput{Success: true, Count: 1, Synced: []agentic.MirrorSync{{Repo: "go-io"}}}
// out := agentic.MirrorOutput{Success: true, Count: 1, Synced: []agentic.MirrorSync{{Repo: "go-io"}}}
type MirrorOutput struct {
Success bool `json:"success"`
Synced []MirrorSync `json:"synced"`
@ -30,9 +24,7 @@ type MirrorOutput struct {
Count int `json:"count"`
}
// MirrorSync records one repo sync.
//
// sync := agentic.MirrorSync{Repo: "go-io", CommitsAhead: 3, FilesChanged: 12}
// sync := agentic.MirrorSync{Repo: "go-io", CommitsAhead: 3, FilesChanged: 12}
type MirrorSync struct {
Repo string `json:"repo"`
CommitsAhead int `json:"commits_ahead"`
@ -146,7 +138,7 @@ func (s *PrepSubsystem) mirror(ctx context.Context, _ *mcp.CallToolRequest, inpu
}, nil
}
// createGitHubPR creates a PR from dev → main using the gh CLI.
// url, err := s.createGitHubPR(ctx, repoDir, "go-io", 3, 12)
func (s *PrepSubsystem) createGitHubPR(ctx context.Context, repoDir, repo string, commits, files int) (string, error) {
ghRepo := core.Sprintf("%s/%s", GitHubOrg(), repo)
process := s.Core().Process()
@ -183,17 +175,14 @@ func (s *PrepSubsystem) createGitHubPR(ctx context.Context, repoDir, repo string
return "", nil
}
// ensureDevBranch creates the dev branch on GitHub if it doesn't exist.
func (s *PrepSubsystem) ensureDevBranch(repoDir string) {
s.Core().Process().RunIn(context.Background(), repoDir, "git", "push", "github", "HEAD:refs/heads/dev")
}
// hasRemote checks if a git remote exists.
func (s *PrepSubsystem) hasRemote(repoDir, name string) bool {
return s.Core().Process().RunIn(context.Background(), repoDir, "git", "remote", "get-url", name).OK
}
// commitsAhead returns how many commits HEAD is ahead of the ref.
func (s *PrepSubsystem) commitsAhead(repoDir, base, head string) int {
r := s.Core().Process().RunIn(context.Background(), repoDir, "git", "rev-list", core.Concat(base, "..", head), "--count")
if !r.OK {
@ -203,7 +192,6 @@ func (s *PrepSubsystem) commitsAhead(repoDir, base, head string) int {
return parseInt(out)
}
// filesChanged returns the number of files changed between two refs.
func (s *PrepSubsystem) filesChanged(repoDir, base, head string) int {
r := s.Core().Process().RunIn(context.Background(), repoDir, "git", "diff", "--name-only", core.Concat(base, "..", head))
if !r.OK {
@ -216,7 +204,6 @@ func (s *PrepSubsystem) filesChanged(repoDir, base, head string) int {
return len(core.Split(out, "\n"))
}
// listLocalRepos returns repo names that exist as directories in basePath.
func (s *PrepSubsystem) listLocalRepos(basePath string) []string {
paths := core.PathGlob(core.JoinPath(basePath, "*"))
var repos []string
@ -233,7 +220,6 @@ func (s *PrepSubsystem) listLocalRepos(basePath string) []string {
return repos
}
// extractJSONField extracts a simple string field from JSON array output.
func extractJSONField(jsonStr, field string) string {
if jsonStr == "" || field == "" {
return ""

View file

@ -11,44 +11,30 @@ import (
core "dappco.re/go/core"
)
// fs provides unrestricted filesystem access (root "/" = no sandbox).
//
// r := fs.Read("/etc/hostname")
// if r.OK { core.Print(nil, "%s", r.Value.(string)) }
// r := fs.Read("/etc/hostname")
// if r.OK { core.Print(nil, "%s", r.Value.(string)) }
var fs = (&core.Fs{}).NewUnrestricted()
// LocalFs returns an unrestricted filesystem instance for use by other packages.
//
// f := agentic.LocalFs()
// r := f.Read("/tmp/agent-status.json")
// f := agentic.LocalFs()
// r := f.Read("/tmp/agent-status.json")
func LocalFs() *core.Fs { return fs }
// WorkspaceRoot returns the root directory for agent workspaces.
// Checks CORE_WORKSPACE env var first, falls back to HomeDir()/Code/.core/workspace.
//
// workspaceDir := core.JoinPath(agentic.WorkspaceRoot(), "core", "go-io", "task-42")
// workspaceDir := core.JoinPath(agentic.WorkspaceRoot(), "core", "go-io", "task-42")
func WorkspaceRoot() string {
return core.JoinPath(CoreRoot(), "workspace")
}
// WorkspaceStatusPaths returns all workspace status files across supported layouts.
//
// paths := agentic.WorkspaceStatusPaths()
// paths := agentic.WorkspaceStatusPaths()
func WorkspaceStatusPaths() []string {
return workspaceStatusPaths(WorkspaceRoot())
}
// WorkspaceStatusPath returns the status file for a workspace directory.
//
// path := agentic.WorkspaceStatusPath("/srv/.core/workspace/core/go-io/task-5")
// path := agentic.WorkspaceStatusPath("/srv/.core/workspace/core/go-io/task-5")
func WorkspaceStatusPath(workspaceDir string) string {
return core.JoinPath(workspaceDir, "status.json")
}
// WorkspaceName extracts the unique workspace name from a full path.
// Given /Users/snider/Code/.core/workspace/core/go-io/dev → core/go-io/dev
//
// name := agentic.WorkspaceName("/Users/snider/Code/.core/workspace/core/go-io/dev")
// name := agentic.WorkspaceName("/Users/snider/Code/.core/workspace/core/go-io/dev")
func WorkspaceName(workspaceDir string) string {
root := WorkspaceRoot()
name := core.TrimPrefix(workspaceDir, root)
@ -59,10 +45,7 @@ func WorkspaceName(workspaceDir string) string {
return name
}
// CoreRoot returns the root directory for core ecosystem files.
// Checks CORE_WORKSPACE env var first, falls back to HomeDir()/Code/.core.
//
// root := agentic.CoreRoot()
// root := agentic.CoreRoot()
func CoreRoot() string {
if root := core.Env("CORE_WORKSPACE"); root != "" {
return root
@ -70,9 +53,7 @@ func CoreRoot() string {
return core.JoinPath(HomeDir(), "Code", ".core")
}
// HomeDir returns the user home directory used by agentic path helpers.
//
// home := agentic.HomeDir()
// home := agentic.HomeDir()
func HomeDir() string {
if home := core.Env("CORE_HOME"); home != "" {
return home
@ -127,9 +108,7 @@ func workspaceStatusPaths(workspaceRoot string) []string {
return paths
}
// WorkspaceRepoDir returns the checked-out repo directory for a workspace.
//
// repoDir := agentic.WorkspaceRepoDir("/srv/.core/workspace/core/go-io/task-5")
// repoDir := agentic.WorkspaceRepoDir("/srv/.core/workspace/core/go-io/task-5")
func WorkspaceRepoDir(workspaceDir string) string {
return core.JoinPath(workspaceDir, "repo")
}
@ -138,9 +117,7 @@ func workspaceRepoDir(workspaceDir string) string {
return WorkspaceRepoDir(workspaceDir)
}
// WorkspaceMetaDir returns the metadata directory for a workspace.
//
// metaDir := agentic.WorkspaceMetaDir("/srv/.core/workspace/core/go-io/task-5")
// metaDir := agentic.WorkspaceMetaDir("/srv/.core/workspace/core/go-io/task-5")
func WorkspaceMetaDir(workspaceDir string) string {
return core.JoinPath(workspaceDir, ".meta")
}
@ -149,9 +126,7 @@ func workspaceMetaDir(workspaceDir string) string {
return WorkspaceMetaDir(workspaceDir)
}
// WorkspaceBlockedPath returns the BLOCKED.md path for a workspace.
//
// blocked := agentic.WorkspaceBlockedPath("/srv/.core/workspace/core/go-io/task-5")
// blocked := agentic.WorkspaceBlockedPath("/srv/.core/workspace/core/go-io/task-5")
func WorkspaceBlockedPath(workspaceDir string) string {
return core.JoinPath(WorkspaceRepoDir(workspaceDir), "BLOCKED.md")
}
@ -160,9 +135,7 @@ func workspaceBlockedPath(workspaceDir string) string {
return WorkspaceBlockedPath(workspaceDir)
}
// WorkspaceAnswerPath returns the ANSWER.md path for a workspace.
//
// answer := agentic.WorkspaceAnswerPath("/srv/.core/workspace/core/go-io/task-5")
// answer := agentic.WorkspaceAnswerPath("/srv/.core/workspace/core/go-io/task-5")
func WorkspaceAnswerPath(workspaceDir string) string {
return core.JoinPath(WorkspaceRepoDir(workspaceDir), "ANSWER.md")
}
@ -171,9 +144,7 @@ func workspaceAnswerPath(workspaceDir string) string {
return WorkspaceAnswerPath(workspaceDir)
}
// WorkspaceLogFiles returns captured agent log files for a workspace.
//
// logs := agentic.WorkspaceLogFiles("/srv/.core/workspace/core/go-io/task-5")
// logs := agentic.WorkspaceLogFiles("/srv/.core/workspace/core/go-io/task-5")
func WorkspaceLogFiles(workspaceDir string) []string {
return core.PathGlob(core.JoinPath(WorkspaceMetaDir(workspaceDir), "agent-*.log"))
}
@ -182,17 +153,12 @@ func workspaceLogFiles(workspaceDir string) []string {
return WorkspaceLogFiles(workspaceDir)
}
// PlansRoot returns the root directory for agent plans.
//
// plansDir := agentic.PlansRoot()
// plansDir := agentic.PlansRoot()
func PlansRoot() string {
return core.JoinPath(CoreRoot(), "plans")
}
// AgentName returns the name of this agent based on hostname.
// Checks AGENT_NAME env var first.
//
// name := agentic.AgentName() // "cladius" on Snider's Mac, "charon" elsewhere
// name := agentic.AgentName() // "cladius" on Snider's Mac, "charon" elsewhere
func AgentName() string {
if name := core.Env("AGENT_NAME"); name != "" {
return name
@ -204,9 +170,7 @@ func AgentName() string {
return "charon"
}
// DefaultBranch detects the default branch of a repo (main, master, etc.).
//
// base := s.DefaultBranch("./src")
// base := s.DefaultBranch("/srv/Code/core/go-io/repo")
func (s *PrepSubsystem) DefaultBranch(repoDir string) string {
ctx := context.Background()
process := s.Core().Process()
@ -225,9 +189,7 @@ func (s *PrepSubsystem) DefaultBranch(repoDir string) string {
return "main"
}
// GitHubOrg returns the GitHub org for mirror operations.
//
// org := agentic.GitHubOrg() // "dAppCore"
// org := agentic.GitHubOrg() // "dAppCore"
func GitHubOrg() string {
if org := core.Env("GITHUB_ORG"); org != "" {
return org

View file

@ -7,10 +7,8 @@ import (
"dappco.re/go/core/process"
)
// ProcessAlive checks whether a managed process is still running.
//
// alive := agentic.ProcessAlive(c, proc.ID, proc.Info().PID)
// alive := agentic.ProcessAlive(c, "", 12345) // legacy PID fallback
// alive := agentic.ProcessAlive(c, proc.ID, proc.Info().PID)
// alive := agentic.ProcessAlive(c, "", 12345) // legacy PID fallback
func ProcessAlive(c *core.Core, processID string, pid int) bool {
if c == nil {
return false

View file

@ -40,11 +40,7 @@ type Phase struct {
Notes string `json:"notes,omitempty"`
}
// --- Input/Output types ---
// PlanCreateInput is the input for agentic_plan_create.
//
// input := agentic.PlanCreateInput{Title: "Migrate pkg/agentic", Objective: "Use Core primitives everywhere"}
// input := agentic.PlanCreateInput{Title: "Migrate pkg/agentic", Objective: "Use Core primitives everywhere"}
type PlanCreateInput struct {
Title string `json:"title"`
Objective string `json:"objective"`
@ -54,33 +50,25 @@ type PlanCreateInput struct {
Notes string `json:"notes,omitempty"`
}
// PlanCreateOutput is the output for agentic_plan_create.
//
// out := agentic.PlanCreateOutput{Success: true, ID: "id-1-a3f2b1"}
// out := agentic.PlanCreateOutput{Success: true, ID: "id-1-a3f2b1"}
type PlanCreateOutput struct {
Success bool `json:"success"`
ID string `json:"id"`
Path string `json:"path"`
}
// PlanReadInput is the input for agentic_plan_read.
//
// input := agentic.PlanReadInput{ID: "id-1-a3f2b1"}
// input := agentic.PlanReadInput{ID: "id-1-a3f2b1"}
type PlanReadInput struct {
ID string `json:"id"`
}
// PlanReadOutput is the output for agentic_plan_read.
//
// out := agentic.PlanReadOutput{Success: true, Plan: agentic.Plan{ID: "id-1-a3f2b1"}}
// out := agentic.PlanReadOutput{Success: true, Plan: agentic.Plan{ID: "id-1-a3f2b1"}}
type PlanReadOutput struct {
Success bool `json:"success"`
Plan Plan `json:"plan"`
}
// PlanUpdateInput is the input for agentic_plan_update.
//
// input := agentic.PlanUpdateInput{ID: "id-1-a3f2b1", Status: "verified"}
// input := agentic.PlanUpdateInput{ID: "id-1-a3f2b1", Status: "verified"}
type PlanUpdateInput struct {
ID string `json:"id"`
Status string `json:"status,omitempty"`
@ -91,48 +79,36 @@ type PlanUpdateInput struct {
Agent string `json:"agent,omitempty"`
}
// PlanUpdateOutput is the output for agentic_plan_update.
//
// out := agentic.PlanUpdateOutput{Success: true, Plan: agentic.Plan{Status: "verified"}}
// out := agentic.PlanUpdateOutput{Success: true, Plan: agentic.Plan{Status: "verified"}}
type PlanUpdateOutput struct {
Success bool `json:"success"`
Plan Plan `json:"plan"`
}
// PlanDeleteInput is the input for agentic_plan_delete.
//
// input := agentic.PlanDeleteInput{ID: "id-1-a3f2b1"}
// input := agentic.PlanDeleteInput{ID: "id-1-a3f2b1"}
type PlanDeleteInput struct {
ID string `json:"id"`
}
// PlanDeleteOutput is the output for agentic_plan_delete.
//
// out := agentic.PlanDeleteOutput{Success: true, Deleted: "id-1-a3f2b1"}
// out := agentic.PlanDeleteOutput{Success: true, Deleted: "id-1-a3f2b1"}
type PlanDeleteOutput struct {
Success bool `json:"success"`
Deleted string `json:"deleted"`
}
// PlanListInput is the input for agentic_plan_list.
//
// input := agentic.PlanListInput{Repo: "go-io", Status: "ready"}
// input := agentic.PlanListInput{Repo: "go-io", Status: "ready"}
type PlanListInput struct {
Status string `json:"status,omitempty"`
Repo string `json:"repo,omitempty"`
}
// PlanListOutput is the output for agentic_plan_list.
//
// out := agentic.PlanListOutput{Success: true, Count: 2, Plans: []agentic.Plan{{ID: "id-1-a3f2b1"}}}
// out := agentic.PlanListOutput{Success: true, Count: 2, Plans: []agentic.Plan{{ID: "id-1-a3f2b1"}}}
type PlanListOutput struct {
Success bool `json:"success"`
Count int `json:"count"`
Plans []Plan `json:"plans"`
}
// --- Registration ---
func (s *PrepSubsystem) registerPlanTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{
Name: "agentic_plan_create",
@ -160,8 +136,6 @@ func (s *PrepSubsystem) registerPlanTools(server *mcp.Server) {
}, s.planList)
}
// --- Handlers ---
func (s *PrepSubsystem) planCreate(_ context.Context, _ *mcp.CallToolRequest, input PlanCreateInput) (*mcp.CallToolResult, PlanCreateOutput, error) {
if input.Title == "" {
return nil, PlanCreateOutput{}, core.E("planCreate", "title is required", nil)
@ -356,17 +330,13 @@ func (s *PrepSubsystem) planList(_ context.Context, _ *mcp.CallToolRequest, inpu
}, nil
}
// --- Helpers ---
func planPath(dir, id string) string {
safe := core.SanitisePath(id)
return core.JoinPath(dir, core.Concat(safe, ".json"))
}
// readPlanResult reads and decodes a plan file as core.Result.
//
// result := readPlanResult(PlansRoot(), "plan-id")
// if result.OK { plan := result.Value.(*Plan) }
// result := readPlanResult(PlansRoot(), "plan-id")
// if result.OK { plan := result.Value.(*Plan) }
func readPlanResult(dir, id string) core.Result {
r := fs.Read(planPath(dir, id))
if !r.OK {
@ -405,10 +375,8 @@ func readPlan(dir, id string) (*Plan, error) {
return plan, nil
}
// writePlanResult writes a plan file and returns core.Result.
//
// result := writePlanResult(PlansRoot(), plan)
// if result.OK { path := result.Value.(string) }
// result := writePlanResult(PlansRoot(), plan)
// if result.OK { path := result.Value.(string) }
func writePlanResult(dir string, plan *Plan) core.Result {
if plan == nil {
return core.Result{Value: core.E("writePlan", "plan is required", nil), OK: false}

View file

@ -10,8 +10,6 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- agentic_create_pr ---
// CreatePRInput is the input for agentic_create_pr.
//
// input := agentic.CreatePRInput{Workspace: "core/go-io/task-42", Title: "Fix watcher panic"}
@ -179,8 +177,6 @@ func (s *PrepSubsystem) commentOnIssue(ctx context.Context, org, repo string, is
s.forge.Issues.CreateComment(ctx, org, repo, int64(issue), comment)
}
// --- agentic_list_prs ---
// ListPRsInput is the input for agentic_list_prs.
//
// input := agentic.ListPRsInput{Org: "core", Repo: "go-io", State: "open", Limit: 10}

View file

@ -287,8 +287,6 @@ func (s *PrepSubsystem) RegisterTools(server *mcp.Server) {
// _ = subsystem.Shutdown(context.Background())
func (s *PrepSubsystem) Shutdown(_ context.Context) error { return nil }
// --- Input/Output types ---
// input := agentic.PrepInput{Repo: "go-io", Issue: 15, Task: "Migrate to Core primitives"}
type PrepInput struct {
Repo string `json:"repo"` // required: e.g. "go-io"
@ -511,8 +509,6 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques
return nil, out, nil
}
// --- Spec Injection ---
// copyRepoSpecs copies RFC spec files from the plans repo into the workspace specs/ folder.
// Maps repo name to plans directory: go-io → core/go/io, agent → core/agent, core-bio → core/php/bio.
// Preserves subdirectory structure so sub-package specs land in specs/{pkg}/RFC.md.
@ -574,8 +570,6 @@ func (s *PrepSubsystem) copyRepoSpecs(workspaceDir, repo string) {
}
}
// --- Public API for CLI testing ---
// TestPrepWorkspace exposes prepWorkspace for CLI testing.
//
// _, out, err := prep.TestPrepWorkspace(ctx, input)
@ -590,8 +584,6 @@ func (s *PrepSubsystem) TestBuildPrompt(ctx context.Context, input PrepInput, br
return s.buildPrompt(ctx, input, branch, repoPath)
}
// --- Prompt Building ---
// buildPrompt assembles all context into a single prompt string.
// Context is gathered from: persona, flow, issue, brain, consumers, git log, wiki, plan.
func (s *PrepSubsystem) buildPrompt(ctx context.Context, input PrepInput, branch, repoPath string) (string, int, int) {
@ -678,8 +670,6 @@ func (s *PrepSubsystem) buildPrompt(ctx context.Context, input PrepInput, branch
return b.String(), memories, consumers
}
// --- Context Helpers (return strings, not write files) ---
func (s *PrepSubsystem) getIssueBody(ctx context.Context, org, repo string, issue int) string {
idx := core.Sprintf("%d", issue)
iss, err := s.forge.Issues.Get(ctx, forge.Params{"owner": org, "repo": repo, "index": idx})
@ -864,8 +854,6 @@ func (s *PrepSubsystem) renderPlan(templateSlug string, variables map[string]str
return plan.String()
}
// --- Detection helpers (unchanged) ---
func detectLanguage(repoPath string) string {
checks := []struct {
file string

View file

@ -141,10 +141,7 @@ func (s *PrepSubsystem) delayForAgent(agent string) time.Duration {
return time.Duration(rate.SustainedDelay) * time.Second
}
// countRunningByAgent counts running workspaces for a specific agent type
// using the in-memory Registry. Falls back to disk scan if Registry is empty.
//
// n := s.countRunningByAgent("codex") // counts all codex:* variants
// n := s.countRunningByAgent("codex")
func (s *PrepSubsystem) countRunningByAgent(agent string) int {
var runtime *core.Core
if s.ServiceRuntime != nil {
@ -182,10 +179,7 @@ func (s *PrepSubsystem) countRunningByAgentDisk(runtime *core.Core, agent string
return count
}
// countRunningByModel counts running workspaces for a specific agent:model string
// using the in-memory Registry.
//
// n := s.countRunningByModel("codex:gpt-5.4") // counts only that model
// n := s.countRunningByModel("codex:gpt-5.4")
func (s *PrepSubsystem) countRunningByModel(agent string) int {
var runtime *core.Core
if s.ServiceRuntime != nil {
@ -268,11 +262,8 @@ func (s *PrepSubsystem) canDispatchAgent(agent string) bool {
return true
}
// modelVariant extracts the model name from an agent string.
//
// codex:gpt-5.4 → gpt-5.4
// codex:gpt-5.3-codex-spark → gpt-5.3-codex-spark
// claude → ""
// model := modelVariant("codex:gpt-5.4")
// _ = model
func modelVariant(agent string) string {
parts := core.SplitN(agent, ":", 2)
if len(parts) < 2 {

View file

@ -8,8 +8,6 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- agentic_dispatch_remote tool ---
// RemoteDispatchInput dispatches a task to a remote core-agent over HTTP.
//
// input := agentic.RemoteDispatchInput{Host: "charon", Repo: "go-io", Task: "Run the review queue"}

View file

@ -8,8 +8,6 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- agentic_status_remote tool ---
// RemoteStatusInput queries a remote core-agent for workspace status.
//
// input := agentic.RemoteStatusInput{Host: "charon"}

View file

@ -11,11 +11,7 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// --- agentic_review_queue tool ---
// ReviewQueueInput controls the review queue runner.
//
// input := agentic.ReviewQueueInput{Reviewer: "coderabbit", Limit: 4, DryRun: true}
// input := agentic.ReviewQueueInput{Reviewer: "coderabbit", Limit: 4, DryRun: true}
type ReviewQueueInput struct {
Limit int `json:"limit,omitempty"` // Max PRs to process this run (default: 4)
Reviewer string `json:"reviewer,omitempty"` // "coderabbit" (default), "codex", or "both"
@ -23,9 +19,7 @@ type ReviewQueueInput struct {
LocalOnly bool `json:"local_only,omitempty"` // Run review locally, don't touch GitHub
}
// ReviewQueueOutput reports what happened.
//
// out := agentic.ReviewQueueOutput{Success: true, Processed: []agentic.ReviewResult{{Repo: "go-io", Verdict: "clean"}}}
// out := agentic.ReviewQueueOutput{Success: true, Processed: []agentic.ReviewResult{{Repo: "go-io", Verdict: "clean"}}}
type ReviewQueueOutput struct {
Success bool `json:"success"`
Processed []ReviewResult `json:"processed"`
@ -33,9 +27,7 @@ type ReviewQueueOutput struct {
RateLimit *RateLimitInfo `json:"rate_limit,omitempty"`
}
// ReviewResult is the outcome of reviewing one repo.
//
// result := agentic.ReviewResult{Repo: "go-io", Verdict: "findings", Findings: 3, Action: "fix_dispatched"}
// result := agentic.ReviewResult{Repo: "go-io", Verdict: "findings", Findings: 3, Action: "fix_dispatched"}
type ReviewResult struct {
Repo string `json:"repo"`
Verdict string `json:"verdict"` // clean, findings, rate_limited, error
@ -44,9 +36,7 @@ type ReviewResult struct {
Detail string `json:"detail,omitempty"`
}
// RateLimitInfo tracks CodeRabbit rate limit state.
//
// limit := agentic.RateLimitInfo{Limited: true, Message: "retry after 2026-03-22T06:00:00Z"}
// limit := agentic.RateLimitInfo{Limited: true, Message: "retry after 2026-03-22T06:00:00Z"}
type RateLimitInfo struct {
Limited bool `json:"limited"`
RetryAt time.Time `json:"retry_at,omitempty"`
@ -143,7 +133,7 @@ func (s *PrepSubsystem) reviewQueue(ctx context.Context, _ *mcp.CallToolRequest,
}, nil
}
// findReviewCandidates returns repos that are ahead of GitHub main.
// repos := s.findReviewCandidates("/srv/Code/core")
func (s *PrepSubsystem) findReviewCandidates(basePath string) []string {
paths := core.PathGlob(core.JoinPath(basePath, "*"))
@ -164,7 +154,7 @@ func (s *PrepSubsystem) findReviewCandidates(basePath string) []string {
return candidates
}
// reviewRepo runs CodeRabbit on a single repo and takes action.
// result := s.reviewRepo(ctx, repoDir, "go-io", "coderabbit", false, false)
func (s *PrepSubsystem) reviewRepo(ctx context.Context, repoDir, repo, reviewer string, dryRun, localOnly bool) ReviewResult {
result := ReviewResult{Repo: repo}
process := s.Core().Process()
@ -253,7 +243,7 @@ func (s *PrepSubsystem) reviewRepo(ctx context.Context, repoDir, repo, reviewer
return result
}
// pushAndMerge pushes to GitHub dev and merges the PR.
// _ = s.pushAndMerge(ctx, repoDir, "go-io")
func (s *PrepSubsystem) pushAndMerge(ctx context.Context, repoDir, repo string) error {
process := s.Core().Process()
if r := process.RunIn(ctx, repoDir, "git", "push", "github", "HEAD:refs/heads/dev", "--force"); !r.OK {
@ -270,7 +260,7 @@ func (s *PrepSubsystem) pushAndMerge(ctx context.Context, repoDir, repo string)
return nil
}
// dispatchFixFromQueue dispatches an opus agent to fix CodeRabbit findings.
// _ = s.dispatchFixFromQueue(ctx, "go-io", task)
func (s *PrepSubsystem) dispatchFixFromQueue(ctx context.Context, repo, task string) error {
// Use the dispatch system — creates workspace, spawns agent
input := DispatchInput{
@ -288,7 +278,7 @@ func (s *PrepSubsystem) dispatchFixFromQueue(ctx context.Context, repo, task str
return nil
}
// countFindings estimates the number of findings in CodeRabbit output.
// findings := countFindings(output)
func countFindings(output string) int {
// Count lines that look like findings
count := 0
@ -306,8 +296,7 @@ func countFindings(output string) int {
return count
}
// parseRetryAfter extracts the retry duration from a rate limit message.
// Example: "please try after 4 minutes and 56 seconds"
// delay := parseRetryAfter("please try after 4 minutes and 56 seconds")
func parseRetryAfter(message string) time.Duration {
if retryAfterPattern == nil {
return 5 * time.Minute
@ -325,9 +314,7 @@ func parseRetryAfter(message string) time.Duration {
return 5 * time.Minute
}
// buildReviewCommand returns the command and args for the chosen reviewer.
//
// cmd, args := s.buildReviewCommand(repoDir, "coderabbit")
// cmd, args := s.buildReviewCommand(repoDir, "coderabbit")
func (s *PrepSubsystem) buildReviewCommand(repoDir, reviewer string) (string, []string) {
switch reviewer {
case "codex":
@ -337,7 +324,7 @@ func (s *PrepSubsystem) buildReviewCommand(repoDir, reviewer string) (string, []
}
}
// storeReviewOutput saves raw review output for training data collection.
// s.storeReviewOutput(repoDir, "go-io", "coderabbit", output)
func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string) {
dataDir := core.JoinPath(HomeDir(), ".core", "training", "reviews")
fs.EnsureDir(dataDir)
@ -369,9 +356,7 @@ func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string
core.WriteAll(r.Value, core.Concat(jsonLine, "\n"))
}
// saveRateLimitState writes the current rate-limit snapshot.
//
// s.saveRateLimitState(&RateLimitInfo{Limited: true, RetryAt: time.Now().Add(30 * time.Minute)})
// s.saveRateLimitState(&RateLimitInfo{Limited: true, RetryAt: time.Now().Add(30 * time.Minute)})
func (s *PrepSubsystem) saveRateLimitState(info *RateLimitInfo) {
path := core.JoinPath(HomeDir(), ".core", "coderabbit-ratelimit.json")
if r := fs.WriteAtomic(path, core.JSONMarshalString(info)); !r.OK {
@ -383,7 +368,7 @@ func (s *PrepSubsystem) saveRateLimitState(info *RateLimitInfo) {
}
}
// loadRateLimitState reads persisted rate limit info.
// info := s.loadRateLimitState()
func (s *PrepSubsystem) loadRateLimitState() *RateLimitInfo {
path := core.JoinPath(HomeDir(), ".core", "coderabbit-ratelimit.json")
r := fs.Read(path)

View file

@ -2,19 +2,10 @@
package agentic
// StartRunner preserves the legacy PrepSubsystem call after queue ownership moved to pkg/runner.Service.
//
// subsystem := agentic.NewPrep()
// subsystem.StartRunner()
//
// The runner service registers as core.WithService(runner.Register) and
// manages its own background loop, frozen state, and concurrency checks.
// subsystem := agentic.NewPrep()
// subsystem.StartRunner()
func (s *PrepSubsystem) StartRunner() {}
// Poke preserves the legacy queue signal after queue ownership moved to pkg/runner.Service.
//
// subsystem := agentic.NewPrep()
// subsystem.Poke()
//
// Runner catches AgentCompleted via HandleIPCEvents and pokes itself.
// subsystem := agentic.NewPrep()
// subsystem.Poke()
func (s *PrepSubsystem) Poke() {}

View file

@ -101,8 +101,6 @@ func workspaceStatusValue(result core.Result) (*WorkspaceStatus, bool) {
return workspaceStatus, true
}
// --- agentic_status tool ---
// input := agentic.StatusInput{Workspace: "core/go-io/task-42", Limit: 50}
type StatusInput struct {
Workspace string `json:"workspace,omitempty"` // specific workspace name, or empty for all

View file

@ -1,8 +1,6 @@
// SPDX-License-Identifier: EUPL-1.2
// HTTP transport for Core API streams.
// This is the ONE file in core/agent that imports net/http.
// All other files use the exported helpers: HTTPGet, HTTPPost, HTTPCall.
package agentic
@ -26,10 +24,8 @@ type httpStream struct {
response []byte
}
// Send issues the configured HTTP request and caches the response body for Receive.
//
// stream := &httpStream{client: defaultClient, url: "https://forge.lthn.ai/api/v1/version", method: "GET"}
// _ = stream.Send(nil)
// stream := &httpStream{client: defaultClient, url: "https://forge.lthn.ai/api/v1/version", method: "GET"}
// _ = stream.Send(nil)
func (s *httpStream) Send(data []byte) error {
request, err := http.NewRequestWithContext(context.Background(), s.method, s.url, core.NewReader(string(data)))
if err != nil {
@ -55,26 +51,20 @@ func (s *httpStream) Send(data []byte) error {
return nil
}
// Receive returns the cached response body from the last Send call.
//
// stream := &httpStream{response: []byte(`{"ok":true}`)}
// data, _ := stream.Receive()
// _ = data
// stream := &httpStream{response: []byte(`{"ok":true}`)}
// data, _ := stream.Receive()
// _ = data
func (s *httpStream) Receive() ([]byte, error) {
return s.response, nil
}
// Close satisfies core.Stream for one-shot HTTP requests.
//
// stream := &httpStream{}
// _ = stream.Close()
// stream := &httpStream{}
// _ = stream.Close()
func (s *httpStream) Close() error {
return nil
}
// RegisterHTTPTransport registers the HTTP/HTTPS protocol handler with Core API.
//
// agentic.RegisterHTTPTransport(c)
// agentic.RegisterHTTPTransport(c)
func RegisterHTTPTransport(c *core.Core) {
factory := func(handle *core.DriveHandle) (core.Stream, error) {
token := handle.Options.String("token")
@ -89,50 +79,32 @@ func RegisterHTTPTransport(c *core.Core) {
c.API().RegisterProtocol("https", factory)
}
// --- REST helpers — all HTTP in core/agent routes through these ---
// HTTPGet performs a GET request. Returns Result{Value: string (response body), OK: bool}.
// Auth is "token {token}" for Forge, "Bearer {token}" for Brain.
//
// result := agentic.HTTPGet(ctx, "https://forge.lthn.ai/api/v1/repos", "my-token", "token")
// result := agentic.HTTPGet(ctx, "https://forge.lthn.ai/api/v1/repos", "my-token", "token")
func HTTPGet(ctx context.Context, url, token, authScheme string) core.Result {
return httpDo(ctx, "GET", url, "", token, authScheme)
}
// HTTPPost performs a POST request with a JSON body. Returns Result{Value: string, OK: bool}.
//
// result := agentic.HTTPPost(ctx, url, core.JSONMarshalString(payload), token, "token")
// result := agentic.HTTPPost(ctx, url, core.JSONMarshalString(payload), token, "token")
func HTTPPost(ctx context.Context, url, body, token, authScheme string) core.Result {
return httpDo(ctx, "POST", url, body, token, authScheme)
}
// HTTPPatch performs a PATCH request with a JSON body.
//
// result := agentic.HTTPPatch(ctx, url, body, token, "token")
// result := agentic.HTTPPatch(ctx, url, body, token, "token")
func HTTPPatch(ctx context.Context, url, body, token, authScheme string) core.Result {
return httpDo(ctx, "PATCH", url, body, token, authScheme)
}
// HTTPDelete performs a DELETE request.
//
// result := agentic.HTTPDelete(ctx, url, body, token, "Bearer")
// result := agentic.HTTPDelete(ctx, url, body, token, "Bearer")
func HTTPDelete(ctx context.Context, url, body, token, authScheme string) core.Result {
return httpDo(ctx, "DELETE", url, body, token, authScheme)
}
// HTTPDo performs an HTTP request with the specified method.
//
// result := agentic.HTTPDo(ctx, "PUT", url, body, token, "token")
// result := agentic.HTTPDo(ctx, "PUT", url, body, token, "token")
func HTTPDo(ctx context.Context, method, url, body, token, authScheme string) core.Result {
return httpDo(ctx, method, url, body, token, authScheme)
}
// --- Drive-aware REST helpers — route through c.Drive() for endpoint resolution ---
// DriveGet performs a GET request using a named Drive endpoint.
// Reads base URL and token from the Drive handle registered in Core.
//
// result := DriveGet(c, "forge", "/api/v1/repos/core/go-io", "token")
// result := DriveGet(c, "forge", "/api/v1/repos/core/go-io", "token")
func DriveGet(c *core.Core, drive, path, authScheme string) core.Result {
base, token := driveEndpoint(c, drive)
if base == "" {
@ -141,9 +113,7 @@ func DriveGet(c *core.Core, drive, path, authScheme string) core.Result {
return httpDo(context.Background(), "GET", core.Concat(base, path), "", token, authScheme)
}
// DrivePost performs a POST request using a named Drive endpoint.
//
// result := DrivePost(c, "forge", "/api/v1/repos/core/go-io/issues", body, "token")
// result := DrivePost(c, "forge", "/api/v1/repos/core/go-io/issues", body, "token")
func DrivePost(c *core.Core, drive, path, body, authScheme string) core.Result {
base, token := driveEndpoint(c, drive)
if base == "" {
@ -152,9 +122,7 @@ func DrivePost(c *core.Core, drive, path, body, authScheme string) core.Result {
return httpDo(context.Background(), "POST", core.Concat(base, path), body, token, authScheme)
}
// DriveDo performs an HTTP request using a named Drive endpoint.
//
// result := DriveDo(c, "forge", "PATCH", "/api/v1/repos/core/go-io/pulls/5", body, "token")
// result := DriveDo(c, "forge", "PATCH", "/api/v1/repos/core/go-io/pulls/5", body, "token")
func DriveDo(c *core.Core, drive, method, path, body, authScheme string) core.Result {
base, token := driveEndpoint(c, drive)
if base == "" {
@ -163,7 +131,6 @@ func DriveDo(c *core.Core, drive, method, path, body, authScheme string) core.Re
return httpDo(context.Background(), method, core.Concat(base, path), body, token, authScheme)
}
// driveEndpoint reads base URL and token from a named Drive handle.
func driveEndpoint(c *core.Core, name string) (base, token string) {
driveResult := c.Drive().Get(name)
if !driveResult.OK {
@ -173,7 +140,6 @@ func driveEndpoint(c *core.Core, name string) (base, token string) {
return driveHandle.Transport, driveHandle.Options.String("token")
}
// httpDo is the single HTTP execution point. Every HTTP call in core/agent routes here.
func httpDo(ctx context.Context, method, url, body, token, authScheme string) core.Result {
var request *http.Request
var err error
@ -210,10 +176,7 @@ func httpDo(ctx context.Context, method, url, body, token, authScheme string) co
return core.Result{Value: readResult.Value.(string), OK: response.StatusCode < 400}
}
// --- MCP Streamable HTTP Transport ---
// mcpInitialize performs the MCP initialise handshake over Streamable HTTP.
// Returns the session ID from the Mcp-Session-Id header.
// sessionID, err := mcpInitialize(ctx, url, token)
func mcpInitialize(ctx context.Context, url, token string) (string, error) {
result := mcpInitializeResult(ctx, url, token)
if !result.OK {
@ -285,7 +248,6 @@ func mcpInitializeResult(ctx context.Context, url, token string) core.Result {
return core.Result{Value: sessionID, OK: true}
}
// mcpCall sends a JSON-RPC request and returns the parsed response.
func mcpCall(ctx context.Context, url, token, sessionID string, body []byte) ([]byte, error) {
result := mcpCallResult(ctx, url, token, sessionID, body)
if !result.OK {
@ -322,7 +284,6 @@ func mcpCallResult(ctx context.Context, url, token, sessionID string, body []byt
return readSSEDataResult(response)
}
// readSSEData reads an SSE response and extracts JSON from data: lines.
func readSSEData(response *http.Response) ([]byte, error) {
result := readSSEDataResult(response)
if !result.OK {
@ -339,7 +300,6 @@ func readSSEData(response *http.Response) ([]byte, error) {
return data, nil
}
// readSSEDataResult parses an SSE response and extracts the first data: payload as core.Result.
func readSSEDataResult(response *http.Response) core.Result {
readResult := core.ReadAll(response.Body)
if !readResult.OK {
@ -354,7 +314,6 @@ func readSSEDataResult(response *http.Response) core.Result {
return core.Result{Value: core.E("readSSEData", "no data in SSE response", nil), OK: false}
}
// mcpHeaders applies standard MCP HTTP headers.
func mcpHeaders(request *http.Request, token, sessionID string) {
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Accept", "application/json, text/event-stream")
@ -366,7 +325,6 @@ func mcpHeaders(request *http.Request, token, sessionID string) {
}
}
// drainSSE reads and discards an SSE response body.
func drainSSE(response *http.Response) {
core.ReadAll(response.Body)
}

View file

@ -11,11 +11,9 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// -- Input/Output types -------------------------------------------------------
// input := brain.RememberInput{
// Content: "Use core.Env for system paths.",
// Type: "convention",
// Content: "Use core.Env for system paths.",
// Type: "convention",
// }
type RememberInput struct {
Content string `json:"content"`
@ -28,8 +26,8 @@ type RememberInput struct {
}
// output := brain.RememberOutput{
// Success: true,
// MemoryID: "mem_123",
// Success: true,
// MemoryID: "mem_123",
// }
type RememberOutput struct {
Success bool `json:"success"`
@ -38,8 +36,8 @@ type RememberOutput struct {
}
// input := brain.RecallInput{
// Query: "core.Env conventions",
// TopK: 5,
// Query: "core.Env conventions",
// TopK: 5,
// }
type RecallInput struct {
Query string `json:"query"`
@ -48,8 +46,8 @@ type RecallInput struct {
}
// filter := brain.RecallFilter{
// Project: "agent",
// Type: "convention",
// Project: "agent",
// Type: "convention",
// }
type RecallFilter struct {
Project string `json:"project,omitempty"`
@ -59,8 +57,8 @@ type RecallFilter struct {
}
// output := brain.RecallOutput{
// Success: true,
// Count: 1,
// Success: true,
// Count: 1,
// }
type RecallOutput struct {
Success bool `json:"success"`
@ -69,9 +67,9 @@ type RecallOutput struct {
}
// memory := brain.Memory{
// ID: "mem_123",
// Type: "convention",
// Content: "Use core.Env for system paths.",
// ID: "mem_123",
// Type: "convention",
// Content: "Use core.Env for system paths.",
// }
type Memory struct {
ID string `json:"id"`
@ -88,8 +86,8 @@ type Memory struct {
}
// input := brain.ForgetInput{
// ID: "mem_123",
// Reason: "superseded",
// ID: "mem_123",
// Reason: "superseded",
// }
type ForgetInput struct {
ID string `json:"id"`
@ -97,8 +95,8 @@ type ForgetInput struct {
}
// output := brain.ForgetOutput{
// Success: true,
// Forgotten: "mem_123",
// Success: true,
// Forgotten: "mem_123",
// }
type ForgetOutput struct {
Success bool `json:"success"`
@ -107,8 +105,8 @@ type ForgetOutput struct {
}
// input := brain.ListInput{
// Project: "agent",
// Limit: 20,
// Project: "agent",
// Limit: 20,
// }
type ListInput struct {
Project string `json:"project,omitempty"`
@ -118,8 +116,8 @@ type ListInput struct {
}
// output := brain.ListOutput{
// Success: true,
// Count: 2,
// Success: true,
// Count: 2,
// }
type ListOutput struct {
Success bool `json:"success"`
@ -127,8 +125,6 @@ type ListOutput struct {
Memories []Memory `json:"memories"`
}
// -- Tool registration --------------------------------------------------------
func (s *Subsystem) registerBrainTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{
Name: "brain_remember",
@ -151,8 +147,6 @@ func (s *Subsystem) registerBrainTools(server *mcp.Server) {
}, s.brainList)
}
// -- Tool handlers ------------------------------------------------------------
func (s *Subsystem) brainRemember(_ context.Context, _ *mcp.CallToolRequest, input RememberInput) (*mcp.CallToolResult, RememberOutput, error) {
if s.bridge == nil {
return nil, RememberOutput{}, errBridgeNotAvailable

View file

@ -125,12 +125,8 @@ func mountEmbed(filesystem embed.FS, baseDir string) core.Result {
}
}
// --- Prompts ---
// Template tries Prompt then Task (backwards compat).
//
// r := lib.Template("coding")
// if r.OK { content := r.Value.(string) }
// r := lib.Template("coding")
// if r.OK { content := r.Value.(string) }
func Template(slug string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -141,10 +137,8 @@ func Template(slug string) core.Result {
return Task(slug)
}
// Prompt reads a system prompt by slug.
//
// r := lib.Prompt("coding")
// if r.OK { content := r.Value.(string) }
// r := lib.Prompt("coding")
// if r.OK { content := r.Value.(string) }
func Prompt(slug string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -152,10 +146,8 @@ func Prompt(slug string) core.Result {
return promptFS.ReadString(core.Concat(slug, ".md"))
}
// Task reads a structured task plan by slug. Tries .md, .yaml, .yml.
//
// r := lib.Task("code/review")
// if r.OK { content := r.Value.(string) }
// r := lib.Task("code/review")
// if r.OK { content := r.Value.(string) }
func Task(slug string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -180,10 +172,8 @@ type Bundle struct {
Files map[string]string
}
// TaskBundle reads a task and its companion files.
//
// r := lib.TaskBundle("code/review")
// if r.OK { b := r.Value.(lib.Bundle) }
// r := lib.TaskBundle("code/review")
// if r.OK { b := r.Value.(lib.Bundle) }
func TaskBundle(slug string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -212,10 +202,8 @@ func TaskBundle(slug string) core.Result {
return core.Result{Value: b, OK: true}
}
// Flow reads a build/release workflow by slug.
//
// r := lib.Flow("go")
// if r.OK { content := r.Value.(string) }
// r := lib.Flow("go")
// if r.OK { content := r.Value.(string) }
func Flow(slug string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -223,10 +211,8 @@ func Flow(slug string) core.Result {
return flowFS.ReadString(core.Concat(slug, ".md"))
}
// Persona reads a domain/role persona by path.
//
// r := lib.Persona("secops/developer")
// if r.OK { content := r.Value.(string) }
// r := lib.Persona("secops/developer")
// if r.OK { content := r.Value.(string) }
func Persona(path string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -234,8 +220,6 @@ func Persona(path string) core.Result {
return personaFS.ReadString(core.Concat(path, ".md"))
}
// --- Workspace Templates ---
// WorkspaceData is the data passed to workspace templates.
//
// data := &lib.WorkspaceData{
@ -259,13 +243,11 @@ type WorkspaceData struct {
TestCmd string
}
// ExtractWorkspace creates an agent workspace from a template.
// Template names: "default", "security", "review".
//
// r := lib.ExtractWorkspace("default", "/tmp/ws", &lib.WorkspaceData{
// Repo: "go-io", Task: "fix tests", Agent: "codex",
// })
// core.Println(r.OK)
//
// core.Println(r.OK)
func ExtractWorkspace(templateName, targetDir string, data *WorkspaceData) core.Result {
if result := ensureMounted(); !result.OK {
if err, ok := result.Value.(error); ok {
@ -309,11 +291,8 @@ func ExtractWorkspace(templateName, targetDir string, data *WorkspaceData) core.
return core.Result{Value: targetDir, OK: true}
}
// WorkspaceFile reads a single file from a workspace template.
// Returns the file content as a string.
//
// r := lib.WorkspaceFile("default", "CODEX-PHP.md.tmpl")
// if r.OK { content := r.Value.(string) }
// r := lib.WorkspaceFile("default", "CODEX-PHP.md.tmpl")
// if r.OK { content := r.Value.(string) }
func WorkspaceFile(templateName, filename string) core.Result {
if result := ensureMounted(); !result.OK {
return result
@ -326,26 +305,16 @@ func WorkspaceFile(templateName, filename string) core.Result {
return embed.ReadString(filename)
}
// --- List Functions ---
// ListPrompts returns available system prompt slugs.
//
// prompts := lib.ListPrompts() // ["coding", "review", ...]
// prompts := lib.ListPrompts() // ["coding", "review", ...]
func ListPrompts() []string { return listNames("prompt") }
// ListFlows returns available build/release flow slugs.
//
// flows := lib.ListFlows() // ["go", "php", "node", ...]
// flows := lib.ListFlows() // ["go", "php", "node", ...]
func ListFlows() []string { return listNames("flow") }
// ListWorkspaces returns available workspace template names.
//
// templates := lib.ListWorkspaces() // ["default", "security", ...]
// templates := lib.ListWorkspaces() // ["default", "security", ...]
func ListWorkspaces() []string { return listNames("workspace") }
// ListTasks returns available task plan slugs, including nested paths.
//
// tasks := lib.ListTasks() // ["bug-fix", "code/review", "code/refactor", ...]
// tasks := lib.ListTasks() // ["bug-fix", "code/review", "code/refactor", ...]
func ListTasks() []string {
if result := ensureMounted(); !result.OK {
return nil
@ -357,9 +326,7 @@ func ListTasks() []string {
return names.AsSlice()
}
// ListPersonas returns available persona paths, including nested directories.
//
// personas := lib.ListPersonas() // ["code/go", "secops/developer", ...]
// personas := lib.ListPersonas() // ["code/go", "secops/developer", ...]
func ListPersonas() []string {
if result := ensureMounted(); !result.OK {
return nil

View file

@ -3,8 +3,6 @@
// c.ACTION(messages.AgentCompleted{Agent: "codex", Repo: "go-io", Status: "completed"})
package messages
// --- Agent Lifecycle ---
// c.ACTION(messages.AgentStarted{Agent: "codex", Repo: "go-io", Workspace: "core/go-io/task-5"})
type AgentStarted struct {
Agent string
@ -20,8 +18,6 @@ type AgentCompleted struct {
Status string // completed, failed, blocked
}
// --- QA & PR Pipeline ---
// c.ACTION(messages.QAResult{Workspace: "core/go-io/task-5", Repo: "go-io", Passed: true})
type QAResult struct {
Workspace string
@ -53,8 +49,6 @@ type PRNeedsReview struct {
Reason string
}
// --- Queue ---
// c.ACTION(messages.QueueDrained{Completed: 3})
type QueueDrained struct {
Completed int
@ -76,8 +70,6 @@ type RateLimitDetected struct {
Duration string
}
// --- Monitor Events ---
// c.ACTION(messages.HarvestComplete{Repo: "go-io", Branch: "agent/fix-tests", Files: 5})
type HarvestComplete struct {
Repo string

View file

@ -1,10 +1,7 @@
// SPDX-License-Identifier: EUPL-1.2
// result := m.harvestWorkspace("/srv/.core/workspace/core/go-io/task-5")
// if result != nil && result.rejected == "" { /* ready-for-review */ }
//
// Completed workspaces are scanned, validated, and marked ready for review.
// The code does not auto-push; review remains an explicit action.
// if result != nil && result.rejected == "" { core.Print(nil, "%s", result.repo) }
package monitor
@ -17,7 +14,6 @@ import (
core "dappco.re/go/core"
)
// harvestResult tracks what happened during harvest.
type harvestResult struct {
repo string
branch string
@ -60,7 +56,7 @@ func (m *Subsystem) harvestCompleted() string {
}
// result := m.harvestWorkspace("/srv/.core/workspace/core/go-io/task-5")
// if result != nil && result.rejected == "" { /* ready-for-review */ }
// if result != nil && result.rejected == "" { core.Print(nil, "%s", result.repo) }
func (m *Subsystem) harvestWorkspace(workspaceDir string) *harvestResult {
statusResult := fs.Read(agentic.WorkspaceStatusPath(workspaceDir))
if !statusResult.OK {
@ -245,9 +241,7 @@ func (m *Subsystem) pushBranch(repoDir, branch string) error {
return nil
}
// updateStatus rewrites status.json after a harvest decision.
//
// updateStatus(workspaceDir, "ready-for-review", "")
// updateStatus(workspaceDir, "ready-for-review", "")
func updateStatus(workspaceDir, status, question string) {
statusResult := fs.Read(agentic.WorkspaceStatusPath(workspaceDir))
if !statusResult.OK {

View file

@ -9,7 +9,7 @@ import (
core "dappco.re/go/core"
)
// fs reuses the shared unrestricted filesystem used by agentic.
// fs := agentic.LocalFs()
var fs = agentic.LocalFs()
func runnerWorkspaceStatusFromAgentic(status *agentic.WorkspaceStatus) *WorkspaceStatus {

View file

@ -11,10 +11,8 @@ import (
"gopkg.in/yaml.v3"
)
// DispatchConfig mirrors the `dispatch:` block in `agents.yaml`.
//
// config := runner.DispatchConfig{
// DefaultAgent: "codex", DefaultTemplate: "coding", WorkspaceRoot: "/srv/core/workspace",
// DefaultAgent: "codex", DefaultTemplate: "coding", WorkspaceRoot: "/srv/core/workspace",
// }
type DispatchConfig struct {
DefaultAgent string `yaml:"default_agent"`
@ -22,10 +20,8 @@ type DispatchConfig struct {
WorkspaceRoot string `yaml:"workspace_root"`
}
// RateConfig mirrors one agent pool under `rates:` in `agents.yaml`.
//
// rate := runner.RateConfig{
// ResetUTC: "06:00", DailyLimit: 200, SustainedDelay: 120, BurstWindow: 2, BurstDelay: 300,
// ResetUTC: "06:00", DailyLimit: 200, SustainedDelay: 120, BurstWindow: 2, BurstDelay: 300,
// }
type RateConfig struct {
ResetUTC string `yaml:"reset_utc"`
@ -47,10 +43,8 @@ type ConcurrencyLimit struct {
Models map[string]int
}
// UnmarshalYAML handles both int and map forms for concurrency limits.
//
// var limit ConcurrencyLimit
// _ = yaml.Unmarshal([]byte("total: 5\ngpt-5.4: 1\n"), &limit)
// var limit ConcurrencyLimit
// _ = yaml.Unmarshal([]byte("total: 5\ngpt-5.4: 1\n"), &limit)
func (c *ConcurrencyLimit) UnmarshalYAML(value *yaml.Node) error {
var n int
if err := value.Decode(&n); err == nil {
@ -71,11 +65,9 @@ func (c *ConcurrencyLimit) UnmarshalYAML(value *yaml.Node) error {
return nil
}
// AgentsConfig mirrors the full `agents.yaml` file.
//
// config := runner.AgentsConfig{
// Version: 1,
// Dispatch: runner.DispatchConfig{DefaultAgent: "codex", DefaultTemplate: "coding"},
// Version: 1,
// Dispatch: runner.DispatchConfig{DefaultAgent: "codex", DefaultTemplate: "coding"},
// }
type AgentsConfig struct {
Version int `yaml:"version"`
@ -84,10 +76,8 @@ type AgentsConfig struct {
Rates map[string]RateConfig `yaml:"rates"`
}
// loadAgentsConfig reads `agents.yaml` from the Core root.
//
// config := s.loadAgentsConfig()
// core.Println(config.Dispatch.DefaultAgent)
// config := s.loadAgentsConfig()
// core.Println(config.Dispatch.DefaultAgent)
func (s *Service) loadAgentsConfig() *AgentsConfig {
paths := []string{
core.JoinPath(CoreRoot(), "agents.yaml"),
@ -115,9 +105,7 @@ func (s *Service) loadAgentsConfig() *AgentsConfig {
}
}
// canDispatchAgent checks both pool-level and per-model concurrency limits.
//
// if !s.canDispatchAgent("codex") { /* queue it */ }
// if can, reason := s.canDispatchAgent("codex"); !can { _ = reason }
func (s *Service) canDispatchAgent(agent string) (bool, string) {
var concurrency map[string]ConcurrencyLimit
if s.ServiceRuntime != nil {
@ -157,9 +145,7 @@ func (s *Service) canDispatchAgent(agent string) (bool, string) {
return true, ""
}
// countRunningByAgent counts running workspaces using the in-memory Registry.
//
// n := s.countRunningByAgent("codex")
// n := s.countRunningByAgent("codex")
func (s *Service) countRunningByAgent(agent string) int {
var runtime *core.Core
if s.ServiceRuntime != nil {
@ -180,9 +166,7 @@ func (s *Service) countRunningByAgent(agent string) int {
return count
}
// countRunningByModel counts running workspaces for a specific `agent:model`.
//
// n := s.countRunningByModel("codex:gpt-5.4")
// n := s.countRunningByModel("codex:gpt-5.4")
func (s *Service) countRunningByModel(agent string) int {
var runtime *core.Core
if s.ServiceRuntime != nil {
@ -203,9 +187,7 @@ func (s *Service) countRunningByModel(agent string) int {
return count
}
// drainQueue fills any free concurrency slots from queued workspaces.
//
// s.drainQueue()
// s.drainQueue()
func (s *Service) drainQueue() {
if s.frozen {
return
@ -336,8 +318,6 @@ func (s *Service) delayForAgent(agent string) time.Duration {
return time.Duration(rate.SustainedDelay) * time.Second
}
// --- Helpers ---
func baseAgent(agent string) string {
return core.SplitN(agent, ":", 2)[0]
}

View file

@ -250,8 +250,6 @@ func (s *Service) handleWorkspaceQuery(_ *core.Core, query core.Query) core.Resu
return core.Result{Value: s.workspaces, OK: true}
}
// --- Actions ---
func (s *Service) actionDispatch(_ context.Context, options core.Options) core.Result {
if s.frozen {
return core.Result{Value: core.E("runner.actionDispatch", "queue is frozen", nil), OK: false}
@ -342,8 +340,6 @@ func (s *Service) actionPoke(_ context.Context, _ core.Options) core.Result {
return core.Result{OK: true}
}
// --- Queue runner ---
func (s *Service) startRunner() {
s.pokeCh = make(chan struct{}, 1)
@ -369,8 +365,6 @@ func (s *Service) runLoop() {
}
}
// --- Workspace hydration ---
func (s *Service) hydrateWorkspaces() {
if s.workspaces == nil {
s.workspaces = core.NewRegistry[*WorkspaceStatus]()
@ -392,8 +386,6 @@ func (s *Service) hydrateWorkspaces() {
}
}
// --- Types ---
// AgentNotification is the channel payload sent on `agent.status`.
//
// n := runner.AgentNotification{
@ -419,9 +411,7 @@ type WorkspaceQuery struct {
Status string
}
// WorkspaceStatus tracks the state of an agent workspace.
//
// workspaceStatus := &runner.WorkspaceStatus{Status: "running", Agent: "codex", Repo: "go-io", PID: 12345}
// workspaceStatus := &runner.WorkspaceStatus{Status: "running", Agent: "codex", Repo: "go-io", PID: 12345}
type WorkspaceStatus struct {
Status string `json:"status"`
Agent string `json:"agent"`