From 41ce428a96ed526022f58c0540f2120c0eba0dbd Mon Sep 17 00:00:00 2001 From: Max Novich Date: Mon, 24 Mar 2025 09:50:28 -0700 Subject: [PATCH] fix windows native uvx (#1775) --- ui/desktop/forge.config.ts | 6 +--- ui/desktop/package.json | 2 +- ui/desktop/scripts/build-main.js | 48 ++++++++++++++++++++++++++++++ ui/desktop/src/main.ts | 5 ++++ ui/desktop/src/utils/binaryPath.ts | 24 +++++++-------- ui/desktop/vite.preload.config.ts | 15 +++++++++- 6 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 ui/desktop/scripts/build-main.js diff --git a/ui/desktop/forge.config.ts b/ui/desktop/forge.config.ts index 6ba21347..bf00c642 100644 --- a/ui/desktop/forge.config.ts +++ b/ui/desktop/forge.config.ts @@ -1,5 +1,6 @@ const { FusesPlugin } = require('@electron-forge/plugin-fuses'); const { FuseV1Options, FuseVersion } = require('@electron/fuses'); +const { resolve } = require('path'); let cfg = { asar: true, @@ -73,19 +74,14 @@ module.exports = { { name: '@electron-forge/plugin-vite', config: { - // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc. - // If you are familiar with Vite configuration, it will look really familiar. build: [ { - // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`. entry: 'src/main.ts', config: 'vite.main.config.ts', - target: 'main', }, { entry: 'src/preload.ts', config: 'vite.preload.config.ts', - target: 'preload', }, ], renderer: [ diff --git a/ui/desktop/package.json b/ui/desktop/package.json index fc6fb511..043d7785 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -12,7 +12,7 @@ "package": "electron-forge package", "make": "electron-forge make", "bundle:default": "npm run make && cd out/Goose-darwin-arm64 && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose.zip", - "bundle:windows": "npm run make -- --platform=win32 --arch=x64 && node scripts/copy-windows-dlls.js", + "bundle:windows": "node scripts/build-main.js && npm run make -- --platform=win32 --arch=x64 && node scripts/copy-windows-dlls.js", "bundle:intel": "npm run make -- --arch=x64 && cd out/Goose-darwin-x64 && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose_intel_mac.zip", "debug": "echo 'run --remote-debugging-port=8315' && lldb out/Goose-darwin-arm64/Goose.app", "test-e2e": "electron-forge start > /tmp/out.txt & ELECTRON_PID=$! && sleep 12 && if grep -q 'renderer: ChatWindow loaded' /tmp/out.txt; then echo 'process is running'; pkill -f electron; else echo 'not starting correctly'; cat /tmp/out.txt; pkill -f electron; exit 1; fi", diff --git a/ui/desktop/scripts/build-main.js b/ui/desktop/scripts/build-main.js new file mode 100644 index 00000000..4de4cb53 --- /dev/null +++ b/ui/desktop/scripts/build-main.js @@ -0,0 +1,48 @@ +const { build } = require('vite'); +const { resolve } = require('path'); +const fs = require('fs'); + +async function buildMain() { + try { + const outDir = resolve(__dirname, '../.vite/build'); + + // Ensure output directory exists + if (!fs.existsSync(outDir)) { + fs.mkdirSync(outDir, { recursive: true }); + } + + await build({ + configFile: resolve(__dirname, '../vite.main.config.ts'), + build: { + outDir, + emptyOutDir: false, + ssr: true, + rollupOptions: { + input: resolve(__dirname, '../src/main.ts'), + output: { + format: 'cjs', + entryFileNames: 'main.js' + }, + external: [ + 'electron', + 'electron-squirrel-startup', + 'path', + 'fs', + 'url', + 'child_process', + 'crypto', + 'os', + 'util' + ] + } + } + }); + + console.log('Main process build complete'); + } catch (e) { + console.error('Error building main process:', e); + process.exit(1); + } +} + +buildMain(); \ No newline at end of file diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 1ee43581..4544bc4f 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -414,6 +414,11 @@ ipcMain.handle('check-ollama', async () => { } }); +// Handle binary path requests +ipcMain.handle('get-binary-path', (event, binaryName) => { + return getBinaryPath(app, binaryName); +}); + app.whenReady().then(async () => { // Test error feature - only enabled with GOOSE_TEST_ERROR=true if (process.env.GOOSE_TEST_ERROR === 'true') { diff --git a/ui/desktop/src/utils/binaryPath.ts b/ui/desktop/src/utils/binaryPath.ts index abe1358b..caec53b5 100644 --- a/ui/desktop/src/utils/binaryPath.ts +++ b/ui/desktop/src/utils/binaryPath.ts @@ -8,39 +8,38 @@ export const getBinaryPath = (app: Electron.App, binaryName: string): string => const isPackaged = app.isPackaged; const isWindows = process.platform === 'win32'; - // On Windows, use .cmd for npx and .exe for uvx const executableName = isWindows ? binaryName === 'npx' ? 'npx.cmd' : `${binaryName}.exe` : binaryName; - // List of possible paths to check const possiblePaths = []; if (isDev && !isPackaged) { - // In development, check multiple possible locations possiblePaths.push( path.join(process.cwd(), 'src', 'bin', executableName), path.join(process.cwd(), 'bin', executableName), path.join(process.cwd(), '..', '..', 'target', 'release', executableName) ); } else { - // In production, check resources paths possiblePaths.push( path.join(process.resourcesPath, 'bin', executableName), path.join(app.getAppPath(), 'resources', 'bin', executableName) ); + + if (isWindows) { + possiblePaths.push( + path.join(process.resourcesPath, executableName), + path.join(app.getAppPath(), 'resources', executableName), + path.join(app.getPath('exe'), '..', 'bin', executableName) + ); + } } - // Log all paths we're checking - log.info('Checking binary paths:', possiblePaths); - - // Try each path and return the first one that exists for (const binPath of possiblePaths) { try { if (fs.existsSync(binPath)) { - log.info(`Found binary at: ${binPath}`); return binPath; } } catch (error) { @@ -48,8 +47,7 @@ export const getBinaryPath = (app: Electron.App, binaryName: string): string => } } - // If we get here, we couldn't find the binary - const error = `Could not find ${binaryName} binary in any of the expected locations: ${possiblePaths.join(', ')}`; - log.error(error); - throw new Error(error); + throw new Error( + `Could not find ${binaryName} binary in any of the expected locations: ${possiblePaths.join(', ')}` + ); }; diff --git a/ui/desktop/vite.preload.config.ts b/ui/desktop/vite.preload.config.ts index 690be5b1..fa6f0d27 100644 --- a/ui/desktop/vite.preload.config.ts +++ b/ui/desktop/vite.preload.config.ts @@ -1,4 +1,17 @@ import { defineConfig } from 'vite'; // https://vitejs.dev/config -export default defineConfig({}); +export default defineConfig({ + build: { + ssr: true, + outDir: '.vite/build', + rollupOptions: { + input: 'src/preload.ts', + output: { + format: 'cjs', + entryFileNames: 'preload.js' + }, + external: ['electron'] + } + } +});