diff --git a/desktop/package.json b/desktop/package.json index cc2be698..68dd56b1 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -55,6 +55,15 @@ { "from": "build/dist/cowagent-backend", "to": "backend/cowagent-backend" + }, + { + "from": "resources", + "to": ".", + "filter": [ + "icon.png", + "trayTemplate.png", + "trayTemplate@2x.png" + ] } ], "mac": { diff --git a/desktop/src/main/index.ts b/desktop/src/main/index.ts index acafb341..54d3d9c4 100644 --- a/desktop/src/main/index.ts +++ b/desktop/src/main/index.ts @@ -43,6 +43,16 @@ function getIconPath(ext: string = 'png'): string | undefined { return undefined } +// Resolve the optional monochrome macOS menu-bar template icon. Returns +// undefined when the asset isn't present, so the tray falls back gracefully. +function getTrayTemplatePath(): string | undefined { + const file = 'trayTemplate.png' + const p = isDev + ? path.resolve(__dirname, '../../resources', file) + : path.join(process.resourcesPath, file) + return fs.existsSync(p) ? p : undefined +} + const isMac = process.platform === 'darwin' const isWin = process.platform === 'win32' @@ -258,6 +268,9 @@ app.whenReady().then(async () => { createTray({ getWindow: () => mainWindow, iconPath: getIconPath('png'), + // Monochrome menu-bar icon for macOS; falls back to the colored icon when + // the template asset is absent (see createTray). + templateIconPath: getTrayTemplatePath(), onQuit: () => { isQuitting = true app.quit() diff --git a/desktop/src/main/tray.ts b/desktop/src/main/tray.ts index 3039754d..a043e767 100644 --- a/desktop/src/main/tray.ts +++ b/desktop/src/main/tray.ts @@ -4,23 +4,33 @@ let tray: Tray | null = null interface TrayDeps { getWindow: () => BrowserWindow | null + // Colored icon used on Windows/Linux trays. iconPath?: string + // Monochrome (black + alpha) template icon for the macOS menu bar; renders + // correctly in both light and dark menu bars when set as a template image. + templateIconPath?: string // Called when the user picks "Quit" so the app can fully exit. onQuit: () => void } // Build a system tray icon with a minimal menu. The tray lets users restore the // window after closing it to the background and start a new chat quickly. -export function createTray({ getWindow, iconPath, onQuit }: TrayDeps): Tray | null { +export function createTray({ getWindow, iconPath, templateIconPath, onQuit }: TrayDeps): Tray | null { if (tray) return tray - if (!iconPath) return null - let image = nativeImage.createFromPath(iconPath) + const isMac = process.platform === 'darwin' + // Prefer the monochrome template icon on macOS (menu-bar convention). + const sourcePath = isMac && templateIconPath ? templateIconPath : iconPath + if (!sourcePath) return null + + let image = nativeImage.createFromPath(sourcePath) if (image.isEmpty()) return null // Tray icons render small; resize to avoid an oversized image on some platforms. image = image.resize({ width: 18, height: 18 }) - // macOS renders template images correctly in both light/dark menubars. - if (process.platform === 'darwin') image.setTemplateImage(false) + // A template image must be pure black + alpha; macOS then auto-inverts it for + // light/dark menu bars. Only mark it as such when we actually loaded the + // dedicated template asset (a colored icon as template would render as a blob). + if (isMac && templateIconPath) image.setTemplateImage(true) tray = new Tray(image) tray.setToolTip(app.name) diff --git a/desktop/src/main/updater.ts b/desktop/src/main/updater.ts index 12dde5a3..aec52736 100644 --- a/desktop/src/main/updater.ts +++ b/desktop/src/main/updater.ts @@ -1,8 +1,9 @@ import { app, BrowserWindow } from 'electron' -import pkg from 'electron-updater' - -// electron-updater ships as CommonJS; grab autoUpdater from the default export. -const { autoUpdater } = pkg +// electron-updater is CommonJS: its members live on module.exports, with no +// meaningful default export. Under module=commonjs + esModuleInterop, a named +// import compiles to `electron_updater_1.autoUpdater` and resolves correctly, +// whereas `import pkg from 'electron-updater'` yields undefined. +import { autoUpdater } from 'electron-updater' // Status payloads pushed to the renderer over the 'update-status' channel. // The renderer drives the NavRail badge + update panel from these.