mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-27 13:23:57 +02:00
fix: resolve macos bun interop
Use Bun-safe Electron and child_process import patterns for macOS GitHub Actions tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import { EventEmitter } from 'node:events';
|
|||||||
import { rm } from 'node:fs/promises';
|
import { rm } from 'node:fs/promises';
|
||||||
import { basename, dirname } from 'node:path';
|
import { basename, dirname } from 'node:path';
|
||||||
|
|
||||||
import { dialog, shell } from 'electron';
|
import electron from 'electron';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AgentActivityEvent,
|
AgentActivityEvent,
|
||||||
@@ -107,6 +107,8 @@ import {
|
|||||||
validateSessionToolingSelectionIds,
|
validateSessionToolingSelectionIds,
|
||||||
} from '@main/sessionToolingConfig';
|
} from '@main/sessionToolingConfig';
|
||||||
|
|
||||||
|
const { dialog, shell } = electron;
|
||||||
|
|
||||||
type AppServiceEvents = {
|
type AppServiceEvents = {
|
||||||
'workspace-updated': [WorkspaceState];
|
'workspace-updated': [WorkspaceState];
|
||||||
'session-event': [SessionEventRecord];
|
'session-event': [SessionEventRecord];
|
||||||
|
|||||||
@@ -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 { promisify } from 'node:util';
|
||||||
|
|
||||||
import type { ProjectGitChangeSummary, ProjectGitCommitSummary, ProjectGitContext } from '@shared/domain/project';
|
import type { ProjectGitChangeSummary, ProjectGitCommitSummary, ProjectGitContext } from '@shared/domain/project';
|
||||||
import { nowIso } from '@shared/utils/ids';
|
import { nowIso } from '@shared/utils/ids';
|
||||||
|
|
||||||
type ExecFileException = childProcess.ExecFileException;
|
|
||||||
|
|
||||||
const execFileAsync = promisify(childProcess.execFile);
|
const execFileAsync = promisify(childProcess.execFile);
|
||||||
const GIT_TIMEOUT_MS = 5_000;
|
const GIT_TIMEOUT_MS = 5_000;
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -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 { registerIpcHandlers } from '@main/ipc/registerIpcHandlers';
|
||||||
import { AryxAppService } from '@main/AryxAppService';
|
import { AryxAppService } from '@main/AryxAppService';
|
||||||
import { createMainWindow } from '@main/windows/createMainWindow';
|
import { createMainWindow } from '@main/windows/createMainWindow';
|
||||||
import { applyTitleBarTheme } from '@main/windows/titleBarTheme';
|
import { applyTitleBarTheme } from '@main/windows/titleBarTheme';
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | undefined;
|
const { app, BrowserWindow } = electron;
|
||||||
|
|
||||||
|
let mainWindow: BrowserWindowType | undefined;
|
||||||
let appService: AryxAppService | undefined;
|
let appService: AryxAppService | undefined;
|
||||||
|
|
||||||
async function bootstrap(): Promise<void> {
|
async function bootstrap(): Promise<void> {
|
||||||
|
|||||||
@@ -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 { ipcChannels } from '@shared/contracts/channels';
|
||||||
import type {
|
import type {
|
||||||
@@ -27,6 +28,8 @@ import type { AppearanceTheme } from '@shared/domain/tooling';
|
|||||||
import { AryxAppService } from '@main/AryxAppService';
|
import { AryxAppService } from '@main/AryxAppService';
|
||||||
import { applyTitleBarTheme } from '@main/windows/titleBarTheme';
|
import { applyTitleBarTheme } from '@main/windows/titleBarTheme';
|
||||||
|
|
||||||
|
const { ipcMain } = electron;
|
||||||
|
|
||||||
export function registerIpcHandlers(window: BrowserWindow, service: AryxAppService): void {
|
export function registerIpcHandlers(window: BrowserWindow, service: AryxAppService): void {
|
||||||
ipcMain.handle(ipcChannels.describeSidecarCapabilities, () => service.describeSidecarCapabilities());
|
ipcMain.handle(ipcChannels.describeSidecarCapabilities, () => service.describeSidecarCapabilities());
|
||||||
ipcMain.handle(ipcChannels.refreshSidecarCapabilities, () => service.refreshSidecarCapabilities());
|
ipcMain.handle(ipcChannels.refreshSidecarCapabilities, () => service.refreshSidecarCapabilities());
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { app } from 'electron';
|
import electron from 'electron';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
|
||||||
|
const { app } = electron;
|
||||||
|
|
||||||
export function getWorkspaceFilePath(): string {
|
export function getWorkspaceFilePath(): string {
|
||||||
return join(app.getPath('userData'), 'workspace.json');
|
return join(app.getPath('userData'), 'workspace.json');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { app } from 'electron';
|
import electron from 'electron';
|
||||||
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';
|
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
import { TurnCancelledError } from '@main/sidecar/turnCancelledError';
|
import { TurnCancelledError } from '@main/sidecar/turnCancelledError';
|
||||||
import { resolveSidecarProcess } from '@main/sidecar/sidecarRuntime';
|
import { resolveSidecarProcess } from '@main/sidecar/sidecarRuntime';
|
||||||
|
|
||||||
|
const { app } = electron;
|
||||||
|
|
||||||
type PendingCommand =
|
type PendingCommand =
|
||||||
| ({
|
| ({
|
||||||
processId: number;
|
processId: number;
|
||||||
|
|||||||
@@ -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 { join } from 'node:path';
|
||||||
|
|
||||||
import { resolveWindowIconPath } from '@main/windows/appIcon';
|
import { resolveWindowIconPath } from '@main/windows/appIcon';
|
||||||
|
|
||||||
export function createMainWindow(): BrowserWindow {
|
const { app, BrowserWindow, Menu, shell } = electron;
|
||||||
|
|
||||||
|
export function createMainWindow(): BrowserWindowType {
|
||||||
Menu.setApplicationMenu(null);
|
Menu.setApplicationMenu(null);
|
||||||
|
|
||||||
const window = new BrowserWindow({
|
const window = new BrowserWindow({
|
||||||
|
|||||||
@@ -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';
|
import type { AppearanceTheme } from '@shared/domain/tooling';
|
||||||
|
|
||||||
|
const { nativeTheme } = electron;
|
||||||
|
|
||||||
interface TitleBarColors {
|
interface TitleBarColors {
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
overlay: { color: string; symbolColor: string };
|
overlay: { color: string; symbolColor: string };
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { contextBridge, ipcRenderer } from 'electron';
|
import electron from 'electron';
|
||||||
|
|
||||||
import { ipcChannels } from '@shared/contracts/channels';
|
import { ipcChannels } from '@shared/contracts/channels';
|
||||||
import type { ElectronApi } from '@shared/contracts/ipc';
|
import type { ElectronApi } from '@shared/contracts/ipc';
|
||||||
|
|
||||||
|
const { contextBridge, ipcRenderer } = electron;
|
||||||
|
|
||||||
const api: ElectronApi = {
|
const api: ElectronApi = {
|
||||||
describeSidecarCapabilities: () => ipcRenderer.invoke(ipcChannels.describeSidecarCapabilities),
|
describeSidecarCapabilities: () => ipcRenderer.invoke(ipcChannels.describeSidecarCapabilities),
|
||||||
refreshSidecarCapabilities: () => ipcRenderer.invoke(ipcChannels.refreshSidecarCapabilities),
|
refreshSidecarCapabilities: () => ipcRenderer.invoke(ipcChannels.refreshSidecarCapabilities),
|
||||||
|
|||||||
@@ -8,19 +8,26 @@ import { createWorkspaceSeed, type WorkspaceState } from '@shared/domain/workspa
|
|||||||
|
|
||||||
const TIMESTAMP = '2026-03-25T00:00:00.000Z';
|
const TIMESTAMP = '2026-03-25T00:00:00.000Z';
|
||||||
|
|
||||||
mock.module('electron', () => ({
|
mock.module('electron', () => {
|
||||||
app: {
|
const electronMock = {
|
||||||
isPackaged: false,
|
app: {
|
||||||
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
isPackaged: false,
|
||||||
getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures',
|
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
||||||
},
|
getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures',
|
||||||
dialog: {
|
},
|
||||||
showOpenDialog: async () => ({ canceled: true, filePaths: [] }),
|
dialog: {
|
||||||
},
|
showOpenDialog: async () => ({ canceled: true, filePaths: [] }),
|
||||||
shell: {
|
},
|
||||||
openPath: async () => '',
|
shell: {
|
||||||
},
|
openPath: async () => '',
|
||||||
}));
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...electronMock,
|
||||||
|
default: electronMock,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
mock.module('keytar', () => ({
|
mock.module('keytar', () => ({
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -2,19 +2,26 @@ import { describe, expect, mock, test } from 'bun:test';
|
|||||||
|
|
||||||
import type { SidecarCapabilities } from '@shared/contracts/sidecar';
|
import type { SidecarCapabilities } from '@shared/contracts/sidecar';
|
||||||
|
|
||||||
mock.module('electron', () => ({
|
mock.module('electron', () => {
|
||||||
app: {
|
const electronMock = {
|
||||||
isPackaged: false,
|
app: {
|
||||||
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
isPackaged: false,
|
||||||
getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures',
|
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
||||||
},
|
getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures',
|
||||||
dialog: {
|
},
|
||||||
showOpenDialog: async () => ({ canceled: true, filePaths: [] }),
|
dialog: {
|
||||||
},
|
showOpenDialog: async () => ({ canceled: true, filePaths: [] }),
|
||||||
shell: {
|
},
|
||||||
openPath: async () => '',
|
shell: {
|
||||||
},
|
openPath: async () => '',
|
||||||
}));
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...electronMock,
|
||||||
|
default: electronMock,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
mock.module('keytar', () => ({
|
mock.module('keytar', () => ({
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -9,19 +9,26 @@ import { createWorkspaceSeed, type WorkspaceState } from '@shared/domain/workspa
|
|||||||
const TIMESTAMP = '2026-03-25T00:00:00.000Z';
|
const TIMESTAMP = '2026-03-25T00:00:00.000Z';
|
||||||
const SCRATCHPAD_PATH = 'C:\\workspace\\personal\\repositories\\aryx\\scratchpad';
|
const SCRATCHPAD_PATH = 'C:\\workspace\\personal\\repositories\\aryx\\scratchpad';
|
||||||
|
|
||||||
mock.module('electron', () => ({
|
mock.module('electron', () => {
|
||||||
app: {
|
const electronMock = {
|
||||||
isPackaged: false,
|
app: {
|
||||||
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
isPackaged: false,
|
||||||
getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures',
|
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
||||||
},
|
getPath: () => 'C:\\workspace\\personal\\repositories\\aryx\\tests\\fixtures',
|
||||||
dialog: {
|
},
|
||||||
showOpenDialog: async () => ({ canceled: true, filePaths: [] }),
|
dialog: {
|
||||||
},
|
showOpenDialog: async () => ({ canceled: true, filePaths: [] }),
|
||||||
shell: {
|
},
|
||||||
openPath: async () => '',
|
shell: {
|
||||||
},
|
openPath: async () => '',
|
||||||
}));
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...electronMock,
|
||||||
|
default: electronMock,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
mock.module('keytar', () => ({
|
mock.module('keytar', () => ({
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -42,12 +42,19 @@ class FakeChildProcess extends EventEmitter {
|
|||||||
|
|
||||||
const spawnedProcesses: FakeChildProcess[] = [];
|
const spawnedProcesses: FakeChildProcess[] = [];
|
||||||
|
|
||||||
mock.module('electron', () => ({
|
mock.module('electron', () => {
|
||||||
app: {
|
const electronMock = {
|
||||||
isPackaged: false,
|
app: {
|
||||||
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
isPackaged: false,
|
||||||
},
|
getAppPath: () => 'C:\\workspace\\personal\\repositories\\aryx',
|
||||||
}));
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...electronMock,
|
||||||
|
default: electronMock,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
mock.module('node:child_process', () => ({
|
mock.module('node:child_process', () => ({
|
||||||
spawn: () => {
|
spawn: () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user