diff --git a/src/main/AryxAppService.ts b/src/main/AryxAppService.ts index 84e3ad1..ff7d21d 100644 --- a/src/main/AryxAppService.ts +++ b/src/main/AryxAppService.ts @@ -2,7 +2,7 @@ import { EventEmitter } from 'node:events'; import { rm } from 'node:fs/promises'; import { basename, dirname } from 'node:path'; -import { dialog, shell } from 'electron'; +import electron from 'electron'; import type { AgentActivityEvent, @@ -107,6 +107,8 @@ import { validateSessionToolingSelectionIds, } from '@main/sessionToolingConfig'; +const { dialog, shell } = electron; + type AppServiceEvents = { 'workspace-updated': [WorkspaceState]; 'session-event': [SessionEventRecord]; diff --git a/src/main/git/gitService.ts b/src/main/git/gitService.ts index 7148c6b..51f4027 100644 --- a/src/main/git/gitService.ts +++ b/src/main/git/gitService.ts @@ -1,11 +1,9 @@ -import * as childProcess from 'node:child_process'; +import childProcess, { type ExecFileException } from 'node:child_process'; import { promisify } from 'node:util'; import type { ProjectGitChangeSummary, ProjectGitCommitSummary, ProjectGitContext } from '@shared/domain/project'; import { nowIso } from '@shared/utils/ids'; -type ExecFileException = childProcess.ExecFileException; - const execFileAsync = promisify(childProcess.execFile); const GIT_TIMEOUT_MS = 5_000; diff --git a/src/main/index.ts b/src/main/index.ts index 95d98dc..1d61e20 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,11 +1,14 @@ -import { app, BrowserWindow } from 'electron'; +import electron from 'electron'; +import type { BrowserWindow as BrowserWindowType } from 'electron'; import { registerIpcHandlers } from '@main/ipc/registerIpcHandlers'; import { AryxAppService } from '@main/AryxAppService'; import { createMainWindow } from '@main/windows/createMainWindow'; import { applyTitleBarTheme } from '@main/windows/titleBarTheme'; -let mainWindow: BrowserWindow | undefined; +const { app, BrowserWindow } = electron; + +let mainWindow: BrowserWindowType | undefined; let appService: AryxAppService | undefined; async function bootstrap(): Promise { diff --git a/src/main/ipc/registerIpcHandlers.ts b/src/main/ipc/registerIpcHandlers.ts index d97dc4d..29c54b0 100644 --- a/src/main/ipc/registerIpcHandlers.ts +++ b/src/main/ipc/registerIpcHandlers.ts @@ -1,4 +1,5 @@ -import { BrowserWindow, ipcMain } from 'electron'; +import electron from 'electron'; +import type { BrowserWindow } from 'electron'; import { ipcChannels } from '@shared/contracts/channels'; import type { @@ -27,6 +28,8 @@ import type { AppearanceTheme } from '@shared/domain/tooling'; import { AryxAppService } from '@main/AryxAppService'; import { applyTitleBarTheme } from '@main/windows/titleBarTheme'; +const { ipcMain } = electron; + export function registerIpcHandlers(window: BrowserWindow, service: AryxAppService): void { ipcMain.handle(ipcChannels.describeSidecarCapabilities, () => service.describeSidecarCapabilities()); ipcMain.handle(ipcChannels.refreshSidecarCapabilities, () => service.refreshSidecarCapabilities()); diff --git a/src/main/persistence/appPaths.ts b/src/main/persistence/appPaths.ts index 1d4cf3f..f8f0668 100644 --- a/src/main/persistence/appPaths.ts +++ b/src/main/persistence/appPaths.ts @@ -1,6 +1,8 @@ -import { app } from 'electron'; +import electron from 'electron'; import { join } from 'node:path'; +const { app } = electron; + export function getWorkspaceFilePath(): string { return join(app.getPath('userData'), 'workspace.json'); } diff --git a/src/main/sidecar/sidecarProcess.ts b/src/main/sidecar/sidecarProcess.ts index a6d4e20..fff3a06 100644 --- a/src/main/sidecar/sidecarProcess.ts +++ b/src/main/sidecar/sidecarProcess.ts @@ -1,4 +1,4 @@ -import { app } from 'electron'; +import electron from 'electron'; import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'; import type { @@ -23,6 +23,8 @@ import { import { TurnCancelledError } from '@main/sidecar/turnCancelledError'; import { resolveSidecarProcess } from '@main/sidecar/sidecarRuntime'; +const { app } = electron; + type PendingCommand = | ({ processId: number; diff --git a/src/main/windows/createMainWindow.ts b/src/main/windows/createMainWindow.ts index e733c50..5d69ad8 100644 --- a/src/main/windows/createMainWindow.ts +++ b/src/main/windows/createMainWindow.ts @@ -1,9 +1,12 @@ -import { app, BrowserWindow, Menu, shell } from 'electron'; +import electron from 'electron'; +import type { BrowserWindow as BrowserWindowType } from 'electron'; import { join } from 'node:path'; import { resolveWindowIconPath } from '@main/windows/appIcon'; -export function createMainWindow(): BrowserWindow { +const { app, BrowserWindow, Menu, shell } = electron; + +export function createMainWindow(): BrowserWindowType { Menu.setApplicationMenu(null); const window = new BrowserWindow({ diff --git a/src/main/windows/titleBarTheme.ts b/src/main/windows/titleBarTheme.ts index 1595e4c..43aaa30 100644 --- a/src/main/windows/titleBarTheme.ts +++ b/src/main/windows/titleBarTheme.ts @@ -1,7 +1,10 @@ -import { nativeTheme, type BrowserWindow } from 'electron'; +import electron from 'electron'; +import type { BrowserWindow } from 'electron'; import type { AppearanceTheme } from '@shared/domain/tooling'; +const { nativeTheme } = electron; + interface TitleBarColors { backgroundColor: string; overlay: { color: string; symbolColor: string }; diff --git a/src/preload/index.ts b/src/preload/index.ts index 8a43b98..e3ee00b 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1,8 +1,10 @@ -import { contextBridge, ipcRenderer } from 'electron'; +import electron from 'electron'; import { ipcChannels } from '@shared/contracts/channels'; import type { ElectronApi } from '@shared/contracts/ipc'; +const { contextBridge, ipcRenderer } = electron; + const api: ElectronApi = { describeSidecarCapabilities: () => ipcRenderer.invoke(ipcChannels.describeSidecarCapabilities), refreshSidecarCapabilities: () => ipcRenderer.invoke(ipcChannels.refreshSidecarCapabilities), diff --git a/tests/main/appServiceDiscoveredTooling.test.ts b/tests/main/appServiceDiscoveredTooling.test.ts index cf69823..ee4e931 100644 --- a/tests/main/appServiceDiscoveredTooling.test.ts +++ b/tests/main/appServiceDiscoveredTooling.test.ts @@ -8,19 +8,26 @@ import { createWorkspaceSeed, type WorkspaceState } from '@shared/domain/workspa const TIMESTAMP = '2026-03-25T00:00:00.000Z'; -mock.module('electron', () => ({ - app: { - isPackaged: false, - getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', - getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures', - }, - dialog: { - showOpenDialog: async () => ({ canceled: true, filePaths: [] }), - }, - shell: { - openPath: async () => '', - }, -})); +mock.module('electron', () => { + const electronMock = { + app: { + isPackaged: false, + getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', + getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures', + }, + dialog: { + showOpenDialog: async () => ({ canceled: true, filePaths: [] }), + }, + shell: { + openPath: async () => '', + }, + }; + + return { + ...electronMock, + default: electronMock, + }; +}); mock.module('keytar', () => ({ default: { diff --git a/tests/main/appServiceSidecarCapabilities.test.ts b/tests/main/appServiceSidecarCapabilities.test.ts index 8622786..df12da0 100644 --- a/tests/main/appServiceSidecarCapabilities.test.ts +++ b/tests/main/appServiceSidecarCapabilities.test.ts @@ -2,19 +2,26 @@ import { describe, expect, mock, test } from 'bun:test'; import type { SidecarCapabilities } from '@shared/contracts/sidecar'; -mock.module('electron', () => ({ - app: { - isPackaged: false, - getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', - getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures', - }, - dialog: { - showOpenDialog: async () => ({ canceled: true, filePaths: [] }), - }, - shell: { - openPath: async () => '', - }, -})); +mock.module('electron', () => { + const electronMock = { + app: { + isPackaged: false, + getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', + getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures', + }, + dialog: { + showOpenDialog: async () => ({ canceled: true, filePaths: [] }), + }, + shell: { + openPath: async () => '', + }, + }; + + return { + ...electronMock, + default: electronMock, + }; +}); mock.module('keytar', () => ({ default: { diff --git a/tests/main/appServiceTooling.test.ts b/tests/main/appServiceTooling.test.ts index c014f6b..d42e7e4 100644 --- a/tests/main/appServiceTooling.test.ts +++ b/tests/main/appServiceTooling.test.ts @@ -9,19 +9,26 @@ import { createWorkspaceSeed, type WorkspaceState } from '@shared/domain/workspa const TIMESTAMP = '2026-03-25T00:00:00.000Z'; const SCRATCHPAD_PATH = 'C:\\workspace\\personal\\repositories\\aryx\\scratchpad'; -mock.module('electron', () => ({ - app: { - isPackaged: false, - getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', - getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures', - }, - dialog: { - showOpenDialog: async () => ({ canceled: true, filePaths: [] }), - }, - shell: { - openPath: async () => '', - }, -})); +mock.module('electron', () => { + const electronMock = { + app: { + isPackaged: false, + getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', + getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures', + }, + dialog: { + showOpenDialog: async () => ({ canceled: true, filePaths: [] }), + }, + shell: { + openPath: async () => '', + }, + }; + + return { + ...electronMock, + default: electronMock, + }; +}); mock.module('keytar', () => ({ default: { diff --git a/tests/main/sidecarProcess.test.ts b/tests/main/sidecarProcess.test.ts index c7e9399..b0bdd7d 100644 --- a/tests/main/sidecarProcess.test.ts +++ b/tests/main/sidecarProcess.test.ts @@ -42,12 +42,19 @@ class FakeChildProcess extends EventEmitter { const spawnedProcesses: FakeChildProcess[] = []; -mock.module('electron', () => ({ - app: { - isPackaged: false, - getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', - }, -})); +mock.module('electron', () => { + const electronMock = { + app: { + isPackaged: false, + getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx', + }, + }; + + return { + ...electronMock, + default: electronMock, + }; +}); mock.module('node:child_process', () => ({ spawn: () => {