From df5c59263e3a56d6f479acae597f43099b37cdb0 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 5 May 2026 16:27:22 +0800 Subject: [PATCH] refactor(typeaware): no-unnecessary-type-conversion + unbound-method sweep (T3.b partial) (#754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: clear no-unnecessary-type-conversion + unbound-method (T3.b partial) Fixes 15 files within the hard cap: unbound-method (interface method shorthand → property function syntax): - pane-context.tsx: PaneContextValue + PaneFocusContextValue (fixes agent-panel, browser-panel, draft-panel) - provider-runner.ts: ProviderTurnRunner interface - process-tree.ts: process.kill.bind(process) no-unnecessary-type-conversion (remove redundant Boolean()/String() wraps): - agent-timeline-store.ts, worktree-session.ts, pairing-qr.ts - sherpa-realtime-session.ts, sherpa-stt.ts (String() → direct call chain) - workspace-execution.ts, confirm-dialog.ts, use-archive-agent.ts - use-agent-history.ts, left-sidebar.tsx, autocomplete.tsx, dropdown-menu.tsx Deferred (9 errors across 7 files, all single-line Boolean(hovered) removals): project-picker-modal.tsx, agent-list.tsx, branch-switcher.tsx, file-explorer-pane.tsx, workspace-open-in-editor-button.tsx, browser-pane.electron.tsx, sortable-inline-list.web.tsx * fix(app): preserve Boolean coercion fallback in archive state lookups readPendingState(...)[key] and (pendingQuery.data ?? {})[key] return boolean | undefined at runtime — noUncheckedIndexedAccess is off so TypeScript types this as boolean but the actual value can be undefined. Add ?? false to maintain the explicit boolean return contract. --- packages/app/src/components/left-sidebar.tsx | 2 +- packages/app/src/components/ui/autocomplete.tsx | 2 +- packages/app/src/components/ui/dropdown-menu.tsx | 4 ++-- packages/app/src/hooks/use-agent-history.ts | 2 +- packages/app/src/hooks/use-archive-agent.ts | 4 ++-- packages/app/src/panels/pane-context.tsx | 10 +++++----- packages/app/src/utils/confirm-dialog.ts | 2 +- packages/app/src/utils/workspace-execution.ts | 2 +- .../server/src/server/agent/agent-timeline-store.ts | 2 +- .../src/server/agent/providers/provider-runner.ts | 6 +++--- packages/server/src/server/pairing-qr.ts | 2 +- .../providers/local/sherpa/sherpa-realtime-session.ts | 8 ++++---- .../server/speech/providers/local/sherpa/sherpa-stt.ts | 4 ++-- packages/server/src/server/worktree-session.ts | 2 +- packages/server/src/utils/process-tree.ts | 2 +- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/app/src/components/left-sidebar.tsx b/packages/app/src/components/left-sidebar.tsx index 09cab7b4b..69952a689 100644 --- a/packages/app/src/components/left-sidebar.tsx +++ b/packages/app/src/components/left-sidebar.tsx @@ -308,7 +308,7 @@ function HostPickerTrigger({ const pressableStyle = useCallback( ({ hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => [ styles.hostTrigger, - Boolean(hovered) && styles.hostTriggerHovered, + hovered && styles.hostTriggerHovered, ], [], ); diff --git a/packages/app/src/components/ui/autocomplete.tsx b/packages/app/src/components/ui/autocomplete.tsx index 96dc6f304..5ed6e960d 100644 --- a/packages/app/src/components/ui/autocomplete.tsx +++ b/packages/app/src/components/ui/autocomplete.tsx @@ -72,7 +72,7 @@ function AutocompleteRow({ const pressableStyle = useCallback( ({ hovered = false, pressed }: PressableStateCallbackType & { hovered?: boolean }) => [ styles.item, - (Boolean(hovered) || pressed || isSelected) && styles.itemActive, + (hovered || pressed || isSelected) && styles.itemActive, ], [isSelected], ); diff --git a/packages/app/src/components/ui/dropdown-menu.tsx b/packages/app/src/components/ui/dropdown-menu.tsx index 64942832a..a83434379 100644 --- a/packages/app/src/components/ui/dropdown-menu.tsx +++ b/packages/app/src/components/ui/dropdown-menu.tsx @@ -315,7 +315,7 @@ export function DropdownMenuTrigger({ const pressableStyle = useCallback( ({ pressed, hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => { if (typeof style === "function") { - return style({ pressed, hovered: Boolean(hovered), open: ctx.open }); + return style({ pressed, hovered, open: ctx.open }); } return style; }, @@ -324,7 +324,7 @@ export function DropdownMenuTrigger({ const renderChildren = useCallback( ({ pressed, hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => { - const state: TriggerState = { pressed, hovered: Boolean(hovered), open: ctx.open }; + const state: TriggerState = { pressed, hovered, open: ctx.open }; return typeof children === "function" ? children(state) : children; }, [children, ctx.open], diff --git a/packages/app/src/hooks/use-agent-history.ts b/packages/app/src/hooks/use-agent-history.ts index 1b17c5bee..2744b8417 100644 --- a/packages/app/src/hooks/use-agent-history.ts +++ b/packages/app/src/hooks/use-agent-history.ts @@ -141,7 +141,7 @@ export function useAgentHistory(options: { isLoading, isInitialLoad, isRevalidating, - hasMore: Boolean(hasNextPage), + hasMore: hasNextPage, isLoadingMore: isFetchingNextPage, refreshAll, loadMore, diff --git a/packages/app/src/hooks/use-archive-agent.ts b/packages/app/src/hooks/use-archive-agent.ts index f68b0e104..79ba980be 100644 --- a/packages/app/src/hooks/use-archive-agent.ts +++ b/packages/app/src/hooks/use-archive-agent.ts @@ -100,7 +100,7 @@ function isAgentArchiving(input: IsAgentArchivingInput): boolean { if (!key) { return false; } - return Boolean(readPendingState(input.queryClient)[key]); + return readPendingState(input.queryClient)[key] ?? false; } function removeAgentFromListPayload( @@ -420,7 +420,7 @@ export function useArchiveAgent() { if (!key) { return false; } - return Boolean((pendingQuery.data ?? {})[key]); + return (pendingQuery.data ?? {})[key] ?? false; }, [pendingQuery.data], ); diff --git a/packages/app/src/panels/pane-context.tsx b/packages/app/src/panels/pane-context.tsx index c39cc10a0..4ee0c6c0a 100644 --- a/packages/app/src/panels/pane-context.tsx +++ b/packages/app/src/panels/pane-context.tsx @@ -7,17 +7,17 @@ export interface PaneContextValue { workspaceId: string; tabId: string; target: WorkspaceTabTarget; - openTab(target: WorkspaceTabTarget): void; - closeCurrentTab(): void; - retargetCurrentTab(target: WorkspaceTabTarget): void; - openFileInWorkspace(filePath: string): void; + openTab: (target: WorkspaceTabTarget) => void; + closeCurrentTab: () => void; + retargetCurrentTab: (target: WorkspaceTabTarget) => void; + openFileInWorkspace: (filePath: string) => void; } export interface PaneFocusContextValue { isWorkspaceFocused: boolean; isPaneFocused: boolean; isInteractive: boolean; - focusPane(): void; + focusPane: () => void; } const PaneContext = createContext(null); diff --git a/packages/app/src/utils/confirm-dialog.ts b/packages/app/src/utils/confirm-dialog.ts index a04c6e16b..eb6917acc 100644 --- a/packages/app/src/utils/confirm-dialog.ts +++ b/packages/app/src/utils/confirm-dialog.ts @@ -86,7 +86,7 @@ async function showDesktopConfirmDialog(input: ConfirmDialogInput): Promise minSeq, - hasNewer: Boolean(lastSelected && lastSelected.seq < maxSeq), + hasNewer: lastSelected !== null && lastSelected !== undefined && lastSelected.seq < maxSeq, rows: selected.map(cloneRow), }; } diff --git a/packages/server/src/server/agent/providers/provider-runner.ts b/packages/server/src/server/agent/providers/provider-runner.ts index d13d171b6..6b02e65cb 100644 --- a/packages/server/src/server/agent/providers/provider-runner.ts +++ b/packages/server/src/server/agent/providers/provider-runner.ts @@ -12,9 +12,9 @@ export type ProviderFinalTextReducer = (params: { }) => string; export interface ProviderTurnRunner { - startTurn(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<{ turnId: string }>; - subscribe(callback: (event: AgentStreamEvent) => void): () => void; - getSessionId(): string | Promise; + startTurn: (prompt: AgentPromptInput, options?: AgentRunOptions) => Promise<{ turnId: string }>; + subscribe: (callback: (event: AgentStreamEvent) => void) => () => void; + getSessionId: () => string | Promise; } export interface RunProviderTurnOptions extends ProviderTurnRunner { diff --git a/packages/server/src/server/pairing-qr.ts b/packages/server/src/server/pairing-qr.ts index 872e7e7db..8b8f31f44 100644 --- a/packages/server/src/server/pairing-qr.ts +++ b/packages/server/src/server/pairing-qr.ts @@ -13,7 +13,7 @@ function parseBooleanEnv(value: string | undefined): boolean | undefined { function shouldPrintPairingQr(): boolean { const env = parseBooleanEnv(process.env.PASEO_PAIRING_QR); if (env !== undefined) return env; - return Boolean(process.stdout.isTTY); + return process.stdout.isTTY ?? false; } export async function renderPairingQr(url: string): Promise { diff --git a/packages/server/src/server/speech/providers/local/sherpa/sherpa-realtime-session.ts b/packages/server/src/server/speech/providers/local/sherpa/sherpa-realtime-session.ts index fbf449130..4106d96bd 100644 --- a/packages/server/src/server/speech/providers/local/sherpa/sherpa-realtime-session.ts +++ b/packages/server/src/server/speech/providers/local/sherpa/sherpa-realtime-session.ts @@ -59,10 +59,10 @@ export class SherpaRealtimeTranscriptionSession } const rawResult = this.engine.recognizer.getResult(this.stream); - const text = String( + const text = ( (typeof rawResult === "object" && rawResult && "text" in rawResult ? rawResult.text - : undefined) ?? "", + : undefined) ?? "" ).trim(); if (text !== this.lastPartialText) { this.lastPartialText = text; @@ -97,10 +97,10 @@ export class SherpaRealtimeTranscriptionSession } const rawFinal = this.engine.recognizer.getResult(this.stream); - const finalText = String( + const finalText = ( (typeof rawFinal === "object" && rawFinal && "text" in rawFinal ? rawFinal.text - : undefined) ?? "", + : undefined) ?? "" ).trim(); const segmentId = this.currentSegmentId; const previousSegmentId = this.previousSegmentId; diff --git a/packages/server/src/server/speech/providers/local/sherpa/sherpa-stt.ts b/packages/server/src/server/speech/providers/local/sherpa/sherpa-stt.ts index 37bf45fe1..12c1e73c0 100644 --- a/packages/server/src/server/speech/providers/local/sherpa/sherpa-stt.ts +++ b/packages/server/src/server/speech/providers/local/sherpa/sherpa-stt.ts @@ -165,10 +165,10 @@ export class SherpaOnnxSTT implements SpeechToTextProvider { } const rawResult = this.engine.recognizer.getResult(stream); - const text = String( + const text = ( (typeof rawResult === "object" && rawResult && "text" in rawResult ? rawResult.text - : undefined) ?? "", + : undefined) ?? "" ).trim(); const duration = Date.now() - start; this.logger.debug({ duration, textLength: text.length }, "Sherpa transcription complete"); diff --git a/packages/server/src/server/worktree-session.ts b/packages/server/src/server/worktree-session.ts index bb6af62c7..e7a857dc2 100644 --- a/packages/server/src/server/worktree-session.ts +++ b/packages/server/src/server/worktree-session.ts @@ -662,7 +662,7 @@ export async function runWorktreeSetupInBackground( let setupResults: WorktreeSetupCommandResult[] = []; let setupStarted = false; const progressAccumulator = createWorktreeSetupProgressAccumulator(); - const workspaceId = String(options.workspaceId); + const workspaceId = options.workspaceId; const emitSetupProgress = (status: "running" | "completed" | "failed", error: string | null) => { const snapshot: WorkspaceSetupSnapshot = { diff --git a/packages/server/src/utils/process-tree.ts b/packages/server/src/utils/process-tree.ts index 5963d8ffc..5c0a37f35 100644 --- a/packages/server/src/utils/process-tree.ts +++ b/packages/server/src/utils/process-tree.ts @@ -75,7 +75,7 @@ export function signalProcessTree( } try { - (options.kill ?? process.kill)(-pid, signal); + (options.kill ?? process.kill.bind(process))(-pid, signal); return; } catch { // Fall back to the direct child when no separate process group exists.