first-commit
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run

This commit is contained in:
Zakaria
2026-05-04 14:58:14 -04:00
commit a46764fb1b
1210 changed files with 233231 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
{
"name": "@open-design/desktop",
"version": "0.3.0",
"private": true,
"type": "module",
"main": "./dist/main/index.js",
"files": [
"dist"
],
"exports": {
"./main": {
"types": "./dist/main/index.d.ts",
"default": "./dist/main/index.js"
}
},
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"dependencies": {
"@open-design/platform": "workspace:0.3.0",
"@open-design/sidecar": "workspace:0.3.0",
"@open-design/sidecar-proto": "workspace:0.3.0"
},
"devDependencies": {
"@types/node": "24.12.2",
"electron": "41.3.0",
"typescript": "6.0.3"
},
"engines": {
"node": "~24"
}
}
+158
View File
@@ -0,0 +1,158 @@
import { realpathSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { app } from "electron";
import {
APP_KEYS,
OPEN_DESIGN_SIDECAR_CONTRACT,
SIDECAR_ENV,
SIDECAR_MESSAGES,
normalizeDesktopSidecarMessage,
type DesktopClickInput,
type DesktopEvalInput,
type DesktopScreenshotInput,
type SidecarStamp,
type WebStatusSnapshot,
} from "@open-design/sidecar-proto";
import {
bootstrapSidecarRuntime,
createJsonIpcServer,
requestJsonIpc,
resolveAppIpcPath,
type JsonIpcServerHandle,
type SidecarRuntimeContext,
} from "@open-design/sidecar";
import { readProcessStamp } from "@open-design/platform";
import { createDesktopRuntime } from "./runtime.js";
const TOOLS_DEV_PARENT_PID_ENV = SIDECAR_ENV.TOOLS_DEV_PARENT_PID;
export type DesktopMainOptions = {
beforeShutdown?: () => Promise<void>;
discoverWebUrl?: () => Promise<string | null>;
};
function isDirectEntry(): boolean {
const entryPath = process.argv[1];
if (entryPath == null || entryPath.length === 0 || entryPath.startsWith("--")) return false;
try {
return realpathSync(entryPath) === realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
function isProcessAlive(pid: number): boolean {
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
function attachParentMonitor(stop: () => Promise<void>): void {
const parentPid = Number(process.env[TOOLS_DEV_PARENT_PID_ENV]);
if (!Number.isInteger(parentPid) || parentPid <= 0) return;
const timer = setInterval(() => {
if (isProcessAlive(parentPid)) return;
clearInterval(timer);
void stop().finally(() => process.exit(0));
}, 1000);
timer.unref();
}
function createWebDiscovery(runtime: SidecarRuntimeContext<SidecarStamp>): () => Promise<string | null> {
return async () => {
const webIpc = resolveAppIpcPath({
app: APP_KEYS.WEB,
contract: OPEN_DESIGN_SIDECAR_CONTRACT,
namespace: runtime.namespace,
});
const web = await requestJsonIpc<WebStatusSnapshot>(webIpc, { type: SIDECAR_MESSAGES.STATUS }, { timeoutMs: 600 }).catch(() => null);
return web?.url ?? null;
};
}
export async function runDesktopMain(
runtime: SidecarRuntimeContext<SidecarStamp>,
options: DesktopMainOptions = {},
): Promise<void> {
await app.whenReady();
const desktop = await createDesktopRuntime({
discoverUrl: options.discoverWebUrl ?? createWebDiscovery(runtime),
});
let ipcServer: JsonIpcServerHandle | null = null;
let shuttingDown = false;
async function shutdown(): Promise<void> {
if (shuttingDown) return;
shuttingDown = true;
await options.beforeShutdown?.().catch((error: unknown) => {
console.error("desktop beforeShutdown failed", error);
});
await ipcServer?.close().catch(() => undefined);
await desktop.close().catch(() => undefined);
app.quit();
}
attachParentMonitor(shutdown);
ipcServer = await createJsonIpcServer({
socketPath: runtime.ipc,
handler: async (message: unknown) => {
const request = normalizeDesktopSidecarMessage(message);
switch (request.type) {
case SIDECAR_MESSAGES.STATUS:
return desktop.status();
case SIDECAR_MESSAGES.EVAL:
return await desktop.eval(request.input as DesktopEvalInput);
case SIDECAR_MESSAGES.SCREENSHOT:
return await desktop.screenshot(request.input as DesktopScreenshotInput);
case SIDECAR_MESSAGES.CONSOLE:
return desktop.console();
case SIDECAR_MESSAGES.CLICK:
return await desktop.click(request.input as DesktopClickInput);
case SIDECAR_MESSAGES.SHUTDOWN:
setImmediate(() => {
void shutdown().finally(() => process.exit(0));
});
return { accepted: true };
}
},
});
app.on("window-all-closed", () => {
void shutdown().finally(() => process.exit(0));
});
app.on("activate", () => {
desktop.show();
});
for (const signal of ["SIGINT", "SIGTERM"] as const) {
process.on(signal, () => {
void shutdown().finally(() => process.exit(0));
});
}
}
if (isDirectEntry()) {
const stamp = readProcessStamp(process.argv.slice(2), OPEN_DESIGN_SIDECAR_CONTRACT);
if (stamp == null) throw new Error("sidecar stamp is required");
const runtime = bootstrapSidecarRuntime(stamp, process.env, {
app: APP_KEYS.DESKTOP,
contract: OPEN_DESIGN_SIDECAR_CONTRACT,
});
void runDesktopMain(runtime).catch((error: unknown) => {
console.error(error instanceof Error ? error.stack || error.message : String(error));
process.exit(1);
});
}
+357
View File
@@ -0,0 +1,357 @@
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, isAbsolute, resolve } from "node:path";
import { BrowserWindow } from "electron";
const PENDING_POLL_MS = 120;
const RUNNING_POLL_MS = 2000;
const MAX_CONSOLE_ENTRIES = 200;
export type DesktopEvalInput = {
expression: string;
};
export type DesktopEvalResult = {
error?: string;
ok: boolean;
value?: unknown;
};
export type DesktopScreenshotInput = {
path: string;
};
export type DesktopScreenshotResult = {
path: string;
};
export type DesktopConsoleEntry = {
level: string;
text: string;
timestamp: string;
};
export type DesktopConsoleResult = {
entries: DesktopConsoleEntry[];
};
export type DesktopClickInput = {
selector: string;
};
export type DesktopClickResult = {
clicked: boolean;
found: boolean;
};
export type DesktopStatusSnapshot = {
pid?: number;
state: "idle" | "running" | "unknown";
title?: string | null;
updatedAt?: string;
url?: string | null;
windowVisible?: boolean;
};
export type DesktopRuntime = {
close(): Promise<void>;
click(input: DesktopClickInput): Promise<DesktopClickResult>;
console(): DesktopConsoleResult;
eval(input: DesktopEvalInput): Promise<DesktopEvalResult>;
screenshot(input: DesktopScreenshotInput): Promise<DesktopScreenshotResult>;
show(): void;
status(): DesktopStatusSnapshot;
};
export type DesktopRuntimeOptions = {
discoverUrl(): Promise<string | null>;
};
const MAC_WINDOW_CHROME =
process.platform === "darwin"
? ({
titleBarStyle: "hiddenInset" as const,
trafficLightPosition: { x: 14, y: 12 },
})
: {};
const MAC_WINDOW_CHROME_CSS = `
.app-chrome-header {
--app-chrome-traffic-space: 56px !important;
-webkit-app-region: drag;
}
.app-chrome-traffic-space {
flex: 0 0 56px !important;
width: 56px !important;
}
.app-chrome-header button,
.app-chrome-header [role="button"],
.app-chrome-header [contenteditable],
.app-chrome-actions,
.app-chrome-actions *,
.avatar-popover,
.avatar-popover * {
-webkit-app-region: no-drag;
}
.app-chrome-drag {
-webkit-app-region: drag;
}
.entry-brand,
.entry-header {
-webkit-app-region: drag;
}
.entry-brand button,
.entry-brand [role="button"],
.entry-header button,
.entry-header [role="button"],
.entry-tabs,
.entry-tabs *,
.entry-side-resizer,
.avatar-popover,
.avatar-popover * {
-webkit-app-region: no-drag;
}
`;
function createPendingHtml(): string {
return `data:text/html;charset=utf-8,${encodeURIComponent(`<!doctype html>
<html>
<head>
<title>Open Design</title>
<style>
body {
align-items: center;
background: #05070d;
color: #f7f7fb;
display: flex;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
height: 100vh;
justify-content: center;
margin: 0;
}
main {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 24px;
padding: 32px;
}
p { color: #aeb7d5; margin: 12px 0 0; }
</style>
</head>
<body>
<main>
<h1>Open Design</h1>
<p>Waiting for the web runtime URL…</p>
</main>
</body>
</html>`)}`;
}
function normalizeScreenshotPath(filePath: string): string {
return isAbsolute(filePath) ? filePath : resolve(process.cwd(), filePath);
}
function mapConsoleLevel(level: number): string {
switch (level) {
case 0:
return "debug";
case 1:
return "info";
case 2:
return "warn";
case 3:
return "error";
default:
return "log";
}
}
async function applyWindowChromeCss(window: BrowserWindow): Promise<void> {
if (process.platform !== "darwin" || window.isDestroyed()) return;
await window.webContents.insertCSS(MAC_WINDOW_CHROME_CSS, { cssOrigin: "user" });
}
function installWindowChromeCssHook(window: BrowserWindow): void {
window.webContents.on("did-finish-load", () => {
void applyWindowChromeCss(window).catch((error: unknown) => {
console.error("desktop window chrome CSS injection failed", error);
});
});
}
function showWindowButtons(window: BrowserWindow): void {
if (process.platform !== "darwin" || window.isDestroyed()) return;
window.setWindowButtonVisibility(true);
}
// Windows focus-stealing prevention can leave a detached-spawned GUI
// window minimized or hidden even when constructed with show:true,
// leaving users unable to locate the window. Cross-platform safe: only
// acts when the window is actually minimized or hidden, preserving any
// user-adjusted window state.
function ensureWindowVisible(window: BrowserWindow): void {
if (window.isDestroyed()) return;
if (window.isMinimized()) window.restore();
if (!window.isVisible()) window.show();
window.focus();
}
// PPTX is rendered by the agent into the project folder and reaches the
// renderer through a normal `<a download>` link to /api/projects/:id/raw/*.
// Without this hook Electron writes the bytes straight to the OS Downloads
// folder, so the user never gets to pick a destination. setSaveDialogOptions
// makes Electron show the native Save As panel before the download starts.
const SAVE_AS_EXTENSIONS = new Set([".pptx"]);
function attachDownloadSaveAsDialog(window: BrowserWindow): void {
window.webContents.session.on("will-download", (_event, item) => {
const filename = item.getFilename();
const dot = filename.lastIndexOf(".");
const ext = dot >= 0 ? filename.slice(dot).toLowerCase() : "";
if (!SAVE_AS_EXTENSIONS.has(ext)) return;
item.setSaveDialogOptions({
title: "Save As",
defaultPath: filename,
filters: [
{ name: "PowerPoint Presentation", extensions: ["pptx"] },
{ name: "All Files", extensions: ["*"] },
],
});
});
}
export async function createDesktopRuntime(options: DesktopRuntimeOptions): Promise<DesktopRuntime> {
const consoleEntries: DesktopConsoleEntry[] = [];
const window = new BrowserWindow({
height: 900,
show: true,
title: "Open Design",
...MAC_WINDOW_CHROME,
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
width: 1280,
});
installWindowChromeCssHook(window);
showWindowButtons(window);
attachDownloadSaveAsDialog(window);
let currentUrl: string | null = null;
let stopped = false;
let timer: NodeJS.Timeout | null = null;
window.on("focus", () => showWindowButtons(window));
window.on("blur", () => showWindowButtons(window));
if (process.platform === "darwin") {
window.on("close", (event) => {
if (!stopped) {
event.preventDefault();
window.hide();
}
});
}
(window.webContents as any).on("console-message", (event: { level?: number | string; message?: string }) => {
const level = typeof event.level === "number" ? mapConsoleLevel(event.level) : (event.level ?? "log");
consoleEntries.push({
level,
text: event.message ?? "",
timestamp: new Date().toISOString(),
});
if (consoleEntries.length > MAX_CONSOLE_ENTRIES) {
consoleEntries.splice(0, consoleEntries.length - MAX_CONSOLE_ENTRIES);
}
});
await window.loadURL(createPendingHtml());
showWindowButtons(window);
ensureWindowVisible(window);
const schedule = (delayMs: number) => {
if (stopped) return;
timer = setTimeout(() => {
void tick();
}, delayMs);
};
const tick = async () => {
if (stopped || window.isDestroyed()) return;
try {
const url = await options.discoverUrl();
if (url != null && url !== currentUrl) {
currentUrl = url;
await window.loadURL(url);
showWindowButtons(window);
}
schedule(url == null ? PENDING_POLL_MS : RUNNING_POLL_MS);
} catch (error) {
console.error("desktop web discovery failed", error);
schedule(PENDING_POLL_MS);
}
};
void tick();
return {
async click(input) {
if (window.isDestroyed()) return { clicked: false, found: false };
const selector = JSON.stringify(input.selector);
return await window.webContents.executeJavaScript(
`(() => {
const element = document.querySelector(${selector});
if (!element) return { found: false, clicked: false };
if (typeof element.click === "function") element.click();
return { found: true, clicked: true };
})()`,
true,
);
},
async close() {
stopped = true;
if (timer != null) {
clearTimeout(timer);
timer = null;
}
if (!window.isDestroyed()) window.close();
},
console() {
return { entries: [...consoleEntries] };
},
async eval(input) {
if (window.isDestroyed()) return { error: "desktop window is destroyed", ok: false };
try {
const value = await window.webContents.executeJavaScript(input.expression, true);
return { ok: true, value };
} catch (error) {
return { error: error instanceof Error ? error.message : String(error), ok: false };
}
},
async screenshot(input) {
if (window.isDestroyed()) throw new Error("desktop window is destroyed");
const outputPath = normalizeScreenshotPath(input.path);
const image = await window.webContents.capturePage();
await mkdir(dirname(outputPath), { recursive: true });
await writeFile(outputPath, image.toPNG());
return { path: outputPath };
},
show() {
if (!window.isDestroyed()) {
window.show();
window.focus();
}
},
status() {
return {
pid: process.pid,
state: window.isDestroyed() ? "unknown" : "running",
title: window.isDestroyed() ? null : window.getTitle(),
updatedAt: new Date().toISOString(),
url: currentUrl,
windowVisible: !window.isDestroyed() && window.isVisible(),
};
},
};
}
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["ES2024", "DOM"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"resolveJsonModule": true,
"rootDir": "./src",
"skipLibCheck": true,
"strict": true,
"target": "ES2024",
"types": ["node"]
},
"include": ["src/**/*.ts"]
}