Compare commits

..
8 Commits
Author SHA1 Message Date
David Kaya fa355197cb chore: release v0.0.29 2026-04-16 14:48:09 +02:00
David KayaandCopilot 5f263002f0 fix: pass mainWindow argument to showAndFocusWindow in second-instance handler
The showAndFocusWindow function signature was updated to require a
mainWindow parameter, but the call site in the second-instance handler
was not updated, causing a TypeScript compilation error that broke CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 14:43:41 +02:00
David Kaya 1376de4148 chore: release v0.0.28 2026-04-16 14:17:21 +02:00
David Kaya 5ce6bb4b0a Merge branch 'agents/tray-icon-main-window-fix' 2026-04-16 14:16:33 +02:00
David KayaandCopilot 47d3fb0a29 fix: tray icon click opens main window reliably after quick prompt use
showAndFocusWindow() used BrowserWindow.getAllWindows()[0] to find the
main window, which breaks once the quick prompt window is created —
the array order is not guaranteed and windows[0] may resolve to the
quick prompt instead, causing the show/focus calls to target a hidden,
frameless window.

Accept the main window reference as an explicit parameter and guard
against destroyed windows with isDestroyed().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 14:00:30 +02:00
David Kaya 4da31cbdd6 Merge branch 'agents/single-instance-app-launch' 2026-04-16 13:56:19 +02:00
David KayaandCopilot f15323e37e feat: enforce single-instance app launch
Use Electron's requestSingleInstanceLock() to prevent opening
multiple instances. When a second instance is attempted, the
existing window is restored and focused instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 13:54:22 +02:00
David KayaandCopilot f8fe9d866e fix: use platform-native paths in release tests for cross-OS compatibility
The release workflow tests hardcoded Windows-style backslash paths
(C:\workspace\...) which caused path.relative() to produce incorrect
results on Linux and macOS, where backslashes are not path separators.

Replace hardcoded paths with resolve()/join() calls that produce
platform-native paths, fixing CI failures on Linux and macOS.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 13:53:49 +02:00
4 changed files with 32 additions and 18 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "aryx",
"version": "0.0.27",
"version": "0.0.29",
"description": "Orchestrator for Copilot-powered agent workflows across multiple projects.",
"private": true,
"main": "dist-electron/main/index.js",
+16 -4
View File
@@ -16,6 +16,12 @@ import { createDefaultQuickPromptSettings } from '@shared/domain/tooling';
const { app, BrowserWindow } = electron;
// Enforce single instance — quit immediately if another instance already holds the lock.
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
}
let mainWindow: BrowserWindowType | undefined;
let quickPromptWindow: BrowserWindowType | undefined;
let appService: AryxAppService | undefined;
@@ -63,9 +69,9 @@ async function bootstrap(): Promise<void> {
applyTitleBarTheme(mainWindow, workspace.settings.theme);
systemTray = new SystemTray({
onShowWindow: showAndFocusWindow,
onShowWindow: () => showAndFocusWindow(mainWindow!),
onCreateScratchpad: () => {
showAndFocusWindow();
showAndFocusWindow(mainWindow!);
mainWindow?.webContents.send('tray:create-scratchpad');
},
onQuit: () => app.quit(),
@@ -109,6 +115,12 @@ async function bootstrap(): Promise<void> {
autoUpdateService.start();
}
app.on('second-instance', () => {
if (mainWindow && !mainWindow.isDestroyed()) {
showAndFocusWindow(mainWindow);
}
});
app.whenReady().then(bootstrap);
app.on('window-all-closed', () => {
@@ -127,8 +139,8 @@ app.on('window-all-closed', () => {
app.on('activate', async () => {
if (BrowserWindow.getAllWindows().length === 0) {
await bootstrap();
} else {
showAndFocusWindow();
} else if (mainWindow && !mainWindow.isDestroyed()) {
showAndFocusWindow(mainWindow);
}
});
+3 -5
View File
@@ -3,7 +3,7 @@ import { join } from 'node:path';
import type { WorkspaceState } from '@shared/domain/workspace';
const { app, Menu, Tray, nativeImage, BrowserWindow } = electron;
const { app, Menu, Tray, nativeImage } = electron;
type TrayType = InstanceType<typeof Tray>;
type NativeImageType = ReturnType<typeof nativeImage.createFromPath>;
@@ -123,10 +123,8 @@ export function setupCloseToTray(
/**
* Show and focus the main window, restoring from tray if hidden.
*/
export function showAndFocusWindow(): void {
const windows = BrowserWindow.getAllWindows();
const mainWindow = windows[0];
if (!mainWindow) return;
export function showAndFocusWindow(mainWindow: Electron.BrowserWindow): void {
if (mainWindow.isDestroyed()) return;
// On macOS, show the dock icon again
if (process.platform === 'darwin') {
+12 -8
View File
@@ -1,3 +1,4 @@
import { join, resolve } from 'node:path';
import { describe, expect, test } from 'bun:test';
import {
@@ -8,6 +9,9 @@ import {
type ReleaseDependencies,
} from '../../scripts/release';
const testRepositoryRoot = resolve('/test-workspace/aryx');
const testPackageJsonPath = join(testRepositoryRoot, 'package.json');
function gitSuccess(stdout = '', stderr = ''): GitCommandResult {
return {
exitCode: 0,
@@ -109,8 +113,8 @@ describe('release workflow', () => {
const result = await runReleaseWorkflow(
{
repositoryRoot: 'C:\\workspace\\personal\\projects\\aryx',
packageJsonPath: 'C:\\workspace\\personal\\projects\\aryx\\package.json',
repositoryRoot: testRepositoryRoot,
packageJsonPath: testPackageJsonPath,
},
dependencies,
);
@@ -148,8 +152,8 @@ describe('release workflow', () => {
await expect(
runReleaseWorkflow(
{
repositoryRoot: 'C:\\workspace\\personal\\projects\\aryx',
packageJsonPath: 'C:\\workspace\\personal\\projects\\aryx\\package.json',
repositoryRoot: testRepositoryRoot,
packageJsonPath: testPackageJsonPath,
},
dependencies,
),
@@ -173,8 +177,8 @@ describe('release workflow', () => {
await expect(
runReleaseWorkflow(
{
repositoryRoot: 'C:\\workspace\\personal\\projects\\aryx',
packageJsonPath: 'C:\\workspace\\personal\\projects\\aryx\\package.json',
repositoryRoot: testRepositoryRoot,
packageJsonPath: testPackageJsonPath,
bumpArg: 'minor',
},
dependencies,
@@ -204,8 +208,8 @@ describe('release workflow', () => {
await expect(
runReleaseWorkflow(
{
repositoryRoot: 'C:\\workspace\\personal\\projects\\aryx',
packageJsonPath: 'C:\\workspace\\personal\\projects\\aryx\\package.json',
repositoryRoot: testRepositoryRoot,
packageJsonPath: testPackageJsonPath,
},
dependencies,
),