package repos import ( "context" "time" "gitmanager/internal/git" ) // Detail is the enriched view of a single repository shown in the detail panel. // It embeds the cached State and adds data fetched on demand via the git // boundary (all read-only — AGENT.md §1.3). type Detail struct { State Branches []git.Branch `json:"branches"` Commits []git.Commit `json:"commits"` RemoteDetails []git.Remote `json:"remoteDetails"` } // Get returns the cached State for a repo path, or false if it is not indexed. func (i *Index) Get(path string) (State, bool) { i.mu.RLock() defer i.mu.RUnlock() s, ok := i.byKey[path] return s, ok } // BuildDetail enriches a cached State with branches, recent commits, and remote // URLs. Errors on the enriching calls are non-fatal: whatever succeeds is // returned, and the partial failure is recorded on Detail.Error. func BuildDetail(ctx context.Context, g *git.CLI, base State) Detail { ctx, cancel := context.WithTimeout(ctx, 20*time.Second) defer cancel() d := Detail{State: base} if branches, err := g.LocalBranches(ctx, base.Path); err == nil { d.Branches = branches } else { d.Error = err.Error() } if commits, err := g.RecentCommits(ctx, base.Path, 20); err == nil { d.Commits = commits } else if d.Error == "" { d.Error = err.Error() } if remotes, err := g.RemoteDetails(ctx, base.Path); err == nil { d.RemoteDetails = remotes } else if d.Error == "" { d.Error = err.Error() } return d }