feat(agentic): add dispatch lifecycle commands

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-01 14:05:18 +00:00
parent dc9a81e101
commit c55f4e4f5e
2 changed files with 100 additions and 0 deletions

View file

@ -20,6 +20,9 @@ func (s *PrepSubsystem) registerCommands(ctx context.Context) {
c.Command("run/task", core.Command{Description: "Run a single task end-to-end", Action: s.cmdRunTask})
c.Command("run/orchestrator", core.Command{Description: "Run the queue orchestrator (standalone, no MCP)", Action: s.cmdOrchestrator})
c.Command("dispatch", core.Command{Description: "Dispatch queued agents", Action: s.cmdDispatch})
c.Command("dispatch/start", core.Command{Description: "Start the dispatch queue runner", Action: s.cmdDispatchStart})
c.Command("dispatch/shutdown", core.Command{Description: "Freeze the dispatch queue gracefully", Action: s.cmdDispatchShutdown})
c.Command("dispatch/shutdown-now", core.Command{Description: "Hard stop the dispatch queue and kill running agents", Action: s.cmdDispatchShutdownNow})
c.Command("prep", core.Command{Description: "Prepare a workspace: clone repo, build prompt", Action: s.cmdPrep})
c.Command("prep-workspace", core.Command{Description: "Prepare a workspace: clone repo, build prompt", Action: s.cmdPrep})
c.Command("generate", core.Command{Description: "Generate content from a prompt using the platform content pipeline", Action: s.cmdGenerate})
@ -110,6 +113,49 @@ func (s *PrepSubsystem) cmdDispatch(_ core.Options) core.Result {
return s.runDispatchLoop("dispatch")
}
func (s *PrepSubsystem) cmdDispatchStart(_ core.Options) core.Result {
_, output, err := s.dispatchStart(s.commandContext(), nil, ShutdownInput{})
if err != nil {
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
if output.Message != "" {
core.Print(nil, "%s", output.Message)
}
return core.Result{Value: output, OK: true}
}
func (s *PrepSubsystem) cmdDispatchShutdown(_ core.Options) core.Result {
_, output, err := s.shutdownGraceful(s.commandContext(), nil, ShutdownInput{})
if err != nil {
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
if output.Message != "" {
core.Print(nil, "%s", output.Message)
}
return core.Result{Value: output, OK: true}
}
func (s *PrepSubsystem) cmdDispatchShutdownNow(_ core.Options) core.Result {
_, output, err := s.shutdownNow(s.commandContext(), nil, ShutdownInput{})
if err != nil {
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
if output.Message != "" {
core.Print(nil, "%s", output.Message)
}
if output.Running > 0 || output.Queued > 0 {
core.Print(nil, "running: %d", output.Running)
core.Print(nil, "queued: %d", output.Queued)
}
return core.Result{Value: output, OK: true}
}
func (s *PrepSubsystem) runDispatchLoop(label string) core.Result {
ctx := s.commandContext()
core.Print(nil, "core-agent %s running (pid %s)", label, core.Env("PID"))

View file

@ -1146,6 +1146,57 @@ func TestCommands_CmdDispatch_Good_CancelledCtx(t *testing.T) {
assert.True(t, r.OK)
}
func TestCommands_CmdDispatchStart_Good(t *testing.T) {
s, c := testPrepWithCore(t, nil)
called := false
c.Action("runner.start", func(_ context.Context, _ core.Options) core.Result {
called = true
return core.Result{OK: true}
})
output := captureStdout(t, func() {
r := s.cmdDispatchStart(core.NewOptions())
assert.True(t, r.OK)
})
assert.True(t, called)
assert.Contains(t, output, "dispatch started")
}
func TestCommands_CmdDispatchShutdown_Good(t *testing.T) {
s, c := testPrepWithCore(t, nil)
called := false
c.Action("runner.stop", func(_ context.Context, _ core.Options) core.Result {
called = true
return core.Result{OK: true}
})
output := captureStdout(t, func() {
r := s.cmdDispatchShutdown(core.NewOptions())
assert.True(t, r.OK)
})
assert.True(t, called)
assert.Contains(t, output, "queue frozen")
}
func TestCommands_CmdDispatchShutdownNow_Good(t *testing.T) {
s, c := testPrepWithCore(t, nil)
called := false
c.Action("runner.kill", func(_ context.Context, _ core.Options) core.Result {
called = true
return core.Result{OK: true}
})
output := captureStdout(t, func() {
r := s.cmdDispatchShutdownNow(core.NewOptions())
assert.True(t, r.OK)
})
assert.True(t, called)
assert.Contains(t, output, "killed all agents")
}
func TestCommands_ParseIntStr_Good(t *testing.T) {
assert.Equal(t, 42, parseIntString("42"))
assert.Equal(t, 123, parseIntString("issue-123"))
@ -1166,6 +1217,9 @@ func TestCommands_RegisterCommands_Good_AllRegistered(t *testing.T) {
assert.Contains(t, cmds, "run/task")
assert.Contains(t, cmds, "run/orchestrator")
assert.Contains(t, cmds, "dispatch")
assert.Contains(t, cmds, "dispatch/start")
assert.Contains(t, cmds, "dispatch/shutdown")
assert.Contains(t, cmds, "dispatch/shutdown-now")
assert.Contains(t, cmds, "prep")
assert.Contains(t, cmds, "complete")
assert.Contains(t, cmds, "scan")