add desktop codex login and analyst copilot
This commit is contained in:
parent
fb25b5ac97
commit
a8d183f38e
24 changed files with 4127 additions and 97 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { app, BrowserWindow, shell } from "electron";
|
||||
import type { Event as ElectronEvent } from "electron";
|
||||
import { app, BrowserWindow, ipcMain, shell } from "electron";
|
||||
import type { Event as ElectronEvent, IpcMainInvokeEvent } from "electron";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import {
|
||||
DESKTOP_PRODUCTION_URL,
|
||||
|
|
@ -7,11 +8,25 @@ import {
|
|||
isTrustedAppUrl,
|
||||
resolveDesktopStartUrl
|
||||
} from "./security.js";
|
||||
import { IslandflowDesktopAiService } from "./desktop-ai.js";
|
||||
import {
|
||||
DESKTOP_AI_CANCEL_LOGIN,
|
||||
DESKTOP_AI_GET_STATE,
|
||||
DESKTOP_AI_LOGIN_BROWSER,
|
||||
DESKTOP_AI_LOGIN_DEVICE,
|
||||
DESKTOP_AI_LOGOUT,
|
||||
DESKTOP_AI_RUN_TASK,
|
||||
DESKTOP_AI_STATE_CHANNEL,
|
||||
DESKTOP_AI_UPDATE_PREFERENCES
|
||||
} from "./desktop-ai-ipc.js";
|
||||
|
||||
const WINDOW_BACKGROUND_COLOR = "#06080b";
|
||||
const WINDOW_TITLE = "Islandflow";
|
||||
|
||||
let mainWindow: BrowserWindow | null = null;
|
||||
let desktopAiService: IslandflowDesktopAiService | null = null;
|
||||
|
||||
const PRELOAD_PATH = fileURLToPath(new URL("./preload.js", import.meta.url));
|
||||
|
||||
const canOpenExternalUrl = (sourceUrl: string, targetUrl: string): boolean => {
|
||||
return isTrustedAppUrl(sourceUrl) && isSafeExternalUrl(targetUrl);
|
||||
|
|
@ -61,6 +76,7 @@ const createMainWindow = (): BrowserWindow => {
|
|||
title: WINDOW_TITLE,
|
||||
backgroundColor: WINDOW_BACKGROUND_COLOR,
|
||||
webPreferences: {
|
||||
preload: PRELOAD_PATH,
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
sandbox: true,
|
||||
|
|
@ -92,6 +108,68 @@ const createMainWindow = (): BrowserWindow => {
|
|||
return window;
|
||||
};
|
||||
|
||||
const broadcastDesktopAiState = (): void => {
|
||||
if (!desktopAiService) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = desktopAiService.getState();
|
||||
for (const window of BrowserWindow.getAllWindows()) {
|
||||
window.webContents.send(DESKTOP_AI_STATE_CHANNEL, state);
|
||||
}
|
||||
};
|
||||
|
||||
const getTrustedSenderUrl = (event: IpcMainInvokeEvent): string => {
|
||||
const senderUrl = event.senderFrame?.url || event.sender.getURL();
|
||||
if (!isTrustedAppUrl(senderUrl)) {
|
||||
throw new Error(`Rejected desktop AI IPC from untrusted origin: ${senderUrl || "unknown"}`);
|
||||
}
|
||||
|
||||
return senderUrl;
|
||||
};
|
||||
|
||||
const registerDesktopAiIpc = (service: IslandflowDesktopAiService): void => {
|
||||
const guard = (event: IpcMainInvokeEvent): void => {
|
||||
getTrustedSenderUrl(event);
|
||||
};
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_GET_STATE, async (event) => {
|
||||
guard(event);
|
||||
await service.start();
|
||||
return service.getState();
|
||||
});
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_LOGIN_BROWSER, async (event) => {
|
||||
guard(event);
|
||||
await service.loginWithBrowser();
|
||||
});
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_LOGIN_DEVICE, async (event) => {
|
||||
guard(event);
|
||||
await service.loginWithDeviceCode();
|
||||
});
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_CANCEL_LOGIN, async (event) => {
|
||||
guard(event);
|
||||
await service.cancelLogin();
|
||||
});
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_LOGOUT, async (event) => {
|
||||
guard(event);
|
||||
await service.logout();
|
||||
});
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_UPDATE_PREFERENCES, async (event, next) => {
|
||||
guard(event);
|
||||
await service.updatePreferences(next);
|
||||
});
|
||||
|
||||
ipcMain.handle(DESKTOP_AI_RUN_TASK, async (event, request) => {
|
||||
guard(event);
|
||||
return service.runTask(request);
|
||||
});
|
||||
};
|
||||
|
||||
const ensureMainWindow = (): void => {
|
||||
if (mainWindow) {
|
||||
return;
|
||||
|
|
@ -101,6 +179,20 @@ const ensureMainWindow = (): void => {
|
|||
};
|
||||
|
||||
app.whenReady().then(() => {
|
||||
desktopAiService = new IslandflowDesktopAiService(
|
||||
app.getPath("userData"),
|
||||
async (url) => {
|
||||
await shell.openExternal(url);
|
||||
},
|
||||
() => {
|
||||
broadcastDesktopAiState();
|
||||
}
|
||||
);
|
||||
registerDesktopAiIpc(desktopAiService);
|
||||
void desktopAiService.start().catch((error) => {
|
||||
console.error("[desktop-ai] Failed to start Codex bridge:", error);
|
||||
broadcastDesktopAiState();
|
||||
});
|
||||
ensureMainWindow();
|
||||
|
||||
app.on("activate", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue