agent/pkg/agentic/runner.go
Snider 6d4b92737e feat(agent): background runner, slim status, Docker dispatch, stopwatch, CLI fixes
- Add background queue runner (runner.go) — 30s tick + poke on completion
- drainQueue now loops to fill all slots per tick
- Add run orchestrator command — standalone queue runner without MCP
- Slim agentic_status — stats only, blocked workspaces listed
- Docker containerised dispatch — all agents run in core-dev container
- Forge stopwatch start/stop on issue when agent starts/completes
- issue create supports --milestone, --assignee, --ref
- Auto-PR targets dev branch (not main)
- PR body includes Closes #N for issue-linked work
- CLI usage strings use spaces not slashes
- Review agent uses exec with sandbox bypass (not codex review subcommand)
- Local model support via codex --oss with socat Ollama proxy

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-23 12:53:33 +00:00

42 lines
864 B
Go

// SPDX-License-Identifier: EUPL-1.2
package agentic
import "time"
// StartRunner begins the background queue runner.
// Ticks every 30s to drain queued tasks into available slots.
// Also responds to Poke() for immediate drain on completion events.
//
// prep.StartRunner()
func (s *PrepSubsystem) StartRunner() {
s.pokeCh = make(chan struct{}, 1)
go s.runLoop()
}
func (s *PrepSubsystem) runLoop() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
s.drainQueue()
case <-s.pokeCh:
s.drainQueue()
}
}
}
// Poke signals the runner to check the queue immediately.
// Non-blocking — if a poke is already pending, this is a no-op.
//
// s.Poke() // after agent completion
func (s *PrepSubsystem) Poke() {
if s.pokeCh == nil {
return
}
select {
case s.pokeCh <- struct{}{}:
default:
}
}