feat(desktop): add monitor scheduler, Playwright CDP layer, and account health
Move monitor-task scheduling authority onto the client with a durable file-backed queue that survives restart, drops stale cross-day tasks, enforces per-platform serialism, and adapts global concurrency from Electron process metrics. Publish tasks keep their existing FIFO. Add a hidden Playwright CDP manager that attaches to Electron Chromium on account session partitions, lets adapters opt into `executionMode: "playwright"`, and leaves the existing hidden WebContentsView path in place for current adapters. Introduce an account-health subsystem with silent probes, projected health/auth states, and IPC invalidation events so the renderer can show accurate auth/probe status and verification timestamps. Server-side, derive and forward title/business_date/scheduler_group_key/ question_text metadata on desktop task events so the local scheduler can defer same-question fan-out before leasing.
This commit is contained in:
@@ -4,13 +4,17 @@ import { join } from "node:path";
|
||||
import { BrowserWindow, WebContentsView, app, ipcMain, nativeTheme } from "electron/main";
|
||||
import type {
|
||||
BrowserWindow as ElectronBrowserWindow,
|
||||
WebContents as ElectronWebContents,
|
||||
WebContentsView as ElectronWebContentsView,
|
||||
} from "electron/main";
|
||||
import type { DesktopAccountInfo, DesktopRuntimeSessionSyncRequest } from "@geo/shared-types";
|
||||
|
||||
import { initAccountHealth } from "./account-health";
|
||||
import { bindPublishAccount, openPublishAccountConsole } from "./account-binder";
|
||||
import { initProcessMetricsSampler } from "./process-metrics";
|
||||
import { getPlaywrightCDPPort, startHiddenPlaywrightReaper } from "./playwright-cdp";
|
||||
import { registerRendererDevtoolsProxyTarget } from "./renderer-devtools-proxy";
|
||||
import { onRuntimeInvalidated } from "./runtime-events";
|
||||
import {
|
||||
refreshRuntimeAccounts,
|
||||
releaseRuntimeSession,
|
||||
@@ -32,6 +36,7 @@ app.commandLine.appendSwitch(
|
||||
);
|
||||
app.commandLine.appendSwitch("disable-quic");
|
||||
app.commandLine.appendSwitch("disable-background-networking");
|
||||
app.commandLine.appendSwitch("remote-debugging-port", String(getPlaywrightCDPPort()));
|
||||
app.userAgentFallback = STANDARD_USER_AGENT;
|
||||
|
||||
console.info("[desktop-main] boot", {
|
||||
@@ -50,6 +55,7 @@ process.on("uncaughtException", (error) => {
|
||||
});
|
||||
|
||||
let mainWindow: ElectronBrowserWindow | null = null;
|
||||
let mainRendererContents: ElectronWebContents | null = null;
|
||||
let quitReleaseInFlight = false;
|
||||
|
||||
function rendererURL(): string | null {
|
||||
@@ -77,9 +83,15 @@ async function mountRendererView(window: ElectronBrowserWindow): Promise<void> {
|
||||
|
||||
view.webContents.setWindowOpenHandler(() => ({ action: "deny" }));
|
||||
registerRendererDevtoolsProxyTarget(view.webContents);
|
||||
mainRendererContents = view.webContents;
|
||||
window.contentView.addChildView(view);
|
||||
syncViewBounds(window, view);
|
||||
window.on("resize", () => syncViewBounds(window, view));
|
||||
window.on("closed", () => {
|
||||
if (mainRendererContents === view.webContents) {
|
||||
mainRendererContents = null;
|
||||
}
|
||||
});
|
||||
|
||||
const devServerURL = rendererURL();
|
||||
if (devServerURL) {
|
||||
@@ -189,10 +201,18 @@ if (!initSingleInstance(() => {
|
||||
app.whenReady().then(async () => {
|
||||
registerBridgeHandlers();
|
||||
await initSessionRegistry();
|
||||
initAccountHealth();
|
||||
initTransport();
|
||||
initScheduler();
|
||||
initProcessMetricsSampler();
|
||||
startHotViewReaper();
|
||||
startHiddenPlaywrightReaper();
|
||||
onRuntimeInvalidated((event) => {
|
||||
if (!mainRendererContents || mainRendererContents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
mainRendererContents.send("desktop:runtime-invalidated", event);
|
||||
});
|
||||
mainWindow = await createMainWindow();
|
||||
initTray(() => {
|
||||
if (!mainWindow) {
|
||||
|
||||
Reference in New Issue
Block a user