f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
186 lines
5.6 KiB
Go
186 lines
5.6 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
|
|
"go.kenn.io/agentsview/internal/db"
|
|
"go.kenn.io/agentsview/internal/service"
|
|
"go.kenn.io/agentsview/internal/update"
|
|
)
|
|
|
|
func (s *Server) registerMetadataRoutes() {
|
|
group := newRouteGroup(s.api, "/api/v1", "Metadata")
|
|
|
|
get(s, group, "/projects", "List projects", s.humaListProjects)
|
|
get(s, group, "/machines", "List machines", s.humaListMachines)
|
|
get(s, group, "/branches", "List branches", s.humaListBranches)
|
|
get(s, group, "/agents", "List agents", s.humaListAgents)
|
|
get(s, group, "/stats", "Get stats", s.humaGetStats)
|
|
get(s, group, "/session-stats", "Get session stats", s.humaGetSessionStats)
|
|
get(s, group, "/version", "Get server version", s.humaGetVersion)
|
|
get(s, group, "/update/check", "Check for updates", s.humaCheckUpdate)
|
|
}
|
|
|
|
type statsInput struct {
|
|
BoolIncludeInput
|
|
}
|
|
|
|
type sessionStatsInput struct {
|
|
BoolIncludeInput
|
|
Since string `query:"since" doc:"Start of window"`
|
|
Until string `query:"until" doc:"End of window"`
|
|
Agent string `query:"agent" doc:"Filter by agent"`
|
|
IncludeProjects []string `query:"include_project" doc:"Restrict to these projects"`
|
|
ExcludeProjects []string `query:"exclude_project" doc:"Exclude these projects"`
|
|
Timezone string `query:"timezone" doc:"IANA timezone name"`
|
|
IncludeGitOutcomes bool `query:"include_git_outcomes" doc:"Include git-derived outcome stats"`
|
|
IncludeGitHubOutcomes bool `query:"include_github_outcomes" doc:"Include GitHub PR outcome stats"`
|
|
}
|
|
|
|
type projectsResponse struct {
|
|
Projects []db.ProjectInfo `json:"projects"`
|
|
}
|
|
|
|
type machinesResponse struct {
|
|
Machines []string `json:"machines"`
|
|
}
|
|
|
|
type branchesResponse struct {
|
|
Branches []db.BranchInfo `json:"branches"`
|
|
}
|
|
|
|
type agentsResponse struct {
|
|
Agents []db.AgentInfo `json:"agents"`
|
|
}
|
|
|
|
func (s *Server) humaGetStats(
|
|
ctx context.Context,
|
|
in *statsInput,
|
|
) (*jsonOutput[db.Stats], error) {
|
|
stats, err := s.db.GetStats(ctx, !in.IncludeOneShot, !in.IncludeAutomated)
|
|
if err != nil {
|
|
return nil, serverError(err)
|
|
}
|
|
return &jsonOutput[db.Stats]{Body: stats}, nil
|
|
}
|
|
|
|
func (s *Server) humaGetSessionStats(
|
|
ctx context.Context,
|
|
in *sessionStatsInput,
|
|
) (*jsonOutput[*service.SessionStats], error) {
|
|
githubToken := ""
|
|
if in.IncludeGitHubOutcomes {
|
|
githubToken = s.githubToken(ctx)
|
|
}
|
|
stats, err := s.sessions.Stats(ctx, service.StatsFilter{
|
|
ApplyDefaultVisibility: true,
|
|
Since: in.Since,
|
|
Until: in.Until,
|
|
Agent: in.Agent,
|
|
IncludeOneShot: in.IncludeOneShot,
|
|
IncludeAutomated: in.IncludeAutomated,
|
|
IncludeProjects: in.IncludeProjects,
|
|
ExcludeProjects: in.ExcludeProjects,
|
|
Timezone: in.Timezone,
|
|
IncludeGitOutcomes: in.IncludeGitOutcomes,
|
|
IncludeGitHubOutcomes: in.IncludeGitHubOutcomes,
|
|
GHToken: githubToken,
|
|
})
|
|
if err != nil {
|
|
if handled := handleHumaContextError(err); handled != nil {
|
|
return nil, handled
|
|
}
|
|
if handled := handleHumaReadOnly(err); handled != nil {
|
|
return nil, handled
|
|
}
|
|
var inputErr *db.StatsInputError
|
|
if errors.As(err, &inputErr) {
|
|
return nil, apiError(http.StatusBadRequest, inputErr.Msg)
|
|
}
|
|
return nil, internalError("session stats error", err)
|
|
}
|
|
return &jsonOutput[*service.SessionStats]{Body: stats}, nil
|
|
}
|
|
|
|
func (s *Server) humaListProjects(
|
|
ctx context.Context,
|
|
in *statsInput,
|
|
) (*jsonOutput[projectsResponse], error) {
|
|
projects, err := s.db.GetProjects(ctx, !in.IncludeOneShot, !in.IncludeAutomated)
|
|
if err != nil {
|
|
return nil, serverError(err)
|
|
}
|
|
return &jsonOutput[projectsResponse]{Body: projectsResponse{Projects: projects}}, nil
|
|
}
|
|
|
|
func (s *Server) humaListMachines(
|
|
ctx context.Context,
|
|
in *statsInput,
|
|
) (*jsonOutput[machinesResponse], error) {
|
|
machines, err := s.db.GetMachines(ctx, !in.IncludeOneShot, !in.IncludeAutomated)
|
|
if err != nil {
|
|
return nil, serverError(err)
|
|
}
|
|
return &jsonOutput[machinesResponse]{Body: machinesResponse{Machines: machines}}, nil
|
|
}
|
|
|
|
func (s *Server) humaListBranches(
|
|
ctx context.Context,
|
|
in *statsInput,
|
|
) (*jsonOutput[branchesResponse], error) {
|
|
branches, err := s.db.GetBranches(ctx, !in.IncludeOneShot, !in.IncludeAutomated)
|
|
if err != nil {
|
|
return nil, serverError(err)
|
|
}
|
|
return &jsonOutput[branchesResponse]{Body: branchesResponse{Branches: branches}}, nil
|
|
}
|
|
|
|
func (s *Server) humaListAgents(
|
|
ctx context.Context,
|
|
in *statsInput,
|
|
) (*jsonOutput[agentsResponse], error) {
|
|
agents, err := s.db.GetAgents(ctx, !in.IncludeOneShot, !in.IncludeAutomated)
|
|
if err != nil {
|
|
return nil, serverError(err)
|
|
}
|
|
return &jsonOutput[agentsResponse]{Body: agentsResponse{Agents: agents}}, nil
|
|
}
|
|
|
|
func (s *Server) humaGetVersion(
|
|
_ context.Context,
|
|
_ *emptyInput,
|
|
) (*jsonOutput[VersionInfo], error) {
|
|
return &jsonOutput[VersionInfo]{Body: s.version}, nil
|
|
}
|
|
|
|
func (s *Server) humaCheckUpdate(
|
|
_ context.Context,
|
|
_ *emptyInput,
|
|
) (*jsonOutput[updateCheckResponse], error) {
|
|
if s.cfg.DisableUpdateCheck {
|
|
return &jsonOutput[updateCheckResponse]{
|
|
Body: updateCheckResponse{CurrentVersion: s.version.Version},
|
|
}, nil
|
|
}
|
|
checkFn := s.updateCheckFn
|
|
if checkFn == nil {
|
|
checkFn = update.CheckForUpdate
|
|
}
|
|
info, err := checkFn(s.version.Version, false, s.dataDir)
|
|
if err != nil || info == nil {
|
|
return &jsonOutput[updateCheckResponse]{
|
|
Body: updateCheckResponse{CurrentVersion: s.version.Version},
|
|
}, nil
|
|
}
|
|
return &jsonOutput[updateCheckResponse]{
|
|
Body: updateCheckResponse{
|
|
UpdateAvailable: !info.IsDevBuild,
|
|
CurrentVersion: info.CurrentVersion,
|
|
LatestVersion: info.LatestVersion,
|
|
IsDevBuild: info.IsDevBuild,
|
|
},
|
|
}, nil
|
|
}
|