fix(desktop-client): stop false manual-verification states and auto-revive probes after sleep/offline

Challenge detection previously regex-matched the entire page innerText, so
chat transcripts or console copy containing words like 验证码/安全验证/verify
flagged healthy accounts as challenge_required. Detection is now scoped to
real evidence only (visible captcha vendor widgets, short modal copy, sparse
interstitial pages) via a shared challenge-signals module used by the generic
AI probe, doubao/kimi/qwen auth rules, and the deepseek runtime snapshot.
Platform API error codes (e.g. baijiahao_challenge_required) keep working.

Account health also could not recover after lid-close sleep or a network
drop: offline probes misread cached console pages as expired, and expired
records null out nextProbeAt so they were never re-probed. Probing is now
skipped while offline (network_error backoff instead), and powerMonitor
resume/unlock plus an offline-to-online transition watch schedule jittered
recovery probes for all tracked accounts, including expired ones. Challenge
rechecks wait 8s so transient widgets during page load no longer stick.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 11:06:51 +08:00
parent c7bad83496
commit abacc1f421
7 changed files with 287 additions and 77 deletions
@@ -1,6 +1,7 @@
import type { Cookie, Session, WebContents } from 'electron/main'
import type { AccountHealthProfile, AuthProbeResult } from '../../auth-types'
import { PAGE_CHALLENGE_SIGNAL_COUNT_SNIPPET } from '../../challenge-signals'
import type { GenericAIPageState } from '../../generic-ai-auth'
import { normalizeRemoteUrl } from '../common'
@@ -269,9 +270,7 @@ export async function readDoubaoAuthPageState(
const loggedOutSignalCount = /(未登录|登录后继续|请先登录|扫码登录|手机号登录)/.test(bodyText)
? 1
: 0;
const challengeSignalCount = /(验证码|滑块|人机验证|安全验证|短信验证|captcha|verification)/i.test(bodyText)
? 1
: 0;
const challengeSignalCount = ${PAGE_CHALLENGE_SIGNAL_COUNT_SNIPPET};
const account = pickAccountTrigger();
const displayName = account?.displayName || null;
const avatarUrl = isAccountAvatarUrl(account?.avatarUrl || null)