chore(lint): no-explicit-any in small app files (batch 2)

This commit is contained in:
Mohamed Boudra
2026-04-24 06:46:41 +07:00
parent 056dc46e74
commit de27e31116
22 changed files with 130 additions and 73 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef } from "react";
import { useLocalSearchParams, useRouter } from "expo-router";
import { useLocalSearchParams, useRouter, type Href } from "expo-router";
import { HostRouteBootstrapBoundary } from "@/components/host-route-bootstrap-boundary";
import { useSessionStore } from "@/stores/session-store";
import { useResolveWorkspaceIdByCwd } from "@/stores/session-store-hooks";
@@ -44,7 +44,7 @@ function HostAgentReadyRouteContent() {
}
if (!serverId || !agentId) {
redirectedRef.current = true;
router.replace("/" as any);
router.replace("/" as Href);
return;
}
@@ -55,7 +55,7 @@ function HostAgentReadyRouteContent() {
serverId,
workspaceId: resolvedWorkspaceId,
target: { kind: "agent", agentId },
}) as any,
}) as Href,
);
}
}, [agentId, resolvedWorkspaceId, router, serverId]);
@@ -107,7 +107,7 @@ function HostAgentReadyRouteContent() {
serverId,
workspaceId,
target: { kind: "agent", agentId },
}) as any,
}) as Href,
);
return;
}

View File

