feat(monitoring): add DeepSeek monitoring end-to-end
- desktop: new DeepSeek page adapter and monitor registry - desktop: extract generic AI auth helpers into shared module and skip binding when challenge signals are present - admin-web: render DeepSeek HTML answers with inline citation anchors and surface reference-number badges on source cards - server: fall back to inline_links/source_panel_links and read text/siteName fields when extracting DeepSeek citations Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,11 @@ import {
|
||||
isWindowReadyForDetection,
|
||||
loadWindowURLSafely,
|
||||
} from "./external-window";
|
||||
import {
|
||||
buildGenericAIPageFingerprintFallback,
|
||||
genericAIPageLooksAuthenticated,
|
||||
type GenericAIPageState,
|
||||
} from "./generic-ai-auth";
|
||||
import { upsertDesktopAccount } from "./transport/api-client";
|
||||
import { STANDARD_USER_AGENT } from "./user-agent";
|
||||
import {
|
||||
@@ -681,18 +686,6 @@ function sanitizeDetectedAccount(account: DetectedAccount): DetectedAccount {
|
||||
};
|
||||
}
|
||||
|
||||
interface GenericAIPageState {
|
||||
displayName: string | null;
|
||||
avatarUrl: string | null;
|
||||
fingerprint: string | null;
|
||||
credentialFingerprint: string | null;
|
||||
currentPath: string | null;
|
||||
strongAuthSignalCount: number;
|
||||
loginSignalCount: number;
|
||||
loggedOutSignalCount: number;
|
||||
challengeSignalCount: number;
|
||||
}
|
||||
|
||||
async function readGenericAIPageState(
|
||||
webContents: WebContents | null | undefined,
|
||||
): Promise<GenericAIPageState | null> {
|
||||
@@ -1004,10 +997,6 @@ function safeParseURL(input: string): URL | null {
|
||||
}
|
||||
}
|
||||
|
||||
function genericAIConversationPath(pathname: string): boolean {
|
||||
return /^\/(?:chat|c|conversation)(?:\/|$)/i.test(pathname);
|
||||
}
|
||||
|
||||
function isLikelyGenericAICredentialName(name: string): boolean {
|
||||
const normalized = name.trim().toLowerCase();
|
||||
if (/^(x[-_]?csrf[-_]?token|xsrf[-_]?token|csrf[-_]?token|csrf|_csrf)$/i.test(normalized)) {
|
||||
@@ -1029,29 +1018,6 @@ function isLikelyGenericAICredentialValue(value: string | null | undefined): boo
|
||||
return normalized.length >= 8;
|
||||
}
|
||||
|
||||
function genericAIPageLooksAuthenticated(currentURL: string, pageState: GenericAIPageState | null): boolean {
|
||||
const current = safeParseURL(currentURL);
|
||||
const currentPath = normalizeURLPath(current?.pathname ?? pageState?.currentPath ?? "");
|
||||
const strongAuthSignalCount = pageState?.strongAuthSignalCount ?? 0;
|
||||
const loginSignalCount = pageState?.loginSignalCount ?? 0;
|
||||
const loggedOutSignalCount = pageState?.loggedOutSignalCount ?? 0;
|
||||
const onConversationPath = genericAIConversationPath(currentPath);
|
||||
|
||||
if (loggedOutSignalCount > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loginSignalCount > 0 && strongAuthSignalCount === 0 && !onConversationPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loginSignalCount > 0) {
|
||||
return strongAuthSignalCount >= 2 && !onConversationPath;
|
||||
}
|
||||
|
||||
return strongAuthSignalCount > 0 || onConversationPath;
|
||||
}
|
||||
|
||||
async function buildGenericAISessionFingerprint(
|
||||
platformId: string,
|
||||
session: Session,
|
||||
@@ -1087,7 +1053,7 @@ async function buildGenericAISessionFingerprint(
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
return null;
|
||||
return buildGenericAIPageFingerprintFallback(platformId, pageState);
|
||||
}
|
||||
|
||||
return boundedIdentity(`${platformId}-session`, parts.join("||"));
|
||||
@@ -1115,6 +1081,9 @@ async function detectGenericAIPlatform(
|
||||
}
|
||||
|
||||
const pageState = await readGenericAIPageState(context.webContents).catch(() => null);
|
||||
if ((pageState?.challengeSignalCount ?? 0) > 0) {
|
||||
return null;
|
||||
}
|
||||
if (!genericAIPageLooksAuthenticated(currentURL, pageState)) {
|
||||
return null;
|
||||
}
|
||||
@@ -2692,6 +2661,7 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
||||
);
|
||||
|
||||
const detectAndBind = async () => {
|
||||
syncDetectionState();
|
||||
const currentURL = window.isDestroyed() ? "" : window.webContents.getURL();
|
||||
const canProbe = detectReady || /^https?:\/\//i.test(currentURL);
|
||||
if (finished || checking || !canProbe || window.isDestroyed()) {
|
||||
|
||||
Reference in New Issue
Block a user