From 056dc46e746a6bd5f77cbadfaf17d31037e783f8 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 24 Apr 2026 06:35:38 +0700 Subject: [PATCH] chore(lint): no-explicit-any in small app files (batch 1) --- packages/app/src/app/_layout.tsx | 2 +- packages/app/src/app/pair-scan.tsx | 4 ++-- .../app/src/components/adaptive-modal-sheet.tsx | 4 ++-- packages/app/src/components/agent-list.tsx | 4 ++-- packages/app/src/components/code-insets.ts | 4 +++- .../app/src/components/combined-model-selector.tsx | 3 ++- packages/app/src/components/command-center.tsx | 2 +- packages/app/src/components/diff-scroll.tsx | 8 ++++++-- packages/app/src/components/explorer-sidebar.tsx | 2 +- .../src/components/headers/header-toggle-button.tsx | 2 +- packages/app/src/components/left-sidebar.tsx | 2 +- .../app/src/components/project-picker-modal.tsx | 2 +- packages/app/src/components/split-drop-zone.tsx | 4 ++-- packages/app/src/components/ui/combobox.tsx | 4 ++-- .../src/desktop/components/pair-device-section.tsx | 2 +- packages/app/src/hooks/use-command-center.ts | 2 +- packages/app/src/hooks/use-open-project.ts | 4 ++-- .../terminal/runtime/terminal-emulator-runtime.ts | 2 +- packages/app/src/utils/app-version.ts | 4 +++- packages/app/src/utils/os-notifications.ts | 13 ++++++++++++- packages/app/src/utils/shortcut-platform.ts | 2 +- packages/app/vitest.setup.ts | 2 +- 22 files changed, 49 insertions(+), 29 deletions(-) diff --git a/packages/app/src/app/_layout.tsx b/packages/app/src/app/_layout.tsx index acb6b5cde..53e051c77 100644 --- a/packages/app/src/app/_layout.tsx +++ b/packages/app/src/app/_layout.tsx @@ -680,7 +680,7 @@ function OfferLinkListener({ void upsertDaemonFromOfferUrl(url) .then((profile) => { if (cancelled) return; - const serverId = (profile as any)?.serverId; + const serverId = (profile as { serverId?: unknown } | null)?.serverId; if (typeof serverId !== "string" || !serverId) return; router.replace(buildHostRootRoute(serverId)); return; diff --git a/packages/app/src/app/pair-scan.tsx b/packages/app/src/app/pair-scan.tsx index 694247d32..e8f65ad20 100644 --- a/packages/app/src/app/pair-scan.tsx +++ b/packages/app/src/app/pair-scan.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Alert, Pressable, Text, View } from "react-native"; -import { useLocalSearchParams, useRouter } from "expo-router"; +import { useLocalSearchParams, useRouter, type Href } from "expo-router"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { CameraView, useCameraPermissions } from "expo-camera"; @@ -147,7 +147,7 @@ export default function PairScanScreen() { try { router.back(); } catch { - router.replace("/" as any); + router.replace("/" as Href); } }, [router]); diff --git a/packages/app/src/components/adaptive-modal-sheet.tsx b/packages/app/src/components/adaptive-modal-sheet.tsx index 2cd7f6f9e..0618a1fd7 100644 --- a/packages/app/src/components/adaptive-modal-sheet.tsx +++ b/packages/app/src/components/adaptive-modal-sheet.tsx @@ -1,5 +1,5 @@ import { forwardRef, useCallback, useEffect, useMemo } from "react"; -import type { ReactNode } from "react"; +import type { ReactNode, Ref } from "react"; import { createPortal } from "react-dom"; import { Modal, Pressable, ScrollView, Text, TextInput, View } from "react-native"; import type { TextInputProps } from "react-native"; @@ -333,7 +333,7 @@ export const AdaptiveTextInput = forwardRef( const isMobile = useIsCompactFormFactor(); if (isMobile) { - return ; + return } {...props} />; } return ; diff --git a/packages/app/src/components/agent-list.tsx b/packages/app/src/components/agent-list.tsx index f9a8a2318..0668515f6 100644 --- a/packages/app/src/components/agent-list.tsx +++ b/packages/app/src/components/agent-list.tsx @@ -10,7 +10,7 @@ import { } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useCallback, useMemo, useState, type ReactElement } from "react"; -import { router } from "expo-router"; +import { router, type Href } from "expo-router"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { useIsCompactFormFactor } from "@/constants/layout"; import { formatTimeAgo } from "@/utils/time"; @@ -319,7 +319,7 @@ export function AgentList({ onAgentSelect?.(); if (!workspaceId) { - router.navigate(buildHostAgentDetailRoute(serverId, agentId) as any); + router.navigate(buildHostAgentDetailRoute(serverId, agentId) as Href); return; } diff --git a/packages/app/src/components/code-insets.ts b/packages/app/src/components/code-insets.ts index 62756602a..bcb34bf59 100644 --- a/packages/app/src/components/code-insets.ts +++ b/packages/app/src/components/code-insets.ts @@ -1,3 +1,5 @@ +import type { Theme } from "@/styles/theme"; + /** * Compute the pixel width for a line-number gutter based on the highest * line number that will be displayed. Minimum width accommodates 2 digits. @@ -7,7 +9,7 @@ export function lineNumberGutterWidth(maxLineNumber: number): number { return digits * 8 + 12; } -export function getCodeInsets(theme: any) { +export function getCodeInsets(theme: Theme) { let padding: number; if (typeof theme.spacing?.[3] === "number") padding = theme.spacing[3]; else if (typeof theme.spacing?.[4] === "number") padding = theme.spacing[4]; diff --git a/packages/app/src/components/combined-model-selector.tsx b/packages/app/src/components/combined-model-selector.tsx index 054fbfb08..967071ab5 100644 --- a/packages/app/src/components/combined-model-selector.tsx +++ b/packages/app/src/components/combined-model-selector.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import type { Ref } from "react"; import { View, Text, @@ -462,7 +463,7 @@ function ProviderSearchInput({ } // @ts-expect-error - outlineStyle is web-only style={inputStyle} placeholder="Search models..." diff --git a/packages/app/src/components/command-center.tsx b/packages/app/src/components/command-center.tsx index 6664bb8bd..f524d9a6e 100644 --- a/packages/app/src/components/command-center.tsx +++ b/packages/app/src/components/command-center.tsx @@ -389,7 +389,7 @@ const styles = StyleSheet.create((theme) => ({ fontSize: theme.fontSize.lg, paddingVertical: theme.spacing[1], outlineStyle: "none", - } as any, + } as object, results: { flexGrow: 0, }, diff --git a/packages/app/src/components/diff-scroll.tsx b/packages/app/src/components/diff-scroll.tsx index 0acb2091d..273c700a4 100644 --- a/packages/app/src/components/diff-scroll.tsx +++ b/packages/app/src/components/diff-scroll.tsx @@ -6,7 +6,11 @@ import { type StyleProp, type ViewStyle, } from "react-native"; -import { ScrollView, type ScrollView as ScrollViewType } from "react-native-gesture-handler"; +import { + ScrollView, + type ScrollView as ScrollViewType, + type GestureType, +} from "react-native-gesture-handler"; import { useHorizontalScrollOptional } from "@/contexts/horizontal-scroll-context"; import { useExplorerSidebarAnimation } from "@/contexts/explorer-sidebar-animation-context"; @@ -31,7 +35,7 @@ export function DiffScroll({ const scrollViewRef = useRef(null); // Get the close gesture ref from animation context (may not be available outside sidebar) - let closeGestureRef: React.MutableRefObject | undefined; + let closeGestureRef: React.MutableRefObject | undefined; try { const animation = useExplorerSidebarAnimation(); closeGestureRef = animation.closeGestureRef; diff --git a/packages/app/src/components/explorer-sidebar.tsx b/packages/app/src/components/explorer-sidebar.tsx index fb6479a9e..87e4c89bf 100644 --- a/packages/app/src/components/explorer-sidebar.tsx +++ b/packages/app/src/components/explorer-sidebar.tsx @@ -590,4 +590,4 @@ const styles = StyleSheet.create((theme) => ({ })); const DESKTOP_SIDEBAR_BORDER_STYLE = [styles.desktopSidebarBorder, { flex: 1 }]; -const RESIZE_HANDLE_STYLE = [styles.resizeHandle, isWeb && ({ cursor: "col-resize" } as any)]; +const RESIZE_HANDLE_STYLE = [styles.resizeHandle, isWeb && ({ cursor: "col-resize" } as object)]; diff --git a/packages/app/src/components/headers/header-toggle-button.tsx b/packages/app/src/components/headers/header-toggle-button.tsx index bf2c0816b..790b6e43e 100644 --- a/packages/app/src/components/headers/header-toggle-button.tsx +++ b/packages/app/src/components/headers/header-toggle-button.tsx @@ -39,7 +39,7 @@ export function HeaderToggleButton({ const expandedState = (props.accessibilityState as { expanded?: boolean } | undefined)?.expanded; const ariaExpandedProps = isWeb && typeof expandedState === "boolean" - ? ({ "aria-expanded": expandedState } as any) + ? ({ "aria-expanded": expandedState } as Record) : null; const combinedStyle = useMemo(() => [headerIconSlotStyle.slot, style], [style]); diff --git a/packages/app/src/components/left-sidebar.tsx b/packages/app/src/components/left-sidebar.tsx index ed6647d71..ee384b595 100644 --- a/packages/app/src/components/left-sidebar.tsx +++ b/packages/app/src/components/left-sidebar.tsx @@ -728,7 +728,7 @@ function DesktopSidebar({ ); const desktopSidebarBorderStyle = useMemo(() => [styles.desktopSidebarBorder, { flex: 1 }], []); const resizeHandleStyle = useMemo( - () => [styles.resizeHandle, isWeb && ({ cursor: "col-resize" } as any)], + () => [styles.resizeHandle, isWeb && ({ cursor: "col-resize" } as object)], [], ); diff --git a/packages/app/src/components/project-picker-modal.tsx b/packages/app/src/components/project-picker-modal.tsx index 1637538d4..91d92cd49 100644 --- a/packages/app/src/components/project-picker-modal.tsx +++ b/packages/app/src/components/project-picker-modal.tsx @@ -300,7 +300,7 @@ const styles = StyleSheet.create((theme) => ({ fontSize: theme.fontSize.lg, paddingVertical: theme.spacing[1], outlineStyle: "none", - } as any, + } as object, results: { flexGrow: 0, }, diff --git a/packages/app/src/components/split-drop-zone.tsx b/packages/app/src/components/split-drop-zone.tsx index 7963403dc..b761f6b93 100644 --- a/packages/app/src/components/split-drop-zone.tsx +++ b/packages/app/src/components/split-drop-zone.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useMemo, type Ref } from "react"; import { useDroppable } from "@dnd-kit/core"; import { View } from "react-native"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; @@ -62,7 +62,7 @@ export function SplitDropZone({ paneId, active, preview }: SplitDropZoneProps) { } return ( - + } style={styles.overlay} pointerEvents="none"> {previewStyles ? ( <> diff --git a/packages/app/src/components/ui/combobox.tsx b/packages/app/src/components/ui/combobox.tsx index 56f774ecc..d98c41365 100644 --- a/packages/app/src/components/ui/combobox.tsx +++ b/packages/app/src/components/ui/combobox.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; -import type { ReactElement, ReactNode } from "react"; +import type { ReactElement, ReactNode, Ref } from "react"; import { View, Text, @@ -155,7 +155,7 @@ export function SearchInput({ } // @ts-expect-error - outlineStyle is web-only style={SEARCH_INPUT_STYLE} placeholder={placeholder} diff --git a/packages/app/src/desktop/components/pair-device-section.tsx b/packages/app/src/desktop/components/pair-device-section.tsx index 03b9ce0fb..0283495e8 100644 --- a/packages/app/src/desktop/components/pair-device-section.tsx +++ b/packages/app/src/desktop/components/pair-device-section.tsx @@ -196,5 +196,5 @@ const styles = StyleSheet.create((theme) => ({ paddingVertical: theme.spacing[2], paddingHorizontal: theme.spacing[3], outlineStyle: "none", - } as any, + } as object, })); diff --git a/packages/app/src/hooks/use-command-center.ts b/packages/app/src/hooks/use-command-center.ts index 07680beb5..8f022804c 100644 --- a/packages/app/src/hooks/use-command-center.ts +++ b/packages/app/src/hooks/use-command-center.ts @@ -209,7 +209,7 @@ export function useCommandCenter() { workspaceDirectory: agent.cwd, }); if (!workspaceId) { - router.navigate(buildHostAgentDetailRoute(agent.serverId, agent.id) as any); + router.navigate(buildHostAgentDetailRoute(agent.serverId, agent.id) as Href); return; } const route = prepareWorkspaceTab({ diff --git a/packages/app/src/hooks/use-open-project.ts b/packages/app/src/hooks/use-open-project.ts index c9879d6e0..4e5e4d174 100644 --- a/packages/app/src/hooks/use-open-project.ts +++ b/packages/app/src/hooks/use-open-project.ts @@ -1,5 +1,5 @@ import { useCallback } from "react"; -import { router } from "expo-router"; +import { router, type Href } from "expo-router"; import type { DaemonClient } from "@server/client/daemon-client"; import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { @@ -76,7 +76,7 @@ export function useOpenProject(serverId: string | null): (path: string) => Promi draftId: generateDraftId(), }), replaceRoute: (route) => { - router.replace(route as any); + router.replace(route as Href); }, }); }, diff --git a/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts b/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts index 6b0a49391..090e082a8 100644 --- a/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts +++ b/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts @@ -75,7 +75,7 @@ declare global { const isMac = typeof navigator !== "undefined" && (/Macintosh|Mac OS/i.test(navigator.userAgent ?? "") || - /Mac/i.test((navigator as any).platform ?? "")); + /Mac/i.test((navigator as Navigator & { platform?: string }).platform ?? "")); const DEFAULT_TOUCH_SCROLL_LINE_HEIGHT_PX = 18; const FIT_TIMEOUT_DELAYS_MS = [0, 16, 48, 120, 250, 500, 1_000, 2_000]; diff --git a/packages/app/src/utils/app-version.ts b/packages/app/src/utils/app-version.ts index 2aca02c0d..eff3f3873 100644 --- a/packages/app/src/utils/app-version.ts +++ b/packages/app/src/utils/app-version.ts @@ -25,7 +25,9 @@ export function resolveAppVersion(): string | null { return expoVersion; } - const manifestVersion = toVersionOrNull((Constants as any).manifest?.version); + const manifestVersion = toVersionOrNull( + (Constants as unknown as { manifest?: { version?: unknown } }).manifest?.version, + ); if (manifestVersion) { return manifestVersion; } diff --git a/packages/app/src/utils/os-notifications.ts b/packages/app/src/utils/os-notifications.ts index 8762c5d88..353f19513 100644 --- a/packages/app/src/utils/os-notifications.ts +++ b/packages/app/src/utils/os-notifications.ts @@ -51,7 +51,18 @@ function getWebNotificationConstructor(): { }, ): unknown; } | null { - const NotificationConstructor = (globalThis as { Notification?: any }).Notification; + const NotificationConstructor = ( + globalThis as { + Notification?: { + permission: string; + requestPermission?: () => Promise; + new ( + title: string, + options?: { body?: string; data?: Record; icon?: string }, + ): unknown; + }; + } + ).Notification; return NotificationConstructor ?? null; } diff --git a/packages/app/src/utils/shortcut-platform.ts b/packages/app/src/utils/shortcut-platform.ts index 40678364a..6c1498341 100644 --- a/packages/app/src/utils/shortcut-platform.ts +++ b/packages/app/src/utils/shortcut-platform.ts @@ -10,7 +10,7 @@ export function getShortcutOs(): ShortcutOs { if (getIsElectronRuntimeMac()) return "mac"; if (typeof navigator === "undefined") return "non-mac"; const ua = navigator.userAgent ?? ""; - const platform = (navigator as any).platform ?? ""; + const platform = (navigator as Navigator & { platform?: string }).platform ?? ""; const isApple = /Macintosh|Mac OS|iPhone|iPad|iPod/i.test(ua) || /Mac|iPhone|iPad|iPod/i.test(platform); return isApple ? "mac" : "non-mac"; diff --git a/packages/app/vitest.setup.ts b/packages/app/vitest.setup.ts index 3b2b6fbc7..800f73fa7 100644 --- a/packages/app/vitest.setup.ts +++ b/packages/app/vitest.setup.ts @@ -1,7 +1,7 @@ // @ts-nocheck import { vi } from "vitest"; -const globalWithTestShims = globalThis as typeof globalThis & Record; +const globalWithTestShims = globalThis as typeof globalThis & Record; globalWithTestShims.__DEV__ = false;