package brief import ( "context" "github.com/yan1h/agent-coding-workflow/internal/infra/git" ) // RepoOrientation 是仓库的轻量定向信息:当前分支、最近若干提交摘要、脏文件路径。 // 用于给 agent 一个"我现在在哪个分支、最近发生了什么、工作树是否干净"的速览。 type RepoOrientation struct { Branch string RecentCommits []string DirtyFiles []string } // IsEmpty 报告该定向信息是否完全为空(无分支、无提交、无脏文件)。 func (o RepoOrientation) IsEmpty() bool { return o.Branch == "" && len(o.RecentCommits) == 0 && len(o.DirtyFiles) == 0 } // RepoOrienter 是 brief 对 git 的窄接口:给定目录返回有界的仓库定向信息。 // 让 brief 可在没有真实仓库的情况下被单测(注入 fake orienter)。 type RepoOrienter interface { Orient(ctx context.Context, dir, branch string, maxCommits, maxDirty int) RepoOrientation } // gitClient 是 orienter 对 git.Runner 的最小子集。*git.DefaultRunner 直接满足。 type gitClient interface { Log(ctx context.Context, dir string, n int) ([]git.Commit, error) Status(ctx context.Context, dir string) ([]git.FileStatus, error) } // gitOrienter 是 RepoOrienter 的生产实现,基于 infra/git 的 Log + Status。 // 设计为"尽力而为且永不致命":任何 git 调用失败只产生部分/空的定向信息, // 不返回 error,从而不会拖垮整份简报(git 失败不应阻塞 prompt 注入)。 type gitOrienter struct{ g gitClient } // NewRepoOrienter 用给定 git runner 构造 RepoOrienter。 func NewRepoOrienter(g gitClient) RepoOrienter { return &gitOrienter{g: g} } func (o *gitOrienter) Orient(ctx context.Context, dir, branch string, maxCommits, maxDirty int) RepoOrientation { out := RepoOrientation{Branch: branch} if dir == "" || o.g == nil { return out } if maxCommits > 0 { if commits, err := o.g.Log(ctx, dir, maxCommits); err == nil { for _, c := range commits { short := c.Hash if len(short) > 8 { short = short[:8] } out.RecentCommits = append(out.RecentCommits, short+" "+c.Subject) } } } if maxDirty > 0 { if files, err := o.g.Status(ctx, dir); err == nil { for i, f := range files { if i >= maxDirty { break } out.DirtyFiles = append(out.DirtyFiles, f.Path) } } } return out }