From 150e023fe280cb86901a7513aa0fc0c25920747f Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 30 Jun 2026 14:11:50 -0500 Subject: [PATCH] refactor(desktop): extract uninstall IPC from main.cjs into uninstall-ipc.cjs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eighth main.cjs cluster peel. The two hermes:uninstall:* handlers (summary, run) move verbatim into electron/uninstall-ipc.cjs behind a registerUninstallIpc({ ipcMain, getUninstallSummary, runDesktopUninstall }) registrar. The uninstall engine stays in the main process and is injected. Channel names unchanged → preload + renderer untouched. Adds electron/uninstall-ipc.test.cjs (surface invariant + run mode normalization). --- apps/desktop/electron/main.cjs | 8 ++- apps/desktop/electron/uninstall-ipc.cjs | 14 ++++++ apps/desktop/electron/uninstall-ipc.test.cjs | 51 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 apps/desktop/electron/uninstall-ipc.cjs create mode 100644 apps/desktop/electron/uninstall-ipc.test.cjs 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', '']) +})