diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index 4ec0d4e..3ca2a8f 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -265,6 +265,9 @@ export default function App() {
onSetSessionArchived={(sessionId, isArchived) => {
void api.setSessionArchived({ sessionId, isArchived });
}}
+ onRefreshGitContext={(projectId) => {
+ void api.refreshProjectGitContext(projectId);
+ }}
workspace={workspace}
/>
}
diff --git a/src/renderer/components/ChatPane.tsx b/src/renderer/components/ChatPane.tsx
index 342a28f..53382c9 100644
--- a/src/renderer/components/ChatPane.tsx
+++ b/src/renderer/components/ChatPane.tsx
@@ -1,5 +1,5 @@
import { type KeyboardEvent, useEffect, useRef, useState } from 'react';
-import { AlertCircle, ArrowUp, Bot, ChevronDown, Loader2, Sparkles, User } from 'lucide-react';
+import { AlertCircle, ArrowUp, Bot, ChevronDown, Circle, GitBranch, Loader2, Sparkles, User } from 'lucide-react';
import { MarkdownContent } from '@renderer/components/MarkdownContent';
import { getAssistantMessagePhase } from '@renderer/lib/messagePhase';
@@ -318,7 +318,20 @@ export function ChatPane({
diff --git a/src/renderer/components/Sidebar.tsx b/src/renderer/components/Sidebar.tsx
index 752a1c8..b2b57bd 100644
--- a/src/renderer/components/Sidebar.tsx
+++ b/src/renderer/components/Sidebar.tsx
@@ -1,11 +1,14 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import {
+ AlertTriangle,
Archive,
ArrowLeftRight,
ChevronDown,
ChevronRight,
+ Circle,
Copy,
FolderOpen,
+ GitBranch,
GitFork,
ListOrdered,
Lock,
@@ -14,6 +17,7 @@ import {
Pencil,
Pin,
Plus,
+ RefreshCw,
Search,
Settings,
Sparkles,
@@ -23,7 +27,7 @@ import {
} from 'lucide-react';
import type { OrchestrationMode, PatternDefinition } from '@shared/domain/pattern';
-import { isScratchpadProject, type ProjectRecord } from '@shared/domain/project';
+import { isScratchpadProject, type ProjectRecord, type ProjectGitContext } from '@shared/domain/project';
import type { SessionRecord } from '@shared/domain/session';
import { querySessions } from '@shared/domain/sessionLibrary';
import type { WorkspaceState } from '@shared/domain/workspace';
@@ -39,6 +43,7 @@ interface SidebarProps {
onDuplicateSession: (sessionId: string) => void;
onSetSessionPinned: (sessionId: string, isPinned: boolean) => void;
onSetSessionArchived: (sessionId: string, isArchived: boolean) => void;
+ onRefreshGitContext: (projectId: string) => void;
}
/* ── Mode icon + accent colour mapping ─────────────────────── */
@@ -68,6 +73,53 @@ function relativeTime(iso: string): string {
return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
}
+/* ── Git context badge ──────────────────────────────────────── */
+
+function GitContextBadge({ git }: { git: ProjectGitContext }) {
+ if (git.status === 'not-repository') {
+ return (
+
+ no repo
+
+ );
+ }
+
+ if (git.status === 'git-missing') {
+ return (
+
+
+ no git
+
+ );
+ }
+
+ if (git.status === 'error') {
+ return (
+
+
+ error
+
+ );
+ }
+
+ const branchLabel = git.branch ?? git.head?.shortHash ?? 'HEAD';
+ const parts: string[] = [];
+ if (git.isDirty && git.changedFileCount) parts.push(`${git.changedFileCount} changed`);
+ if (git.ahead) parts.push(`↑${git.ahead}`);
+ if (git.behind) parts.push(`↓${git.behind}`);
+
+ return (
+
+
+ {branchLabel}
+ {git.isDirty && }
+
+ );
+}
+
/* ── Context menu item ─────────────────────────────────────── */
function ActionMenuItem({
@@ -257,6 +309,7 @@ function ProjectGroup({
onOpenMenu,
onRenameSubmit,
onRenameCancel,
+ onRefreshGitContext,
}: {
project: ProjectRecord;
sessions: SessionRecord[];
@@ -267,7 +320,8 @@ function ProjectGroup({
onOpenMenu: (sessionId: string, e: React.MouseEvent) => void;
onRenameSubmit: (sessionId: string, title: string) => void;
onRenameCancel: () => void;
-}) {
+ onRefreshGitContext?: (projectId: string) => void;
+}){
const [expanded, setExpanded] = useState(true);
const isScratchpad = isScratchpadProject(project);
@@ -309,7 +363,24 @@ function ProjectGroup({
)}
{project.name}
+ {!isScratchpad && project.git && (
+
+ )}
+
+ {!isScratchpad && onRefreshGitContext && (
+ {
+ e.stopPropagation();
+ onRefreshGitContext(project.id);
+ }}
+ role="button"
+ title="Refresh git status"
+ >
+
+
+ )}
{runningCount > 0 && (
@@ -362,6 +433,7 @@ export function Sidebar({
onDuplicateSession,
onSetSessionPinned,
onSetSessionArchived,
+ onRefreshGitContext,
}: SidebarProps) {
const scratchpadProject = workspace.projects.find((project) => isScratchpadProject(project));
const userProjects = workspace.projects.filter((project) => !isScratchpadProject(project));
@@ -570,6 +642,7 @@ export function Sidebar({
onOpenMenu={handleOpenMenu}
onRenameSubmit={handleRenameSubmit}
onRenameCancel={() => setRenamingSessionId(undefined)}
+ onRefreshGitContext={onRefreshGitContext}
renamingSessionId={renamingSessionId}
patterns={workspace.patterns}
project={project}