feat(boss): Chief of Staff Boss + spun-crow registry with cap (#42)

This commit is contained in:
Smokey committed 2026-10-28 09:01:26 -06:00
1 parent ccb0e503c5
commit 663c8a19d8
10 files changed
+329 -20

No files matched your search

+12 -4
View File
@@ -32,6 +32,7 @@ type Server struct {
approver *WebApprover
hub *Hub
nests *NestStore
crows *CrowStore
msgs *MessageStore
ctx context.Context // cancelled on shutdown; lists and streams end with it
beat time.Duration
@@ -45,13 +46,17 @@ func NewServer(ctx context.Context, p *Pipeline, approver *WebApprover, nests *N
// WithMessages attaches the nest conversation log (chatroom path).
func (s *Server) WithMessages(m *MessageStore) *Server { s.msgs = m; return s }
// WithCrows attaches the spun-crow registry (the Boss writes through it).
func (s *Server) WithCrows(c *CrowStore) *Server { s.crows = c; return s }
func (s *Server) Handler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("POST /api/lists", s.postList)
mux.HandleFunc("GET /api/events", s.events)
mux.HandleFunc("POST /api/verdicts", s.postVerdict)
mux.HandleFunc("GET /api/trust", s.trust)
mux.HandleFunc("GET /api/crows", s.crows)
mux.HandleFunc("GET /api/personas", s.crowPersonas)
mux.HandleFunc("GET /api/crows", s.getCrowRegistry)
mux.HandleFunc("GET /api/nests", s.getNests)
mux.HandleFunc("POST /api/nests", s.postNest)
mux.HandleFunc("GET /api/nests/{nest_id}/messages", s.getNestMessages)
@@ -82,6 +87,8 @@ func cmdServe(args []string) {
must(err)
msgs, err := LoadMessageStore(filepath.Join(dataDir, "messages"))
must(err)
spun, err := LoadCrowStore(filepath.Join(dataDir, "crows.json"))
must(err)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
@@ -93,7 +100,7 @@ func cmdServe(args []string) {
if jev != nil {
fmt.Printf("Sentry triage: %s, LLM fallback\n", jev.Name())
}
s := NewServer(ctx, p, approver, nests).WithMessages(msgs)
s := NewServer(ctx, p, approver, nests).WithMessages(msgs).WithCrows(spun)
srv := &http.Server{Addr: *addr, Handler: s.Handler(), ReadHeaderTimeout: 10 * time.Second}
go func() {
@@ -318,8 +325,9 @@ func (s *Server) postNest(w http.ResponseWriter, r *http.Request) {
}
}
// crows lists each crow's persona for the UI (name, epithet, strength, backstory).
func (s *Server) crows(w http.ResponseWriter, r *http.Request) {
// crowPersonas lists each persona crow for the UI (name, epithet, strength,
// backstory). The spun-crow registry lives at GET /api/crows (crowreg.go).
func (s *Server) crowPersonas(w http.ResponseWriter, r *http.Request) {
out := make([]map[string]string, 0, len(rosterOrder))
for _, n := range rosterOrder {
p := personas[n]