From f11d1d47a1ad417f76163a1754c1eca1c55a002d Mon Sep 17 00:00:00 2001 From: Virgil Date: Mon, 30 Mar 2026 21:11:06 +0000 Subject: [PATCH] fix(ax): continue AX naming cleanup Co-Authored-By: Virgil --- cmd/core-agent/main.go | 22 +-- pkg/agentic/actions.go | 244 +++++++++++++++--------------- pkg/agentic/auto_pr.go | 52 +++---- pkg/agentic/commands.go | 96 ++++++------ pkg/agentic/commands_forge.go | 82 +++++----- pkg/agentic/commands_workspace.go | 30 ++-- pkg/agentic/dispatch.go | 70 ++++----- pkg/agentic/handlers.go | 20 +-- pkg/agentic/pr.go | 60 ++++---- pkg/agentic/process_register.go | 38 ++--- pkg/agentic/queue.go | 64 ++++---- pkg/agentic/resume.go | 26 ++-- pkg/agentic/verify.go | 80 +++++----- pkg/brain/brain.go | 6 +- pkg/brain/direct.go | 26 ++-- pkg/brain/messaging.go | 10 +- pkg/monitor/harvest.go | 50 +++--- pkg/monitor/monitor.go | 20 +-- pkg/runner/paths.go | 16 +- pkg/runner/queue.go | 64 ++++---- pkg/runner/runner.go | 118 +++++++-------- pkg/setup/service.go | 6 +- pkg/setup/setup.go | 66 ++++---- 23 files changed, 633 insertions(+), 633 deletions(-) diff --git a/cmd/core-agent/main.go b/cmd/core-agent/main.go index a2878e9..bce63bd 100644 --- a/cmd/core-agent/main.go +++ b/cmd/core-agent/main.go @@ -28,7 +28,7 @@ func main() { // core.Println(c.App().Name) // "core-agent" // core.Println(c.App().Version) // "dev" or linked version func newCoreAgent() *core.Core { - c := core.New( + coreApp := core.New( core.WithOptions(core.NewOptions(core.Option{Key: "name", Value: "core-agent"})), core.WithService(agentic.ProcessRegister), core.WithService(agentic.Register), @@ -37,15 +37,15 @@ func newCoreAgent() *core.Core { core.WithService(brain.Register), core.WithService(registerMCPService), ) - c.App().Version = appVersion() + coreApp.App().Version = appVersion() - c.Cli().SetBanner(func(_ *core.Cli) string { - return core.Concat("core-agent ", c.App().Version, " — agentic orchestration for the Core ecosystem") + coreApp.Cli().SetBanner(func(_ *core.Cli) string { + return core.Concat("core-agent ", coreApp.App().Version, " — agentic orchestration for the Core ecosystem") }) - registerAppCommands(c) + registerAppCommands(coreApp) - return c + return coreApp } // appVersion resolves the build version injected at link time. @@ -69,19 +69,19 @@ func runCoreAgent() error { // runApp starts services, runs the CLI with explicit args, then shuts down. // // err := runApp(c, []string{"version"}) -func runApp(c *core.Core, cliArgs []string) error { - if c == nil { +func runApp(coreApp *core.Core, cliArgs []string) error { + if coreApp == nil { return core.E("main.runApp", "core is required", nil) } - defer c.ServiceShutdown(context.Background()) + defer coreApp.ServiceShutdown(context.Background()) - result := c.ServiceStartup(c.Context(), nil) + result := coreApp.ServiceStartup(coreApp.Context(), nil) if !result.OK { return resultError("main.runApp", "startup failed", result) } - if cli := c.Cli(); cli != nil { + if cli := coreApp.Cli(); cli != nil { result = cli.Run(cliArgs...) if !result.OK { return resultError("main.runApp", "cli failed", result) diff --git a/pkg/agentic/actions.go b/pkg/agentic/actions.go index 1491826..75c5a66 100644 --- a/pkg/agentic/actions.go +++ b/pkg/agentic/actions.go @@ -4,7 +4,7 @@ // Each handler adapts (ctx, Options) → Result to call the existing MCP tool method. // Registered during OnStartup — the Action registry IS the capability map. // -// c.Action("agentic.dispatch").Run(ctx, opts) +// c.Action("agentic.dispatch").Run(ctx, options) // c.Actions() // all registered capabilities package agentic @@ -21,16 +21,16 @@ import ( // handleDispatch dispatches a subagent to work on a repo task. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleDispatch(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handleDispatch(ctx context.Context, options core.Options) core.Result { input := DispatchInput{ - Repo: opts.String("repo"), - Task: opts.String("task"), - Agent: opts.String("agent"), - Issue: opts.Int("issue"), + Repo: options.String("repo"), + Task: options.String("task"), + Agent: options.String("agent"), + Issue: options.Int("issue"), } _, out, err := s.dispatch(ctx, nil, input) if err != nil { @@ -41,15 +41,15 @@ func (s *PrepSubsystem) handleDispatch(ctx context.Context, opts core.Options) c // handlePrep prepares a workspace without dispatching an agent. // -// r := 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}, // )) -func (s *PrepSubsystem) handlePrep(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handlePrep(ctx context.Context, options core.Options) core.Result { input := PrepInput{ - Repo: opts.String("repo"), - Org: opts.String("org"), - Issue: opts.Int("issue"), + Repo: options.String("repo"), + Org: options.String("org"), + Issue: options.Int("issue"), } _, out, err := s.prepWorkspace(ctx, nil, input) if err != nil { @@ -60,12 +60,12 @@ func (s *PrepSubsystem) handlePrep(ctx context.Context, opts core.Options) core. // handleStatus lists workspace statuses. // -// r := c.Action("agentic.status").Run(ctx, core.NewOptions()) -func (s *PrepSubsystem) handleStatus(ctx context.Context, opts core.Options) core.Result { +// result := c.Action("agentic.status").Run(ctx, core.NewOptions()) +func (s *PrepSubsystem) handleStatus(ctx context.Context, options core.Options) core.Result { input := StatusInput{ - Workspace: opts.String("workspace"), - Limit: opts.Int("limit"), - Status: opts.String("status"), + Workspace: options.String("workspace"), + Limit: options.Int("limit"), + Status: options.String("status"), } _, out, err := s.status(ctx, nil, input) if err != nil { @@ -76,13 +76,13 @@ func (s *PrepSubsystem) handleStatus(ctx context.Context, opts core.Options) cor // handleResume resumes a blocked workspace. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleResume(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handleResume(ctx context.Context, options core.Options) core.Result { input := ResumeInput{ - Workspace: opts.String("workspace"), - Answer: opts.String("answer"), + Workspace: options.String("workspace"), + Answer: options.String("answer"), } _, out, err := s.resume(ctx, nil, input) if err != nil { @@ -93,11 +93,11 @@ func (s *PrepSubsystem) handleResume(ctx context.Context, opts core.Options) cor // handleScan scans forge repos for actionable issues. // -// r := c.Action("agentic.scan").Run(ctx, core.NewOptions()) -func (s *PrepSubsystem) handleScan(ctx context.Context, opts core.Options) core.Result { +// result := c.Action("agentic.scan").Run(ctx, core.NewOptions()) +func (s *PrepSubsystem) handleScan(ctx context.Context, options core.Options) core.Result { input := ScanInput{ - Org: opts.String("org"), - Limit: opts.Int("limit"), + Org: options.String("org"), + Limit: options.Int("limit"), } _, out, err := s.scan(ctx, nil, input) if err != nil { @@ -108,15 +108,15 @@ func (s *PrepSubsystem) handleScan(ctx context.Context, opts core.Options) core. // handleWatch watches a workspace for completion. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleWatch(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handleWatch(ctx context.Context, options core.Options) core.Result { input := WatchInput{ - PollInterval: opts.Int("poll_interval"), - Timeout: opts.Int("timeout"), + PollInterval: options.Int("poll_interval"), + Timeout: options.Int("timeout"), } - if workspace := opts.String("workspace"); workspace != "" { + if workspace := options.String("workspace"); workspace != "" { input.Workspaces = []string{workspace} } _, out, err := s.watch(ctx, nil, input) @@ -128,83 +128,83 @@ func (s *PrepSubsystem) handleWatch(ctx context.Context, opts core.Options) core // handlePrompt reads an embedded prompt by slug. // -// r := c.Action("agentic.prompt").Run(ctx, core.NewOptions( +// result := c.Action("agentic.prompt").Run(ctx, core.NewOptions( // core.Option{Key: "slug", Value: "coding"}, // )) -func (s *PrepSubsystem) handlePrompt(_ context.Context, opts core.Options) core.Result { - return lib.Prompt(opts.String("slug")) +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. // -// r := c.Action("agentic.task").Run(ctx, core.NewOptions( +// result := c.Action("agentic.task").Run(ctx, core.NewOptions( // core.Option{Key: "slug", Value: "bug-fix"}, // )) -func (s *PrepSubsystem) handleTask(_ context.Context, opts core.Options) core.Result { - return lib.Task(opts.String("slug")) +func (s *PrepSubsystem) handleTask(_ context.Context, options core.Options) core.Result { + return lib.Task(options.String("slug")) } // handleFlow reads an embedded flow by slug. // -// r := c.Action("agentic.flow").Run(ctx, core.NewOptions( +// result := c.Action("agentic.flow").Run(ctx, core.NewOptions( // core.Option{Key: "slug", Value: "go"}, // )) -func (s *PrepSubsystem) handleFlow(_ context.Context, opts core.Options) core.Result { - return lib.Flow(opts.String("slug")) +func (s *PrepSubsystem) handleFlow(_ context.Context, options core.Options) core.Result { + return lib.Flow(options.String("slug")) } // handlePersona reads an embedded persona by path. // -// r := 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"}, // )) -func (s *PrepSubsystem) handlePersona(_ context.Context, opts core.Options) core.Result { - return lib.Persona(opts.String("path")) +func (s *PrepSubsystem) handlePersona(_ context.Context, options core.Options) core.Result { + return lib.Persona(options.String("path")) } // --- Pipeline --- // handleComplete runs the named completion task. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleComplete(ctx context.Context, opts core.Options) core.Result { - return s.Core().Task("agent.completion").Run(ctx, s.Core(), opts) +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. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleQA(ctx context.Context, opts core.Options) core.Result { +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") { return core.Result{Value: true, OK: true} } - wsDir := opts.String("workspace") + wsDir := options.String("workspace") if wsDir == "" { return core.Result{Value: core.E("agentic.qa", "workspace is required", nil), OK: false} } passed := s.runQA(wsDir) if !passed { if result := ReadStatusResult(wsDir); result.OK { - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if ok { - st.Status = "failed" - st.Question = "QA check failed — build or tests did not pass" - writeStatusResult(wsDir, st) + workspaceStatus.Status = "failed" + workspaceStatus.Question = "QA check failed — build or tests did not pass" + writeStatusResult(wsDir, workspaceStatus) } } } // Emit QA result for observability (monitor picks this up) if s.ServiceRuntime != nil { result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) repo := "" if ok { - repo = st.Repo + repo = workspaceStatus.Repo } s.Core().ACTION(messages.QAResult{ Workspace: WorkspaceName(wsDir), @@ -217,14 +217,14 @@ func (s *PrepSubsystem) handleQA(ctx context.Context, opts core.Options) core.Re // handleAutoPR creates a PR for a completed workspace. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleAutoPR(ctx context.Context, opts core.Options) core.Result { +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} } - wsDir := opts.String("workspace") + wsDir := options.String("workspace") if wsDir == "" { return core.Result{Value: core.E("agentic.auto-pr", "workspace is required", nil), OK: false} } @@ -233,13 +233,13 @@ func (s *PrepSubsystem) handleAutoPR(ctx context.Context, opts core.Options) cor // Emit PRCreated for observability if s.ServiceRuntime != nil { result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) - if ok && st.PRURL != "" { + workspaceStatus, ok := workspaceStatusValue(result) + if ok && workspaceStatus.PRURL != "" { s.Core().ACTION(messages.PRCreated{ - Repo: st.Repo, - Branch: st.Branch, - PRURL: st.PRURL, - PRNum: extractPRNumber(st.PRURL), + Repo: workspaceStatus.Repo, + Branch: workspaceStatus.Branch, + PRURL: workspaceStatus.PRURL, + PRNum: extractPRNumber(workspaceStatus.PRURL), }) } } @@ -248,14 +248,14 @@ func (s *PrepSubsystem) handleAutoPR(ctx context.Context, opts core.Options) cor // handleVerify verifies and auto-merges a PR. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleVerify(ctx context.Context, opts core.Options) core.Result { +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} } - wsDir := opts.String("workspace") + wsDir := options.String("workspace") if wsDir == "" { return core.Result{Value: core.E("agentic.verify", "workspace is required", nil), OK: false} } @@ -264,20 +264,20 @@ func (s *PrepSubsystem) handleVerify(ctx context.Context, opts core.Options) cor // Emit merge/review events for observability if s.ServiceRuntime != nil { result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if ok { - if st.Status == "merged" { + if workspaceStatus.Status == "merged" { s.Core().ACTION(messages.PRMerged{ - Repo: st.Repo, - PRURL: st.PRURL, - PRNum: extractPRNumber(st.PRURL), + Repo: workspaceStatus.Repo, + PRURL: workspaceStatus.PRURL, + PRNum: extractPRNumber(workspaceStatus.PRURL), }) - } else if st.Question != "" { + } else if workspaceStatus.Question != "" { s.Core().ACTION(messages.PRNeedsReview{ - Repo: st.Repo, - PRURL: st.PRURL, - PRNum: extractPRNumber(st.PRURL), - Reason: st.Question, + Repo: workspaceStatus.Repo, + PRURL: workspaceStatus.PRURL, + PRNum: extractPRNumber(workspaceStatus.PRURL), + Reason: workspaceStatus.Question, }) } } @@ -287,11 +287,11 @@ func (s *PrepSubsystem) handleVerify(ctx context.Context, opts core.Options) cor // handleIngest creates issues from agent findings. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleIngest(ctx context.Context, opts core.Options) core.Result { - wsDir := opts.String("workspace") +func (s *PrepSubsystem) handleIngest(ctx context.Context, options core.Options) core.Result { + wsDir := options.String("workspace") if wsDir == "" { return core.Result{Value: core.E("agentic.ingest", "workspace is required", nil), OK: false} } @@ -301,20 +301,20 @@ func (s *PrepSubsystem) handleIngest(ctx context.Context, opts core.Options) cor // handlePoke drains the dispatch queue. // -// r := c.Action("agentic.poke").Run(ctx, core.NewOptions()) -func (s *PrepSubsystem) handlePoke(ctx context.Context, opts core.Options) core.Result { +// result := c.Action("agentic.poke").Run(ctx, core.NewOptions()) +func (s *PrepSubsystem) handlePoke(ctx context.Context, _ core.Options) core.Result { s.Poke() return core.Result{OK: true} } // handleMirror mirrors agent branches to GitHub. // -// r := c.Action("agentic.mirror").Run(ctx, core.NewOptions( +// result := c.Action("agentic.mirror").Run(ctx, core.NewOptions( // core.Option{Key: "repo", Value: "go-io"}, // )) -func (s *PrepSubsystem) handleMirror(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handleMirror(ctx context.Context, options core.Options) core.Result { input := MirrorInput{ - Repo: opts.String("repo"), + Repo: options.String("repo"), } _, out, err := s.mirror(ctx, nil, input) if err != nil { @@ -327,74 +327,74 @@ func (s *PrepSubsystem) handleMirror(ctx context.Context, opts core.Options) cor // handleIssueGet retrieves a forge issue. // -// r := c.Action("agentic.issue.get").Run(ctx, core.NewOptions( +// result := c.Action("agentic.issue.get").Run(ctx, core.NewOptions( // core.Option{Key: "repo", Value: "go-io"}, // core.Option{Key: "number", Value: "42"}, // )) -func (s *PrepSubsystem) handleIssueGet(ctx context.Context, opts core.Options) core.Result { - return s.cmdIssueGet(opts) +func (s *PrepSubsystem) handleIssueGet(ctx context.Context, options core.Options) core.Result { + return s.cmdIssueGet(options) } // handleIssueList lists forge issues. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleIssueList(ctx context.Context, opts core.Options) core.Result { - return s.cmdIssueList(opts) +func (s *PrepSubsystem) handleIssueList(ctx context.Context, options core.Options) core.Result { + return s.cmdIssueList(options) } // handleIssueCreate creates a forge issue. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleIssueCreate(ctx context.Context, opts core.Options) core.Result { - return s.cmdIssueCreate(opts) +func (s *PrepSubsystem) handleIssueCreate(ctx context.Context, options core.Options) core.Result { + return s.cmdIssueCreate(options) } // handlePRGet retrieves a forge PR. // -// r := c.Action("agentic.pr.get").Run(ctx, core.NewOptions( +// result := c.Action("agentic.pr.get").Run(ctx, core.NewOptions( // core.Option{Key: "_arg", Value: "go-io"}, // core.Option{Key: "number", Value: "12"}, // )) -func (s *PrepSubsystem) handlePRGet(ctx context.Context, opts core.Options) core.Result { - return s.cmdPRGet(opts) +func (s *PrepSubsystem) handlePRGet(ctx context.Context, options core.Options) core.Result { + return s.cmdPRGet(options) } // handlePRList lists forge PRs. // -// r := 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"}, // )) -func (s *PrepSubsystem) handlePRList(ctx context.Context, opts core.Options) core.Result { - return s.cmdPRList(opts) +func (s *PrepSubsystem) handlePRList(ctx context.Context, options core.Options) core.Result { + return s.cmdPRList(options) } // handlePRMerge merges a forge PR. // -// r := c.Action("agentic.pr.merge").Run(ctx, core.NewOptions( +// result := c.Action("agentic.pr.merge").Run(ctx, core.NewOptions( // core.Option{Key: "_arg", Value: "go-io"}, // core.Option{Key: "number", Value: "12"}, // )) -func (s *PrepSubsystem) handlePRMerge(ctx context.Context, opts core.Options) core.Result { - return s.cmdPRMerge(opts) +func (s *PrepSubsystem) handlePRMerge(ctx context.Context, options core.Options) core.Result { + return s.cmdPRMerge(options) } // --- Review --- // handleReviewQueue runs CodeRabbit review on a workspace. // -// r := 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"}, // )) -func (s *PrepSubsystem) handleReviewQueue(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handleReviewQueue(ctx context.Context, options core.Options) core.Result { input := ReviewQueueInput{ - Limit: opts.Int("limit"), - Reviewer: opts.String("reviewer"), - DryRun: opts.Bool("dry_run"), + Limit: options.Int("limit"), + Reviewer: options.String("reviewer"), + DryRun: options.Bool("dry_run"), } _, out, err := s.reviewQueue(ctx, nil, input) if err != nil { @@ -407,15 +407,15 @@ func (s *PrepSubsystem) handleReviewQueue(ctx context.Context, opts core.Options // handleEpic creates an epic (multi-repo task breakdown). // -// r := 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"}, // )) -func (s *PrepSubsystem) handleEpic(ctx context.Context, opts core.Options) core.Result { +func (s *PrepSubsystem) handleEpic(ctx context.Context, options core.Options) core.Result { input := EpicInput{ - Repo: opts.String("repo"), - Org: opts.String("org"), - Title: opts.String("title"), - Body: opts.String("body"), + Repo: options.String("repo"), + Org: options.String("org"), + Title: options.String("title"), + Body: options.String("body"), } _, out, err := s.createEpic(ctx, nil, input) if err != nil { @@ -426,20 +426,20 @@ func (s *PrepSubsystem) handleEpic(ctx context.Context, opts core.Options) core. // handleWorkspaceQuery answers workspace state queries from Core QUERY calls. // -// r := c.QUERY(agentic.WorkspaceQuery{Name: "core/go-io/task-42"}) -// r := c.QUERY(agentic.WorkspaceQuery{Status: "blocked"}) -func (s *PrepSubsystem) handleWorkspaceQuery(_ *core.Core, q core.Query) core.Result { - wq, ok := q.(WorkspaceQuery) +// result := c.QUERY(agentic.WorkspaceQuery{Name: "core/go-io/task-42"}) +// result := c.QUERY(agentic.WorkspaceQuery{Status: "blocked"}) +func (s *PrepSubsystem) handleWorkspaceQuery(_ *core.Core, query core.Query) core.Result { + workspaceQuery, ok := query.(WorkspaceQuery) if !ok { return core.Result{} } - if wq.Name != "" { - return s.workspaces.Get(wq.Name) + if workspaceQuery.Name != "" { + return s.workspaces.Get(workspaceQuery.Name) } - if wq.Status != "" { + if workspaceQuery.Status != "" { var names []string - s.workspaces.Each(func(name string, st *WorkspaceStatus) { - if st.Status == wq.Status { + s.workspaces.Each(func(name string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status == workspaceQuery.Status { names = append(names, name) } }) diff --git a/pkg/agentic/auto_pr.go b/pkg/agentic/auto_pr.go index 713e500..1610f8b 100644 --- a/pkg/agentic/auto_pr.go +++ b/pkg/agentic/auto_pr.go @@ -13,8 +13,8 @@ import ( // if the agent made any commits beyond the initial clone. func (s *PrepSubsystem) autoCreatePR(wsDir string) { result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) - if !ok || st.Branch == "" || st.Repo == "" { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.Branch == "" || workspaceStatus.Repo == "" { return } @@ -25,78 +25,78 @@ func (s *PrepSubsystem) autoCreatePR(wsDir string) { // PRs target dev — agents never merge directly to main base := "dev" - r := process.RunIn(ctx, repoDir, "git", "log", "--oneline", core.Concat("origin/", base, "..HEAD")) - if !r.OK { + processResult := process.RunIn(ctx, repoDir, "git", "log", "--oneline", core.Concat("origin/", base, "..HEAD")) + if !processResult.OK { return } - out := core.Trim(r.Value.(string)) + out := core.Trim(processResult.Value.(string)) if out == "" { return } commitCount := len(core.Split(out, "\n")) - org := st.Org + org := workspaceStatus.Org if org == "" { org = "core" } // Push the branch to forge - forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, st.Repo) - if !process.RunIn(ctx, repoDir, "git", "push", forgeRemote, st.Branch).OK { + forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, workspaceStatus.Repo) + if !process.RunIn(ctx, repoDir, "git", "push", forgeRemote, workspaceStatus.Branch).OK { if result := ReadStatusResult(wsDir); result.OK { - st2, ok := workspaceStatusValue(result) + workspaceStatusUpdate, ok := workspaceStatusValue(result) if !ok { return } - st2.Question = "PR push failed" - writeStatusResult(wsDir, st2) + workspaceStatusUpdate.Question = "PR push failed" + writeStatusResult(wsDir, workspaceStatusUpdate) } return } // Create PR via Forge API - title := core.Sprintf("[agent/%s] %s", st.Agent, truncate(st.Task, 60)) - body := s.buildAutoPRBody(st, commitCount) + title := core.Sprintf("[agent/%s] %s", workspaceStatus.Agent, truncate(workspaceStatus.Task, 60)) + body := s.buildAutoPRBody(workspaceStatus, commitCount) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - prURL, _, err := s.forgeCreatePR(ctx, org, st.Repo, st.Branch, base, title, body) + prURL, _, err := s.forgeCreatePR(ctx, org, workspaceStatus.Repo, workspaceStatus.Branch, base, title, body) if err != nil { if result := ReadStatusResult(wsDir); result.OK { - st2, ok := workspaceStatusValue(result) + workspaceStatusUpdate, ok := workspaceStatusValue(result) if !ok { return } - st2.Question = core.Sprintf("PR creation failed: %v", err) - writeStatusResult(wsDir, st2) + workspaceStatusUpdate.Question = core.Sprintf("PR creation failed: %v", err) + writeStatusResult(wsDir, workspaceStatusUpdate) } return } // Update status with PR URL if result := ReadStatusResult(wsDir); result.OK { - st2, ok := workspaceStatusValue(result) + workspaceStatusUpdate, ok := workspaceStatusValue(result) if !ok { return } - st2.PRURL = prURL - writeStatusResult(wsDir, st2) + workspaceStatusUpdate.PRURL = prURL + writeStatusResult(wsDir, workspaceStatusUpdate) } } -func (s *PrepSubsystem) buildAutoPRBody(st *WorkspaceStatus, commits int) string { +func (s *PrepSubsystem) buildAutoPRBody(workspaceStatus *WorkspaceStatus, commits int) string { b := core.NewBuilder() b.WriteString("## Task\n\n") - b.WriteString(st.Task) + b.WriteString(workspaceStatus.Task) b.WriteString("\n\n") - if st.Issue > 0 { - b.WriteString(core.Sprintf("Closes #%d\n\n", st.Issue)) + if workspaceStatus.Issue > 0 { + b.WriteString(core.Sprintf("Closes #%d\n\n", workspaceStatus.Issue)) } - b.WriteString(core.Sprintf("**Agent:** %s\n", st.Agent)) + b.WriteString(core.Sprintf("**Agent:** %s\n", workspaceStatus.Agent)) b.WriteString(core.Sprintf("**Commits:** %d\n", commits)) - b.WriteString(core.Sprintf("**Branch:** `%s`\n", st.Branch)) + b.WriteString(core.Sprintf("**Branch:** `%s`\n", workspaceStatus.Branch)) b.WriteString("\n---\n") b.WriteString("Auto-created by core-agent dispatch system.\n") b.WriteString("Co-Authored-By: Virgil \n") diff --git a/pkg/agentic/commands.go b/pkg/agentic/commands.go index 72058aa..30540df 100644 --- a/pkg/agentic/commands.go +++ b/pkg/agentic/commands.go @@ -34,16 +34,16 @@ func (s *PrepSubsystem) commandContext() context.Context { return context.Background() } -func (s *PrepSubsystem) cmdRunTask(opts core.Options) core.Result { - return s.runTask(s.commandContext(), opts) +func (s *PrepSubsystem) cmdRunTask(options core.Options) core.Result { + return s.runTask(s.commandContext(), options) } -func (s *PrepSubsystem) runTask(ctx context.Context, opts core.Options) core.Result { - repo := opts.String("repo") - agent := opts.String("agent") - task := opts.String("task") - issueStr := opts.String("issue") - org := opts.String("org") +func (s *PrepSubsystem) runTask(ctx context.Context, options core.Options) core.Result { + repo := options.String("repo") + agent := options.String("agent") + task := options.String("task") + issueStr := options.String("issue") + org := options.String("org") if repo == "" || task == "" { core.Print(nil, "usage: core-agent run task --repo= --task=\"...\" --agent=codex [--issue=N] [--org=core]") @@ -98,40 +98,40 @@ func (s *PrepSubsystem) cmdOrchestrator(_ core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdPrep(opts core.Options) core.Result { - repo := opts.String("_arg") +func (s *PrepSubsystem) cmdPrep(options core.Options) core.Result { + repo := options.String("_arg") if repo == "" { core.Print(nil, "usage: core-agent prep --issue=N|--pr=N|--branch=X --task=\"...\"") return core.Result{Value: core.E("agentic.cmdPrep", "repo is required", nil), OK: false} } - input := PrepInput{ + prepInput := PrepInput{ Repo: repo, - Org: opts.String("org"), - Task: opts.String("task"), - Template: opts.String("template"), - Persona: opts.String("persona"), - DryRun: opts.Bool("dry-run"), + Org: options.String("org"), + Task: options.String("task"), + Template: options.String("template"), + Persona: options.String("persona"), + DryRun: options.Bool("dry-run"), } - if v := opts.String("issue"); v != "" { - input.Issue = parseIntStr(v) + if value := options.String("issue"); value != "" { + prepInput.Issue = parseIntStr(value) } - if v := opts.String("pr"); v != "" { - input.PR = parseIntStr(v) + if value := options.String("pr"); value != "" { + prepInput.PR = parseIntStr(value) } - if v := opts.String("branch"); v != "" { - input.Branch = v + if value := options.String("branch"); value != "" { + prepInput.Branch = value } - if v := opts.String("tag"); v != "" { - input.Tag = v + if value := options.String("tag"); value != "" { + prepInput.Tag = value } - if input.Issue == 0 && input.PR == 0 && input.Branch == "" && input.Tag == "" { - input.Branch = "dev" + if prepInput.Issue == 0 && prepInput.PR == 0 && prepInput.Branch == "" && prepInput.Tag == "" { + prepInput.Branch = "dev" } - _, out, err := s.TestPrepWorkspace(context.Background(), input) + _, out, err := s.TestPrepWorkspace(context.Background(), prepInput) if err != nil { core.Print(nil, "error: %v", err) return core.Result{Value: err, OK: false} @@ -151,11 +151,11 @@ func (s *PrepSubsystem) cmdPrep(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdStatus(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdStatus(_ core.Options) core.Result { wsRoot := WorkspaceRoot() fsys := s.Core().Fs() - r := fsys.List(wsRoot) - if !r.OK { + listResult := fsys.List(wsRoot) + if !listResult.OK { core.Print(nil, "no workspaces found at %s", wsRoot) return core.Result{OK: true} } @@ -172,33 +172,33 @@ func (s *PrepSubsystem) cmdStatus(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdPrompt(opts core.Options) core.Result { - repo := opts.String("_arg") +func (s *PrepSubsystem) cmdPrompt(options core.Options) core.Result { + repo := options.String("_arg") if repo == "" { core.Print(nil, "usage: core-agent prompt --task=\"...\"") return core.Result{Value: core.E("agentic.cmdPrompt", "repo is required", nil), OK: false} } - org := opts.String("org") + org := options.String("org") if org == "" { org = "core" } - task := opts.String("task") + task := options.String("task") if task == "" { task = "Review and report findings" } repoPath := core.JoinPath(HomeDir(), "Code", org, repo) - input := PrepInput{ + prepInput := PrepInput{ Repo: repo, Org: org, Task: task, - Template: opts.String("template"), - Persona: opts.String("persona"), + Template: options.String("template"), + Persona: options.String("persona"), } - prompt, memories, consumers := s.TestBuildPrompt(context.Background(), input, "dev", repoPath) + prompt, memories, consumers := s.TestBuildPrompt(context.Background(), prepInput, "dev", repoPath) core.Print(nil, "memories: %d", memories) core.Print(nil, "consumers: %d", consumers) core.Print(nil, "") @@ -206,29 +206,29 @@ func (s *PrepSubsystem) cmdPrompt(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdExtract(opts core.Options) core.Result { - tmpl := opts.String("_arg") - if tmpl == "" { - tmpl = "default" +func (s *PrepSubsystem) cmdExtract(options core.Options) core.Result { + templateName := options.String("_arg") + if templateName == "" { + templateName = "default" } - target := opts.String("target") + target := options.String("target") if target == "" { target = core.JoinPath(WorkspaceRoot(), "test-extract") } - data := &lib.WorkspaceData{ + workspaceData := &lib.WorkspaceData{ Repo: "test-repo", Branch: "dev", Task: "test extraction", Agent: "codex", } - core.Print(nil, "extracting template %q to %s", tmpl, target) - if result := lib.ExtractWorkspace(tmpl, target, data); !result.OK { + core.Print(nil, "extracting template %q to %s", templateName, target) + if result := lib.ExtractWorkspace(templateName, target, workspaceData); !result.OK { if err, ok := result.Value.(error); ok { - return core.Result{Value: core.E("agentic.cmdExtract", core.Concat("extract workspace template ", tmpl), err), OK: false} + return core.Result{Value: core.E("agentic.cmdExtract", core.Concat("extract workspace template ", templateName), err), OK: false} } - return core.Result{Value: core.E("agentic.cmdExtract", core.Concat("extract workspace template ", tmpl), nil), OK: false} + return core.Result{Value: core.E("agentic.cmdExtract", core.Concat("extract workspace template ", templateName), nil), OK: false} } fsys := s.Core().Fs() diff --git a/pkg/agentic/commands_forge.go b/pkg/agentic/commands_forge.go index ede2952..cf6da53 100644 --- a/pkg/agentic/commands_forge.go +++ b/pkg/agentic/commands_forge.go @@ -71,14 +71,14 @@ func pullRequestAuthor(pr pullRequestView) string { return pr.User.Login } -// parseForgeArgs extracts org and repo from opts. -func parseForgeArgs(opts core.Options) (org, repo string, num int64) { - org = opts.String("org") +// parseForgeArgs extracts org and repo from options. +func parseForgeArgs(options core.Options) (org, repo string, num int64) { + org = options.String("org") if org == "" { org = "core" } - repo = opts.String("_arg") - if v := opts.String("number"); v != "" { + repo = options.String("_arg") + if v := options.String("number"); v != "" { num, _ = strconv.ParseInt(v, 10, 64) } return @@ -100,9 +100,9 @@ func (s *PrepSubsystem) registerForgeCommands() { c.Command("repo/list", core.Command{Description: "List Forge repos for an org", Action: s.cmdRepoList}) } -func (s *PrepSubsystem) cmdIssueGet(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdIssueGet(options core.Options) core.Result { ctx := context.Background() - org, repo, num := parseForgeArgs(opts) + org, repo, num := parseForgeArgs(options) if repo == "" || num == 0 { core.Print(nil, "usage: core-agent issue get --number=N [--org=core]") return core.Result{Value: core.E("agentic.cmdIssueGet", "repo and number are required", nil), OK: false} @@ -123,9 +123,9 @@ func (s *PrepSubsystem) cmdIssueGet(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdIssueList(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdIssueList(options core.Options) core.Result { ctx := context.Background() - org, repo, _ := parseForgeArgs(opts) + org, repo, _ := parseForgeArgs(options) if repo == "" { core.Print(nil, "usage: core-agent issue list [--org=core]") return core.Result{Value: core.E("agentic.cmdIssueList", "repo is required", nil), OK: false} @@ -145,10 +145,10 @@ func (s *PrepSubsystem) cmdIssueList(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdIssueComment(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdIssueComment(options core.Options) core.Result { ctx := context.Background() - org, repo, num := parseForgeArgs(opts) - body := opts.String("body") + org, repo, num := parseForgeArgs(options) + body := options.String("body") if repo == "" || num == 0 || body == "" { core.Print(nil, "usage: core-agent issue comment --number=N --body=\"text\" [--org=core]") return core.Result{Value: core.E("agentic.cmdIssueComment", "repo, number, and body are required", nil), OK: false} @@ -162,15 +162,15 @@ func (s *PrepSubsystem) cmdIssueComment(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdIssueCreate(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdIssueCreate(options core.Options) core.Result { ctx := context.Background() - org, repo, _ := parseForgeArgs(opts) - title := opts.String("title") - body := opts.String("body") - labels := opts.String("labels") - milestone := opts.String("milestone") - assignee := opts.String("assignee") - ref := opts.String("ref") + org, repo, _ := parseForgeArgs(options) + title := options.String("title") + body := options.String("body") + labels := options.String("labels") + milestone := options.String("milestone") + assignee := options.String("assignee") + ref := options.String("ref") if repo == "" || title == "" { core.Print(nil, "usage: core-agent issue create --title=\"...\" [--body=\"...\"] [--labels=\"agentic,bug\"] [--milestone=\"v0.2.0\"] [--assignee=virgil] [--ref=dev] [--org=core]") return core.Result{Value: core.E("agentic.cmdIssueCreate", "repo and title are required", nil), OK: false} @@ -219,9 +219,9 @@ func (s *PrepSubsystem) cmdIssueCreate(opts core.Options) core.Result { return core.Result{Value: issue.Index, OK: true} } -func (s *PrepSubsystem) cmdPRGet(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdPRGet(options core.Options) core.Result { ctx := context.Background() - org, repo, num := parseForgeArgs(opts) + org, repo, num := parseForgeArgs(options) if repo == "" || num == 0 { core.Print(nil, "usage: core-agent pr get --number=N [--org=core]") return core.Result{Value: core.E("agentic.cmdPRGet", "repo and number are required", nil), OK: false} @@ -245,9 +245,9 @@ func (s *PrepSubsystem) cmdPRGet(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdPRList(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdPRList(options core.Options) core.Result { ctx := context.Background() - org, repo, _ := parseForgeArgs(opts) + org, repo, _ := parseForgeArgs(options) if repo == "" { core.Print(nil, "usage: core-agent pr list [--org=core]") return core.Result{Value: core.E("agentic.cmdPRList", "repo is required", nil), OK: false} @@ -267,10 +267,10 @@ func (s *PrepSubsystem) cmdPRList(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdPRMerge(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdPRMerge(options core.Options) core.Result { ctx := context.Background() - org, repo, num := parseForgeArgs(opts) - method := opts.String("method") + org, repo, num := parseForgeArgs(options) + method := options.String("method") if method == "" { method = "merge" } @@ -286,30 +286,30 @@ func (s *PrepSubsystem) cmdPRMerge(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdRepoGet(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdRepoGet(options core.Options) core.Result { ctx := context.Background() - org, repo, _ := parseForgeArgs(opts) + org, repo, _ := parseForgeArgs(options) if repo == "" { core.Print(nil, "usage: core-agent repo get [--org=core]") return core.Result{Value: core.E("agentic.cmdRepoGet", "repo is required", nil), OK: false} } - r, err := s.forge.Repos.Get(ctx, forge.Params{"owner": org, "repo": repo}) + repositoryResult, err := s.forge.Repos.Get(ctx, forge.Params{"owner": org, "repo": repo}) if err != nil { core.Print(nil, "error: %v", err) return core.Result{Value: err, OK: false} } - core.Print(nil, "%s/%s", r.Owner.UserName, r.Name) - core.Print(nil, " description: %s", r.Description) - core.Print(nil, " default: %s", r.DefaultBranch) - core.Print(nil, " private: %v", r.Private) - core.Print(nil, " archived: %v", r.Archived) - core.Print(nil, " url: %s", r.HTMLURL) + core.Print(nil, "%s/%s", repositoryResult.Owner.UserName, repositoryResult.Name) + core.Print(nil, " description: %s", repositoryResult.Description) + core.Print(nil, " default: %s", repositoryResult.DefaultBranch) + core.Print(nil, " private: %v", repositoryResult.Private) + core.Print(nil, " archived: %v", repositoryResult.Archived) + core.Print(nil, " url: %s", repositoryResult.HTMLURL) return core.Result{OK: true} } -func (s *PrepSubsystem) cmdRepoList(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdRepoList(options core.Options) core.Result { ctx := context.Background() - org := opts.String("org") + org := options.String("org") if org == "" { org = "core" } @@ -318,12 +318,12 @@ func (s *PrepSubsystem) cmdRepoList(opts core.Options) core.Result { core.Print(nil, "error: %v", err) return core.Result{Value: err, OK: false} } - for _, r := range repos { + for _, repository := range repos { archived := "" - if r.Archived { + if repository.Archived { archived = " (archived)" } - core.Print(nil, " %-30s %s%s", r.Name, r.Description, archived) + core.Print(nil, " %-30s %s%s", repository.Name, repository.Description, archived) } core.Print(nil, "\n %d repos", len(repos)) return core.Result{OK: true} diff --git a/pkg/agentic/commands_workspace.go b/pkg/agentic/commands_workspace.go index f3c311d..df9e977 100644 --- a/pkg/agentic/commands_workspace.go +++ b/pkg/agentic/commands_workspace.go @@ -25,11 +25,11 @@ func (s *PrepSubsystem) cmdWorkspaceList(_ core.Options) core.Result { wsDir := core.PathDir(sf) wsName := WorkspaceName(wsDir) result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if !ok { continue } - core.Print(nil, " %-8s %-8s %-10s %s", st.Status, st.Agent, st.Repo, wsName) + core.Print(nil, " %-8s %-8s %-10s %s", workspaceStatus.Status, workspaceStatus.Agent, workspaceStatus.Repo, wsName) count++ } if count == 0 { @@ -38,10 +38,10 @@ func (s *PrepSubsystem) cmdWorkspaceList(_ core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdWorkspaceClean(opts core.Options) core.Result { +func (s *PrepSubsystem) cmdWorkspaceClean(options core.Options) core.Result { wsRoot := WorkspaceRoot() fsys := s.Core().Fs() - filter := opts.String("_arg") + filter := options.String("_arg") if filter == "" { filter = "all" } @@ -53,11 +53,11 @@ func (s *PrepSubsystem) cmdWorkspaceClean(opts core.Options) core.Result { wsDir := core.PathDir(sf) wsName := WorkspaceName(wsDir) result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if !ok { continue } - status := st.Status + status := workspaceStatus.Status switch filter { case "all": @@ -93,8 +93,8 @@ func (s *PrepSubsystem) cmdWorkspaceClean(opts core.Options) core.Result { return core.Result{OK: true} } -func (s *PrepSubsystem) cmdWorkspaceDispatch(opts core.Options) core.Result { - repo := opts.String("_arg") +func (s *PrepSubsystem) cmdWorkspaceDispatch(options core.Options) core.Result { + repo := options.String("_arg") if repo == "" { core.Print(nil, "usage: core-agent workspace dispatch --task=\"...\" --issue=N|--pr=N|--branch=X [--agent=codex]") return core.Result{Value: core.E("agentic.cmdWorkspaceDispatch", "repo is required", nil), OK: false} @@ -104,13 +104,13 @@ func (s *PrepSubsystem) cmdWorkspaceDispatch(opts core.Options) core.Result { // not gated by the frozen-queue entitlement. input := DispatchInput{ Repo: repo, - Task: opts.String("task"), - Agent: opts.String("agent"), - Org: opts.String("org"), - Template: opts.String("template"), - Branch: opts.String("branch"), - Issue: parseIntStr(opts.String("issue")), - PR: parseIntStr(opts.String("pr")), + Task: options.String("task"), + Agent: options.String("agent"), + Org: options.String("org"), + Template: options.String("template"), + Branch: options.String("branch"), + Issue: parseIntStr(options.String("issue")), + PR: parseIntStr(options.String("pr")), } _, out, err := s.dispatch(context.Background(), nil, input) if err != nil { diff --git a/pkg/agentic/dispatch.go b/pkg/agentic/dispatch.go index 77c19ed..f7bb38b 100644 --- a/pkg/agentic/dispatch.go +++ b/pkg/agentic/dispatch.go @@ -15,7 +15,7 @@ import ( // workspaceTracker is the interface runner.Service satisfies. // Uses *WorkspaceStatus from agentic — runner imports agentic for the type. type workspaceTracker interface { - TrackWorkspace(name string, st any) + TrackWorkspace(name string, status any) } // DispatchInput is the input for agentic_dispatch. @@ -60,16 +60,16 @@ func (s *PrepSubsystem) registerDispatchTool(server *mcp.Server) { // agentCommand returns the command and args for a given agent type. // Supports model variants: "gemini", "gemini:flash", "codex", "claude", "claude:haiku". func agentCommand(agent, prompt string) (string, []string, error) { - r := agentCommandResult(agent, prompt) - if !r.OK { - err, _ := r.Value.(error) + commandResult := agentCommandResult(agent, prompt) + if !commandResult.OK { + err, _ := commandResult.Value.(error) if err == nil { err = core.E("agentCommand", "failed to resolve command", nil) } return "", nil, err } - result, ok := r.Value.(agentCommandResultValue) + result, ok := commandResult.Value.(agentCommandResultValue) if !ok { return "", nil, core.E("agentCommand", "invalid command result", nil) } @@ -242,8 +242,8 @@ func agentOutputFile(wsDir, agent string) string { // Returns (status, question) — "completed", "blocked", or "failed". func detectFinalStatus(repoDir string, exitCode int, procStatus string) (string, string) { blockedPath := core.JoinPath(repoDir, "BLOCKED.md") - if r := fs.Read(blockedPath); r.OK && core.Trim(r.Value.(string)) != "" { - return "blocked", core.Trim(r.Value.(string)) + if blockedResult := fs.Read(blockedPath); blockedResult.OK && core.Trim(blockedResult.Value.(string)) != "" { + return "blocked", core.Trim(blockedResult.Value.(string)) } if exitCode != 0 || procStatus == "failed" || procStatus == "killed" { question := "" @@ -283,15 +283,15 @@ func (s *PrepSubsystem) startIssueTracking(wsDir string) { return } result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) - if !ok || st.Issue == 0 { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.Issue == 0 { return } - org := st.Org + org := workspaceStatus.Org if org == "" { org = "core" } - s.forge.Issues.StartStopwatch(context.Background(), org, st.Repo, int64(st.Issue)) + s.forge.Issues.StartStopwatch(context.Background(), org, workspaceStatus.Repo, int64(workspaceStatus.Issue)) } // stopIssueTracking stops a Forge stopwatch on the workspace's issue. @@ -300,25 +300,25 @@ func (s *PrepSubsystem) stopIssueTracking(wsDir string) { return } result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) - if !ok || st.Issue == 0 { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.Issue == 0 { return } - org := st.Org + org := workspaceStatus.Org if org == "" { org = "core" } - s.forge.Issues.StopStopwatch(context.Background(), org, st.Repo, int64(st.Issue)) + s.forge.Issues.StopStopwatch(context.Background(), org, workspaceStatus.Repo, int64(workspaceStatus.Issue)) } // broadcastStart emits IPC + audit events for agent start. func (s *PrepSubsystem) broadcastStart(agent, wsDir string) { wsName := WorkspaceName(wsDir) result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) repo := "" if ok { - repo = st.Repo + repo = workspaceStatus.Repo } if s.ServiceRuntime != nil { s.Core().ACTION(messages.AgentStarted{ @@ -334,10 +334,10 @@ func (s *PrepSubsystem) broadcastComplete(agent, wsDir, finalStatus string) { emitCompletionEvent(agent, wsName, finalStatus) if s.ServiceRuntime != nil { result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) repo := "" if ok { - repo = st.Repo + repo = workspaceStatus.Repo } s.Core().ACTION(messages.AgentCompleted{ Agent: agent, Repo: repo, @@ -359,16 +359,16 @@ func (s *PrepSubsystem) onAgentComplete(agent, wsDir, outputFile string, exitCod // Update workspace status (disk + registry) result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if ok { - st.Status = finalStatus - st.PID = 0 - st.Question = question - writeStatusResult(wsDir, st) - s.TrackWorkspace(WorkspaceName(wsDir), st) + workspaceStatus.Status = finalStatus + workspaceStatus.PID = 0 + workspaceStatus.Question = question + writeStatusResult(wsDir, workspaceStatus) + s.TrackWorkspace(WorkspaceName(wsDir), workspaceStatus) // Rate-limit tracking - s.trackFailureRate(agent, finalStatus, st.StartedAt) + s.trackFailureRate(agent, finalStatus, workspaceStatus.StartedAt) } // Forge time tracking @@ -380,7 +380,7 @@ func (s *PrepSubsystem) onAgentComplete(agent, wsDir, outputFile string, exitCod // Run completion pipeline via PerformAsync for successful agents. // Gets ActionTaskStarted/Completed broadcasts + WaitGroup integration for graceful shutdown. // - // c.PerformAsync("agentic.complete", opts) → runs agent.completion Task in background + // c.PerformAsync("agentic.complete", options) → runs agent.completion Task in background if finalStatus == "completed" && s.ServiceRuntime != nil { s.Core().PerformAsync("agentic.complete", core.NewOptions( core.Option{Key: "workspace", Value: wsDir}, @@ -568,13 +568,13 @@ func (s *PrepSubsystem) dispatch(ctx context.Context, req *mcp.CallToolRequest, // Step 2: Ask runner service for permission (frozen + concurrency check). // Runner owns the gate — agentic owns the spawn. if s.ServiceRuntime != nil { - r := s.Core().Action("runner.dispatch").Run(ctx, core.NewOptions( + dispatchResult := s.Core().Action("runner.dispatch").Run(ctx, core.NewOptions( core.Option{Key: "agent", Value: input.Agent}, core.Option{Key: "repo", Value: input.Repo}, )) - if !r.OK { + if !dispatchResult.OK { // Runner denied — queue it - st := &WorkspaceStatus{ + workspaceStatus := &WorkspaceStatus{ Status: "queued", Agent: input.Agent, Repo: input.Repo, @@ -584,9 +584,9 @@ func (s *PrepSubsystem) dispatch(ctx context.Context, req *mcp.CallToolRequest, StartedAt: time.Now(), Runs: 0, } - writeStatusResult(wsDir, st) + writeStatusResult(wsDir, workspaceStatus) if runnerSvc, ok := core.ServiceFor[workspaceTracker](s.Core(), "runner"); ok { - runnerSvc.TrackWorkspace(WorkspaceName(wsDir), st) + runnerSvc.TrackWorkspace(WorkspaceName(wsDir), workspaceStatus) } return nil, DispatchOutput{ Success: true, @@ -604,7 +604,7 @@ func (s *PrepSubsystem) dispatch(ctx context.Context, req *mcp.CallToolRequest, return nil, DispatchOutput{}, err } - st := &WorkspaceStatus{ + workspaceStatus := &WorkspaceStatus{ Status: "running", Agent: input.Agent, Repo: input.Repo, @@ -616,11 +616,11 @@ func (s *PrepSubsystem) dispatch(ctx context.Context, req *mcp.CallToolRequest, StartedAt: time.Now(), Runs: 1, } - writeStatusResult(wsDir, st) + writeStatusResult(wsDir, workspaceStatus) // Track in runner's registry (runner owns workspace state) if s.ServiceRuntime != nil { if runnerSvc, ok := core.ServiceFor[workspaceTracker](s.Core(), "runner"); ok { - runnerSvc.TrackWorkspace(WorkspaceName(wsDir), st) + runnerSvc.TrackWorkspace(WorkspaceName(wsDir), workspaceStatus) } } diff --git a/pkg/agentic/handlers.go b/pkg/agentic/handlers.go index f4d4afc..51a6660 100644 --- a/pkg/agentic/handlers.go +++ b/pkg/agentic/handlers.go @@ -39,15 +39,15 @@ func (s *PrepSubsystem) HandleIPCEvents(c *core.Core, msg core.Message) core.Res } // Update status with real PID if result := ReadStatusResult(wsDir); result.OK { - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if !ok { break } - st.PID = pid - st.ProcessID = processID - writeStatusResult(wsDir, st) + workspaceStatus.PID = pid + workspaceStatus.ProcessID = processID + writeStatusResult(wsDir, workspaceStatus) if runnerSvc, ok := core.ServiceFor[workspaceTracker](c, "runner"); ok { - runnerSvc.TrackWorkspace(WorkspaceName(wsDir), st) + runnerSvc.TrackWorkspace(WorkspaceName(wsDir), workspaceStatus) } } _ = outputFile @@ -59,8 +59,8 @@ func (s *PrepSubsystem) HandleIPCEvents(c *core.Core, msg core.Message) core.Res // SpawnFromQueue spawns an agent in a pre-prepped workspace. // Called by runner.Service via ServiceFor interface matching. // -// r := prep.SpawnFromQueue("codex", prompt, wsDir) -// pid := r.Value.(int) +// spawnResult := prep.SpawnFromQueue("codex", prompt, wsDir) +// pid := spawnResult.Value.(int) func (s *PrepSubsystem) SpawnFromQueue(agent, prompt, wsDir string) core.Result { pid, _, _, err := s.spawnAgent(agent, prompt, wsDir) if err != nil { @@ -88,12 +88,12 @@ func resolveWorkspace(name string) string { func findWorkspaceByPR(repo, branch string) string { for _, path := range WorkspaceStatusPaths() { wsDir := core.PathDir(path) - result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + statusResult := ReadStatusResult(wsDir) + workspaceStatus, ok := workspaceStatusValue(statusResult) if !ok { continue } - if st.Repo == repo && st.Branch == branch { + if workspaceStatus.Repo == repo && workspaceStatus.Branch == branch { return wsDir } } diff --git a/pkg/agentic/pr.go b/pkg/agentic/pr.go index 5274572..3f23fb6 100644 --- a/pkg/agentic/pr.go +++ b/pkg/agentic/pr.go @@ -60,25 +60,25 @@ func (s *PrepSubsystem) createPR(ctx context.Context, _ *mcp.CallToolRequest, in // Read workspace status for repo, branch, issue context result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if !ok { err, _ := result.Value.(error) return nil, CreatePROutput{}, core.E("createPR", "no status.json", err) } - if st.Branch == "" { + if workspaceStatus.Branch == "" { process := s.Core().Process() - r := process.RunIn(ctx, repoDir, "git", "rev-parse", "--abbrev-ref", "HEAD") - if !r.OK { + result := process.RunIn(ctx, repoDir, "git", "rev-parse", "--abbrev-ref", "HEAD") + if !result.OK { return nil, CreatePROutput{}, core.E("createPR", "failed to detect branch", nil) } - st.Branch = core.Trim(r.Value.(string)) - if st.Branch == "" { + workspaceStatus.Branch = core.Trim(result.Value.(string)) + if workspaceStatus.Branch == "" { return nil, CreatePROutput{}, core.E("createPR", "failed to detect branch", nil) } } - org := st.Org + org := workspaceStatus.Org if org == "" { org = "core" } @@ -90,48 +90,48 @@ func (s *PrepSubsystem) createPR(ctx context.Context, _ *mcp.CallToolRequest, in // Build PR title title := input.Title if title == "" { - title = st.Task + title = workspaceStatus.Task } if title == "" { - title = core.Sprintf("Agent work on %s", st.Branch) + title = core.Sprintf("Agent work on %s", workspaceStatus.Branch) } // Build PR body body := input.Body if body == "" { - body = s.buildPRBody(st) + body = s.buildPRBody(workspaceStatus) } if input.DryRun { return nil, CreatePROutput{ Success: true, Title: title, - Branch: st.Branch, - Repo: st.Repo, + Branch: workspaceStatus.Branch, + Repo: workspaceStatus.Repo, }, nil } // Push branch to Forge (origin is the local clone, not Forge) - forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, st.Repo) - r := s.Core().Process().RunIn(ctx, repoDir, "git", "push", forgeRemote, st.Branch) - if !r.OK { - return nil, CreatePROutput{}, core.E("createPR", core.Concat("git push failed: ", r.Value.(string)), nil) + forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, workspaceStatus.Repo) + pushResult := s.Core().Process().RunIn(ctx, repoDir, "git", "push", forgeRemote, workspaceStatus.Branch) + if !pushResult.OK { + return nil, CreatePROutput{}, core.E("createPR", core.Concat("git push failed: ", pushResult.Value.(string)), nil) } // Create PR via Forge API - prURL, prNum, err := s.forgeCreatePR(ctx, org, st.Repo, st.Branch, base, title, body) + prURL, prNum, err := s.forgeCreatePR(ctx, org, workspaceStatus.Repo, workspaceStatus.Branch, base, title, body) if err != nil { return nil, CreatePROutput{}, core.E("createPR", "failed to create PR", err) } // Update status with PR URL - st.PRURL = prURL - writeStatusResult(wsDir, st) + workspaceStatus.PRURL = prURL + writeStatusResult(wsDir, workspaceStatus) // Comment on issue if tracked - if st.Issue > 0 { + if workspaceStatus.Issue > 0 { comment := core.Sprintf("Pull request created: %s", prURL) - s.commentOnIssue(ctx, org, st.Repo, st.Issue, comment) + s.commentOnIssue(ctx, org, workspaceStatus.Repo, workspaceStatus.Issue, comment) } return nil, CreatePROutput{ @@ -139,24 +139,24 @@ func (s *PrepSubsystem) createPR(ctx context.Context, _ *mcp.CallToolRequest, in PRURL: prURL, PRNum: prNum, Title: title, - Branch: st.Branch, - Repo: st.Repo, + Branch: workspaceStatus.Branch, + Repo: workspaceStatus.Repo, Pushed: true, }, nil } -func (s *PrepSubsystem) buildPRBody(st *WorkspaceStatus) string { +func (s *PrepSubsystem) buildPRBody(workspaceStatus *WorkspaceStatus) string { b := core.NewBuilder() b.WriteString("## Summary\n\n") - if st.Task != "" { - b.WriteString(st.Task) + if workspaceStatus.Task != "" { + b.WriteString(workspaceStatus.Task) b.WriteString("\n\n") } - if st.Issue > 0 { - b.WriteString(core.Sprintf("Closes #%d\n\n", st.Issue)) + if workspaceStatus.Issue > 0 { + b.WriteString(core.Sprintf("Closes #%d\n\n", workspaceStatus.Issue)) } - b.WriteString(core.Sprintf("**Agent:** %s\n", st.Agent)) - b.WriteString(core.Sprintf("**Runs:** %d\n", st.Runs)) + b.WriteString(core.Sprintf("**Agent:** %s\n", workspaceStatus.Agent)) + b.WriteString(core.Sprintf("**Runs:** %d\n", workspaceStatus.Runs)) b.WriteString("\n---\n*Created by agentic dispatch*\n") return b.String() } diff --git a/pkg/agentic/process_register.go b/pkg/agentic/process_register.go index e3755d1..87e6cfe 100644 --- a/pkg/agentic/process_register.go +++ b/pkg/agentic/process_register.go @@ -37,8 +37,8 @@ func ProcessRegister(c *core.Core) core.Result { if !ok { return core.Result{Value: core.E("agentic.ProcessRegister", "unexpected process service type", nil), OK: false} } - if r := c.RegisterService("process", service); !r.OK { - return r + if registerResult := c.RegisterService("process", service); !registerResult.OK { + return registerResult } handlers := &processActionHandlers{service: service} @@ -49,12 +49,12 @@ func ProcessRegister(c *core.Core) core.Result { return core.Result{OK: true} } -func (h *processActionHandlers) handleRun(ctx context.Context, opts core.Options) core.Result { +func (h *processActionHandlers) handleRun(ctx context.Context, options core.Options) core.Result { output, err := h.service.RunWithOptions(ctx, process.RunOptions{ - Command: opts.String("command"), - Args: optionStrings(opts, "args"), - Dir: opts.String("dir"), - Env: optionStrings(opts, "env"), + Command: options.String("command"), + Args: optionStrings(options, "args"), + Dir: options.String("dir"), + Env: optionStrings(options, "env"), }) if err != nil { return core.Result{Value: err, OK: false} @@ -62,13 +62,13 @@ func (h *processActionHandlers) handleRun(ctx context.Context, opts core.Options return core.Result{Value: output, OK: true} } -func (h *processActionHandlers) handleStart(ctx context.Context, opts core.Options) core.Result { +func (h *processActionHandlers) handleStart(ctx context.Context, options core.Options) core.Result { proc, err := h.service.StartWithOptions(ctx, process.RunOptions{ - Command: opts.String("command"), - Args: optionStrings(opts, "args"), - Dir: opts.String("dir"), - Env: optionStrings(opts, "env"), - Detach: opts.Bool("detach"), + Command: options.String("command"), + Args: optionStrings(options, "args"), + Dir: options.String("dir"), + Env: optionStrings(options, "env"), + Detach: options.Bool("detach"), }) if err != nil { return core.Result{Value: err, OK: false} @@ -76,8 +76,8 @@ func (h *processActionHandlers) handleStart(ctx context.Context, opts core.Optio return core.Result{Value: proc, OK: true} } -func (h *processActionHandlers) handleKill(_ context.Context, opts core.Options) core.Result { - id := opts.String("id") +func (h *processActionHandlers) handleKill(_ context.Context, options core.Options) core.Result { + id := options.String("id") if id == "" { return core.Result{Value: core.E("agentic.ProcessRegister", "process id is required", nil), OK: false} } @@ -87,12 +87,12 @@ func (h *processActionHandlers) handleKill(_ context.Context, opts core.Options) return core.Result{OK: true} } -func optionStrings(opts core.Options, key string) []string { - r := opts.Get(key) - if !r.OK { +func optionStrings(options core.Options, key string) []string { + result := options.Get(key) + if !result.OK { return nil } - switch values := r.Value.(type) { + switch values := result.Value.(type) { case []string: return values case []any: diff --git a/pkg/agentic/queue.go b/pkg/agentic/queue.go index d69663b..015603d 100644 --- a/pkg/agentic/queue.go +++ b/pkg/agentic/queue.go @@ -87,12 +87,12 @@ func (s *PrepSubsystem) loadAgentsConfig() *AgentsConfig { } for _, path := range paths { - r := fs.Read(path) - if !r.OK { + readResult := fs.Read(path) + if !readResult.OK { continue } var config AgentsConfig - if err := yaml.Unmarshal([]byte(r.Value.(string)), &config); err != nil { + if err := yaml.Unmarshal([]byte(readResult.Value.(string)), &config); err != nil { continue } return &config @@ -169,8 +169,8 @@ func (s *PrepSubsystem) countRunningByAgent(agent string) int { } if s.workspaces != nil && s.workspaces.Len() > 0 { count := 0 - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status == "running" && baseAgent(st.Agent) == agent && ProcessAlive(runtime, st.ProcessID, st.PID) { + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status == "running" && baseAgent(workspaceStatus.Agent) == agent && ProcessAlive(runtime, workspaceStatus.ProcessID, workspaceStatus.PID) { count++ } }) @@ -187,14 +187,14 @@ func (s *PrepSubsystem) countRunningByAgentDisk(runtime *core.Core, agent string count := 0 for _, statusPath := range WorkspaceStatusPaths() { result := ReadStatusResult(core.PathDir(statusPath)) - st, ok := workspaceStatusValue(result) - if !ok || st.Status != "running" { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.Status != "running" { continue } - if baseAgent(st.Agent) != agent { + if baseAgent(workspaceStatus.Agent) != agent { continue } - if ProcessAlive(runtime, st.ProcessID, st.PID) { + if ProcessAlive(runtime, workspaceStatus.ProcessID, workspaceStatus.PID) { count++ } } @@ -212,8 +212,8 @@ func (s *PrepSubsystem) countRunningByModel(agent string) int { } if s.workspaces != nil && s.workspaces.Len() > 0 { count := 0 - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status == "running" && st.Agent == agent && ProcessAlive(runtime, st.ProcessID, st.PID) { + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status == "running" && workspaceStatus.Agent == agent && ProcessAlive(runtime, workspaceStatus.ProcessID, workspaceStatus.PID) { count++ } }) @@ -230,14 +230,14 @@ func (s *PrepSubsystem) countRunningByModelDisk(runtime *core.Core, agent string count := 0 for _, statusPath := range WorkspaceStatusPaths() { result := ReadStatusResult(core.PathDir(statusPath)) - st, ok := workspaceStatusValue(result) - if !ok || st.Status != "running" { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.Status != "running" { continue } - if st.Agent != agent { + if workspaceStatus.Agent != agent { continue } - if ProcessAlive(runtime, st.ProcessID, st.PID) { + if ProcessAlive(runtime, workspaceStatus.ProcessID, workspaceStatus.PID) { count++ } } @@ -255,9 +255,9 @@ func baseAgent(agent string) string { func (s *PrepSubsystem) canDispatchAgent(agent string) bool { var concurrency map[string]ConcurrencyLimit if s.ServiceRuntime != nil { - r := s.Core().Config().Get("agents.concurrency") - if r.OK { - concurrency, _ = r.Value.(map[string]ConcurrencyLimit) + configurationResult := s.Core().Config().Get("agents.concurrency") + if configurationResult.OK { + concurrency, _ = configurationResult.Value.(map[string]ConcurrencyLimit) } } if concurrency == nil { @@ -329,45 +329,45 @@ func (s *PrepSubsystem) drainOne() bool { for _, statusPath := range WorkspaceStatusPaths() { wsDir := core.PathDir(statusPath) result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) - if !ok || st.Status != "queued" { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.Status != "queued" { continue } - if !s.canDispatchAgent(st.Agent) { + if !s.canDispatchAgent(workspaceStatus.Agent) { continue } // Skip if agent pool is in rate-limit backoff - pool := baseAgent(st.Agent) + pool := baseAgent(workspaceStatus.Agent) if until, ok := s.backoff[pool]; ok && time.Now().Before(until) { continue } // Apply rate delay before spawning - delay := s.delayForAgent(st.Agent) + delay := s.delayForAgent(workspaceStatus.Agent) if delay > 0 { time.Sleep(delay) } // Re-check concurrency after delay (another task may have started) - if !s.canDispatchAgent(st.Agent) { + if !s.canDispatchAgent(workspaceStatus.Agent) { continue } - prompt := core.Concat("TASK: ", st.Task, "\n\nResume from where you left off. Read CODEX.md for conventions. Commit when done.") + prompt := core.Concat("TASK: ", workspaceStatus.Task, "\n\nResume from where you left off. Read CODEX.md for conventions. Commit when done.") - pid, processID, _, err := s.spawnAgent(st.Agent, prompt, wsDir) + pid, processID, _, err := s.spawnAgent(workspaceStatus.Agent, prompt, wsDir) if err != nil { continue } - st.Status = "running" - st.PID = pid - st.ProcessID = processID - st.Runs++ - writeStatusResult(wsDir, st) - s.TrackWorkspace(WorkspaceName(wsDir), st) + workspaceStatus.Status = "running" + workspaceStatus.PID = pid + workspaceStatus.ProcessID = processID + workspaceStatus.Runs++ + writeStatusResult(wsDir, workspaceStatus) + s.TrackWorkspace(WorkspaceName(wsDir), workspaceStatus) return true } diff --git a/pkg/agentic/resume.go b/pkg/agentic/resume.go index 1333946..8973f19 100644 --- a/pkg/agentic/resume.go +++ b/pkg/agentic/resume.go @@ -53,18 +53,18 @@ func (s *PrepSubsystem) resume(ctx context.Context, _ *mcp.CallToolRequest, inpu // Read current status result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) if !ok { err, _ := result.Value.(error) return nil, ResumeOutput{}, core.E("resume", "no status.json in workspace", err) } - if st.Status != "blocked" && st.Status != "failed" && st.Status != "completed" { - return nil, ResumeOutput{}, core.E("resume", core.Concat("workspace is ", st.Status, ", not resumable (must be blocked, failed, or completed)"), nil) + if workspaceStatus.Status != "blocked" && workspaceStatus.Status != "failed" && workspaceStatus.Status != "completed" { + return nil, ResumeOutput{}, core.E("resume", core.Concat("workspace is ", workspaceStatus.Status, ", not resumable (must be blocked, failed, or completed)"), nil) } // Determine agent - agent := st.Agent + agent := workspaceStatus.Agent if input.Agent != "" { agent = input.Agent } @@ -73,14 +73,14 @@ func (s *PrepSubsystem) resume(ctx context.Context, _ *mcp.CallToolRequest, inpu if input.Answer != "" { answerPath := workspaceAnswerPath(wsDir) content := core.Sprintf("# Answer\n\n%s\n", input.Answer) - if r := fs.Write(answerPath, content); !r.OK { - err, _ := r.Value.(error) + if writeResult := fs.Write(answerPath, content); !writeResult.OK { + err, _ := writeResult.Value.(error) return nil, ResumeOutput{}, core.E("resume", "failed to write ANSWER.md", err) } } // Build resume prompt — inline the task and answer, no file references - prompt := core.Concat("You are resuming previous work.\n\nORIGINAL TASK:\n", st.Task) + prompt := core.Concat("You are resuming previous work.\n\nORIGINAL TASK:\n", workspaceStatus.Task) if input.Answer != "" { prompt = core.Concat(prompt, "\n\nANSWER TO YOUR QUESTION:\n", input.Answer) } @@ -102,12 +102,12 @@ func (s *PrepSubsystem) resume(ctx context.Context, _ *mcp.CallToolRequest, inpu } // Update status - st.Status = "running" - st.PID = pid - st.ProcessID = processID - st.Runs++ - st.Question = "" - writeStatusResult(wsDir, st) + workspaceStatus.Status = "running" + workspaceStatus.PID = pid + workspaceStatus.ProcessID = processID + workspaceStatus.Runs++ + workspaceStatus.Question = "" + writeStatusResult(wsDir, workspaceStatus) return nil, ResumeOutput{ Success: true, diff --git a/pkg/agentic/verify.go b/pkg/agentic/verify.go index ad73b7c..dcb45cb 100644 --- a/pkg/agentic/verify.go +++ b/pkg/agentic/verify.go @@ -18,18 +18,18 @@ import ( // agentic_dispatch repo=go-crypt template=verify persona=engineering/engineering-security-engineer func (s *PrepSubsystem) autoVerifyAndMerge(wsDir string) { result := ReadStatusResult(wsDir) - st, ok := workspaceStatusValue(result) - if !ok || st.PRURL == "" || st.Repo == "" { + workspaceStatus, ok := workspaceStatusValue(result) + if !ok || workspaceStatus.PRURL == "" || workspaceStatus.Repo == "" { return } repoDir := WorkspaceRepoDir(wsDir) - org := st.Org + org := workspaceStatus.Org if org == "" { org = "core" } - prNum := extractPRNumber(st.PRURL) + prNum := extractPRNumber(workspaceStatus.PRURL) if prNum == 0 { return } @@ -47,7 +47,7 @@ func (s *PrepSubsystem) autoVerifyAndMerge(wsDir string) { } // Attempt 1: run tests and try to merge - mergeOutcome := s.attemptVerifyAndMerge(repoDir, org, st.Repo, st.Branch, prNum) + mergeOutcome := s.attemptVerifyAndMerge(repoDir, org, workspaceStatus.Repo, workspaceStatus.Branch, prNum) if mergeOutcome == mergeSuccess { markMerged() return @@ -55,8 +55,8 @@ func (s *PrepSubsystem) autoVerifyAndMerge(wsDir string) { // Attempt 2: rebase onto main and retry if mergeOutcome == mergeConflict || mergeOutcome == testFailed { - if s.rebaseBranch(repoDir, st.Branch) { - if s.attemptVerifyAndMerge(repoDir, org, st.Repo, st.Branch, prNum) == mergeSuccess { + if s.rebaseBranch(repoDir, workspaceStatus.Branch) { + if s.attemptVerifyAndMerge(repoDir, org, workspaceStatus.Repo, workspaceStatus.Branch, prNum) == mergeSuccess { markMerged() return } @@ -64,15 +64,15 @@ func (s *PrepSubsystem) autoVerifyAndMerge(wsDir string) { } // Both attempts failed — flag for human review - s.flagForReview(org, st.Repo, prNum, mergeOutcome) + s.flagForReview(org, workspaceStatus.Repo, prNum, mergeOutcome) if result := ReadStatusResult(wsDir); result.OK { - st2, ok := workspaceStatusValue(result) + workspaceStatusUpdate, ok := workspaceStatusValue(result) if !ok { return } - st2.Question = "Flagged for review — auto-merge failed after retry" - writeStatusResult(wsDir, st2) + workspaceStatusUpdate.Question = "Flagged for review — auto-merge failed after retry" + writeStatusResult(wsDir, workspaceStatusUpdate) } } @@ -99,7 +99,7 @@ func (s *PrepSubsystem) attemptVerifyAndMerge(repoDir, org, repo, branch string, ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - if r := s.forgeMergePR(ctx, org, repo, prNum); !r.OK { + if mergeResult := s.forgeMergePR(ctx, org, repo, prNum); !mergeResult.OK { comment := core.Sprintf("## Tests Passed — Merge Failed\n\n`%s` passed but merge failed", testResult.testCmd) s.commentOnIssue(context.Background(), org, repo, prNum, comment) return mergeConflict @@ -126,14 +126,14 @@ func (s *PrepSubsystem) rebaseBranch(repoDir, branch string) bool { } result := ReadStatusResult(core.PathDir(repoDir)) - st, ok := workspaceStatusValue(result) + workspaceStatus, ok := workspaceStatusValue(result) org := "core" repo := "" if ok { - if st.Org != "" { - org = st.Org + if workspaceStatus.Org != "" { + org = workspaceStatus.Org } - repo = st.Repo + repo = workspaceStatus.Repo } forgeRemote := core.Sprintf("ssh://git@forge.lthn.ai:2223/%s/%s.git", org, repo) return process.RunIn(ctx, repoDir, "git", "push", "--force-with-lease", forgeRemote, branch).OK @@ -176,8 +176,8 @@ func (s *PrepSubsystem) ensureLabel(ctx context.Context, org, repo, name, colour // getLabelID fetches the ID of a label by name. func (s *PrepSubsystem) getLabelID(ctx context.Context, org, repo, name string) int { url := core.Sprintf("%s/api/v1/repos/%s/%s/labels", s.forgeURL, org, repo) - r := HTTPGet(ctx, url, s.forgeToken, "token") - if !r.OK { + getResult := HTTPGet(ctx, url, s.forgeToken, "token") + if !getResult.OK { return 0 } @@ -185,7 +185,7 @@ func (s *PrepSubsystem) getLabelID(ctx context.Context, org, repo, name string) ID int `json:"id"` Name string `json:"name"` } - core.JSONUnmarshalString(r.Value.(string), &labels) + core.JSONUnmarshalString(getResult.Value.(string), &labels) for _, l := range labels { if l.Name == name { return l.ID @@ -202,12 +202,12 @@ type verifyResult struct { testCmd string } -func resultText(r core.Result) string { - if text, ok := r.Value.(string); ok { +func resultText(result core.Result) string { + if text, ok := result.Value.(string); ok { return text } - if r.Value != nil { - return core.Sprint(r.Value) + if result.Value != nil { + return core.Sprint(result.Value) } return "" } @@ -229,52 +229,52 @@ func (s *PrepSubsystem) runVerification(repoDir string) verifyResult { func (s *PrepSubsystem) runGoTests(repoDir string) verifyResult { ctx := context.Background() process := s.Core().Process() - r := process.RunWithEnv(ctx, repoDir, []string{"GOWORK=off"}, "go", "test", "./...", "-count=1", "-timeout", "120s") - out := resultText(r) + processResult := process.RunWithEnv(ctx, repoDir, []string{"GOWORK=off"}, "go", "test", "./...", "-count=1", "-timeout", "120s") + out := resultText(processResult) exitCode := 0 - if !r.OK { + if !processResult.OK { exitCode = 1 } - return verifyResult{passed: r.OK, output: out, exitCode: exitCode, testCmd: "go test ./..."} + return verifyResult{passed: processResult.OK, output: out, exitCode: exitCode, testCmd: "go test ./..."} } func (s *PrepSubsystem) runPHPTests(repoDir string) verifyResult { ctx := context.Background() process := s.Core().Process() - r := process.RunIn(ctx, repoDir, "composer", "test", "--no-interaction") - if !r.OK { + composerResult := process.RunIn(ctx, repoDir, "composer", "test", "--no-interaction") + if !composerResult.OK { // Try pest as fallback - r2 := process.RunIn(ctx, repoDir, "./vendor/bin/pest", "--no-interaction") - if !r2.OK { + fallbackResult := process.RunIn(ctx, repoDir, "./vendor/bin/pest", "--no-interaction") + if !fallbackResult.OK { return verifyResult{passed: false, testCmd: "none", output: "No PHP test runner found (composer test and vendor/bin/pest both unavailable)", exitCode: 1} } - return verifyResult{passed: true, output: resultText(r2), exitCode: 0, testCmd: "vendor/bin/pest"} + return verifyResult{passed: true, output: resultText(fallbackResult), exitCode: 0, testCmd: "vendor/bin/pest"} } - return verifyResult{passed: true, output: resultText(r), exitCode: 0, testCmd: "composer test"} + return verifyResult{passed: true, output: resultText(composerResult), exitCode: 0, testCmd: "composer test"} } func (s *PrepSubsystem) runNodeTests(repoDir string) verifyResult { - r := fs.Read(core.JoinPath(repoDir, "package.json")) - if !r.OK { + packageResult := fs.Read(core.JoinPath(repoDir, "package.json")) + if !packageResult.OK { return verifyResult{passed: true, testCmd: "none", output: "Could not read package.json"} } var pkg struct { Scripts map[string]string `json:"scripts"` } - if ur := core.JSONUnmarshalString(r.Value.(string), &pkg); !ur.OK || pkg.Scripts["test"] == "" { + if parseResult := core.JSONUnmarshalString(packageResult.Value.(string), &pkg); !parseResult.OK || pkg.Scripts["test"] == "" { return verifyResult{passed: true, testCmd: "none", output: "No test script in package.json"} } ctx := context.Background() process := s.Core().Process() - r = process.RunIn(ctx, repoDir, "npm", "test") - out := resultText(r) + testResult := process.RunIn(ctx, repoDir, "npm", "test") + out := resultText(testResult) exitCode := 0 - if !r.OK { + if !testResult.OK { exitCode = 1 } - return verifyResult{passed: r.OK, output: out, exitCode: exitCode, testCmd: "npm test"} + return verifyResult{passed: testResult.OK, output: out, exitCode: exitCode, testCmd: "npm test"} } // forgeMergePR merges a PR via the Forge API. diff --git a/pkg/brain/brain.go b/pkg/brain/brain.go index 0cc8739..d3c3e41 100644 --- a/pkg/brain/brain.go +++ b/pkg/brain/brain.go @@ -18,12 +18,12 @@ import ( // fs provides unrestricted filesystem access for shared brain credentials. // // keyPath := core.JoinPath(home, ".claude", "brain.key") -// if r := fs.Read(keyPath); r.OK { -// apiKey = core.Trim(r.Value.(string)) +// if readResult := fs.Read(keyPath); readResult.OK { +// apiKey = core.Trim(readResult.Value.(string)) // } var fs = agentic.LocalFs() -func fieldString(values map[string]any, key string) string { +func stringField(values map[string]any, key string) string { return core.Sprint(values[key]) } diff --git a/pkg/brain/direct.go b/pkg/brain/direct.go index 31635ce..adbbc64 100644 --- a/pkg/brain/direct.go +++ b/pkg/brain/direct.go @@ -38,8 +38,8 @@ func NewDirect() *DirectSubsystem { if apiKey == "" { keyPath = brainKeyPath(agentic.HomeDir()) if keyPath != "" { - if r := fs.Read(keyPath); r.OK { - apiKey = core.Trim(r.Value.(string)) + if readResult := fs.Read(keyPath); readResult.OK { + apiKey = core.Trim(readResult.Value.(string)) if apiKey != "" { core.Info("brain direct subsystem loaded API key from file", "path", keyPath) } @@ -110,22 +110,22 @@ func (s *DirectSubsystem) apiCall(ctx context.Context, method, path string, body if body != nil { bodyStr = core.JSONMarshalString(body) } - r := agentic.HTTPDo(ctx, method, requestURL, bodyStr, s.apiKey, "Bearer") - if !r.OK { + requestResult := agentic.HTTPDo(ctx, method, requestURL, bodyStr, s.apiKey, "Bearer") + if !requestResult.OK { core.Error("brain API call failed", "method", method, "path", path) - if err, ok := r.Value.(error); ok { + if err, ok := requestResult.Value.(error); ok { return core.Result{Value: core.E("brain.apiCall", "API call failed", err), OK: false} } - if responseBody, ok := r.Value.(string); ok && responseBody != "" { + if responseBody, ok := requestResult.Value.(string); ok && responseBody != "" { return core.Result{Value: core.E("brain.apiCall", core.Concat("API call failed: ", core.Trim(responseBody)), nil), OK: false} } return core.Result{Value: core.E("brain.apiCall", "API call failed", nil), OK: false} } var result map[string]any - if ur := core.JSONUnmarshalString(r.Value.(string), &result); !ur.OK { + if parseResult := core.JSONUnmarshalString(requestResult.Value.(string), &result); !parseResult.OK { core.Error("brain API response parse failed", "method", method, "path", path) - err, _ := ur.Value.(error) + err, _ := parseResult.Value.(error) return core.Result{Value: core.E("brain.apiCall", "parse response", err), OK: false} } @@ -191,11 +191,11 @@ func (s *DirectSubsystem) recall(ctx context.Context, _ *mcp.CallToolRequest, in for _, m := range mems { if mm, ok := m.(map[string]any); ok { mem := Memory{ - Content: fieldString(mm, "content"), - Type: fieldString(mm, "type"), - Project: fieldString(mm, "project"), - AgentID: fieldString(mm, "agent_id"), - CreatedAt: fieldString(mm, "created_at"), + Content: stringField(mm, "content"), + Type: stringField(mm, "type"), + Project: stringField(mm, "project"), + AgentID: stringField(mm, "agent_id"), + CreatedAt: stringField(mm, "created_at"), } if id, ok := mm["id"].(string); ok { mem.ID = id diff --git a/pkg/brain/messaging.go b/pkg/brain/messaging.go index f3bf2e7..4255ced 100644 --- a/pkg/brain/messaging.go +++ b/pkg/brain/messaging.go @@ -165,12 +165,12 @@ func parseMessages(result map[string]any) []MessageItem { mm, _ := m.(map[string]any) messages = append(messages, MessageItem{ ID: toInt(mm["id"]), - From: fieldString(mm, "from"), - To: fieldString(mm, "to"), - Subject: fieldString(mm, "subject"), - Content: fieldString(mm, "content"), + From: stringField(mm, "from"), + To: stringField(mm, "to"), + Subject: stringField(mm, "subject"), + Content: stringField(mm, "content"), Read: mm["read"] == true, - CreatedAt: fieldString(mm, "created_at"), + CreatedAt: stringField(mm, "created_at"), }) } return messages diff --git a/pkg/monitor/harvest.go b/pkg/monitor/harvest.go index 7d3ea11..02be512 100644 --- a/pkg/monitor/harvest.go +++ b/pkg/monitor/harvest.go @@ -62,26 +62,26 @@ func (m *Subsystem) harvestCompleted() string { // harvestWorkspace checks a single workspace and pushes if ready. func (m *Subsystem) harvestWorkspace(wsDir string) *harvestResult { - r := fs.Read(agentic.WorkspaceStatusPath(wsDir)) - if !r.OK { + statusResult := fs.Read(agentic.WorkspaceStatusPath(wsDir)) + if !statusResult.OK { return nil } - statusData, ok := resultString(r) + statusData, ok := resultString(statusResult) if !ok { return nil } - var st struct { + var workspaceStatus struct { Status string `json:"status"` Repo string `json:"repo"` Branch string `json:"branch"` } - if r := core.JSONUnmarshalString(statusData, &st); !r.OK { + if parseResult := core.JSONUnmarshalString(statusData, &workspaceStatus); !parseResult.OK { return nil } // Only harvest completed workspaces (not merged, running, etc.) - if st.Status != "completed" { + if workspaceStatus.Status != "completed" { return nil } @@ -91,7 +91,7 @@ func (m *Subsystem) harvestWorkspace(wsDir string) *harvestResult { } // Check if there are commits to push - branch := st.Branch + branch := workspaceStatus.Branch if branch == "" { branch = m.detectBranch(repoDir) } @@ -109,7 +109,7 @@ func (m *Subsystem) harvestWorkspace(wsDir string) *harvestResult { // Safety checks before pushing if reason := m.checkSafety(repoDir); reason != "" { updateStatus(wsDir, "rejected", reason) - return &harvestResult{repo: st.Repo, branch: branch, rejected: reason} + return &harvestResult{repo: workspaceStatus.Repo, branch: branch, rejected: reason} } // Count changed files @@ -120,16 +120,16 @@ func (m *Subsystem) harvestWorkspace(wsDir string) *harvestResult { // explicit review (/review command), not silently in the background. updateStatus(wsDir, "ready-for-review", "") - return &harvestResult{repo: st.Repo, branch: branch, files: files} + return &harvestResult{repo: workspaceStatus.Repo, branch: branch, files: files} } // gitOutput runs a git command and returns trimmed stdout via Core Process. func (m *Subsystem) gitOutput(dir string, args ...string) string { - r := m.Core().Process().RunIn(context.Background(), dir, "git", args...) - if !r.OK { + processResult := m.Core().Process().RunIn(context.Background(), dir, "git", args...) + if !processResult.OK { return "" } - return core.Trim(r.Value.(string)) + return core.Trim(processResult.Value.(string)) } // gitOK runs a git command and returns true if it exits 0. @@ -235,9 +235,9 @@ func (m *Subsystem) countChangedFiles(srcDir string) int { // pushBranch pushes the agent's branch to origin. func (m *Subsystem) pushBranch(srcDir, branch string) error { - r := m.Core().Process().RunIn(context.Background(), srcDir, "git", "push", "origin", branch) - if !r.OK { - if err, ok := r.Value.(error); ok { + processResult := m.Core().Process().RunIn(context.Background(), srcDir, "git", "push", "origin", branch) + if !processResult.OK { + if err, ok := processResult.Value.(error); ok { return core.E("harvest.pushBranch", "push failed", err) } return core.E("harvest.pushBranch", "push failed", nil) @@ -249,27 +249,27 @@ func (m *Subsystem) pushBranch(srcDir, branch string) error { // // updateStatus(wsDir, "ready-for-review", "") func updateStatus(wsDir, status, question string) { - r := fs.Read(agentic.WorkspaceStatusPath(wsDir)) - if !r.OK { + statusResult := fs.Read(agentic.WorkspaceStatusPath(wsDir)) + if !statusResult.OK { return } - statusData, ok := resultString(r) + statusData, ok := resultString(statusResult) if !ok { return } - var st map[string]any - if r := core.JSONUnmarshalString(statusData, &st); !r.OK { + var workspaceStatus map[string]any + if parseResult := core.JSONUnmarshalString(statusData, &workspaceStatus); !parseResult.OK { return } - st["status"] = status + workspaceStatus["status"] = status if question != "" { - st["question"] = question + workspaceStatus["question"] = question } else { - delete(st, "question") // clear stale question from previous state + delete(workspaceStatus, "question") // clear stale question from previous state } statusPath := agentic.WorkspaceStatusPath(wsDir) - if r := fs.WriteAtomic(statusPath, core.JSONMarshalString(st)); !r.OK { - if err, ok := r.Value.(error); ok { + if writeResult := fs.WriteAtomic(statusPath, core.JSONMarshalString(workspaceStatus)); !writeResult.OK { + if err, ok := writeResult.Value.(error); ok { core.Warn("monitor.updateStatus: failed to write status", "path", statusPath, "reason", err) return } diff --git a/pkg/monitor/monitor.go b/pkg/monitor/monitor.go index ecda5c0..de57f6e 100644 --- a/pkg/monitor/monitor.go +++ b/pkg/monitor/monitor.go @@ -19,8 +19,8 @@ import ( "github.com/modelcontextprotocol/go-sdk/mcp" ) -// r := fs.Read(core.JoinPath(wsRoot, name, "status.json")) -// if text, ok := resultString(r); ok { _ = core.JSONUnmarshalString(text, &st) } +// readResult := fs.Read(core.JoinPath(wsRoot, name, "status.json")) +// if text, ok := resultString(readResult); ok { _ = core.JSONUnmarshalString(text, &workspaceStatus) } var fs = agentic.LocalFs() type channelSender interface { @@ -42,16 +42,16 @@ func monitorBrainKey() string { if k := core.Env("CORE_BRAIN_KEY"); k != "" { return k } - if r := fs.Read(brainKeyPath(agentic.HomeDir())); r.OK { - if value, ok := resultString(r); ok { + if readResult := fs.Read(brainKeyPath(agentic.HomeDir())); readResult.OK { + if value, ok := resultString(readResult); ok { return core.Trim(value) } } return "" } -func resultString(r core.Result) (string, bool) { - value, ok := r.Value.(string) +func resultString(result core.Result) (string, bool) { + value, ok := result.Value.(string) if !ok { return "", false } @@ -172,15 +172,15 @@ func (m *Subsystem) Start(ctx context.Context) { }() } -// r := service.OnStartup(context.Background()) -// core.Println(r.OK) +// result := service.OnStartup(context.Background()) +// core.Println(result.OK) func (m *Subsystem) OnStartup(ctx context.Context) core.Result { m.Start(ctx) return core.Result{OK: true} } -// r := service.OnShutdown(context.Background()) -// core.Println(r.OK) +// result := service.OnShutdown(context.Background()) +// core.Println(result.OK) func (m *Subsystem) OnShutdown(ctx context.Context) core.Result { _ = m.Shutdown(ctx) return core.Result{OK: true} diff --git a/pkg/runner/paths.go b/pkg/runner/paths.go index 2a859cd..9252e5c 100644 --- a/pkg/runner/paths.go +++ b/pkg/runner/paths.go @@ -69,16 +69,16 @@ func CoreRoot() string { // result := ReadStatusResult("/srv/core/workspace/core/go-io/task-5") // if result.OK { workspaceStatus := result.Value.(*WorkspaceStatus) } func ReadStatusResult(wsDir string) core.Result { - result := agentic.ReadStatusResult(wsDir) - if !result.OK { - err, _ := result.Value.(error) + statusResult := agentic.ReadStatusResult(wsDir) + if !statusResult.OK { + err, _ := statusResult.Value.(error) if err == nil { return core.Result{Value: core.E("runner.ReadStatusResult", "failed to read status", nil), OK: false} } return core.Result{Value: core.E("runner.ReadStatusResult", "failed to read status", err), OK: false} } - agenticStatus, ok := result.Value.(*agentic.WorkspaceStatus) + agenticStatus, ok := statusResult.Value.(*agentic.WorkspaceStatus) if !ok || agenticStatus == nil { return core.Result{Value: core.E("runner.ReadStatusResult", "invalid status payload", nil), OK: false} } @@ -91,8 +91,8 @@ func ReadStatusResult(wsDir string) core.Result { // WriteStatus writes `status.json` for one workspace directory. // -// r := runner.WriteStatus("/srv/core/workspace/core/go-io/task-5", &runner.WorkspaceStatus{Status: "running", Agent: "codex"}) -// core.Println(r.OK) +// result := runner.WriteStatus("/srv/core/workspace/core/go-io/task-5", &runner.WorkspaceStatus{Status: "running", Agent: "codex"}) +// core.Println(result.OK) func WriteStatus(wsDir string, status *WorkspaceStatus) core.Result { if status == nil { return core.Result{Value: core.E("runner.WriteStatus", "status is required", nil), OK: false} @@ -103,8 +103,8 @@ func WriteStatus(wsDir string, status *WorkspaceStatus) core.Result { return core.Result{Value: core.E("runner.WriteStatus", "status conversion failed", nil), OK: false} } agenticStatus.UpdatedAt = time.Now() - if r := fs.WriteAtomic(agentic.WorkspaceStatusPath(wsDir), core.JSONMarshalString(agenticStatus)); !r.OK { - err, _ := r.Value.(error) + if writeResult := fs.WriteAtomic(agentic.WorkspaceStatusPath(wsDir), core.JSONMarshalString(agenticStatus)); !writeResult.OK { + err, _ := writeResult.Value.(error) if err == nil { return core.Result{Value: core.E("runner.WriteStatus", "failed to write status", nil), OK: false} } diff --git a/pkg/runner/queue.go b/pkg/runner/queue.go index 9950e07..cfb930a 100644 --- a/pkg/runner/queue.go +++ b/pkg/runner/queue.go @@ -93,12 +93,12 @@ func (s *Service) loadAgentsConfig() *AgentsConfig { core.JoinPath(CoreRoot(), "agents.yaml"), } for _, path := range paths { - r := fs.Read(path) - if !r.OK { + readResult := fs.Read(path) + if !readResult.OK { continue } var config AgentsConfig - if err := yaml.Unmarshal([]byte(r.Value.(string)), &config); err != nil { + if err := yaml.Unmarshal([]byte(readResult.Value.(string)), &config); err != nil { continue } return &config @@ -121,9 +121,9 @@ func (s *Service) loadAgentsConfig() *AgentsConfig { func (s *Service) canDispatchAgent(agent string) (bool, string) { var concurrency map[string]ConcurrencyLimit if s.ServiceRuntime != nil { - r := s.Core().Config().Get("agents.concurrency") - if r.OK { - concurrency, _ = r.Value.(map[string]ConcurrencyLimit) + configurationResult := s.Core().Config().Get("agents.concurrency") + if configurationResult.OK { + concurrency, _ = configurationResult.Value.(map[string]ConcurrencyLimit) } } if concurrency == nil { @@ -166,14 +166,14 @@ func (s *Service) countRunningByAgent(agent string) int { runtime = s.Core() } count := 0 - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status != "running" || baseAgent(st.Agent) != agent { + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status != "running" || baseAgent(workspaceStatus.Agent) != agent { return } switch { - case st.PID < 0: + case workspaceStatus.PID < 0: count++ - case st.PID > 0 && agentic.ProcessAlive(runtime, "", st.PID): + case workspaceStatus.PID > 0 && agentic.ProcessAlive(runtime, "", workspaceStatus.PID): count++ } }) @@ -189,14 +189,14 @@ func (s *Service) countRunningByModel(agent string) int { runtime = s.Core() } count := 0 - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status != "running" || st.Agent != agent { + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status != "running" || workspaceStatus.Agent != agent { return } switch { - case st.PID < 0: + case workspaceStatus.PID < 0: count++ - case st.PID > 0 && agentic.ProcessAlive(runtime, "", st.PID): + case workspaceStatus.PID > 0 && agentic.ProcessAlive(runtime, "", workspaceStatus.PID): count++ } }) @@ -221,30 +221,30 @@ func (s *Service) drainQueue() { func (s *Service) drainOne() bool { for _, statusPath := range agentic.WorkspaceStatusPaths() { wsDir := core.PathDir(statusPath) - result := ReadStatusResult(wsDir) - if !result.OK { + statusResult := ReadStatusResult(wsDir) + if !statusResult.OK { continue } - st, ok := result.Value.(*WorkspaceStatus) - if !ok || st == nil || st.Status != "queued" { + workspaceStatus, ok := statusResult.Value.(*WorkspaceStatus) + if !ok || workspaceStatus == nil || workspaceStatus.Status != "queued" { continue } - if can, _ := s.canDispatchAgent(st.Agent); !can { + if can, _ := s.canDispatchAgent(workspaceStatus.Agent); !can { continue } - pool := baseAgent(st.Agent) + pool := baseAgent(workspaceStatus.Agent) if until, ok := s.backoff[pool]; ok && time.Now().Before(until) { continue } - delay := s.delayForAgent(st.Agent) + delay := s.delayForAgent(workspaceStatus.Agent) if delay > 0 { time.Sleep(delay) } - if can, _ := s.canDispatchAgent(st.Agent); !can { + if can, _ := s.canDispatchAgent(workspaceStatus.Agent); !can { continue } @@ -252,7 +252,7 @@ func (s *Service) drainOne() bool { // agentic owns the actual process launch. // Workspace name is relative path from workspace root (e.g. "core/go-ai/dev") wsName := agentic.WorkspaceName(wsDir) - core.Info("drainOne: found queued workspace", "workspace", wsName, "agent", st.Agent) + core.Info("drainOne: found queued workspace", "workspace", wsName, "agent", workspaceStatus.Agent) // Spawn directly — agentic is a Core service, use ServiceFor to get it if s.ServiceRuntime == nil { @@ -261,13 +261,13 @@ func (s *Service) drainOne() bool { type spawner interface { SpawnFromQueue(agent, prompt, wsDir string) core.Result } - prep, ok := core.ServiceFor[spawner](s.Core(), "agentic") + agenticService, ok := core.ServiceFor[spawner](s.Core(), "agentic") if !ok { core.Error("drainOne: agentic service not found") continue } - prompt := core.Concat("TASK: ", st.Task, "\n\nResume from where you left off. Read CODEX.md for conventions. Commit when done.") - spawnResult := prep.SpawnFromQueue(st.Agent, prompt, wsDir) + prompt := core.Concat("TASK: ", workspaceStatus.Task, "\n\nResume from where you left off. Read CODEX.md for conventions. Commit when done.") + spawnResult := agenticService.SpawnFromQueue(workspaceStatus.Agent, prompt, wsDir) if !spawnResult.OK { core.Error("drainOne: spawn failed", "workspace", wsName, "reason", core.Sprint(spawnResult.Value)) continue @@ -279,14 +279,14 @@ func (s *Service) drainOne() bool { } // Only mark running AFTER successful spawn - st.Status = "running" - st.PID = pid - st.Runs++ - if r := WriteStatus(wsDir, st); !r.OK { - core.Error("drainOne: failed to write workspace status", "workspace", wsName, "reason", core.Sprint(r.Value)) + workspaceStatus.Status = "running" + workspaceStatus.PID = pid + workspaceStatus.Runs++ + if writeResult := WriteStatus(wsDir, workspaceStatus); !writeResult.OK { + core.Error("drainOne: failed to write workspace status", "workspace", wsName, "reason", core.Sprint(writeResult.Value)) continue } - s.TrackWorkspace(wsName, st) + s.TrackWorkspace(wsName, workspaceStatus) core.Info("drainOne: spawned", "pid", pid, "workspace", wsName) return true diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index fff0ca4..fea8959 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -108,8 +108,8 @@ func (s *Service) OnStartup(ctx context.Context) core.Result { // OnShutdown freezes the queue. // -// r := service.OnShutdown(context.Background()) -// if r.OK { +// result := service.OnShutdown(context.Background()) +// if result.OK { // core.Println(service.IsFrozen()) // } func (s *Service) OnShutdown(_ context.Context) core.Result { @@ -129,9 +129,9 @@ func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) core.Result { base := baseAgent(ev.Agent) running := s.countRunningByAgent(base) var limit int - r := c.Config().Get("agents.concurrency") - if r.OK { - if concurrency, ok := r.Value.(map[string]ConcurrencyLimit); ok { + configurationResult := c.Config().Get("agents.concurrency") + if configurationResult.OK { + if concurrency, ok := configurationResult.Value.(map[string]ConcurrencyLimit); ok { if cl, has := concurrency[base]; has { limit = cl.Total } @@ -152,26 +152,26 @@ func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) core.Result { case messages.AgentCompleted: // Update workspace status in Registry so concurrency count drops if ev.Workspace != "" { - if r := s.workspaces.Get(ev.Workspace); r.OK { - if st, ok := r.Value.(*WorkspaceStatus); ok && st.Status == "running" { - st.Status = ev.Status - st.PID = 0 + if workspaceResult := s.workspaces.Get(ev.Workspace); workspaceResult.OK { + if workspaceStatus, ok := workspaceResult.Value.(*WorkspaceStatus); ok && workspaceStatus.Status == "running" { + workspaceStatus.Status = ev.Status + workspaceStatus.PID = 0 } } } else { - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Repo == ev.Repo && st.Status == "running" { - st.Status = ev.Status - st.PID = 0 + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Repo == ev.Repo && workspaceStatus.Status == "running" { + workspaceStatus.Status = ev.Status + workspaceStatus.PID = 0 } }) } cBase := baseAgent(ev.Agent) cRunning := s.countRunningByAgent(cBase) var cLimit int - cr := c.Config().Get("agents.concurrency") - if cr.OK { - if concurrency, ok := cr.Value.(map[string]ConcurrencyLimit); ok { + completionResult := c.Config().Get("agents.concurrency") + if completionResult.OK { + if concurrency, ok := completionResult.Value.(map[string]ConcurrencyLimit); ok { if cl, has := concurrency[cBase]; has { cLimit = cl.Total } @@ -222,54 +222,54 @@ func (s *Service) Poke() { // // s.TrackWorkspace("core/go-io/task-5", &WorkspaceStatus{Status: "running", Agent: "codex"}) // s.TrackWorkspace("core/go-io/task-5", &agentic.WorkspaceStatus{Status: "running", Agent: "codex"}) -func (s *Service) TrackWorkspace(name string, st any) { +func (s *Service) TrackWorkspace(name string, status any) { if s.workspaces == nil { return } - var ws *WorkspaceStatus - switch value := st.(type) { + var workspaceStatus *WorkspaceStatus + switch value := status.(type) { case *WorkspaceStatus: - ws = value + workspaceStatus = value case *agentic.WorkspaceStatus: - ws = runnerWorkspaceStatusFromAgentic(value) + workspaceStatus = runnerWorkspaceStatusFromAgentic(value) default: - json := core.JSONMarshalString(st) - var workspace WorkspaceStatus - if r := core.JSONUnmarshalString(json, &workspace); r.OK { - ws = &workspace + statusJSON := core.JSONMarshalString(status) + var decodedWorkspace WorkspaceStatus + if result := core.JSONUnmarshalString(statusJSON, &decodedWorkspace); result.OK { + workspaceStatus = &decodedWorkspace } } - if ws == nil { + if workspaceStatus == nil { return } - s.workspaces.Set(name, ws) + s.workspaces.Set(name, workspaceStatus) // Remove pending reservation now that the real workspace is tracked - s.workspaces.Delete(core.Concat("pending/", ws.Repo)) + s.workspaces.Delete(core.Concat("pending/", workspaceStatus.Repo)) } // Workspaces returns the workspace Registry. // -// s.Workspaces().Each(func(name string, st *WorkspaceStatus) { ... }) +// s.Workspaces().Each(func(name string, workspaceStatus *WorkspaceStatus) { ... }) func (s *Service) Workspaces() *core.Registry[*WorkspaceStatus] { return s.workspaces } // handleWorkspaceQuery answers workspace state queries from Core QUERY calls. // -// r := c.QUERY(runner.WorkspaceQuery{Name: "core/go-io/task-42"}) -// r := c.QUERY(runner.WorkspaceQuery{Status: "running"}) -func (s *Service) handleWorkspaceQuery(_ *core.Core, q core.Query) core.Result { - wq, ok := q.(WorkspaceQuery) +// result := c.QUERY(runner.WorkspaceQuery{Name: "core/go-io/task-42"}) +// result := c.QUERY(runner.WorkspaceQuery{Status: "running"}) +func (s *Service) handleWorkspaceQuery(_ *core.Core, query core.Query) core.Result { + workspaceQuery, ok := query.(WorkspaceQuery) if !ok { return core.Result{} } - if wq.Name != "" { - return s.workspaces.Get(wq.Name) + if workspaceQuery.Name != "" { + return s.workspaces.Get(workspaceQuery.Name) } - if wq.Status != "" { + if workspaceQuery.Status != "" { var names []string - s.workspaces.Each(func(name string, st *WorkspaceStatus) { - if st.Status == wq.Status { + s.workspaces.Each(func(name string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status == workspaceQuery.Status { names = append(names, name) } }) @@ -280,16 +280,16 @@ func (s *Service) handleWorkspaceQuery(_ *core.Core, q core.Query) core.Result { // --- Actions --- -func (s *Service) actionDispatch(_ context.Context, opts core.Options) core.Result { +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} } - agent := opts.String("agent") + agent := options.String("agent") if agent == "" { agent = "codex" } - repo := opts.String("repo") + repo := options.String("repo") s.dispatchMu.Lock() defer s.dispatchMu.Unlock() @@ -313,8 +313,8 @@ func (s *Service) actionDispatch(_ context.Context, opts core.Options) core.Resu func (s *Service) actionStatus(_ context.Context, _ core.Options) core.Result { running, queued, completed, failed := 0, 0, 0, 0 - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - switch st.Status { + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + switch workspaceStatus.Status { case "running": running++ case "queued": @@ -350,16 +350,16 @@ func (s *Service) actionKill(_ context.Context, _ core.Options) core.Result { runtime = s.Core() } killed := 0 - s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status == "running" && st.PID > 0 { - if agentic.ProcessTerminate(runtime, "", st.PID) { + s.workspaces.Each(func(_ string, workspaceStatus *WorkspaceStatus) { + if workspaceStatus.Status == "running" && workspaceStatus.PID > 0 { + if agentic.ProcessTerminate(runtime, "", workspaceStatus.PID) { killed++ } - st.Status = "failed" - st.PID = 0 + workspaceStatus.Status = "failed" + workspaceStatus.PID = 0 } - if st.Status == "queued" { - st.Status = "failed" + if workspaceStatus.Status == "queued" { + workspaceStatus.Status = "failed" } }) return core.Result{Value: core.Sprintf("killed %d agents", killed), OK: true} @@ -405,19 +405,19 @@ func (s *Service) hydrateWorkspaces() { } for _, path := range agentic.WorkspaceStatusPaths() { wsDir := core.PathDir(path) - result := ReadStatusResult(wsDir) - if !result.OK { + statusResult := ReadStatusResult(wsDir) + if !statusResult.OK { continue } - st, ok := result.Value.(*WorkspaceStatus) - if !ok || st == nil { + workspaceStatus, ok := statusResult.Value.(*WorkspaceStatus) + if !ok || workspaceStatus == nil { continue } // Re-queue running agents on restart — process is dead, re-dispatch - if st.Status == "running" { - st.Status = "queued" + if workspaceStatus.Status == "running" { + workspaceStatus.Status = "queued" } - s.workspaces.Set(agentic.WorkspaceName(wsDir), st) + s.workspaces.Set(agentic.WorkspaceName(wsDir), workspaceStatus) } } @@ -442,7 +442,7 @@ type AgentNotification struct { // WorkspaceQuery is the QUERY type for workspace lookups. // -// r := c.QUERY(runner.WorkspaceQuery{Status: "running"}) +// result := c.QUERY(runner.WorkspaceQuery{Status: "running"}) type WorkspaceQuery struct { Name string Status string @@ -450,7 +450,7 @@ type WorkspaceQuery struct { // WorkspaceStatus tracks the state of an agent workspace. // -// st := &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"` diff --git a/pkg/setup/service.go b/pkg/setup/service.go index 5893d5a..fbbc1a4 100644 --- a/pkg/setup/service.go +++ b/pkg/setup/service.go @@ -43,9 +43,9 @@ func (s *Service) OnStartup(ctx context.Context) core.Result { // // remote := service.DetectGitRemote("/srv/repos/agent") func (s *Service) DetectGitRemote(path string) string { - r := s.Core().Process().RunIn(context.Background(), path, "git", "remote", "get-url", "origin") - if !r.OK { + result := s.Core().Process().RunIn(context.Background(), path, "git", "remote", "get-url", "origin") + if !result.OK { return "" } - return parseGitRemote(core.Trim(r.Value.(string))) + return parseGitRemote(core.Trim(result.Value.(string))) } diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 516b1ae..d8d2be7 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -22,24 +22,24 @@ type Options struct { // // result := service.Run(setup.Options{Path: ".", Template: "auto"}) // core.Println(result.OK) -func (s *Service) Run(opts Options) core.Result { - if opts.Path == "" { - opts.Path = core.Env("DIR_CWD") +func (s *Service) Run(options Options) core.Result { + if options.Path == "" { + options.Path = core.Env("DIR_CWD") } - opts.Path = absolutePath(opts.Path) + options.Path = absolutePath(options.Path) - projType := Detect(opts.Path) - allTypes := DetectAll(opts.Path) + projType := Detect(options.Path) + allTypes := DetectAll(options.Path) - core.Print(nil, "Project: %s", core.PathBase(opts.Path)) + core.Print(nil, "Project: %s", core.PathBase(options.Path)) core.Print(nil, "Type: %s", projType) if len(allTypes) > 1 { core.Print(nil, "Also: %v (polyglot)", allTypes) } var tmplName string - if opts.Template != "" { - templateResult := resolveTemplateName(opts.Template, projType) + if options.Template != "" { + templateResult := resolveTemplateName(options.Template, projType) if !templateResult.OK { return templateResult } @@ -53,28 +53,28 @@ func (s *Service) Run(opts Options) core.Result { } // Generate .core/ config files - if result := setupCoreDir(opts, projType); !result.OK { + if result := setupCoreDir(options, projType); !result.OK { return result } // Scaffold from dir template if requested if tmplName != "" { - return s.scaffoldTemplate(opts, projType, tmplName) + return s.scaffoldTemplate(options, projType, tmplName) } - return core.Result{Value: opts.Path, OK: true} + return core.Result{Value: options.Path, OK: true} } // setupCoreDir creates .core/ with build.yaml and test.yaml. -func setupCoreDir(opts Options, projType ProjectType) core.Result { - coreDir := core.JoinPath(opts.Path, ".core") +func setupCoreDir(options Options, projType ProjectType) core.Result { + coreDir := core.JoinPath(options.Path, ".core") - if opts.DryRun { + if options.DryRun { core.Print(nil, "") core.Print(nil, "Would create %s/", coreDir) } else { - if r := fs.EnsureDir(coreDir); !r.OK { - err, _ := r.Value.(error) + if ensureResult := fs.EnsureDir(coreDir); !ensureResult.OK { + err, _ := ensureResult.Value.(error) return core.Result{ Value: core.E("setup.setupCoreDir", "create .core directory", err), OK: false, @@ -83,7 +83,7 @@ func setupCoreDir(opts Options, projType ProjectType) core.Result { } // build.yaml - buildConfig := GenerateBuildConfig(opts.Path, projType) + buildConfig := GenerateBuildConfig(options.Path, projType) if !buildConfig.OK { err, _ := buildConfig.Value.(error) return core.Result{ @@ -91,7 +91,7 @@ func setupCoreDir(opts Options, projType ProjectType) core.Result { OK: false, } } - if result := writeConfig(core.JoinPath(coreDir, "build.yaml"), buildConfig.Value.(string), opts); !result.OK { + if result := writeConfig(core.JoinPath(coreDir, "build.yaml"), buildConfig.Value.(string), options); !result.OK { return result } @@ -104,7 +104,7 @@ func setupCoreDir(opts Options, projType ProjectType) core.Result { OK: false, } } - if result := writeConfig(core.JoinPath(coreDir, "test.yaml"), testConfig.Value.(string), opts); !result.OK { + if result := writeConfig(core.JoinPath(coreDir, "test.yaml"), testConfig.Value.(string), options); !result.OK { return result } @@ -112,29 +112,29 @@ func setupCoreDir(opts Options, projType ProjectType) core.Result { } // scaffoldTemplate extracts a dir template into the target path. -func (s *Service) scaffoldTemplate(opts Options, projType ProjectType, tmplName string) core.Result { +func (s *Service) scaffoldTemplate(options Options, projType ProjectType, tmplName string) core.Result { core.Print(nil, "Template: %s", tmplName) data := &lib.WorkspaceData{ - Repo: core.PathBase(opts.Path), + Repo: core.PathBase(options.Path), Branch: "main", Task: core.Sprintf("Initialise %s project tooling.", projType), Agent: "setup", Language: string(projType), Prompt: "This workspace was scaffolded by pkg/setup. Review the repository and continue from the generated context files.", Flow: formatFlow(projType), - RepoDescription: s.DetectGitRemote(opts.Path), + RepoDescription: s.DetectGitRemote(options.Path), BuildCmd: defaultBuildCommand(projType), TestCmd: defaultTestCommand(projType), } - if opts.DryRun { - core.Print(nil, "Would extract workspace/%s to %s", tmplName, opts.Path) + if options.DryRun { + core.Print(nil, "Would extract workspace/%s to %s", tmplName, options.Path) core.Print(nil, " Template found: %s", tmplName) - return core.Result{Value: opts.Path, OK: true} + return core.Result{Value: options.Path, OK: true} } - if result := lib.ExtractWorkspace(tmplName, opts.Path, data); !result.OK { + if result := lib.ExtractWorkspace(tmplName, options.Path, data); !result.OK { if err, ok := result.Value.(error); ok { return core.Result{ Value: core.E("setup.scaffoldTemplate", core.Concat("extract workspace template ", tmplName), err), @@ -146,22 +146,22 @@ func (s *Service) scaffoldTemplate(opts Options, projType ProjectType, tmplName OK: false, } } - return core.Result{Value: opts.Path, OK: true} + return core.Result{Value: options.Path, OK: true} } -func writeConfig(path, content string, opts Options) core.Result { - if opts.DryRun { +func writeConfig(path, content string, options Options) core.Result { + if options.DryRun { core.Print(nil, " %s", path) return core.Result{Value: path, OK: true} } - if !opts.Force && fs.Exists(path) { + if !options.Force && fs.Exists(path) { core.Print(nil, " skip %s (exists, use --force to overwrite)", core.PathBase(path)) return core.Result{Value: path, OK: true} } - if r := fs.WriteMode(path, content, 0644); !r.OK { - err, _ := r.Value.(error) + if writeResult := fs.WriteMode(path, content, 0644); !writeResult.OK { + err, _ := writeResult.Value.(error) return core.Result{ Value: core.E("setup.writeConfig", core.Concat("write ", core.PathBase(path)), err), OK: false,