feat: add iOS simulator worktree preview

Adds the worktree service, setup cache seeding, and Metro preview mount for /.sim. Also includes the related startup and mobile sidebar fixes needed by the updated worktree app flow.
This commit is contained in:
Mohamed Boudra
2026-06-11 12:23:53 +07:00
parent 6db285b1d9
commit a682476d11
21 changed files with 1143 additions and 189 deletions
@@ -23,11 +23,8 @@ import {
type ExplorerTab,
} from "@/stores/panel-store";
import { useExplorerSidebarAnimation } from "@/contexts/explorer-sidebar-animation-context";
import {
MOBILE_VISUAL_PANEL_AGENT,
MOBILE_VISUAL_PANEL_FILE_EXPLORER,
useSidebarAnimation,
} from "@/contexts/sidebar-animation-context";
import { useSidebarAnimation } from "@/contexts/sidebar-animation-context";
import { canCloseRightSidebarGesture } from "@/utils/sidebar-animation-state";
import { HEADER_INNER_HEIGHT, useIsCompactFormFactor } from "@/constants/layout";
import { GitDiffPane } from "@/git/diff-pane";
import { FileExplorerPane } from "./file-explorer-pane";
@@ -68,7 +65,7 @@ export function ExplorerSidebar({
const { width: viewportWidth } = useWindowDimensions();
const closeTouchStartX = useSharedValue(0);
const closeTouchStartY = useSharedValue(0);
const { mobileVisualPanel, gestureAnimatingRef: mobilePanelGestureAnimatingRef } =
const { mobilePanelState, gestureAnimatingRef: mobilePanelGestureAnimatingRef } =
useSidebarAnimation();
const { style: mobileKeyboardInsetStyle } = useKeyboardShiftStyle({
@@ -166,7 +163,7 @@ export function ExplorerSidebar({
const absDeltaX = Math.abs(deltaX);
const absDeltaY = Math.abs(deltaY);
if (mobileVisualPanel.value !== MOBILE_VISUAL_PANEL_FILE_EXPLORER) {
if (!canCloseRightSidebarGesture(mobilePanelState.value)) {
stateManager.fail();
return;
}
@@ -206,11 +203,9 @@ export function ExplorerSidebar({
windowWidth,
});
if (shouldClose) {
mobileVisualPanel.value = MOBILE_VISUAL_PANEL_AGENT;
animateToClose();
runOnJS(handleCloseFromGesture)();
} else {
mobileVisualPanel.value = MOBILE_VISUAL_PANEL_FILE_EXPLORER;
animateToOpen();
}
})
@@ -222,7 +217,7 @@ export function ExplorerSidebar({
windowWidth,
translateX,
backdropOpacity,
mobileVisualPanel,
mobilePanelState,
animateToOpen,
animateToClose,
handleCloseFromGesture,
@@ -1,15 +1,12 @@
import type { ReactNode } from "react";
import { useHostRuntimeBootstrapState, useStoreReady } from "@/app/_layout";
import { shouldUseDesktopDaemon } from "@/desktop/daemon/desktop-daemon";
import { useHostRuntimeBootstrapState } from "@/app/_layout";
import { StartupSplashScreen } from "@/screens/startup-splash-screen";
export function HostRouteBootstrapBoundary({ children }: { children: ReactNode }) {
const storeReady = useStoreReady();
const bootstrapState = useHostRuntimeBootstrapState();
const isDesktop = shouldUseDesktopDaemon();
if (!storeReady) {
return <StartupSplashScreen bootstrapState={isDesktop ? bootstrapState : undefined} />;
if (bootstrapState.startupBlocker.kind !== "none") {
return <StartupSplashScreen bootstrapState={bootstrapState} />;
}
return children;
+5 -10
View File
@@ -40,11 +40,7 @@ import { Shortcut } from "@/components/ui/shortcut";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useIsCompactFormFactor } from "@/constants/layout";
import { isWeb } from "@/constants/platform";
import {
MOBILE_VISUAL_PANEL_AGENT,
MOBILE_VISUAL_PANEL_AGENT_LIST,
useSidebarAnimation,
} from "@/contexts/sidebar-animation-context";
import { useSidebarAnimation } from "@/contexts/sidebar-animation-context";
import { useOpenProjectPicker } from "@/hooks/use-open-project-picker";
import { useShortcutKeys } from "@/hooks/use-shortcut-keys";
import { useSidebarShortcutModel } from "@/hooks/use-sidebar-shortcut-model";
@@ -64,6 +60,7 @@ import {
import { resolveActiveHost } from "@/utils/active-host";
import { formatConnectionStatus } from "@/utils/daemons";
import { useWindowControlsPadding } from "@/utils/desktop-window";
import { canCloseLeftSidebarGesture } from "@/utils/sidebar-animation-state";
import {
buildHostOpenProjectRoute,
buildHostNewWorkspaceRoute,
@@ -581,7 +578,7 @@ function MobileSidebar({
animateToOpen,
animateToClose,
isGesturing,
mobileVisualPanel,
mobilePanelState,
gestureAnimatingRef,
closeGestureRef,
} = useSidebarAnimation();
@@ -645,7 +642,7 @@ function MobileSidebar({
const absDeltaX = Math.abs(deltaX);
const absDeltaY = Math.abs(deltaY);
if (mobileVisualPanel.value !== MOBILE_VISUAL_PANEL_AGENT_LIST) {
if (!canCloseLeftSidebarGesture(mobilePanelState.value)) {
stateManager.fail();
return;
}
@@ -679,11 +676,9 @@ function MobileSidebar({
isGesturing.value = false;
const shouldClose = event.translationX < -windowWidth / 3 || event.velocityX < -500;
if (shouldClose) {
mobileVisualPanel.value = MOBILE_VISUAL_PANEL_AGENT;
animateToClose();
runOnJS(handleCloseFromGesture)();
} else {
mobileVisualPanel.value = MOBILE_VISUAL_PANEL_AGENT_LIST;
animateToOpen();
}
})
@@ -695,7 +690,7 @@ function MobileSidebar({
closeTouchStartX,
closeTouchStartY,
isGesturing,
mobileVisualPanel,
mobilePanelState,
windowWidth,
translateX,
backdropOpacity,