Files
agent-mgr/internal/api/router.go
Steven Hooker e5b07cc1d8 initial agent-mgr: app builder platform MVP
Go API server + Preact UI + Claude Code adapter.
- App-centric model (ideas, not repos)
- AgentProvider interface for multi-agent support
- K8s pod lifecycle for sandboxed agent sessions
- Gitea integration (create repos, push branches)
- WebSocket streaming for live session output
- Woodpecker CI/CD pipelines (kaniko build + kubectl deploy)
2026-02-18 15:56:32 +01:00

78 lines
2.0 KiB
Go

package api
import (
"io/fs"
"log/slog"
"net/http"
"github.com/agentsphere/agent-mgr/internal/app"
"github.com/agentsphere/agent-mgr/internal/events"
"github.com/agentsphere/agent-mgr/internal/provider"
"github.com/agentsphere/agent-mgr/internal/store"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
type Server struct {
store *store.Store
app *app.Service
registry *provider.Registry
events *events.Bus
log *slog.Logger
}
func NewServer(st *store.Store, appSvc *app.Service, reg *provider.Registry, bus *events.Bus, log *slog.Logger) *Server {
return &Server{store: st, app: appSvc, registry: reg, events: bus, log: log}
}
func (s *Server) Handler(staticFS fs.FS) http.Handler {
r := chi.NewRouter()
r.Use(middleware.RealIP)
r.Use(middleware.Recoverer)
r.Use(middleware.Compress(5))
// API routes
r.Route("/api/v1", func(r chi.Router) {
r.Use(middleware.SetHeader("Content-Type", "application/json"))
r.Post("/apps", s.createApp)
r.Get("/apps", s.listApps)
r.Get("/apps/{appID}", s.getApp)
r.Delete("/apps/{appID}", s.deleteApp)
r.Post("/apps/{appID}/sessions", s.createSession)
r.Get("/apps/{appID}/sessions", s.listSessions)
r.Get("/sessions/{sessionID}", s.getSession)
r.Post("/sessions/{sessionID}/stop", s.stopSession)
r.Post("/sessions/{sessionID}/message", s.sendMessage)
r.Get("/sessions/{sessionID}/ws", s.streamSession)
r.Get("/providers", s.listProviders)
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"status":"ok"}`))
})
})
// Serve SPA for all other routes
if staticFS != nil {
fileServer := http.FileServer(http.FS(staticFS))
r.Get("/*", func(w http.ResponseWriter, r *http.Request) {
// Try to serve the file; if not found, serve index.html (SPA routing)
path := r.URL.Path
f, err := staticFS.Open(path[1:]) // strip leading /
if err != nil {
// Serve index.html for SPA client-side routing
r.URL.Path = "/"
} else {
f.Close()
}
fileServer.ServeHTTP(w, r)
})
}
return r
}