mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 06:02:42 +00:00
feat: show git branch in footer
- Footer now displays active git branch after directory path (e.g., ~/project (main)) - Branch detected by reading .git/HEAD directly (fast, synchronous) - Cache refreshed after each assistant message to detect branch changes - Handles normal branches, detached HEAD, and non-git repos Closes #55
This commit is contained in:
parent
f95f41b1c4
commit
318254bff4
3 changed files with 44 additions and 1 deletions
|
|
@ -1,6 +1,8 @@
|
|||
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 { join } from "path";
|
||||
import { theme } from "../theme/theme.js";
|
||||
|
||||
/**
|
||||
|
|
@ -8,6 +10,7 @@ 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
|
||||
|
||||
constructor(state: AgentState) {
|
||||
this.state = state;
|
||||
|
|
@ -18,7 +21,37 @@ export class FooterComponent implements Component {
|
|||
}
|
||||
|
||||
invalidate(): void {
|
||||
// No cached state to invalidate currently
|
||||
// Invalidate cached branch so it gets re-read on next render
|
||||
this.cachedBranch = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current git branch by reading .git/HEAD directly.
|
||||
* Returns null if not in a git repo, branch name otherwise.
|
||||
*/
|
||||
private getCurrentBranch(): string | null {
|
||||
// Return cached value if available
|
||||
if (this.cachedBranch !== undefined) {
|
||||
return this.cachedBranch;
|
||||
}
|
||||
|
||||
try {
|
||||
const gitHeadPath = join(process.cwd(), ".git", "HEAD");
|
||||
const content = readFileSync(gitHeadPath, "utf8").trim();
|
||||
|
||||
if (content.startsWith("ref: refs/heads/")) {
|
||||
// Normal branch: extract branch name
|
||||
this.cachedBranch = content.slice(16);
|
||||
} else {
|
||||
// Detached HEAD state
|
||||
this.cachedBranch = "detached";
|
||||
}
|
||||
} catch {
|
||||
// Not in a git repo or error reading file
|
||||
this.cachedBranch = null;
|
||||
}
|
||||
|
||||
return this.cachedBranch;
|
||||
}
|
||||
|
||||
render(width: number): string[] {
|
||||
|
|
@ -71,6 +104,12 @@ export class FooterComponent implements Component {
|
|||
pwd = "~" + pwd.slice(home.length);
|
||||
}
|
||||
|
||||
// Add git branch if available
|
||||
const branch = this.getCurrentBranch();
|
||||
if (branch) {
|
||||
pwd = `${pwd} (${branch})`;
|
||||
}
|
||||
|
||||
// Truncate path if too long to fit width
|
||||
const maxPathLength = Math.max(20, width - 10); // Leave some margin
|
||||
if (pwd.length > maxPathLength) {
|
||||
|
|
|
|||
|
|
@ -589,6 +589,9 @@ export class TuiRenderer {
|
|||
|
||||
// Keep the streaming component - it's now the final assistant message
|
||||
this.streamingComponent = null;
|
||||
|
||||
// Invalidate footer cache to refresh git branch (in case agent executed git commands)
|
||||
this.footer.invalidate();
|
||||
}
|
||||
this.ui.requestRender();
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue