From 72387dde916202136fd95c0a616b829e2c9b98ed Mon Sep 17 00:00:00 2001 From: Snider Date: Wed, 25 Mar 2026 00:03:22 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20move=20workspace=20+=20process=20comman?= =?UTF-8?q?ds=20into=20services=20=E2=80=94=20main.go=2098=20lines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ProcessRegister: proper factory in pkg/agentic - Workspace commands (list/clean/dispatch): moved to agentic.registerWorkspaceCommands - workspace.go deleted from cmd/ - main.go: 98 lines, just core.New + app commands + c.Run() Co-Authored-By: Virgil --- cmd/core-agent/main.go | 15 ++-------- .../agentic/commands_workspace.go | 28 ++++++++----------- pkg/agentic/prep.go | 1 + pkg/agentic/process_register.go | 25 +++++++++++++++++ 4 files changed, 39 insertions(+), 30 deletions(-) rename cmd/core-agent/workspace.go => pkg/agentic/commands_workspace.go (84%) create mode 100644 pkg/agentic/process_register.go diff --git a/cmd/core-agent/main.go b/cmd/core-agent/main.go index 1f06a5e..9ee1c49 100644 --- a/cmd/core-agent/main.go +++ b/cmd/core-agent/main.go @@ -4,7 +4,6 @@ import ( "os" "dappco.re/go/core" - "dappco.re/go/core/process" "dappco.re/go/agent/pkg/agentic" "dappco.re/go/agent/pkg/brain" @@ -15,16 +14,7 @@ import ( func main() { c := core.New( core.WithOption("name", "core-agent"), - core.WithService(func(c *core.Core) core.Result { - svc, err := process.NewService(process.Options{})(c) - if err != nil { - return core.Result{Value: err, OK: false} - } - if procSvc, ok := svc.(*process.Service); ok { - _ = process.SetDefault(procSvc) - } - return core.Result{Value: svc, OK: true} - }), + core.WithService(agentic.ProcessRegister), core.WithService(agentic.Register), core.WithService(monitor.Register), core.WithService(brain.Register), @@ -99,9 +89,8 @@ func main() { }, }) - // Forge + Workspace CLI commands (in separate files) + // Forge CLI commands (in forge.go — @TODO move to forge service) registerForgeCommands(c) - registerWorkspaceCommands(c) // registerFlowCommands(c) — on feat/flow-system branch // Run: ServiceStartup → Cli → ServiceShutdown → os.Exit if error diff --git a/cmd/core-agent/workspace.go b/pkg/agentic/commands_workspace.go similarity index 84% rename from cmd/core-agent/workspace.go rename to pkg/agentic/commands_workspace.go index 38410ed..e43f5f1 100644 --- a/cmd/core-agent/workspace.go +++ b/pkg/agentic/commands_workspace.go @@ -1,22 +1,23 @@ // SPDX-License-Identifier: EUPL-1.2 -package main +// Workspace CLI commands registered by the agentic service during OnStartup. + +package agentic import ( "os" - "dappco.re/go/core" - - "dappco.re/go/agent/pkg/agentic" + core "dappco.re/go/core" ) -func registerWorkspaceCommands(c *core.Core) { +// registerWorkspaceCommands adds workspace management commands. +func (s *PrepSubsystem) registerWorkspaceCommands() { + c := s.core - // workspace/list — show all workspaces with status c.Command("workspace/list", core.Command{ Description: "List all agent workspaces with status", Action: func(opts core.Options) core.Result { - wsRoot := agentic.WorkspaceRoot() + wsRoot := WorkspaceRoot() fsys := c.Fs() r := fsys.List(wsRoot) @@ -33,7 +34,6 @@ func registerWorkspaceCommands(c *core.Core) { } statusFile := core.JoinPath(wsRoot, e.Name(), "status.json") if sr := fsys.Read(statusFile); sr.OK { - // Quick parse for status field content := sr.Value.(string) status := extractField(content, "status") repo := extractField(content, "repo") @@ -49,11 +49,10 @@ func registerWorkspaceCommands(c *core.Core) { }, }) - // workspace/clean — remove stale workspaces c.Command("workspace/clean", core.Command{ Description: "Remove completed/failed/blocked workspaces", Action: func(opts core.Options) core.Result { - wsRoot := agentic.WorkspaceRoot() + wsRoot := WorkspaceRoot() fsys := c.Fs() filter := opts.String("_arg") if filter == "" { @@ -115,16 +114,14 @@ func registerWorkspaceCommands(c *core.Core) { }, }) - // workspace/dispatch — dispatch an agent (CLI wrapper for MCP tool) c.Command("workspace/dispatch", core.Command{ Description: "Dispatch an agent to work on a repo task", Action: func(opts core.Options) core.Result { repo := opts.String("_arg") if repo == "" { - core.Print(nil, "usage: core-agent workspace/dispatch --task=\"...\" --issue=N|--pr=N|--branch=X [--agent=codex]") + core.Print(nil, "usage: core-agent workspace dispatch --task=\"...\" --issue=N|--pr=N|--branch=X [--agent=codex]") return core.Result{OK: false} } - core.Print(nil, "dispatch via CLI not yet wired — use MCP agentic_dispatch tool") core.Print(nil, "repo: %s, task: %s", repo, opts.String("task")) return core.Result{OK: true} @@ -133,9 +130,7 @@ func registerWorkspaceCommands(c *core.Core) { } // extractField does a quick JSON field extraction without full unmarshal. -// Looks for "field":"value" pattern. Good enough for status.json. func extractField(jsonStr, field string) string { - // Match both "field":"value" and "field": "value" needle := core.Concat("\"", field, "\"") idx := -1 for i := 0; i <= len(jsonStr)-len(needle); i++ { @@ -147,14 +142,13 @@ func extractField(jsonStr, field string) string { if idx < 0 { return "" } - // Skip : and whitespace to find opening quote for idx < len(jsonStr) && (jsonStr[idx] == ':' || jsonStr[idx] == ' ' || jsonStr[idx] == '\t') { idx++ } if idx >= len(jsonStr) || jsonStr[idx] != '"' { return "" } - idx++ // skip opening quote + idx++ end := idx for end < len(jsonStr) && jsonStr[end] != '"' { end++ diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index 9b3511b..a8dc6fc 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -91,6 +91,7 @@ func (s *PrepSubsystem) SetCore(c *core.Core) { func (s *PrepSubsystem) OnStartup(ctx context.Context) error { s.StartRunner() s.registerCommands(ctx) + s.registerWorkspaceCommands() return nil } diff --git a/pkg/agentic/process_register.go b/pkg/agentic/process_register.go new file mode 100644 index 0000000..235da2a --- /dev/null +++ b/pkg/agentic/process_register.go @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: EUPL-1.2 + +package agentic + +import ( + core "dappco.re/go/core" + "dappco.re/go/core/process" +) + +// ProcessRegister is the service factory for the process management service. +// Wraps core/process for the v0.3.3→v0.4 factory pattern. +// +// core.New( +// core.WithService(agentic.ProcessRegister), +// ) +func ProcessRegister(c *core.Core) core.Result { + svc, err := process.NewService(process.Options{})(c) + if err != nil { + return core.Result{Value: err, OK: false} + } + if procSvc, ok := svc.(*process.Service); ok { + _ = process.SetDefault(procSvc) + } + return core.Result{Value: svc, OK: true} +}