chore: archive tools/ui_inspector snapshot before migration removal.
Keep the last in-template copy on main so history can restore it; product continues in jiangchang-ui-recorder. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
- 主窗 WeWorkWindow → ``ensure_ui_ready("wecom")``
|
||||
- 搜索浮层 SearchResultWindow2 → ``ensure_ui_ready("wecom_search")``
|
||||
未安装 kit 时降级为跳过,不阻断采集。
|
||||
|
||||
Warm cache key = profile + hwnd(经 WeCom Adapter),避免主窗 warm
|
||||
状态错误代表 SearchResultWindow2 已暖。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -10,9 +13,13 @@ from __future__ import annotations
|
||||
import time
|
||||
from typing import Any, Optional
|
||||
|
||||
_CACHE_TTL_SEC = 45.0
|
||||
# A successful provider probe remains valid for the lifetime of a normal
|
||||
# recording flow. The old 45 second TTL made long desktop flows re-run an
|
||||
# expensive WeCom wake in the middle of recording and produced minute-late
|
||||
# evidence.
|
||||
_CACHE_TTL_SEC = 600.0
|
||||
|
||||
# profile -> cache
|
||||
# cache_key -> cache (profile:hwnd:N)
|
||||
_caches: dict[str, dict[str, Any]] = {}
|
||||
|
||||
_PROFILE_WECOM = "wecom"
|
||||
@@ -24,8 +31,26 @@ _THRESHOLDS = {
|
||||
}
|
||||
|
||||
|
||||
def _wecom_adapter():
|
||||
try:
|
||||
from adapters.wecom import wecom_adapter
|
||||
|
||||
return wecom_adapter
|
||||
except Exception:
|
||||
try:
|
||||
from .adapters.wecom import wecom_adapter # type: ignore
|
||||
|
||||
return wecom_adapter
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def resolve_wake_profile(*, class_name: str = "", title: str = "") -> Optional[str]:
|
||||
"""返回应调用的 kit profile id;非企微相关则 None。"""
|
||||
ad = _wecom_adapter()
|
||||
if ad is not None:
|
||||
return ad.wake_profile(class_name=class_name, title=title)
|
||||
# Compatibility fallback if adapter import fails
|
||||
cls = (class_name or "").strip()
|
||||
title = title or ""
|
||||
if cls == "SearchResultWindow2":
|
||||
@@ -50,6 +75,13 @@ def kit_available() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _cache_key(profile: str, hwnd: Optional[int]) -> str:
|
||||
ad = _wecom_adapter()
|
||||
if ad is not None:
|
||||
return ad.cache_key(profile=profile, hwnd=int(hwnd or 0))
|
||||
return f"{profile}:hwnd:{int(hwnd or 0)}"
|
||||
|
||||
|
||||
def auto_ensure_if_wecom(
|
||||
*,
|
||||
class_name: str = "",
|
||||
@@ -68,17 +100,22 @@ def auto_ensure_if_wecom(
|
||||
"available": kit_available(),
|
||||
}
|
||||
|
||||
warm_min = int(_THRESHOLDS.get(profile, 80))
|
||||
ad = _wecom_adapter()
|
||||
warm_min = int(ad.warm_threshold(profile) if ad else _THRESHOLDS.get(profile, 80))
|
||||
key = _cache_key(profile, hwnd)
|
||||
cache = _caches.setdefault(
|
||||
profile, {"t": 0.0, "warm": False, "hwnd": 0, "findall": 0}
|
||||
key, {"t": 0.0, "warm": False, "hwnd": int(hwnd or 0), "findall": 0, "profile": profile}
|
||||
)
|
||||
now = time.monotonic()
|
||||
hint = int(findall_hint) if findall_hint is not None else -1
|
||||
# Require same hwnd in cache — main window warm must not cover search popup.
|
||||
cached_hwnd = int(cache.get("hwnd") or 0)
|
||||
same_window = (not hwnd) or (cached_hwnd == int(hwnd))
|
||||
if (
|
||||
not force
|
||||
and same_window
|
||||
and cache.get("warm")
|
||||
and (now - float(cache.get("t") or 0.0)) < _CACHE_TTL_SEC
|
||||
and (hint < 0 or hint >= warm_min)
|
||||
):
|
||||
return {
|
||||
"applicable": True,
|
||||
@@ -91,6 +128,28 @@ def auto_ensure_if_wecom(
|
||||
"findall": int(cache.get("findall") or 0),
|
||||
"hwnd": int(cache.get("hwnd") or 0),
|
||||
"profile": profile,
|
||||
"cache_key": key,
|
||||
"observed_findall_hint": hint,
|
||||
}
|
||||
|
||||
# A direct probe is authoritative. Do not run an invasive wake merely
|
||||
# because this process did not create the cache entry itself.
|
||||
if not force and hint >= warm_min:
|
||||
cache.update(
|
||||
{"t": now, "warm": True, "hwnd": int(hwnd or 0), "findall": hint}
|
||||
)
|
||||
return {
|
||||
"applicable": True,
|
||||
"available": kit_available(),
|
||||
"skipped": True,
|
||||
"reason": "probe_warm",
|
||||
"ok": True,
|
||||
"warm": True,
|
||||
"wake_applied": False,
|
||||
"findall": hint,
|
||||
"hwnd": int(hwnd or 0),
|
||||
"profile": profile,
|
||||
"cache_key": key,
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -157,16 +216,49 @@ def auto_ensure_if_wecom(
|
||||
"profile": profile,
|
||||
"markers_found": list(after.markers_found) if after is not None else [],
|
||||
}
|
||||
report["cache_key"] = key
|
||||
if result.warm:
|
||||
cache["t"] = now
|
||||
cache["warm"] = True
|
||||
cache["hwnd"] = report["hwnd"]
|
||||
cache["findall"] = findall
|
||||
# Persist under result hwnd so main≠search caches stay separate.
|
||||
final_key = _cache_key(profile, report["hwnd"] or hwnd)
|
||||
final_cache = _caches.setdefault(
|
||||
final_key,
|
||||
{"t": 0.0, "warm": False, "hwnd": int(report["hwnd"] or 0), "findall": 0, "profile": profile},
|
||||
)
|
||||
final_cache["t"] = now
|
||||
final_cache["warm"] = True
|
||||
final_cache["hwnd"] = int(report["hwnd"] or hwnd or 0)
|
||||
final_cache["findall"] = findall
|
||||
report["cache_key"] = final_key
|
||||
else:
|
||||
cache["warm"] = False
|
||||
return report
|
||||
|
||||
|
||||
def note_provider_warm(
|
||||
*, class_name: str = "", title: str = "", hwnd: int = 0, findall: int = 0
|
||||
) -> bool:
|
||||
"""Pin a proven-warm provider so recorder evidence never re-wakes it."""
|
||||
profile = resolve_wake_profile(class_name=class_name, title=title)
|
||||
adapter = _wecom_adapter()
|
||||
threshold = int(
|
||||
adapter.warm_threshold(profile)
|
||||
if adapter and profile
|
||||
else _THRESHOLDS.get(profile or "", 80)
|
||||
)
|
||||
count = int(findall or 0)
|
||||
if not profile or count < threshold:
|
||||
return False
|
||||
key = _cache_key(profile, hwnd)
|
||||
_caches[key] = {
|
||||
"t": time.monotonic(),
|
||||
"warm": True,
|
||||
"hwnd": int(hwnd or 0),
|
||||
"findall": count,
|
||||
"profile": profile,
|
||||
}
|
||||
return True
|
||||
|
||||
|
||||
def format_kit_wake_line(report: Optional[dict[str, Any]]) -> str:
|
||||
if not report:
|
||||
return "kit_wake: (none)"
|
||||
|
||||
Reference in New Issue
Block a user