From 13de3131b797669fadd5da9cfa1b55b7ff62ddda Mon Sep 17 00:00:00 2001 From: Kacper Date: Thu, 11 Dec 2025 21:20:34 +0100 Subject: [PATCH] fix: infinite loop when checking cli status --- .../setup-view/steps/claude-setup-step.tsx | 30 +++++++++++++++---- .../setup-view/steps/codex-setup-step.tsx | 25 ++++++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/app/src/components/views/setup-view/steps/claude-setup-step.tsx b/app/src/components/views/setup-view/steps/claude-setup-step.tsx index 73015d87..20637530 100644 --- a/app/src/components/views/setup-view/steps/claude-setup-step.tsx +++ b/app/src/components/views/setup-view/steps/claude-setup-step.tsx @@ -65,22 +65,40 @@ export function ClaudeSetupStep({ const [apiKey, setApiKey] = useState(""); const [showTokenModal, setShowTokenModal] = useState(false); + // Memoize API functions to prevent infinite loops + const statusApi = useCallback( + () => getElectronAPI().setup?.getClaudeStatus() || Promise.reject(), + [] + ); + + const installApi = useCallback( + () => getElectronAPI().setup?.installClaude() || Promise.reject(), + [] + ); + + const getStoreState = useCallback( + () => useSetupStore.getState().claudeCliStatus, + [] + ); + // Use custom hooks const { isChecking, checkStatus } = useCliStatus({ cliType: "claude", - statusApi: () => - getElectronAPI().setup?.getClaudeStatus() || Promise.reject(), + statusApi, setCliStatus: setClaudeCliStatus, setAuthStatus: setClaudeAuthStatus, }); + const onInstallSuccess = useCallback(() => { + checkStatus(); + }, [checkStatus]); + const { isInstalling, installProgress, install } = useCliInstallation({ cliType: "claude", - installApi: () => - getElectronAPI().setup?.installClaude() || Promise.reject(), + installApi, onProgressEvent: getElectronAPI().setup?.onInstallProgress, - onSuccess: checkStatus, - getStoreState: () => useSetupStore.getState().claudeCliStatus, + onSuccess: onInstallSuccess, + getStoreState, }); const { isSaving: isSavingOAuth, saveToken: saveOAuthToken } = useTokenSave({ diff --git a/app/src/components/views/setup-view/steps/codex-setup-step.tsx b/app/src/components/views/setup-view/steps/codex-setup-step.tsx index 69f8b292..13335e02 100644 --- a/app/src/components/views/setup-view/steps/codex-setup-step.tsx +++ b/app/src/components/views/setup-view/steps/codex-setup-step.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -58,21 +58,34 @@ export function CodexSetupStep({ const [showApiKeyInput, setShowApiKeyInput] = useState(false); const [apiKey, setApiKey] = useState(""); + // Memoize API functions to prevent infinite loops + const statusApi = useCallback( + () => getElectronAPI().setup?.getCodexStatus() || Promise.reject(), + [] + ); + + const installApi = useCallback( + () => getElectronAPI().setup?.installCodex() || Promise.reject(), + [] + ); + // Use custom hooks const { isChecking, checkStatus } = useCliStatus({ cliType: "codex", - statusApi: () => - getElectronAPI().setup?.getCodexStatus() || Promise.reject(), + statusApi, setCliStatus: setCodexCliStatus, setAuthStatus: setCodexAuthStatus, }); + const onInstallSuccess = useCallback(() => { + checkStatus(); + }, [checkStatus]); + const { isInstalling, installProgress, install } = useCliInstallation({ cliType: "codex", - installApi: () => - getElectronAPI().setup?.installCodex() || Promise.reject(), + installApi, onProgressEvent: getElectronAPI().setup?.onInstallProgress, - onSuccess: checkStatus, + onSuccess: onInstallSuccess, }); const { isSaving: isSavingKey, saveToken: saveApiKeyToken } = useTokenSave({