feat(coding-agent): watch .git/HEAD for branch changes (#79)

Auto-updates footer when git branch changes externally (e.g., git checkout in another terminal)
This commit is contained in:
Tino Ehrich 2025-11-29 21:52:13 +01:00 committed by GitHub
parent 532bb69ed6
commit 832273d4d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 52 additions and 1 deletions

View file

@ -1,7 +1,7 @@
import type { AgentState } from "@mariozechner/pi-agent-core";
import type { AssistantMessage } from "@mariozechner/pi-ai";
import { type Component, visibleWidth } from "@mariozechner/pi-tui";
import { readFileSync } from "fs";
import { existsSync, type FSWatcher, readFileSync, watch } from "fs";
import { join } from "path";
import { theme } from "../theme/theme.js";
@ -11,11 +11,56 @@ import { theme } from "../theme/theme.js";
export class FooterComponent implements Component {
private state: AgentState;
private cachedBranch: string | null | undefined = undefined; // undefined = not checked yet, null = not in git repo, string = branch name
private gitWatcher: FSWatcher | null = null;
private onBranchChange: (() => void) | null = null;
constructor(state: AgentState) {
this.state = state;
}
/**
* Set up a file watcher on .git/HEAD to detect branch changes.
* Call the provided callback when branch changes.
*/
watchBranch(onBranchChange: () => void): void {
this.onBranchChange = onBranchChange;
this.setupGitWatcher();
}
private setupGitWatcher(): void {
// Clean up existing watcher
if (this.gitWatcher) {
this.gitWatcher.close();
this.gitWatcher = null;
}
const gitHeadPath = join(process.cwd(), ".git", "HEAD");
if (!existsSync(gitHeadPath)) {
return;
}
try {
this.gitWatcher = watch(gitHeadPath, () => {
this.cachedBranch = undefined; // Invalidate cache
if (this.onBranchChange) {
this.onBranchChange();
}
});
} catch {
// Silently fail if we can't watch
}
}
/**
* Clean up the file watcher
*/
dispose(): void {
if (this.gitWatcher) {
this.gitWatcher.close();
this.gitWatcher = null;
}
}
updateState(state: AgentState): void {
this.state = state;
}

View file

@ -464,6 +464,11 @@ export class TuiRenderer {
this.updateEditorBorderColor();
this.ui.requestRender();
});
// Set up git branch watcher
this.footer.watchBranch(() => {
this.ui.requestRender();
});
}
private subscribeToAgent(): void {
@ -1523,6 +1528,7 @@ export class TuiRenderer {
this.loadingAnimation.stop();
this.loadingAnimation = null;
}
this.footer.dispose();
if (this.isInitialized) {
this.ui.stop();
this.isInitialized = false;