diff --git a/apps/desktop/electron/main.cjs b/apps/desktop/electron/main.cjs index cbe500c94d3..58eba7ef201 100644 --- a/apps/desktop/electron/main.cjs +++ b/apps/desktop/electron/main.cjs @@ -62,6 +62,7 @@ const { registerUpdatesIpc } = require('./updates-ipc.cjs') const { registerLogsIpc } = require('./logs-ipc.cjs') const { registerProjectDirIpc } = require('./project-dir-ipc.cjs') const { registerVscodeThemeIpc } = require('./vscode-theme-ipc.cjs') +const { registerUninstallIpc } = require('./uninstall-ipc.cjs') const { OFFICIAL_REPO_HTTPS_URL, isOfficialSshRemote } = require('./update-remote.cjs') const { resolveBehindCount, shouldCountCommits } = require('./update-count.cjs') const { runRebuildWithRetry } = require('./update-rebuild.cjs') @@ -7127,11 +7128,8 @@ async function runDesktopUninstall(mode) { return { ok: true, mode, willRemoveAppBundle: Boolean(removeBundle), scriptPath } } -ipcMain.handle('hermes:uninstall:summary', async () => getUninstallSummary()) -ipcMain.handle('hermes:uninstall:run', async (_event, payload) => { - const mode = payload && typeof payload === 'object' ? payload.mode : payload - return runDesktopUninstall(String(mode || '')) -}) +// Uninstall IPC lives in uninstall-ipc.cjs; the uninstall engine is injected. +registerUninstallIpc({ getUninstallSummary, ipcMain, runDesktopUninstall }) // VS Code Marketplace theme IPC lives in vscode-theme-ipc.cjs. registerVscodeThemeIpc({ ipcMain }) diff --git a/apps/desktop/electron/uninstall-ipc.cjs b/apps/desktop/electron/uninstall-ipc.cjs new file mode 100644 index 00000000000..d0e71dbae12 --- /dev/null +++ b/apps/desktop/electron/uninstall-ipc.cjs @@ -0,0 +1,14 @@ +'use strict' + +// Uninstall IPC: summarize what a desktop uninstall would remove + run it +// (GUI-only / lite / full). Both delegate to the main-process uninstall engine, +// which is injected. +function registerUninstallIpc({ getUninstallSummary, ipcMain, runDesktopUninstall }) { + ipcMain.handle('hermes:uninstall:summary', async () => getUninstallSummary()) + ipcMain.handle('hermes:uninstall:run', async (_event, payload) => { + const mode = payload && typeof payload === 'object' ? payload.mode : payload + return runDesktopUninstall(String(mode || '')) + }) +} + +module.exports = { registerUninstallIpc } diff --git a/apps/desktop/electron/uninstall-ipc.test.cjs b/apps/desktop/electron/uninstall-ipc.test.cjs new file mode 100644 index 00000000000..dfa8b5a7f27 --- /dev/null +++ b/apps/desktop/electron/uninstall-ipc.test.cjs @@ -0,0 +1,51 @@ +'use strict' + +const assert = require('node:assert/strict') +const test = require('node:test') + +const { registerUninstallIpc } = require('./uninstall-ipc.cjs') + +function fakeIpcMain() { + const handlers = new Map() + + return { + handlers, + handle(channel, handler) { + assert.ok(!handlers.has(channel), `duplicate registration for ${channel}`) + handlers.set(channel, handler) + } + } +} + +test('registerUninstallIpc wires only hermes:uninstall:* channels, each to a handler fn', () => { + const ipcMain = fakeIpcMain() + + registerUninstallIpc({ ipcMain, getUninstallSummary: async () => ({}), runDesktopUninstall: async () => ({}) }) + + assert.deepEqual([...ipcMain.handlers.keys()].sort(), ['hermes:uninstall:run', 'hermes:uninstall:summary']) + + for (const handler of ipcMain.handlers.values()) { + assert.equal(typeof handler, 'function') + } +}) + +test('run normalizes both the {mode} object form and the bare-string form', async () => { + const ipcMain = fakeIpcMain() + const modes = [] + + registerUninstallIpc({ + ipcMain, + getUninstallSummary: async () => ({}), + runDesktopUninstall: async mode => { + modes.push(mode) + + return { mode } + } + }) + + await ipcMain.handlers.get('hermes:uninstall:run')({}, { mode: 'full' }) + await ipcMain.handlers.get('hermes:uninstall:run')({}, 'lite') + await ipcMain.handlers.get('hermes:uninstall:run')({}, null) + + assert.deepEqual(modes, ['full', 'lite', '']) +})