fix: guard browser use cli async state (#3567)

This commit is contained in:
Neil
2026-05-30 02:11:12 -07:00
committed by GitHub
parent bb6ef72348
commit 4eece13cbe
@@ -1,5 +1,5 @@
/* eslint-disable max-lines -- Why: Browser Use setup keeps enablement, CLI registration, skill install, cookie import, examples, and interaction tracking in one pane so the three-step setup state stays coherent. */
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Import, Loader2, MousePointerClick } from 'lucide-react'
import { toast } from 'sonner'
import type { CliInstallStatus } from '../../../../shared/cli-install-types'
@@ -58,6 +58,20 @@ export function BrowserUseSetup({
const [cliStatus, setCliStatus] = useState<CliInstallStatus | null>(null)
const [cliLoading, setCliLoading] = useState(true)
const [cliBusy, setCliBusy] = useState(false)
const mountedRef = useRef(true)
useEffect(() => {
mountedRef.current = true
return () => {
mountedRef.current = false
}
}, [])
const handleCliStatusChange = useCallback((nextStatus: CliInstallStatus): void => {
if (mountedRef.current) {
setCliStatus(nextStatus)
}
}, [])
// Why: the toggle gates only whether we show the setup instructions. We
// persist it in localStorage instead of global settings because it has no
@@ -75,16 +89,20 @@ export function BrowserUseSetup({
}
}
const refreshCli = async (): Promise<void> => {
const refreshCli = useCallback(async (): Promise<void> => {
setCliLoading(true)
try {
setCliStatus(await window.api.cli.getInstallStatus())
handleCliStatusChange(await window.api.cli.getInstallStatus())
} catch (error) {
toast.error(error instanceof Error ? error.message : 'Failed to load CLI status.')
if (mountedRef.current) {
toast.error(error instanceof Error ? error.message : 'Failed to load CLI status.')
}
} finally {
setCliLoading(false)
if (mountedRef.current) {
setCliLoading(false)
}
}
}
}, [handleCliStatusChange])
useEffect(() => {
// Why: skip IPC work when the feature is toggled off — the component
@@ -94,7 +112,7 @@ export function BrowserUseSetup({
}
void refreshCli()
void fetchBrowserSessionProfiles()
}, [browserUseEnabled, fetchBrowserSessionProfiles])
}, [browserUseEnabled, fetchBrowserSessionProfiles, refreshCli])
const defaultProfile = browserSessionProfiles.find((p) => p.id === 'default')
// Why: this step explicitly imports into the default profile, so completion
@@ -121,13 +139,15 @@ export function BrowserUseSetup({
setCliBusy(true)
try {
const next = await ensureOrcaCliAvailableForAgentSkillTerminal({
onStatusChange: setCliStatus
onStatusChange: handleCliStatusChange
})
if (isOrcaCliAvailableOnPath(next)) {
if (mountedRef.current && isOrcaCliAvailableOnPath(next)) {
toast.success('Registered the Orca CLI in PATH.')
}
} finally {
setCliBusy(false)
if (mountedRef.current) {
setCliBusy(false)
}
}
}
@@ -328,7 +348,9 @@ export function BrowserUseSetup({
preInstallNotice={AGENT_SKILL_CLI_PREREQUISITE_NOTICE}
onBeforeOpenTerminal={async () => {
useAppStore.getState().recordFeatureInteraction('agent-browser-setup')
await ensureOrcaCliAvailableForAgentSkillTerminal({ onStatusChange: setCliStatus })
await ensureOrcaCliAvailableForAgentSkillTerminal({
onStatusChange: handleCliStatusChange
})
}}
onRecheck={refreshSkill}
/>