Add git module with repo status overview (/git) and per-repo detail page (/git/[repo]) featuring a color-coded diff viewer (+ green, - red). Reads repo paths from REPO_PATHS env var, calls ops-agent git_status and git_diff commands. Status badges: clean (green), dirty (orange), behind-origin (blue). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
export interface RepoStatus {
|
|
branch: string
|
|
/** Number of commits ahead of upstream (undefined if no upstream) */
|
|
ahead?: number
|
|
/** Number of commits behind upstream (undefined if no upstream) */
|
|
behind?: number
|
|
/** True when there are uncommitted changes */
|
|
dirty: boolean
|
|
}
|
|
|
|
/**
|
|
* Parses `git status --short --branch` output into a RepoStatus.
|
|
*
|
|
* First line format: ## main...origin/main [ahead N, behind M]
|
|
* Remaining lines: XY path (presence means dirty)
|
|
*/
|
|
export function parseGitStatus(output: string): RepoStatus {
|
|
const lines = output.trim().split('\n').filter(Boolean)
|
|
|
|
let branch = 'unknown'
|
|
let ahead: number | undefined
|
|
let behind: number | undefined
|
|
let dirty = false
|
|
|
|
for (const line of lines) {
|
|
if (line.startsWith('## ')) {
|
|
const rest = line.slice(3)
|
|
// "No commits yet on main" or "HEAD (no branch)"
|
|
const trackMatch = rest.match(/^([^.]+)\.\.\.(\S+)/)
|
|
if (trackMatch) {
|
|
branch = trackMatch[1]
|
|
} else {
|
|
branch = rest.split(' ')[0]
|
|
}
|
|
const aheadMatch = rest.match(/ahead (\d+)/)
|
|
const behindMatch = rest.match(/behind (\d+)/)
|
|
if (aheadMatch) ahead = parseInt(aheadMatch[1], 10)
|
|
if (behindMatch) behind = parseInt(behindMatch[1], 10)
|
|
} else {
|
|
// Any non-header line means there are changes
|
|
dirty = true
|
|
}
|
|
}
|
|
|
|
return { branch, ahead, behind, dirty }
|
|
}
|