diff --git a/packages/app/src/attachments/local-file-attachment-store.ts b/packages/app/src/attachments/local-file-attachment-store.ts
index 181771eaf..98111d812 100644
--- a/packages/app/src/attachments/local-file-attachment-store.ts
+++ b/packages/app/src/attachments/local-file-attachment-store.ts
@@ -114,12 +114,14 @@ export function createLocalFileAttachmentStore(params: {
await ensureDirectory(baseDirectory);
const id = input.id ?? generateAttachmentId();
- const mimeTypeFromSource =
- input.source.kind === "data_url"
- ? parseDataUrl(input.source.dataUrl).mimeType
- : input.source.kind === "blob"
- ? input.source.blob.type
- : undefined;
+ let mimeTypeFromSource: string | undefined;
+ if (input.source.kind === "data_url") {
+ mimeTypeFromSource = parseDataUrl(input.source.dataUrl).mimeType;
+ } else if (input.source.kind === "blob") {
+ mimeTypeFromSource = input.source.blob.type;
+ } else {
+ mimeTypeFromSource = undefined;
+ }
const mimeType = normalizeMimeType(input.mimeType ?? mimeTypeFromSource);
const fileName = input.fileName ?? null;
const extension = extensionForAttachment({ fileName, mimeType });
diff --git a/packages/app/src/components/add-host-modal.tsx b/packages/app/src/components/add-host-modal.tsx
index 554750dad..5c81e79ba 100644
--- a/packages/app/src/components/add-host-modal.tsx
+++ b/packages/app/src/components/add-host-modal.tsx
@@ -222,12 +222,14 @@ export function AddHostModal({ visible, onClose, onCancel, onSaved }: AddHostMod
handleClose();
} catch (error) {
const { title, detail, raw: rawDetail } = buildConnectionFailureCopy(endpoint, error);
- const combined =
- rawDetail && detail && rawDetail !== detail
- ? `${title}\n${detail}\nDetails: ${rawDetail}`
- : detail
- ? `${title}\n${detail}`
- : title;
+ let combined: string;
+ if (rawDetail && detail && rawDetail !== detail) {
+ combined = `${title}\n${detail}\nDetails: ${rawDetail}`;
+ } else if (detail) {
+ combined = `${title}\n${detail}`;
+ } else {
+ combined = title;
+ }
setErrorMessage(combined);
if (!isMobile) {
// Desktop/web: also surface it as a dialog for quick visibility.
diff --git a/packages/app/src/components/code-insets.ts b/packages/app/src/components/code-insets.ts
index fb2e17a4d..62756602a 100644
--- a/packages/app/src/components/code-insets.ts
+++ b/packages/app/src/components/code-insets.ts
@@ -8,12 +8,10 @@ export function lineNumberGutterWidth(maxLineNumber: number): number {
}
export function getCodeInsets(theme: any) {
- const padding =
- typeof theme.spacing?.[3] === "number"
- ? theme.spacing[3]
- : typeof theme.spacing?.[4] === "number"
- ? theme.spacing[4]
- : 12;
+ let padding: number;
+ if (typeof theme.spacing?.[3] === "number") padding = theme.spacing[3];
+ else if (typeof theme.spacing?.[4] === "number") padding = theme.spacing[4];
+ else padding = 12;
const extraRight = theme.spacing[4];
const extraBottom = theme.spacing[3];
diff --git a/packages/app/src/components/combined-model-selector.tsx b/packages/app/src/components/combined-model-selector.tsx
index 863d30575..054fbfb08 100644
--- a/packages/app/src/components/combined-model-selector.tsx
+++ b/packages/app/src/components/combined-model-selector.tsx
@@ -217,19 +217,19 @@ function ModelRow({
accessibilityLabel={isFavorite ? "Unfavorite model" : "Favorite model"}
testID={`favorite-model-${row.provider}-${row.modelId}`}
>
- {({ hovered }) => (
-
- )}
+ {({ hovered }) => {
+ let starColor: string;
+ if (isFavorite) starColor = theme.colors.palette.amber[500];
+ else if (hovered) starColor = theme.colors.foregroundMuted;
+ else starColor = theme.colors.border;
+ return (
+
+ );
+ }}
) : null,
[
diff --git a/packages/app/src/components/command-center.tsx b/packages/app/src/components/command-center.tsx
index 306443af2..6664bb8bd 100644
--- a/packages/app/src/components/command-center.tsx
+++ b/packages/app/src/components/command-center.tsx
@@ -101,12 +101,12 @@ function CommandCenterActionRow({
const { theme } = useUnistyles();
const handlePress = useCallback(() => onSelect(item), [onSelect, item]);
const action = item.action;
- const actionIcon =
- action.icon === "plus" ? (
-
- ) : action.icon === "settings" ? (
-
- ) : null;
+ let actionIcon: React.ReactNode = null;
+ if (action.icon === "plus") {
+ actionIcon = ;
+ } else if (action.icon === "settings") {
+ actionIcon = ;
+ }
const titleStyle = useMemo(
() => [styles.title, { color: theme.colors.foreground }],
[theme.colors.foreground],
diff --git a/packages/app/src/components/composer.tsx b/packages/app/src/components/composer.tsx
index 899a4e7a7..8748ad29b 100644
--- a/packages/app/src/components/composer.tsx
+++ b/packages/app/src/components/composer.tsx
@@ -782,8 +782,10 @@ export function Composer({
}
void voice.startVoice(serverId, agentId).catch((error) => {
console.error("[Composer] Failed to start voice mode", error);
- const message =
- error instanceof Error ? error.message : typeof error === "string" ? error : null;
+ let message: string | null;
+ if (error instanceof Error) message = error.message;
+ else if (typeof error === "string") message = error;
+ else message = null;
if (message && message.trim().length > 0) {
toastErrorRef.current(message);
}
diff --git a/packages/app/src/components/git-diff-pane.tsx b/packages/app/src/components/git-diff-pane.tsx
index 0653e570b..78e76be28 100644
--- a/packages/app/src/components/git-diff-pane.tsx
+++ b/packages/app/src/components/git-diff-pane.tsx
@@ -1238,12 +1238,14 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
const hasChanges = files.length > 0;
const diffErrorMessage = diffPayloadError?.message ?? null;
const prErrorMessage = githubFeaturesEnabled ? (prPayloadError?.message ?? null) : null;
- const branchLabel =
- gitStatus?.currentBranch && gitStatus.currentBranch !== "HEAD"
- ? gitStatus.currentBranch
- : notGit
- ? "Not a git repository"
- : "Unknown";
+ let branchLabel: string;
+ if (gitStatus?.currentBranch && gitStatus.currentBranch !== "HEAD") {
+ branchLabel = gitStatus.currentBranch;
+ } else if (notGit) {
+ branchLabel = "Not a git repository";
+ } else {
+ branchLabel = "Unknown";
+ }
const actionsDisabled = !isGit || Boolean(status?.error) || isStatusLoading;
const aheadCount = gitStatus?.aheadBehind?.ahead ?? 0;
const behindBaseCount = gitStatus?.aheadBehind?.behind ?? 0;
@@ -1313,15 +1315,17 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
);
} else if (!hasChanges) {
+ let emptyMessage: string;
+ if (changesPreferences.hideWhitespace) {
+ emptyMessage = "No visible changes after hiding whitespace";
+ } else if (diffMode === "uncommitted") {
+ emptyMessage = "No uncommitted changes";
+ } else {
+ emptyMessage = `No changes vs ${baseRefLabel}`;
+ }
bodyContent = (
-
- {changesPreferences.hideWhitespace
- ? "No visible changes after hiding whitespace"
- : diffMode === "uncommitted"
- ? "No uncommitted changes"
- : `No changes vs ${baseRefLabel}`}
-
+ {emptyMessage}
);
} else {
diff --git a/packages/app/src/components/left-sidebar.tsx b/packages/app/src/components/left-sidebar.tsx
index 7a2150f08..ed6647d71 100644
--- a/packages/app/src/components/left-sidebar.tsx
+++ b/packages/app/src/components/left-sidebar.tsx
@@ -145,12 +145,11 @@ export const LeftSidebar = memo(function LeftSidebar({
const activeHostStatus = activeServerId
? (activeHostSnapshot?.connectionStatus ?? "connecting")
: "idle";
- const activeHostStatusColor =
- activeHostStatus === "online"
- ? theme.colors.palette.green[400]
- : activeHostStatus === "connecting"
- ? theme.colors.palette.amber[500]
- : theme.colors.palette.red[500];
+ let activeHostStatusColor: string;
+ if (activeHostStatus === "online") activeHostStatusColor = theme.colors.palette.green[400];
+ else if (activeHostStatus === "connecting")
+ activeHostStatusColor = theme.colors.palette.amber[500];
+ else activeHostStatusColor = theme.colors.palette.red[500];
const hostOptions = useMemo(
() =>
daemons.map((daemon) => ({
@@ -523,7 +522,10 @@ function MobileSidebar({
pointerEvents: backdropOpacity.value > 0.01 ? "auto" : "none",
}));
- const overlayPointerEvents = isWeb ? (isOpen ? "auto" : "none") : "box-none";
+ let overlayPointerEvents: "auto" | "none" | "box-none";
+ if (!isWeb) overlayPointerEvents = "box-none";
+ else if (isOpen) overlayPointerEvents = "auto";
+ else overlayPointerEvents = "none";
const backdropStyle = useMemo(
() => [staticStyles.backdrop, backdropAnimatedStyle],
diff --git a/packages/app/src/components/provider-diagnostic-sheet.tsx b/packages/app/src/components/provider-diagnostic-sheet.tsx
index 4b748bece..1eb87490a 100644
--- a/packages/app/src/components/provider-diagnostic-sheet.tsx
+++ b/packages/app/src/components/provider-diagnostic-sheet.tsx
@@ -215,7 +215,8 @@ export function ProviderDiagnosticSheet({
Running diagnostic…
- ) : diagnostic ? (
+ ) : null}
+ {!(loading && !diagnostic) && diagnostic ? (
- ) : (
+ ) : null}
+ {!(loading && !diagnostic) && !diagnostic ? (
No diagnostic available.
- )}
+ ) : null}
diff --git a/packages/app/src/components/sidebar-workspace-list.tsx b/packages/app/src/components/sidebar-workspace-list.tsx
index a2de544aa..d9e001948 100644
--- a/packages/app/src/components/sidebar-workspace-list.tsx
+++ b/packages/app/src/components/sidebar-workspace-list.tsx
@@ -196,6 +196,16 @@ interface WorkspaceRowInnerProps {
archiveShortcutKeys?: ShortcutKey[][] | null;
}
+function getWorkspaceArchiveStatus(
+ isWorktree: boolean,
+ archiveStatus: "idle" | "pending" | "success",
+ isArchivingWorkspace: boolean,
+): "idle" | "pending" | "success" {
+ if (isWorktree) return archiveStatus;
+ if (isArchivingWorkspace) return "pending";
+ return "idle";
+}
+
function useSidebarWorkspaceEntry(
serverId: string | null,
workspaceId: string | null,
@@ -369,8 +379,10 @@ function WorkspaceStatusIndicator({
);
}
- const KindIcon =
- workspaceKind === "local_checkout" ? Monitor : workspaceKind === "worktree" ? FolderGit2 : null;
+ let KindIcon: typeof Monitor | typeof FolderGit2 | null;
+ if (workspaceKind === "local_checkout") KindIcon = Monitor;
+ else if (workspaceKind === "worktree") KindIcon = FolderGit2;
+ else KindIcon = null;
if (!KindIcon) return null;
const dotColor = getStatusDotColor({ theme, bucket, showDoneAsInactive: false });
@@ -1187,7 +1199,8 @@ function WorkspaceRowInner({
- ) : workspace.diffStat ? (
+ ) : null}
+ {!(onArchive && (isHovered || isTouchPlatform)) && workspace.diffStat ? (
({
const DND_MODIFIERS: Modifier[] = [restrictToHorizontalAxis];
+function computeDragOpacity(hasExternalContext: boolean, isDragging: boolean): number {
+ if (!isDragging) return 1;
+ return hasExternalContext ? 0.3 : 0.9;
+}
+
function SortableItem({
id,
item,
@@ -77,7 +82,7 @@ function SortableItem({
() => ({
transform: combinedTransform || undefined,
transition,
- opacity: externalDndContext && isDragging ? 0.3 : isDragging ? 0.9 : 1,
+ opacity: computeDragOpacity(Boolean(externalDndContext), isDragging),
zIndex: isDragging ? 1000 : 1,
}),
[combinedTransform, transition, externalDndContext, isDragging],
diff --git a/packages/app/src/components/terminal-emulator.tsx b/packages/app/src/components/terminal-emulator.tsx
index 14f05215d..c596256b6 100644
--- a/packages/app/src/components/terminal-emulator.tsx
+++ b/packages/app/src/components/terminal-emulator.tsx
@@ -583,13 +583,11 @@ export default function TerminalEmulator({
const handleVisible =
scrollbarGeometry.isVisible && (isDraggingScrollbar || isScrollVisible || isHandleHovered);
- const handleOpacity = isDraggingScrollbar
- ? SCROLLBAR_HANDLE_OPACITY_DRAGGING
- : isHandleHovered
- ? SCROLLBAR_HANDLE_OPACITY_HOVERED
- : isScrollVisible
- ? SCROLLBAR_HANDLE_OPACITY_VISIBLE
- : 0;
+ let handleOpacity: number;
+ if (isDraggingScrollbar) handleOpacity = SCROLLBAR_HANDLE_OPACITY_DRAGGING;
+ else if (isHandleHovered) handleOpacity = SCROLLBAR_HANDLE_OPACITY_HOVERED;
+ else if (isScrollVisible) handleOpacity = SCROLLBAR_HANDLE_OPACITY_VISIBLE;
+ else handleOpacity = 0;
const handleWidth =
isDraggingScrollbar || isHandleHovered
? SCROLLBAR_HANDLE_WIDTH_ACTIVE
diff --git a/packages/app/src/components/ui/combobox.tsx b/packages/app/src/components/ui/combobox.tsx
index 9549b8c82..56f774ecc 100644
--- a/packages/app/src/components/ui/combobox.tsx
+++ b/packages/app/src/components/ui/combobox.tsx
@@ -200,17 +200,22 @@ export function ComboboxItem({
}: ComboboxItemProps): ReactElement {
const { theme } = useUnistyles();
- const leadingContent = leadingSlot ? (
- {leadingSlot}
- ) : kind === "directory" || kind === "file" ? (
-
- {kind === "directory" ? (
+ let leadingContent: ReactElement | null = null;
+ if (leadingSlot) {
+ leadingContent = {leadingSlot};
+ } else if (kind === "directory") {
+ leadingContent = (
+
- ) : (
+
+ );
+ } else if (kind === "file") {
+ leadingContent = (
+
- )}
-
- ) : null;
+
+ );
+ }
const itemPressableStyle = useCallback(
({ pressed, hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => [
@@ -482,30 +487,36 @@ export function Combobox({
const measuredTopStartBottom = useMeasuredTopStartPosition
? Math.max(windowHeight - referenceTop + 5, collisionPadding)
: null;
+ let resolvedPositionReady: boolean;
+ if (isDesktopAboveSearch) {
+ resolvedPositionReady = floatingLeft !== null && desktopAboveSearchBottom !== null;
+ } else if (useMeasuredTopStartPosition) {
+ resolvedPositionReady = clampedMeasuredTopStartLeft !== null && measuredTopStartBottom !== null;
+ } else {
+ resolvedPositionReady =
+ floatingLeft !== null &&
+ floatingTop !== null &&
+ (hasNonZeroFloatingPosition || referenceAtOrigin);
+ }
const hasResolvedDesktopPosition =
- referenceWidth !== null &&
- referenceWidth > 0 &&
- (isDesktopAboveSearch
- ? floatingLeft !== null && desktopAboveSearchBottom !== null
- : useMeasuredTopStartPosition
- ? clampedMeasuredTopStartLeft !== null && measuredTopStartBottom !== null
- : floatingLeft !== null &&
- floatingTop !== null &&
- (hasNonZeroFloatingPosition || referenceAtOrigin));
+ referenceWidth !== null && referenceWidth > 0 && resolvedPositionReady;
const shouldHideDesktopContent = desktopPreventInitialFlash && !hasResolvedDesktopPosition;
const shouldUseDesktopFade = !desktopPreventInitialFlash;
- const desktopPositionStyle = isDesktopAboveSearch
- ? {
- left: floatingLeft ?? 0,
- bottom: desktopAboveSearchBottom ?? 0,
- }
- : useMeasuredTopStartPosition
- ? {
- left: clampedMeasuredTopStartLeft ?? 0,
- bottom: measuredTopStartBottom ?? 0,
- }
- : floatingStyles;
+ let desktopPositionStyle: { left: number; bottom: number } | typeof floatingStyles;
+ if (isDesktopAboveSearch) {
+ desktopPositionStyle = {
+ left: floatingLeft ?? 0,
+ bottom: desktopAboveSearchBottom ?? 0,
+ };
+ } else if (useMeasuredTopStartPosition) {
+ desktopPositionStyle = {
+ left: clampedMeasuredTopStartLeft ?? 0,
+ bottom: measuredTopStartBottom ?? 0,
+ };
+ } else {
+ desktopPositionStyle = floatingStyles;
+ }
const { sheetRef: bottomSheetRef, handleSheetChange } = useIsolatedBottomSheetVisibility({
visible: isOpen,
diff --git a/packages/app/src/components/ui/context-menu.tsx b/packages/app/src/components/ui/context-menu.tsx
index 1deb9b3e3..449ad141d 100644
--- a/packages/app/src/components/ui/context-menu.tsx
+++ b/packages/app/src/components/ui/context-menu.tsx
@@ -695,20 +695,22 @@ export function ContextMenuItem({
}, [isDisabled, closeOnSelect, setOpen, onSelect]);
const itemPressableStyle = useCallback(
- ({ pressed, hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => [
- styles.item,
- selected
- ? selectedVariant === "accent"
- ? styles.itemSelectedAccent
- : styles.itemSelected
- : null,
- selected && (hovered || pressed) && selectedVariant !== "accent"
- ? styles.itemSelectedInteractive
- : null,
- isDisabled ? styles.itemDisabled : null,
- hovered && !pressed && !isDisabled ? styles.itemHovered : null,
- pressed && !isDisabled ? styles.itemPressed : null,
- ],
+ ({ pressed, hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => {
+ let selectedStyle: typeof styles.itemSelectedAccent | typeof styles.itemSelected | null;
+ if (!selected) selectedStyle = null;
+ else if (selectedVariant === "accent") selectedStyle = styles.itemSelectedAccent;
+ else selectedStyle = styles.itemSelected;
+ return [
+ styles.item,
+ selectedStyle,
+ selected && (hovered || pressed) && selectedVariant !== "accent"
+ ? styles.itemSelectedInteractive
+ : null,
+ isDisabled ? styles.itemDisabled : null,
+ hovered && !pressed && !isDisabled ? styles.itemHovered : null,
+ pressed && !isDisabled ? styles.itemPressed : null,
+ ];
+ },
[selected, selectedVariant, isDisabled],
);
diff --git a/packages/app/src/contexts/session-context.tsx b/packages/app/src/contexts/session-context.tsx
index a22ff9811..9a0e3dc93 100644
--- a/packages/app/src/contexts/session-context.tsx
+++ b/packages/app/src/contexts/session-context.tsx
@@ -112,12 +112,10 @@ function buildAudioPlaybackSource(chunks: BufferedAudioChunk[]): AudioPlaybackSo
}
const format = chunks[0]?.format ?? "pcm";
- const mimeType =
- format === "pcm"
- ? "audio/pcm;rate=24000;bits=16"
- : format === "mp3"
- ? "audio/mpeg"
- : `audio/${format}`;
+ let mimeType: string;
+ if (format === "pcm") mimeType = "audio/pcm;rate=24000;bits=16";
+ else if (format === "mp3") mimeType = "audio/mpeg";
+ else mimeType = `audio/${format}`;
const bytes = output.slice();
return {
diff --git a/packages/app/src/desktop/components/desktop-updates-section.tsx b/packages/app/src/desktop/components/desktop-updates-section.tsx
index 6fc8a254b..49d5c8178 100644
--- a/packages/app/src/desktop/components/desktop-updates-section.tsx
+++ b/packages/app/src/desktop/components/desktop-updates-section.tsx
@@ -21,6 +21,20 @@ import {
import { useDaemonStatus } from "@/desktop/hooks/use-daemon-status";
import { resolveAppVersion } from "@/utils/app-version";
+function getDaemonManagementButtonLabel(isUpdating: boolean, isPaused: boolean): string {
+ if (isUpdating) return isPaused ? "Resuming..." : "Pausing...";
+ return isPaused ? "Resume" : "Pause";
+}
+
+function getDaemonRestartButtonLabel(
+ isRestarting: boolean,
+ daemonStatus: string | undefined,
+ actionLabel: string,
+): string {
+ if (!isRestarting) return actionLabel;
+ return daemonStatus === "running" ? "Restarting..." : "Starting...";
+}
+
export function LocalDaemonSection() {
const { theme } = useUnistyles();
const showSection = shouldUseDesktopDaemon();
@@ -338,13 +352,10 @@ export function LocalDaemonSection() {
onPress={handleToggleDaemonManagement}
disabled={isUpdatingDaemonManagement}
>
- {isUpdatingDaemonManagement
- ? isDaemonManagementPaused
- ? "Resuming..."
- : "Pausing..."
- : isDaemonManagementPaused
- ? "Resume"
- : "Pause"}
+ {getDaemonManagementButtonLabel(
+ isUpdatingDaemonManagement,
+ isDaemonManagementPaused,
+ )}
@@ -360,11 +371,11 @@ export function LocalDaemonSection() {
onPress={handleUpdateLocalDaemon}
disabled={isRestartingDaemon}
>
- {isRestartingDaemon
- ? daemonStatus?.status === "running"
- ? "Restarting..."
- : "Starting..."
- : daemonActionLabel}
+ {getDaemonRestartButtonLabel(
+ isRestartingDaemon,
+ daemonStatus?.status,
+ daemonActionLabel,
+ )}
diff --git a/packages/app/src/desktop/components/pair-device-section.tsx b/packages/app/src/desktop/components/pair-device-section.tsx
index e098aa46d..03b9ce0fb 100644
--- a/packages/app/src/desktop/components/pair-device-section.tsx
+++ b/packages/app/src/desktop/components/pair-device-section.tsx
@@ -79,7 +79,8 @@ export function PairDeviceSection() {
Loading pairing offer…
- ) : pairingQuery.isError ? (
+ ) : null}
+ {!pairingQuery.isPending && pairingQuery.isError ? (
{pairingQuery.error instanceof Error
@@ -90,7 +91,8 @@ export function PairDeviceSection() {
Retry
- ) : !pairingQuery.data?.url ? (
+ ) : null}
+ {!pairingQuery.isPending && !pairingQuery.isError && !pairingQuery.data?.url ? (
{pairingQuery.data?.relayEnabled === false
@@ -101,7 +103,8 @@ export function PairDeviceSection() {
Retry
- ) : (
+ ) : null}
+ {!pairingQuery.isPending && !pairingQuery.isError && pairingQuery.data?.url ? (
Scan this QR code with Paseo on your phone, or copy the link below.
@@ -109,11 +112,11 @@ export function PairDeviceSection() {
{qrImageSource ? (
- ) : qrQuery.isError ? (
+ ) : null}
+ {!qrImageSource && qrQuery.isError ? (
QR code unavailable.
- ) : (
-
- )}
+ ) : null}
+ {!qrImageSource && !qrQuery.isError ? : null}
@@ -135,7 +138,7 @@ export function PairDeviceSection() {
- )}
+ ) : null}
);
diff --git a/packages/app/src/hooks/use-agent-screen-state-machine.ts b/packages/app/src/hooks/use-agent-screen-state-machine.ts
index e9b33d76f..f4ac29386 100644
--- a/packages/app/src/hooks/use-agent-screen-state-machine.ts
+++ b/packages/app/src/hooks/use-agent-screen-state-machine.ts
@@ -158,13 +158,11 @@ export function deriveAgentScreenViewState({
};
}
- const source: "authoritative" | "optimistic" | "stale" = useOptimisticCreateFlowAgent
- ? "optimistic"
- : input.agent
- ? "authoritative"
- : input.shouldUseOptimisticStream
- ? "optimistic"
- : "stale";
+ let source: "authoritative" | "optimistic" | "stale";
+ if (useOptimisticCreateFlowAgent) source = "optimistic";
+ else if (input.agent) source = "authoritative";
+ else if (input.shouldUseOptimisticStream) source = "optimistic";
+ else source = "stale";
let sync: AgentScreenReadySyncState;
if (!input.isConnected) {
diff --git a/packages/app/src/hooks/use-checkout-pr-status-query.ts b/packages/app/src/hooks/use-checkout-pr-status-query.ts
index 18a7d4f36..97e4d8ed0 100644
--- a/packages/app/src/hooks/use-checkout-pr-status-query.ts
+++ b/packages/app/src/hooks/use-checkout-pr-status-query.ts
@@ -50,15 +50,15 @@ function selectWorkspacePrHint(payload: CheckoutPrStatusPayload): PrHint | null
return null;
}
+ let state: "merged" | "open" | "closed";
+ if (status.isMerged || status.state === "merged") state = "merged";
+ else if (status.state === "open") state = "open";
+ else state = "closed";
+
return {
url: status.url,
number,
- state:
- status.isMerged || status.state === "merged"
- ? "merged"
- : status.state === "open"
- ? "open"
- : "closed",
+ state,
checks: status.checks,
checksStatus: status.checksStatus as PrHint["checksStatus"],
reviewDecision: status.reviewDecision as PrHint["reviewDecision"],
diff --git a/packages/app/src/hooks/use-git-actions.ts b/packages/app/src/hooks/use-git-actions.ts
index c70b6c093..7c9f7626b 100644
--- a/packages/app/src/hooks/use-git-actions.ts
+++ b/packages/app/src/hooks/use-git-actions.ts
@@ -280,12 +280,14 @@ export function useGitActions({ serverId, cwd, icons }: UseGitActionsInput): Use
const pushDisabled = actionsDisabled || pushStatus === "pending";
const archiveDisabled = actionsDisabled || archiveStatus === "pending";
- const branchLabel =
- gitStatus?.currentBranch && gitStatus.currentBranch !== "HEAD"
- ? gitStatus.currentBranch
- : notGit
- ? "Not a git repository"
- : "Unknown";
+ let branchLabel: string;
+ if (gitStatus?.currentBranch && gitStatus.currentBranch !== "HEAD") {
+ branchLabel = gitStatus.currentBranch;
+ } else if (notGit) {
+ branchLabel = "Not a git repository";
+ } else {
+ branchLabel = "Unknown";
+ }
// Build actions
const gitActions: GitActions = useMemo(() => {
diff --git a/packages/app/src/panels/setup-panel.tsx b/packages/app/src/panels/setup-panel.tsx
index e8e3a2a4b..b257a92d5 100644
--- a/packages/app/src/panels/setup-panel.tsx
+++ b/packages/app/src/panels/setup-panel.tsx
@@ -171,14 +171,11 @@ function SetupPanel() {
return null;
})();
- const statusLabel =
- snapshot?.status === "running"
- ? "Running"
- : snapshot?.status === "completed"
- ? "Completed"
- : snapshot?.status === "failed"
- ? "Failed"
- : "Waiting for setup output";
+ let statusLabel: string;
+ if (snapshot?.status === "running") statusLabel = "Running";
+ else if (snapshot?.status === "completed") statusLabel = "Completed";
+ else if (snapshot?.status === "failed") statusLabel = "Failed";
+ else statusLabel = "Waiting for setup output";
return (
Setting up workspace...
- ) : hasNoSetupCommands ? (
+ ) : null}
+ {!isWaiting && hasNoSetupCommands ? (
- ) : (
+ ) : null}
+ {!isWaiting && !hasNoSetupCommands ? (
{commands.map((command) => {
const isExpanded = expandedIndices.has(command.index);
@@ -275,7 +274,7 @@ function SetupPanel() {
) : null}
- )}
+ ) : null}
);
}
diff --git a/packages/app/src/screens/sessions-screen.tsx b/packages/app/src/screens/sessions-screen.tsx
index f47f1250c..aa1e2d650 100644
--- a/packages/app/src/screens/sessions-screen.tsx
+++ b/packages/app/src/screens/sessions-screen.tsx
@@ -70,14 +70,16 @@ function SessionsScreenContent({ serverId }: { serverId: string }) {
- ) : sortedAgents.length === 0 ? (
+ ) : null}
+ {!isInitialLoad && sortedAgents.length === 0 ? (
No sessions yet
- ) : (
+ ) : null}
+ {!isInitialLoad && sortedAgents.length > 0 ? (
- )}
+ ) : null}
);
}
diff --git a/packages/app/src/screens/settings-screen.tsx b/packages/app/src/screens/settings-screen.tsx
index f1e2df9ae..0eae159d6 100644
--- a/packages/app/src/screens/settings-screen.tsx
+++ b/packages/app/src/screens/settings-screen.tsx
@@ -344,6 +344,15 @@ function AboutSection({ appVersionText, isDesktopApp }: AboutSectionProps) {
);
}
+function getUpdateButtonLabel(
+ isInstalling: boolean,
+ latestVersion: string | null | undefined,
+): string {
+ if (isInstalling) return "Installing...";
+ if (latestVersion) return `Update to ${formatVersionWithPrefix(latestVersion)}`;
+ return "Update";
+}
+
function DesktopAppUpdateRow() {
const { settings, updateSettings } = useAppSettings();
const {
@@ -451,11 +460,7 @@ function DesktopAppUpdateRow() {
onPress={handleInstallUpdate}
disabled={isChecking || isInstalling || !availableUpdate}
>
- {isInstalling
- ? "Installing..."
- : availableUpdate?.latestVersion
- ? `Update to ${formatVersionWithPrefix(availableUpdate.latestVersion)}`
- : "Update"}
+ {getUpdateButtonLabel(isInstalling, availableUpdate?.latestVersion)}
diff --git a/packages/app/src/screens/settings/providers-section.tsx b/packages/app/src/screens/settings/providers-section.tsx
index 5befca7ea..b309f9abc 100644
--- a/packages/app/src/screens/settings/providers-section.tsx
+++ b/packages/app/src/screens/settings/providers-section.tsx
@@ -140,11 +140,13 @@ export function ProvidersSection({ serverId }: ProvidersSectionProps) {
Connect to this host to see providers
- ) : isLoading ? (
+ ) : null}
+ {hasServer && isConnected && isLoading ? (
Loading...
- ) : (
+ ) : null}
+ {hasServer && isConnected && !isLoading ? (
{providerDefinitions.map((def, index) => (
))}
- )}
+ ) : null}
{diagnosticProvider ? (
diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx
index 79a3ccaa2..f592ef228 100644
--- a/packages/app/src/screens/workspace/workspace-screen.tsx
+++ b/packages/app/src/screens/workspace/workspace-screen.tsx
@@ -2183,33 +2183,41 @@ function WorkspaceScreenContent({
},
[buildPaneContentModel],
);
- const content = shouldRenderMissingWorkspaceDescriptor({
+ const showMissingWorkspaceDescriptor = shouldRenderMissingWorkspaceDescriptor({
workspace: workspaceDescriptor,
hasHydratedWorkspaces,
- }) ? (
-
-
-
- ) : isMissingWorkspaceExecutionAuthority ? (
-
-
- Workspace execution directory is missing. Reload workspace data before opening tabs.
-
-
- ) : !activeTabDescriptor ? (
- !hasHydratedAgents ? (
+ });
+ let content: React.ReactNode;
+ if (showMissingWorkspaceDescriptor) {
+ content = (
- ) : (
+ );
+ } else if (isMissingWorkspaceExecutionAuthority) {
+ content = (
+
+
+ Workspace execution directory is missing. Reload workspace data before opening tabs.
+
+
+ );
+ } else if (!activeTabDescriptor && !hasHydratedAgents) {
+ content = (
+
+
+
+ );
+ } else if (!activeTabDescriptor) {
+ content = (
No tabs are available yet. Use New tab to create an agent or terminal.
- )
- ) : (
- mountedFocusedPaneTabIds.map((tabId) => {
+ );
+ } else {
+ content = mountedFocusedPaneTabIds.map((tabId) => {
const tabDescriptor = focusedPaneTabDescriptorMap.get(tabId);
if (!tabDescriptor) {
return null;
@@ -2226,8 +2234,8 @@ function WorkspaceScreenContent({
buildPaneContentModel={buildMobilePaneContentModel}
/>
);
- })
- );
+ });
+ }
const buildDesktopPaneContentModel = useCallback(
function buildDesktopPaneContentModel(input: { paneId: string; tab: WorkspaceTabDescriptor }) {
diff --git a/packages/app/src/stores/download-store.ts b/packages/app/src/stores/download-store.ts
index c72f7c9dd..c2cd51c65 100644
--- a/packages/app/src/stores/download-store.ts
+++ b/packages/app/src/stores/download-store.ts
@@ -216,11 +216,10 @@ export const useDownloadStore = create()((set, get) => ({
updated.delete(id);
}
}
- const newActiveId = state.activeDownloadId
- ? updated.has(state.activeDownloadId)
- ? state.activeDownloadId
- : findMostRecentDownloadId(updated)
- : null;
+ let newActiveId: string | null;
+ if (!state.activeDownloadId) newActiveId = null;
+ else if (updated.has(state.activeDownloadId)) newActiveId = state.activeDownloadId;
+ else newActiveId = findMostRecentDownloadId(updated);
return { downloads: updated, activeDownloadId: newActiveId };
});
},