@@ -65,8 +65,8 @@ function stripOpenSearchParamFromBrowserUrl() {
}
function clearConsumedOpenIntent(input: {
navigation: { setParams: (...args: any[]) => void };
router: { replace: (...args: any[]) => void };
navigation: { setParams: (params: { open?: string | undefined }) => void };
router: ReturnType<typeof useRouter>;
serverId: string;
workspaceId: string;
}) {
@@ -137,7 +137,9 @@ function HostWorkspaceLayoutContent() {
const consumptionKey = `${serverId}:${workspaceId}:${openValue}`;
if (consumedIntentRef.current === consumptionKey) {
clearConsumedOpenIntent({
navigation,
navigation: navigation as unknown as {
setParams: (params: { open?: string | undefined }) => void;
},
router,
serverId,
workspaceId,
@@ -161,7 +163,9 @@ function HostWorkspaceLayoutContent() {
// skips search params). Strip ?open from the browser URL directly so the
// address bar reflects the clean workspace route.
clearConsumedOpenIntent({
navigation,
navigation: navigation as unknown as {
setParams: (params: { open?: string | undefined }) => void;
},
router,
serverId,
workspaceId,

View File

@@ -59,7 +59,7 @@ export function ArchivedAgentCallout({ serverId, agentId }: ArchivedAgentCallout
);
}
const styles = StyleSheet.create(((theme: Theme) => ({
const styles = StyleSheet.create((theme: Theme) => ({
container: {
flexDirection: "column",
position: "relative",
@@ -99,4 +99,4 @@ const styles = StyleSheet.create(((theme: Theme) => ({
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.base,
},
})) as any) as Record<string, any>;
})) as unknown as Record<string, object>;

View File

@@ -85,8 +85,8 @@ export function DraggableList<T>({
containerStyle ?? (scrollEnabled ? SCROLL_ENABLED_FLEX_STYLE : undefined);
const shouldShowRefreshControl = showRefreshControl && !nestable;
const ListComponent: typeof DraggableFlatList = (
nestable ? (NestableDraggableFlatList as any) : DraggableFlatList
) as any;
nestable ? (NestableDraggableFlatList as unknown) : DraggableFlatList
) as typeof DraggableFlatList;
const refreshControl = useMemo(
() =>

View File

@@ -150,11 +150,11 @@ vi.mock("@/components/ui/tooltip", () => ({
}: {
asChild?: boolean;
children: React.ReactNode | ((state: { hovered: boolean }) => React.ReactNode);
} & Record<string, any>) =>
} & Record<string, unknown>) =>
asChild ? (
children
) : (
<button type="button" aria-label={props.accessibilityLabel}>
<button type="button" aria-label={props.accessibilityLabel as string | undefined}>
{typeof children === "function" ? children({ hovered: false }) : children}
</button>
),

View File

@@ -1,5 +1,5 @@
import { useCallback, useMemo, useRef, useState } from "react";
import { View } from "react-native";
import { View, type PointerEvent as RNPointerEvent } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
export interface ResizeHandleProps {
@@ -32,8 +32,8 @@ export function ResizeHandle({
const highlighted = active || dragging;
const handlePointerDown = useCallback(
(event: any) => {
const hitAreaElement = event.currentTarget as HTMLElement | null;
(event: RNPointerEvent) => {
const hitAreaElement = event.currentTarget as unknown as HTMLElement | null;
const containerElement = hitAreaElement?.parentElement?.parentElement ?? null;
if (!containerElement) {
return;
@@ -49,7 +49,8 @@ export function ResizeHandle({
pointerStateRef.current = {
containerSize,
pointerStart: direction === "horizontal" ? event.clientX : event.clientY,
pointerStart:
direction === "horizontal" ? event.nativeEvent.clientX : event.nativeEvent.clientY,
leftSize: sizes[index] ?? 0,
rightSize: sizes[index + 1] ?? 0,
};
@@ -129,7 +130,7 @@ export function ResizeHandle({
direction === "horizontal" ? styles.hitAreaHorizontal : styles.hitAreaVertical,
{
cursor: direction === "horizontal" ? "col-resize" : "row-resize",
} as any,
} as object,
],
[direction],
);

View File

@@ -283,7 +283,7 @@ export function Autocomplete({
);
}
const styles = StyleSheet.create(((theme: Theme) => ({
const styles = StyleSheet.create((theme: Theme) => ({
outerWrapper: {
gap: theme.spacing[1],
},
@@ -385,4 +385,4 @@ const styles = StyleSheet.create(((theme: Theme) => ({
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
})) as any) as Record<string, any>;
})) as unknown as Record<string, object>;

View File

@@ -175,7 +175,17 @@ function computePosition({
}
function coerceEventPoint(event: unknown): { pageX: number; pageY: number } | null {
const nativeEvent: any = (event as any)?.nativeEvent ?? event;
const wrapper = event as
| {
nativeEvent?: { pageX?: number; pageY?: number; clientX?: number; clientY?: number };
pageX?: number;
pageY?: number;
clientX?: number;
clientY?: number;
}
| null
| undefined;
const nativeEvent = wrapper?.nativeEvent ?? wrapper;
const pageX = nativeEvent?.pageX;
const pageY = nativeEvent?.pageY;
if (typeof pageX === "number" && typeof pageY === "number") {
@@ -315,7 +325,7 @@ export function ContextMenuTrigger({
if (isNative) {
return;
}
const e: any = event;
const e = event as { preventDefault?: () => void; stopPropagation?: () => void } | undefined;
e?.preventDefault?.();
e?.stopPropagation?.();
openAtEvent(event as GestureResponderEvent);

View File

@@ -24,6 +24,9 @@ import {
} from "@server/shared/agent-attention-notification";
import type { AgentLifecycleStatus } from "@server/shared/agent-lifecycle";
import type { DaemonClient } from "@server/client/daemon-client";
import type { AgentSessionConfig } from "@server/server/agent/agent-sdk-types";
import type { GitSetupOptions } from "@server/shared/messages";
import type { AgentPermissionResponse } from "@server/server/agent/agent-sdk-types";
import { getHostRuntimeStore, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
import { useVoiceAudioEngineOptional, useVoiceRuntimeOptional } from "@/contexts/voice-context";
import type { AudioPlaybackSource } from "@/voice/audio-engine-types";
@@ -1629,11 +1632,11 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider
worktreeName,
requestId,
}: {
config: any;
config: AgentSessionConfig;
initialPrompt: string;
images?: AttachmentMetadata[];
attachments?: AgentAttachment[];
git?: any;
git?: GitSetupOptions;
worktreeName?: string;
requestId?: string;
}) => {
@@ -1704,7 +1707,7 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider
);
const _respondToPermission = useCallback(
(agentId: string, requestId: string, response: any) => {
(agentId: string, requestId: string, response: AgentPermissionResponse) => {
if (!client) {
console.warn("[Session] respondToPermission skipped: daemon unavailable");
return;

View File

@@ -16,7 +16,7 @@ const desktopDaemonMock = vi.hoisted(() => {
const openLocalTransportSession = vi.fn<(...args: unknown[]) => Promise<string>>();
const listenToLocalTransportEvents = vi.fn(
async (
handler: typeof eventHandler extends ((...args: infer A) => any) | null
handler: typeof eventHandler extends ((...args: infer A) => unknown) | null
? (...args: A) => void
: never,
) => {

View File

@@ -1,7 +1,7 @@
import { describe, expect, it, vi, beforeEach } from "vitest";
const desktopHostState = vi.hoisted(() => ({
api: null as any,
api: null as unknown,
}));
vi.mock("@/desktop/host", () => ({

View File

@@ -219,15 +219,18 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
await recorder.record();
attemptGuardRef.current.assertCurrent(attemptId);
} catch (error: any) {
} catch (error) {
setRecordingStartTime(null);
if (error instanceof AttemptCancelledError) {
return;
}
if (error?.message !== "Recording cancelled") {
if ((error as { message?: string })?.message !== "Recording cancelled") {
console.error("[AudioRecorder] Failed to start recording:", error);
}
throw new Error(`Failed to start audio recording: ${error.message}`, { cause: error });
throw new Error(
`Failed to start audio recording: ${(error as { message?: string })?.message ?? String(error)}`,
{ cause: error },
);
}
}, [recordingOptions.sampleRate, recordingOptions.numberOfChannels, recordingOptions.bitRate]);
@@ -290,10 +293,13 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
})();
startStopMutexRef.current = stopPromise;
return await stopPromise;
} catch (error: any) {
} catch (error) {
setRecordingStartTime(null);
console.error("[AudioRecorder] Failed to stop recording:", error);
throw new Error(`Failed to stop audio recording: ${error.message}`, { cause: error });
throw new Error(
`Failed to stop audio recording: ${(error as { message?: string })?.message ?? String(error)}`,
{ cause: error },
);
} finally {
startStopMutexRef.current = null;
}

View File

@@ -189,8 +189,11 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
let stream: MediaStream;
try {
stream = await navigator.mediaDevices.getUserMedia(constraints);
} catch (error: any) {
throw new Error(`Failed to access microphone: ${error?.message ?? error}`, { cause: error });
} catch (error) {
throw new Error(
`Failed to access microphone: ${(error as { message?: string })?.message ?? String(error)}`,
{ cause: error },
);
}
try {
@@ -223,11 +226,14 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
let recorder: MediaRecorder;
try {
recorder = new MediaRecorder(stream, recorderOptions);
} catch (error: any) {
} catch (error) {
cleanupStream();
throw new Error(`Failed to initialize recorder: ${error?.message ?? error}`, {
cause: error,
});
throw new Error(
`Failed to initialize recorder: ${(error as { message?: string })?.message ?? String(error)}`,
{
cause: error,
},
);
}
mediaRecorderRef.current = recorder;

View File

@@ -260,7 +260,10 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
// isn't available (e.g., Playwright tests with a stubbed getUserMedia).
}
const RecorderCtor = typeof window !== "undefined" ? (window as any).MediaRecorder : undefined;
const RecorderCtor =
typeof window !== "undefined"
? (window as Window & { MediaRecorder?: typeof MediaRecorder }).MediaRecorder
: undefined;
if (!RecorderCtor) {
throw new Error("MediaRecorder unavailable");
}
@@ -277,7 +280,7 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
stoppedReject: null,
};
recorder.ondataavailable = (event: any) => {
recorder.ondataavailable = (event: BlobEvent) => {
const data: Blob | undefined = event?.data;
if (data) {
recorderRefs.audioChunks.push(data);

View File

@@ -9,10 +9,14 @@ import { isWeb } from "@/constants/platform";
const STORAGE_PREFIX = "@paseo:expo-push-token:";
function getExpoProjectId(): string | null {
const fromEas = (Constants as any)?.easConfig?.projectId;
const constants = Constants as unknown as {
easConfig?: { projectId?: unknown };
expoConfig?: { extra?: { eas?: { projectId?: unknown } } };
};
const fromEas = constants?.easConfig?.projectId;
if (typeof fromEas === "string" && fromEas.trim()) return fromEas.trim();
const fromExtra = (Constants as any)?.expoConfig?.extra?.eas?.projectId;
const fromExtra = constants?.expoConfig?.extra?.eas?.projectId;
if (typeof fromExtra === "string" && fromExtra.trim()) return fromExtra.trim();
return null;

View File

@@ -18,6 +18,7 @@ vi.mock("@react-native-async-storage/async-storage", () => {
import {
buildExplorerCheckoutKey,
resolveExplorerTabForCheckout,
type ExplorerTab,
} from "@/stores/explorer-tab-memory";
import {
selectIsAgentListOpen,
@@ -108,7 +109,7 @@ describe("panel-store explorer tab resolution", () => {
cwd,
isGit: true,
explorerTabByCheckout: {
[key]: "terminals" as any,
[key]: "terminals" as unknown as ExplorerTab,
},
}),
).toBe("changes");

View File

@@ -29,6 +29,7 @@ import {
removeTabFromTree,
useWorkspaceLayoutStore,
type SplitNode,
type SplitPane,
} from "@/stores/workspace-layout-store";
const SERVER_ID = "server-1";
@@ -55,7 +56,7 @@ function createPane(input: {
tabIds: input.tabIds,
focusedTabId: input.focusedTabId ?? input.tabIds[input.tabIds.length - 1] ?? null,
tabs,
} as any,
} as SplitPane,
};
}
@@ -1048,7 +1049,7 @@ describe("workspace-layout-store actions", () => {
createdAt: 4,
},
],
} as any,
} as SplitPane,
},
focusedPaneId: "main",
},

View File

@@ -405,36 +405,36 @@ export const useWorkspaceTabsStore = create<WorkspaceTabsState>()(
const legacy = persistedState as
| {
version?: number;
state?: any;
state?: unknown;
openTabsByWorkspace?: Record<string, WorkspaceTab[]>;
uiTabsByWorkspace?: Record<string, WorkspaceTab[]>;
focusedTabIdByWorkspace?: Record<string, string>;
tabOrderByWorkspace?: Record<string, string[]>;
lastFocusedTabByWorkspace?: Record<string, any>;
lastFocusedTabByWorkspace?: Record<string, unknown>;
tabOrderLegacyByWorkspace?: Record<string, string[]>;
}
| undefined;
const rawState = (legacy as any)?.state ?? legacy ?? {};
const rawState = ((legacy as { state?: Record<string, unknown> } | undefined)?.state ??
legacy ??
{}) as Record<string, unknown>;
const rawUiTabsByWorkspace =
rawState.uiTabsByWorkspace ??
const rawUiTabsByWorkspace = (rawState.uiTabsByWorkspace ??
rawState.openTabsByWorkspace ??
legacy?.uiTabsByWorkspace ??
legacy?.openTabsByWorkspace ??
{};
const rawFocused =
rawState.focusedTabIdByWorkspace ??
{}) as Record<string, unknown>;
const rawFocused = (rawState.focusedTabIdByWorkspace ??
legacy?.focusedTabIdByWorkspace ??
rawState.lastFocusedTabByWorkspace ??
{};
const rawOrder =
rawState.tabOrderByWorkspace ??
{}) as Record<string, unknown>;
const rawOrder = (rawState.tabOrderByWorkspace ??
legacy?.tabOrderByWorkspace ??
rawState.tabOrderByWorkspace ??
{};
const legacyOrder =
rawState.tabOrderByWorkspace ?? rawState.tabOrderLegacyByWorkspace ?? {};
{}) as Record<string, unknown>;
const legacyOrder = (rawState.tabOrderByWorkspace ??
rawState.tabOrderLegacyByWorkspace ??
{}) as Record<string, unknown>;
const uiTabsByWorkspace: Record<string, WorkspaceTab[]> = {};
const tabOrderByWorkspace: Record<string, string[]> = {};
@@ -523,15 +523,24 @@ export const useWorkspaceTabsStore = create<WorkspaceTabsState>()(
}
for (const key in rawFocused) {
const value = rawFocused[key];
if (typeof value === "string") {
const normalized = trimNonEmpty(value);
const rawValue = rawFocused[key];
if (typeof rawValue === "string") {
const normalized = trimNonEmpty(rawValue);
if (normalized) {
focusedTabIdByWorkspace[key] = normalized;
}
continue;
}
if (!value || typeof value !== "object" || typeof value.kind !== "string") {
if (!rawValue || typeof rawValue !== "object") {
continue;
}
const value = rawValue as {
kind?: string;
agentId?: string;
terminalId?: string;
draftId?: string;
};
if (typeof value.kind !== "string") {
continue;
}
if (value.kind === "agent" && typeof value.agentId === "string" && value.agentId.trim()) {

View File

@@ -62,7 +62,16 @@ function extractState(terminal: ClientTerminal | HeadlessTerminal): SnapshotStat
function extractCursorState(terminal: ClientTerminal | HeadlessTerminal): SnapshotState["cursor"] {
const buffer = terminal.buffer.active;
const coreService = (terminal as any)._core?.coreService;
const coreService = (
terminal as unknown as {
_core?: {
coreService?: {
decPrivateModes?: { cursorStyle?: string; cursorBlink?: boolean };
isCursorHidden?: boolean;
};
};
}
)._core?.coreService;
const cursorStyle = coreService?.decPrivateModes?.cursorStyle;
const normalizedCursorStyle =
cursorStyle === "block" || cursorStyle === "underline" || cursorStyle === "bar"

View File

@@ -7,12 +7,12 @@ function makeAgent(overrides: Partial<AggregatedAgent> = {}): AggregatedAgent {
return {
id: overrides.id ?? "a1",
serverId: overrides.serverId ?? "s1",
serverLabel: (overrides as any).serverLabel ?? "server",
serverLabel: (overrides as { serverLabel?: string }).serverLabel ?? "server",
title: overrides.title ?? null,
status: overrides.status ?? ("running" as AggregatedAgent["status"]),
lastActivityAt: overrides.lastActivityAt ?? now,
cwd: overrides.cwd ?? "/tmp/repo",
provider: overrides.provider ?? ("openai" as any),
provider: overrides.provider ?? ("openai" as AggregatedAgent["provider"]),
requiresAttention: overrides.requiresAttention ?? false,
attentionReason: overrides.attentionReason ?? null,
attentionTimestamp: overrides.attentionTimestamp ?? null,

View File

@@ -1,4 +1,4 @@
import { router } from "expo-router";
import { router, type Href } from "expo-router";
import { isNative } from "@/constants/platform";
import {
activateNavigationWorkspaceSelection,
@@ -65,9 +65,9 @@ export function navigateToPreparedWorkspaceTab(input: NavigateToPreparedWorkspac
}, 0);
return route;
}
router.replace(route as any);
router.replace(route as Href);
} else {
router.navigate(route as any);
router.navigate(route as Href);
}
return route;
}

View File

@@ -98,17 +98,17 @@ export function createAudioEngine(
const microphoneSubscription = native.addExpoTwoWayAudioEventListener(
"onMicrophoneData",
(event: any) => {
(event: { data: Uint8Array }) => {
if (!refs.captureActive || refs.muted) {
return;
}
const pcm = event.data as Uint8Array;
const pcm = event.data;
callbacks.onCaptureData(pcm);
},
);
const volumeSubscription = native.addExpoTwoWayAudioEventListener(
"onInputVolumeLevelData",
(event: any) => {
(event: { data: number }) => {
if (!refs.captureActive) {
return;
}