diff --git a/apps/web/src/components/BranchToolbar.logic.test.ts b/apps/web/src/components/BranchToolbar.logic.test.ts
index 76336f1ef1f..36d42a60fa8 100644
--- a/apps/web/src/components/BranchToolbar.logic.test.ts
+++ b/apps/web/src/components/BranchToolbar.logic.test.ts
@@ -17,6 +17,7 @@ import {
resolvePreviousWorktreeLabel,
resolvePreviousWorktreeSeed,
shouldIncludeBranchPickerItem,
+ shouldShowComposerContextStrip,
shouldShowEnvironmentIndicator,
} from "./BranchToolbar.logic";
@@ -421,6 +422,38 @@ describe("shouldShowEnvironmentIndicator", () => {
});
});
+describe("shouldShowComposerContextStrip", () => {
+ it("keeps the environment indicator visible for a non-Git project", () => {
+ expect(
+ shouldShowComposerContextStrip({
+ hasActiveProject: true,
+ isGitRepo: false,
+ showEnvironmentIndicator: true,
+ }),
+ ).toBe(true);
+ });
+
+ it("hides the strip when a non-Git project has no environment indicator", () => {
+ expect(
+ shouldShowComposerContextStrip({
+ hasActiveProject: true,
+ isGitRepo: false,
+ showEnvironmentIndicator: false,
+ }),
+ ).toBe(false);
+ });
+
+ it("shows Git controls without requiring an environment indicator", () => {
+ expect(
+ shouldShowComposerContextStrip({
+ hasActiveProject: true,
+ isGitRepo: true,
+ showEnvironmentIndicator: false,
+ }),
+ ).toBe(true);
+ });
+});
+
describe("resolveEffectiveEnvMode", () => {
it("treats draft threads already attached to a worktree as current-checkout mode", () => {
expect(
diff --git a/apps/web/src/components/BranchToolbar.logic.ts b/apps/web/src/components/BranchToolbar.logic.ts
index d9737f17a32..485ffbf8d37 100644
--- a/apps/web/src/components/BranchToolbar.logic.ts
+++ b/apps/web/src/components/BranchToolbar.logic.ts
@@ -54,6 +54,14 @@ export function shouldShowEnvironmentIndicator(input: {
return input.activeEnvironment !== null && !input.activeEnvironment.isPrimary;
}
+export function shouldShowComposerContextStrip(input: {
+ hasActiveProject: boolean;
+ isGitRepo: boolean;
+ showEnvironmentIndicator: boolean;
+}): boolean {
+ return input.hasActiveProject && (input.isGitRepo || input.showEnvironmentIndicator);
+}
+
export function resolveEnvModeLabel(mode: EnvMode): string {
return mode === "worktree" ? "New worktree" : "Current checkout";
}
diff --git a/apps/web/src/components/BranchToolbar.tsx b/apps/web/src/components/BranchToolbar.tsx
index a3f043c6536..440f48d7c90 100644
--- a/apps/web/src/components/BranchToolbar.tsx
+++ b/apps/web/src/components/BranchToolbar.tsx
@@ -44,6 +44,7 @@ import { Separator } from "./ui/separator";
interface BranchToolbarProps {
environmentId: EnvironmentId;
threadId: ThreadId;
+ showGitControls: boolean;
draftId?: DraftId;
onEnvModeChange: (mode: EnvMode) => void;
effectiveEnvModeOverride?: EnvMode;
@@ -309,6 +310,7 @@ function useLabelsOverflow(element: HTMLDivElement | null): boolean {
export const BranchToolbar = memo(function BranchToolbar({
environmentId,
threadId,
+ showGitControls,
draftId,
onEnvModeChange,
effectiveEnvModeOverride,
@@ -403,7 +405,7 @@ export const BranchToolbar = memo(function BranchToolbar({
data-compact={labelsOverflow ? "" : undefined}
className="chat-composer-context-strip group/composer-context -mt-4 mx-auto flex w-[calc(100%-2.75rem)] max-w-[calc(48rem-2.75rem)] items-center gap-2 ps-1 pe-2 pt-5 pb-1"
>
- {isMobile ? (
+ {isMobile && showGitControls ? (
-
+ {showGitControls ? (
+
+ ) : null}
>
)}
-
+ {showGitControls ? (
+
+ ) : null}
)}
-
+ {showGitControls ? (
+
+ ) : null}
);
});
diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx
index 7b59530c955..6c2dc1478e6 100644
--- a/apps/web/src/components/ChatView.tsx
+++ b/apps/web/src/components/ChatView.tsx
@@ -244,7 +244,12 @@ import { ChatHeader } from "./chat/ChatHeader";
import { PanelLayoutControls, RightPanelMaximizeControl } from "./chat/PanelLayoutControls";
import { type ExpandedImagePreview } from "./chat/ExpandedImagePreview";
import { NoActiveThreadState } from "./NoActiveThreadState";
-import { resolveEffectiveEnvMode, resolveLocalCheckoutBranchMismatch } from "./BranchToolbar.logic";
+import {
+ resolveEffectiveEnvMode,
+ resolveLocalCheckoutBranchMismatch,
+ shouldShowComposerContextStrip,
+ shouldShowEnvironmentIndicator,
+} from "./BranchToolbar.logic";
import {
getProviderStatusBannerKey,
ProviderStatusBanner,
@@ -1745,6 +1750,14 @@ function ChatViewContent(props: ChatViewProps) {
return envs;
}, [activeProject, allProjects, projectGroupingSettings, primaryEnvironmentId, environmentById]);
const hasMultipleEnvironments = logicalProjectEnvironments.length > 1;
+ const activeEnvironmentOption =
+ logicalProjectEnvironments.find(
+ (environment) => environment.environmentId === activeThread?.environmentId,
+ ) ?? null;
+ const showComposerEnvironmentIndicator = shouldShowEnvironmentIndicator({
+ activeEnvironment: activeEnvironmentOption,
+ canPickEnvironment: hasMultipleEnvironments,
+ });
const openPullRequestDialog = useCallback(
(reference?: string) => {
@@ -2514,7 +2527,11 @@ function ChatViewContent(props: ChatViewProps) {
terminalUiLaunchContext?.threadId === activeThreadId ? terminalUiLaunchContext : null;
// Default true while loading to avoid toolbar flicker.
const isGitRepo = gitStatusQuery.data?.isRepo ?? true;
- const showComposerContextStrip = isGitRepo && activeProject !== null;
+ const showComposerContextStrip = shouldShowComposerContextStrip({
+ hasActiveProject: activeProject !== null,
+ isGitRepo,
+ showEnvironmentIndicator: showComposerEnvironmentIndicator,
+ });
const initialDiffPanelGitScope =
gitStatusQuery.data?.hasWorkingTreeChanges === true ? "unstaged" : "branch";
const diffPanelGitStatusResolutionKey = gitStatusQuery.data ? "resolved" : "pending";
@@ -6180,6 +6197,7 @@ function ChatViewContent(props: ChatViewProps) {