// Package service is the ONE capability layer behind both the HTTP API and the // MCP server (AGENT.md §1.7). HTTP handlers and MCP tool handlers are thin // adapters that call these methods; Git/forge logic never lives in a handler. // Everything here goes through the internal/git (and later internal/forge) // boundaries and obeys the safety rules (§1.4). package service import ( "context" "path/filepath" "gitmanager/internal/git" "gitmanager/internal/repos" ) // Service holds the shared dependencies the capabilities need. type Service struct { git *git.CLI index *repos.Index } // New builds a Service over the git boundary and the scanner's repo index. func New(g *git.CLI, index *repos.Index) *Service { return &Service{git: g, index: index} } // ListRepos returns a snapshot of every discovered repository. func (s *Service) ListRepos() []repos.State { return s.index.List() } // GetRepo returns the cached state for one repo, or false if it is not indexed. // The path is cleaned so separator style does not defeat the exact-match lookup. func (s *Service) GetRepo(path string) (repos.State, bool) { return s.index.Get(filepath.Clean(path)) } // RepoDetail returns the enriched detail (branches, commits, remotes) for one // repo. The second return is false when the path is not an indexed repository — // we never run git against an arbitrary caller-supplied path (§1.3). func (s *Service) RepoDetail(ctx context.Context, path string) (repos.Detail, bool) { base, ok := s.index.Get(filepath.Clean(path)) if !ok { return repos.Detail{}, false } return repos.BuildDetail(ctx, s.git, base), true }