From bee089f78610bfe71d3d39a9e2388d0e3daa5f67 Mon Sep 17 00:00:00 2001 From: Lightning Pixel Date: Mon, 4 May 2026 09:25:20 +0200 Subject: [PATCH 1/5] feat(architecture): python venv error handle --- electron/main/python-setup.ts | 16 ++++++++++++++-- src/areas/setup/FirstRunSetup.tsx | 21 ++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/electron/main/python-setup.ts b/electron/main/python-setup.ts index 197a001..37c8d3c 100644 --- a/electron/main/python-setup.ts +++ b/electron/main/python-setup.ts @@ -107,14 +107,26 @@ function createVenv(pythonExe: string, venvDir: string, win: BrowserWindow): Pro stdio: ['ignore', 'pipe', 'pipe'], env: cleanPythonEnv(), }) + let stderrOut = '' proc.stdout?.on('data', (d: Buffer) => console.log('[venv]', d.toString().trim())) - proc.stderr?.on('data', (d: Buffer) => console.error('[venv]', d.toString().trim())) + proc.stderr?.on('data', (d: Buffer) => { + const text = d.toString().trim() + if (text) { console.error('[venv]', text); stderrOut += text + '\n' } + }) proc.on('close', (code) => { if (code === 0) { win.webContents.send('setup:progress', { step: 'venv', percent: 20 }) resolve() } else { - reject(new Error(`python -m venv exited with code ${code}`)) + let msg = `python -m venv exited with code ${code}` + if (stderrOut) msg += `\n\n${stderrOut.trim()}` + if (process.platform === 'win32') { + msg += + '\n\nYour antivirus may be blocking the Python runtime.' + + `\nTry adding an exclusion for:\n ${pythonExe}` + + '\nOr temporarily pause real-time protection, then click Retry.' + } + reject(new Error(msg)) } }) }) diff --git a/src/areas/setup/FirstRunSetup.tsx b/src/areas/setup/FirstRunSetup.tsx index 52a24cd..9f9c80f 100644 --- a/src/areas/setup/FirstRunSetup.tsx +++ b/src/areas/setup/FirstRunSetup.tsx @@ -193,10 +193,29 @@ function ApplyingUpdatePanel({ version }: { version: string }): JSX.Element { } function ErrorPanel({ message }: { message: string | null }): JSX.Element { + const lines = (message ?? 'Check the console for details').split('\n') + const isAntivirusHint = message?.includes('antivirus') ?? false + return (

Something went wrong

-

{message ?? 'Check the console for details'}

+
+ {lines.map((line, i) => + line === '' ? ( +
+ ) : ( +

{line}

+ ) + )} +
+ {isAntivirusHint && ( +
+

Antivirus detected

+

+ Add the app folder to your antivirus exclusions, then click Retry. +

+
+ )}
+ ) : isDownloading ? ( +
+
+ + {dlFile ?? 'Downloading…'} + + + {dlFileIndex && dlTotalFiles ? `${dlFileIndex}/${dlTotalFiles} · ${dlPercent}%` : `${dlPercent}%`} + +
+
+
+
+
) : installed ? (
@@ -192,23 +209,6 @@ export function ExtensionCard({ ext, installedIds, downloading, loadError, disab )}
- ) : isDownloading ? ( -
-
- - {dlFile ?? 'Downloading…'} - - - {dlFileIndex && dlTotalFiles ? `${dlFileIndex}/${dlTotalFiles} · ${dlPercent}%` : `${dlPercent}%`} - -
-
-
-
-
) : (