mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-05 02:31:47 +00:00
feat(tui): append git branch to cwd label in status bar
Adds useGitBranch hook (async, cached, 15s TTL) and fmtCwdBranch helper so the footer shows `~/repo (main)` instead of just `~/repo`. Degrades silently when git is unavailable or cwd is outside a repo. Partial fix for #12267 (TUI portion; #12277 covers the Python side).
This commit is contained in:
parent
0175ff7516
commit
ff2aa7ccd7
4 changed files with 160 additions and 3 deletions
72
ui-tui/src/hooks/useGitBranch.ts
Normal file
72
ui-tui/src/hooks/useGitBranch.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { execFile } from 'node:child_process'
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const TTL_MS = 15_000
|
||||
const TIMEOUT_MS = 500
|
||||
|
||||
const pexec = promisify(execFile)
|
||||
const cache = new Map<string, { at: number; branch: null | string }>()
|
||||
const inflight = new Map<string, Promise<null | string>>()
|
||||
|
||||
const resolveBranch = async (cwd: string): Promise<null | string> => {
|
||||
try {
|
||||
const { stdout } = await pexec('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { timeout: TIMEOUT_MS })
|
||||
const b = stdout.trim()
|
||||
|
||||
return !b || b === 'HEAD' ? null : b
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const fetchBranch = (cwd: string): Promise<null | string> => {
|
||||
const pending = inflight.get(cwd)
|
||||
|
||||
if (pending) {
|
||||
return pending
|
||||
}
|
||||
|
||||
const p = resolveBranch(cwd).finally(() => inflight.delete(cwd))
|
||||
inflight.set(cwd, p)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
export function useGitBranch(cwd: string): null | string {
|
||||
const [branch, setBranch] = useState<null | string>(() => cache.get(cwd)?.branch ?? null)
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
|
||||
const tick = async () => {
|
||||
const hit = cache.get(cwd)
|
||||
|
||||
if (hit && Date.now() - hit.at < TTL_MS) {
|
||||
if (!cancelled) {
|
||||
setBranch(hit.branch)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const b = await fetchBranch(cwd)
|
||||
cache.set(cwd, { at: Date.now(), branch: b })
|
||||
|
||||
if (!cancelled) {
|
||||
setBranch(b)
|
||||
}
|
||||
}
|
||||
|
||||
void tick()
|
||||
const id = setInterval(() => void tick(), TTL_MS)
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
clearInterval(id)
|
||||
}
|
||||
}, [cwd])
|
||||
|
||||
return branch
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue