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)
78 lines
2.0 KiB
Go
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
|
|
}
|