diff --git a/packages/app/src/components/agent-status-bar.tsx b/packages/app/src/components/agent-status-bar.tsx
index f6ab12284..bd95960e0 100644
--- a/packages/app/src/components/agent-status-bar.tsx
+++ b/packages/app/src/components/agent-status-bar.tsx
@@ -456,10 +456,14 @@ function ControlledStatusBar({
[canSelectMode, disabled],
);
+ const sheetSelectStyle = useMemo(
+ () => [styles.sheetSelect, modelDisabled && styles.disabledSheetSelect],
+ [modelDisabled],
+ );
const renderSheetModelTrigger = useCallback(
({ selectedModelLabel }: { selectedModelLabel: string }) => (
@@ -470,7 +474,7 @@ function ControlledStatusBar({
),
- [ProviderIcon, modelDisabled, theme.colors.foregroundMuted, theme.iconSize.md],
+ [ProviderIcon, sheetSelectStyle, theme.colors.foregroundMuted, theme.iconSize.md],
);
if (!hasAnyControl) {
@@ -1353,6 +1357,15 @@ export function DraftAgentStatusBar({
selectedThinkingOptionId || mappedThinkingOptions[0]?.id || undefined;
const hasSelectedProvider = selectedProvider !== null;
+ const modelOptions = useMemo(
+ () =>
+ models.map((model) => ({
+ id: model.id,
+ label: model.label,
+ })),
+ [models],
+ );
+
const handleToggleFavorite = useCallback(
(provider: string, modelId: string) => {
void updatePreferences((current) =>
@@ -1400,11 +1413,6 @@ export function DraftAgentStatusBar({
);
}
- const modelOptions: StatusOption[] = models.map((model) => ({
- id: model.id,
- label: model.label,
- }));
-
return (
+
{content}
{isEndOfAssistantTurn ? (
) : null}
-
+
);
},
[getGapBetween, renderStreamItemContent, agent.status, streamRenderStrategy],
@@ -916,6 +917,15 @@ function PermissionRequestCard({
const isPlanRequest = request.kind === "plan";
const title = isPlanRequest ? "Plan" : (request.title ?? request.name ?? "Permission Required");
const description = request.description ?? "";
+ const resolvedToolCallDetail = useMemo(
+ () =>
+ request.detail ?? {
+ type: "unknown" as const,
+ input: request.input ?? null,
+ output: null,
+ },
+ [request.detail, request.input],
+ );
const resolvedActions = useMemo((): AgentPermissionAction[] => {
if (request.kind === "question") {
return [];
@@ -1121,13 +1131,7 @@ function PermissionRequestCard({
{!isPlanRequest ? (
) : null}
@@ -1317,3 +1321,16 @@ const permissionStyles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.normal,
},
}));
+
+interface StreamItemWrapperProps {
+ gapBelow: number;
+ children: ReactNode;
+}
+
+function StreamItemWrapper({ gapBelow, children }: StreamItemWrapperProps) {
+ const wrapperStyle = useMemo(
+ () => [stylesheet.streamItemWrapper, { marginBottom: gapBelow }],
+ [gapBelow],
+ );
+ return {children};
+}
diff --git a/packages/app/src/components/file-explorer-pane.tsx b/packages/app/src/components/file-explorer-pane.tsx
index ab2663cd2..626400225 100644
--- a/packages/app/src/components/file-explorer-pane.tsx
+++ b/packages/app/src/components/file-explorer-pane.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useRef } from "react";
+import { useCallback, useEffect, useMemo, useRef, type ReactNode } from "react";
import { useQuery } from "@tanstack/react-query";
import {
ActivityIndicator,
@@ -146,29 +146,21 @@ function TreeRowItem({
{depth > 0 &&
Array.from({ length: depth }, (_, i) => (
-
+
))}
- {isDirectory ? (
- loading ? (
-
- ) : (
+ {(() => {
+ if (!isDirectory) {
+ return ;
+ }
+ if (loading) return ;
+ return (
- )
- ) : (
-
- )}
+ );
+ })()}
{entry.name}
@@ -540,77 +532,84 @@ export function FileExplorerPane({
);
}
- return (
-
- {error ? (
-
- {error}
-
- {showBackFromError ? (
-
- Back
-
- ) : null}
-
- Retry
+ let paneContent: ReactNode;
+ if (error) {
+ paneContent = (
+
+ {error}
+
+ {showBackFromError ? (
+
+ Back
-
+ ) : null}
+
+ Retry
+
- ) : showInitialLoading ? (
-
-
- Loading files…
+
+ );
+ } else if (showInitialLoading) {
+ paneContent = (
+
+
+ Loading files…
+
+ );
+ } else if (treeRows.length === 0) {
+ paneContent = (
+
+ No files
+
+ );
+ } else {
+ paneContent = (
+
+
+
+ {currentSortLabel}
+
+
+
+
+ {isRefreshFetching ? (
+
+ ) : (
+
+ )}
+
+
- ) : treeRows.length === 0 ? (
-
- No files
-
- ) : (
-
-
-
- {currentSortLabel}
-
-
-
-
- {isRefreshFetching ? (
-
- ) : (
-
- )}
-
-
-
-
- {scrollbar.overlay}
-
- )}
-
- );
+
+ {scrollbar.overlay}
+
+ );
+ }
+
+ return {paneContent};
}
function sortEntries(entries: ExplorerEntry[], sortOption: SortOption): ExplorerEntry[] {
@@ -959,3 +958,21 @@ const styles = StyleSheet.create((theme) => ({
padding: theme.spacing[4],
},
}));
+
+const TREE_PANE_CONTAINER_STYLE = [styles.treePane, styles.treePaneFill];
+
+interface IndentGuideProps {
+ index: number;
+}
+
+function IndentGuide({ index }: IndentGuideProps) {
+ const { theme } = useUnistyles();
+ const guideStyle = useMemo(
+ () => [
+ styles.indentGuide,
+ { left: theme.spacing[3] + index * INDENT_PER_LEVEL + 4 },
+ ],
+ [index, theme.spacing],
+ );
+ return ;
+}
diff --git a/packages/app/src/components/terminal-pane.tsx b/packages/app/src/components/terminal-pane.tsx
index 0b7e6d5d3..f8da457a9 100644
--- a/packages/app/src/components/terminal-pane.tsx
+++ b/packages/app/src/components/terminal-pane.tsx
@@ -106,11 +106,13 @@ function ModifierButton({ modifier, active, onToggle }: ModifierButtonProps) {
],
[active],
);
+ const textStyle = useMemo(
+ () => [styles.keyButtonText, active && styles.keyButtonTextActive],
+ [active],
+ );
return (
-
- {MODIFIER_LABELS[modifier]}
-
+ {MODIFIER_LABELS[modifier]}
);
}
@@ -628,16 +630,7 @@ export function TerminalPane({
({
textAlign: "center",
},
}));
+
+const TERMINAL_EMULATOR_DOM_PROPS = {
+ style: { flex: 1 },
+ matchContents: false,
+ scrollEnabled: true,
+ nestedScrollEnabled: true,
+ overScrollMode: "never" as const,
+ bounces: false,
+ automaticallyAdjustContentInsets: false,
+ contentInsetAdjustmentBehavior: "never" as const,
+};
diff --git a/packages/app/src/components/welcome-screen.tsx b/packages/app/src/components/welcome-screen.tsx
index b57e41882..84f34344f 100644
--- a/packages/app/src/components/welcome-screen.tsx
+++ b/packages/app/src/components/welcome-screen.tsx
@@ -283,27 +283,9 @@ export function WelcomeScreen({ onHostAdded }: WelcomeScreenProps) {
- {actions.map((action) => {
- const Icon = action.icon;
- return (
-
-
-
- {action.label}
-
-
- );
- })}
+ {actions.map((action) => (
+
+ ))}