diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f392f97..47576708 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,12 @@ jobs: - name: Install dependencies run: pnpm install --no-frozen-lockfile + - name: Set version from tag + if: startsWith(github.ref, 'refs/tags/v') + run: | + VERSION="${GITHUB_REF#refs/tags/v}" + pnpm pkg set version="$VERSION" + - name: Build app run: pnpm build @@ -71,6 +77,12 @@ jobs: - name: Install dependencies run: pnpm install --no-frozen-lockfile + - name: Set version from tag + if: startsWith(github.ref, 'refs/tags/v') + run: | + VERSION="${GITHUB_REF#refs/tags/v}" + pnpm pkg set version="$VERSION" + - name: Package & Release (macOS) env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -111,6 +123,13 @@ jobs: - name: Install dependencies run: pnpm install --no-frozen-lockfile + - name: Set version from tag + if: startsWith(github.ref, 'refs/tags/v') + shell: bash + run: | + VERSION="${GITHUB_REF#refs/tags/v}" + pnpm pkg set version="$VERSION" + - name: Package & Release (Windows) env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/main/index.ts b/src/main/index.ts index c62d7ed2..97913421 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -18,6 +18,7 @@ import { } from '@shared/constants'; import { createLogger } from '@shared/utils/logger'; import { app, BrowserWindow, ipcMain } from 'electron'; +import { existsSync } from 'fs'; import { join } from 'path'; import { initializeIpcHandlers, removeIpcHandlers } from './ipc/handlers'; @@ -67,6 +68,18 @@ let httpServer: HttpServer; let fileChangeCleanup: (() => void) | null = null; let todoChangeCleanup: (() => void) | null = null; +/** + * Resolve production renderer index path. + * Main bundle lives in dist-electron/main, while renderer lives in out/renderer. + */ +function getRendererIndexPath(): string { + const candidates = [ + join(__dirname, '../../out/renderer/index.html'), + join(__dirname, '../renderer/index.html'), + ]; + return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0]; +} + /** * Wires file watcher events from a ServiceContext to the renderer and HTTP SSE clients. * Cleans up previous listeners before adding new ones. @@ -356,7 +369,9 @@ function createWindow(): void { void mainWindow.loadURL(`http://localhost:${DEV_SERVER_PORT}`); mainWindow.webContents.openDevTools(); } else { - void mainWindow.loadFile(join(__dirname, '../renderer/index.html')); + void mainWindow.loadFile(getRendererIndexPath()).catch((error: unknown) => { + logger.error('Failed to load renderer entry HTML:', error); + }); } // Set traffic light position + notify renderer on first load, and auto-check for updates diff --git a/src/main/services/infrastructure/HttpServer.ts b/src/main/services/infrastructure/HttpServer.ts index 86ad5374..1f2b9bde 100644 --- a/src/main/services/infrastructure/HttpServer.ts +++ b/src/main/services/infrastructure/HttpServer.ts @@ -13,6 +13,7 @@ import { type HttpServices, registerHttpRoutes } from '@main/http'; import { broadcastEvent } from '@main/http/events'; import { createLogger } from '@shared/utils/logger'; import Fastify, { type FastifyInstance } from 'fastify'; +import { existsSync } from 'fs'; import { join } from 'path'; const logger = createLogger('Service:HttpServer'); @@ -57,7 +58,13 @@ export class HttpServer { // Register static file serving (production only) const isDev = process.env.NODE_ENV === 'development'; if (!isDev) { - const rendererPath = join(__dirname, '../../renderer'); + const rendererPathCandidates = [ + join(__dirname, '../../../out/renderer'), + join(__dirname, '../../renderer'), + ]; + const rendererPath = + rendererPathCandidates.find((candidate) => existsSync(candidate)) ?? + rendererPathCandidates[0]; await this.app.register(fastifyStatic, { root: rendererPath, prefix: '/',