feat(FN-3404): add local embedded runtime manager to desktop app

Adds a local runtime manager to the desktop app (FN-3404) — an embedded engine process managed via IPC with packaging for bundled dependencies and lifecycle documentation. Also includes project mapping onboarding UI with persistence and rollback (FN-3505), plus related dashboard API and hook updates

Fusion-Task-Id: FN-3404
This commit is contained in:
Fusion
2026-05-07 19:48:58 -07:00
committed by gsxdsm
parent 65a9371d31
commit 22834e5c4e
13 changed files with 495 additions and 97 deletions

View File

@@ -13,8 +13,7 @@ import {
} from "./native.js";
import { setupTray } from "./tray.js";
import { getRendererUrl, getRendererFilePath, isUrlRenderer } from "./renderer.js";
import { DesktopLocalServerManager } from "./local-server.js";
import { getDesktopShellModeState, readShellSettings } from "./shell-settings.js";
import { LocalRuntimeManager } from "./local-runtime.js";
// Re-export for backward compatibility
export { IS_DEVELOPMENT } from "./renderer.js";
@@ -35,7 +34,7 @@ enableSourceMaps();
let mainWindow: BrowserWindow | null = null;
let tray: Tray | null = null;
let localServerManager: DesktopLocalServerManager | null = null;
let localRuntimeManager: LocalRuntimeManager | null = null;
function getAppWithQuitFlag(): Electron.App & AppWithQuitFlag {
return app as Electron.App & AppWithQuitFlag;
@@ -91,33 +90,33 @@ export async function initializeApp(): Promise<void> {
appName: "Fusion",
});
localServerManager = new DesktopLocalServerManager(process.cwd());
localRuntimeManager = new LocalRuntimeManager({ rootDir: process.cwd() });
tray = new Tray(nativeImage.createEmpty());
setupTray(createdWindow, tray);
registerIpcHandlers(createdWindow, tray, {
onDesktopModeChange: async (mode) => {
if (!localServerManager) {
if (!localRuntimeManager) {
return;
}
if (mode === "local") {
await localServerManager.start();
await localRuntimeManager.startLocal();
} else {
await localServerManager.stop();
await localRuntimeManager.stopLocal();
}
},
getLocalServerState: () => localServerManager?.getState() ?? { status: "idle", error: null },
getServerPort: () => localServerManager?.getPort(),
getRuntimeStatus: () => localRuntimeManager?.getStatus() ?? { source: "none", state: "stopped" },
startLocalRuntime: () => localRuntimeManager?.startLocal() ?? Promise.resolve({ source: "none", state: "stopped" }),
stopLocalRuntime: () => localRuntimeManager?.stopLocal() ?? Promise.resolve({ source: "none", state: "stopped" }),
getServerPort: () => localRuntimeManager?.getServerPort(),
});
registerDeepLinkProtocol();
setupDeepLinkHandler(createdWindow);
setupAutoUpdater(createdWindow);
const shellSettings = await readShellSettings();
const desktopModeState = getDesktopShellModeState(shellSettings);
if (!desktopModeState.isFirstRun && desktopModeState.desktopMode === "local") {
await localServerManager.start();
if (process.env.FUSION_DESKTOP_MODE === "local") {
await localRuntimeManager.startLocal();
}
if (state?.isMaximized === true) {
@@ -144,8 +143,8 @@ export function run(): void {
tray = null;
}
if (localServerManager) {
void localServerManager.stop();
if (localRuntimeManager) {
void localRuntimeManager.stopLocal();
}
});