diff --git a/pkg/agentic/commands_setup.go b/pkg/agentic/commands_setup.go index f7b84b1..987cefd 100644 --- a/pkg/agentic/commands_setup.go +++ b/pkg/agentic/commands_setup.go @@ -3,8 +3,11 @@ package agentic import ( + "context" + "dappco.re/go/agent/pkg/setup" core "dappco.re/go/core" + "github.com/modelcontextprotocol/go-sdk/mcp" ) func (s *PrepSubsystem) registerSetupCommands() { @@ -14,17 +17,27 @@ func (s *PrepSubsystem) registerSetupCommands() { } func (s *PrepSubsystem) cmdSetup(options core.Options) core.Result { + return s.handleSetup(context.Background(), options) +} + +// result := c.Action("agentic.setup").Run(ctx, core.NewOptions( +// +// core.Option{Key: "path", Value: "."}, +// core.Option{Key: "template", Value: "auto"}, +// +// )) +func (s *PrepSubsystem) handleSetup(_ context.Context, options core.Options) core.Result { serviceResult := s.Core().Service("setup") if !serviceResult.OK { if serviceResult.Value != nil { - return core.Result{Value: serviceResult.Value, OK: false} + return core.Result{Value: core.E("agentic.setup", "setup service is required", nil), OK: false} } - return core.Result{Value: core.E("agentic.cmdSetup", "setup service is required", nil), OK: false} + return core.Result{Value: core.E("agentic.setup", "setup service is required", nil), OK: false} } service, ok := serviceResult.Value.(*setup.Service) if !ok || service == nil { - return core.Result{Value: core.E("agentic.cmdSetup", "setup service is required", nil), OK: false} + return core.Result{Value: core.E("agentic.setup", "setup service is required", nil), OK: false} } result := service.Run(setup.Options{ @@ -39,3 +52,44 @@ func (s *PrepSubsystem) cmdSetup(options core.Options) core.Result { return result } + +func (s *PrepSubsystem) registerSetupTool(server *mcp.Server) { + mcp.AddTool(server, &mcp.Tool{ + Name: "agentic_setup", + Description: "Scaffold a workspace with .core config files and optional templates.", + }, s.setupTool) +} + +type SetupInput struct { + Path string `json:"path,omitempty"` + DryRun bool `json:"dry_run,omitempty"` + Force bool `json:"force,omitempty"` + Template string `json:"template,omitempty"` +} + +type SetupOutput struct { + Success bool `json:"success"` + Path string `json:"path"` +} + +func (s *PrepSubsystem) setupTool(ctx context.Context, _ *mcp.CallToolRequest, input SetupInput) (*mcp.CallToolResult, SetupOutput, error) { + result := s.handleSetup(ctx, core.NewOptions( + core.Option{Key: "path", Value: input.Path}, + core.Option{Key: "dry_run", Value: input.DryRun}, + core.Option{Key: "force", Value: input.Force}, + core.Option{Key: "template", Value: input.Template}, + )) + if !result.OK { + return nil, SetupOutput{}, resultErrorValue("agentic.setup", result) + } + + path, ok := result.Value.(string) + if !ok { + return nil, SetupOutput{}, core.E("agentic.setup", "invalid setup output", nil) + } + + return nil, SetupOutput{ + Success: true, + Path: path, + }, nil +} diff --git a/pkg/agentic/commands_setup_test.go b/pkg/agentic/commands_setup_test.go index e88ab92..0fe60d2 100644 --- a/pkg/agentic/commands_setup_test.go +++ b/pkg/agentic/commands_setup_test.go @@ -3,6 +3,7 @@ package agentic import ( + "context" "testing" "time" @@ -64,3 +65,23 @@ func TestCommandsSetup_CmdSetup_Ugly_DryRunDoesNotWrite(t *testing.T) { assert.False(t, fs.Exists(core.JoinPath(dir, ".core"))) assert.False(t, fs.Exists(core.JoinPath(dir, "PROMPT.md"))) } + +func TestCommandsSetup_HandleSetup_Good_ActionAlias(t *testing.T) { + dir := t.TempDir() + require.True(t, fs.WriteMode(core.JoinPath(dir, "go.mod"), "module example.com/test\n", 0644).OK) + + c := core.New(core.WithService(setup.Register)) + s := &PrepSubsystem{ + ServiceRuntime: core.NewServiceRuntime(c, AgentOptions{}), + backoff: make(map[string]time.Time), + failCount: make(map[string]int), + } + + result := s.handleSetup(context.Background(), core.NewOptions(core.Option{Key: "path", Value: dir})) + require.True(t, result.OK) + + createdPath, ok := result.Value.(string) + require.True(t, ok) + assert.Equal(t, dir, createdPath) + assert.True(t, fs.Exists(core.JoinPath(dir, ".core", "build.yaml"))) +} diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index 959e29d..5da2393 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -92,7 +92,7 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result { case "agentic.status", "agentic.scan", "agentic.watch", "agentic.issue.get", "agentic.issue.list", "agentic.issue.assign", "agentic.pr.get", "agentic.pr.list", "agentic.prompt", "agentic.task", "agentic.flow", "agentic.persona", - "agentic.prompt.version", + "agentic.prompt.version", "agentic.setup", "agentic.sync.status", "agentic.fleet.nodes", "agentic.fleet.stats", "agentic.fleet.events", "agentic.credits.balance", "agentic.credits.history", "agentic.subscription.detect", "agentic.subscription.budget", @@ -184,6 +184,7 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result { c.Action("agentic.ingest", s.handleIngest).Description = "Create issues from agent findings" c.Action("agentic.poke", s.handlePoke).Description = "Drain next queued task from the queue" c.Action("agentic.mirror", s.handleMirror).Description = "Mirror agent branches to GitHub" + c.Action("agentic.setup", s.handleSetup).Description = "Scaffold a workspace with .core config files and optional templates" c.Action("agentic.issue.get", s.handleIssueGet).Description = "Get a Forge issue by number" c.Action("agentic.issue.list", s.handleIssueList).Description = "List Forge issues for a repo" @@ -454,6 +455,7 @@ func (s *PrepSubsystem) RegisterTools(server *mcp.Server) { s.registerPRTools(server) s.registerContentTools(server) s.registerLanguageTools(server) + s.registerSetupTool(server) mcp.AddTool(server, &mcp.Tool{ Name: "agentic_scan", diff --git a/pkg/agentic/prep_test.go b/pkg/agentic/prep_test.go index cbd130d..265d381 100644 --- a/pkg/agentic/prep_test.go +++ b/pkg/agentic/prep_test.go @@ -712,6 +712,7 @@ func TestPrep_RegisterTools_Good_RegistersCompletionTool(t *testing.T) { assert.Contains(t, toolNames, "agentic_complete") assert.Contains(t, toolNames, "prompt_version") assert.Contains(t, toolNames, "agentic_prompt_version") + assert.Contains(t, toolNames, "agentic_setup") assert.Contains(t, toolNames, "session_complete") assert.Contains(t, toolNames, "agentic_message_send") assert.Contains(t, toolNames, "agent_send") @@ -738,6 +739,7 @@ func TestPrep_OnStartup_Good_RegistersGenerateCommand(t *testing.T) { assert.Contains(t, c.Commands(), "prep-workspace") assert.Contains(t, c.Commands(), "setup") assert.Contains(t, c.Commands(), "agentic:setup") + assert.True(t, c.Action("agentic.setup").Exists()) assert.Contains(t, c.Commands(), "watch") assert.Contains(t, c.Commands(), "workspace/watch") assert.Contains(t, c.Commands(), "agentic:watch")