feat(desktop): add Kimi and Yuanbao monitoring adapters

- implement kimi/yuanbao monitor adapters with dedicated citation panel detection
- detect Kimi session via kimi-auth cookie during account binding
- harden hidden Playwright and bound windows with skipTaskbar/focusable/hiddenInMissionControl to stop stealing focus
- tag hidden bootstrap windows with a unique token so CDP retention resolves the correct page
- enable yuanbao/kimi/wenxin platforms in dev-seed and default monitoring quota
- update kimi loginUrl to www.kimi.com

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 09:09:20 +08:00
parent 4142c53fa6
commit f91d2645d3
10 changed files with 4035 additions and 12 deletions
+79 -7
View File
@@ -8,6 +8,7 @@ const hiddenPlaywrightIdleTTLms = 5 * 60_000;
const hiddenPlaywrightReaperIntervalMs = 60_000;
const defaultConnectTimeoutMs = 10_000;
const defaultPageTimeoutMs = 45_000;
const hiddenBootstrapMetaName = "geo-hidden-playwright-token";
const cdpPort = Number.parseInt(process.env.GEO_ELECTRON_CDP_PORT ?? "9339", 10);
const cdpEndpointURL = `http://127.0.0.1:${cdpPort}`;
const cdpTargetsListURL = `${cdpEndpointURL}/json/list`;
@@ -79,8 +80,10 @@ export async function retainHiddenPlaywrightPage(options: {
const browser = await connectBrowserOverCDP();
const knownPages = new Set(defaultContext(browser).pages());
const window = createHiddenWindow(options.title, options.session);
const page = await waitForNewPage(browser, knownPages);
const bootstrapToken = createHiddenBootstrapToken();
const bootstrapURL = buildHiddenWindowBootstrapURL(options.title, bootstrapToken);
const window = createHiddenWindow(options.title, options.session, bootstrapURL);
const page = await waitForNewPage(browser, knownPages, bootstrapToken);
page.setDefaultTimeout(defaultPageTimeoutMs);
page.setDefaultNavigationTimeout(defaultPageTimeoutMs);
@@ -181,11 +184,18 @@ function createLease(record: HiddenPlaywrightRecord): HiddenPlaywrightLease {
};
}
function createHiddenWindow(title: string, session: Session): ElectronBrowserWindow {
function createHiddenWindow(
title: string,
session: Session,
bootstrapURL: string,
): ElectronBrowserWindow {
const window = new BrowserWindow({
show: false,
width: 1320,
height: 900,
skipTaskbar: true,
focusable: false,
hiddenInMissionControl: true,
autoHideMenuBar: true,
backgroundColor: nativeTheme.shouldUseDarkColors ? "#15191a" : "#f4f1ea",
title,
@@ -199,10 +209,41 @@ function createHiddenWindow(title: string, session: Session): ElectronBrowserWin
});
window.webContents.setUserAgent(STANDARD_USER_AGENT);
void window.loadURL("about:blank");
void window.loadURL(bootstrapURL);
return window;
}
function createHiddenBootstrapToken(): string {
if (typeof globalThis.crypto?.randomUUID === "function") {
return globalThis.crypto.randomUUID();
}
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
}
function escapeHtml(value: string): string {
return value
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\"", "&quot;")
.replaceAll("'", "&#39;");
}
function buildHiddenWindowBootstrapURL(title: string, token: string): string {
const html = [
"<!doctype html>",
"<html lang=\"en\">",
"<head>",
" <meta charset=\"utf-8\">",
` <meta name=\"${hiddenBootstrapMetaName}\" content=\"${escapeHtml(token)}\">`,
` <title>${escapeHtml(title)} · hidden-playwright</title>`,
"</head>",
` <body data-${hiddenBootstrapMetaName}=\"${escapeHtml(token)}\"></body>`,
"</html>",
].join("");
return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
}
async function ensureRecordTarget(record: HiddenPlaywrightRecord, targetURL: string): Promise<void> {
record.targetURL = targetURL;
@@ -346,18 +387,21 @@ function isConnectOverCDPTimeout(error: unknown): boolean {
async function waitForNewPage(
browser: PlaywrightBrowser,
knownPages: Set<PlaywrightPage>,
bootstrapToken: string,
): Promise<PlaywrightPage> {
const context = defaultContext(browser);
const startedAt = Date.now();
while (Date.now() - startedAt < defaultPageTimeoutMs) {
const nextPage = context.pages().find((page) => !knownPages.has(page));
if (nextPage) {
const nextPages = context.pages().filter((page) => !knownPages.has(page));
for (const nextPage of nextPages) {
if (isDevtoolsPage(nextPage)) {
knownPages.add(nextPage);
continue;
}
return nextPage;
if (await matchesHiddenBootstrapPage(nextPage, bootstrapToken)) {
return nextPage;
}
}
await wait(100);
}
@@ -365,6 +409,34 @@ async function waitForNewPage(
throw new Error("playwright_hidden_page_unavailable");
}
async function matchesHiddenBootstrapPage(
page: PlaywrightPage,
bootstrapToken: string,
): Promise<boolean> {
const url = safePageURL(page);
if (url.includes(bootstrapToken) || url.includes(encodeURIComponent(bootstrapToken))) {
return true;
}
try {
return await page.evaluate(
({ token, metaName }) => {
const metaToken =
document.querySelector(`meta[name="${metaName}"]`)?.getAttribute("content")
?? document.body?.getAttribute(`data-${metaName}`)
?? null;
return metaToken === token;
},
{
token: bootstrapToken,
metaName: hiddenBootstrapMetaName,
},
);
} catch {
return false;
}
}
function defaultContext(browser: PlaywrightBrowser) {
const context = browser.contexts()[0];
if (!context) {