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>
104 lines
3.5 KiB
Python
104 lines
3.5 KiB
Python
"""WeCom (企业微信) adapter — profile / window / postcondition helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Optional
|
|
|
|
from .registry import register_adapter
|
|
|
|
PROFILE_WECOM = "wecom"
|
|
PROFILE_WECOM_SEARCH = "wecom_search"
|
|
|
|
_THRESHOLDS = {
|
|
PROFILE_WECOM: 80,
|
|
PROFILE_WECOM_SEARCH: 20,
|
|
}
|
|
|
|
|
|
class WeComAdapter:
|
|
name = "wecom"
|
|
|
|
def matches(
|
|
self, *, class_name: str = "", title: str = "", process_name: str = ""
|
|
) -> bool:
|
|
return self.wake_profile(class_name=class_name, title=title) is not None or (
|
|
"WXWork" in (process_name or "")
|
|
)
|
|
|
|
def wake_profile(self, *, class_name: str = "", title: str = "") -> Optional[str]:
|
|
cls = (class_name or "").strip()
|
|
title = title or ""
|
|
if cls == "SearchResultWindow2":
|
|
return PROFILE_WECOM_SEARCH
|
|
if cls == "WeWorkWindow":
|
|
return PROFILE_WECOM
|
|
if "WeWork" in cls and (
|
|
"企业微信" in title or "WeCom" in title or "wecom" in title.lower()
|
|
):
|
|
return PROFILE_WECOM
|
|
return None
|
|
|
|
def cache_key(self, *, profile: str, hwnd: int = 0) -> str:
|
|
"""Separate main window vs SearchResultWindow2 warm caches."""
|
|
return f"{profile}:hwnd:{int(hwnd or 0)}"
|
|
|
|
def warm_threshold(self, profile: str) -> int:
|
|
return int(_THRESHOLDS.get(profile, 80))
|
|
|
|
def is_search_popup(self, *, class_name: str = "") -> bool:
|
|
return (class_name or "") == "SearchResultWindow2"
|
|
|
|
def is_main_window(self, *, class_name: str = "") -> bool:
|
|
return (class_name or "") == "WeWorkWindow"
|
|
|
|
def known_ids(self) -> dict[str, str]:
|
|
return {
|
|
"searchedit": "search_box",
|
|
"groupbuddyname": "contact_row_name",
|
|
"search_name": "search_result_name",
|
|
"send_rich_edit": "compose_box",
|
|
"panel_title_label": "panel_title",
|
|
}
|
|
|
|
def propose_postconditions(self, changes: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
props: list[dict[str, Any]] = []
|
|
for ch in changes or []:
|
|
kind = ch.get("kind")
|
|
detail = ch.get("detail") or {}
|
|
if kind == "popup_disappeared" and "SearchResult" in str(
|
|
detail.get("class_name") or ""
|
|
):
|
|
props.append(
|
|
{
|
|
"description": "SearchResultWindow2 disappeared",
|
|
"kind": "window_absent",
|
|
"status": "proposed",
|
|
"detail": detail,
|
|
}
|
|
)
|
|
if kind == "element_appeared":
|
|
name = str(detail.get("name") or detail.get("automation_id") or "")
|
|
if name in {"send_rich_edit", "main_chattext", "panel_title_label"}:
|
|
props.append(
|
|
{
|
|
"description": f"WeCom element {name} appeared",
|
|
"kind": "element_present",
|
|
"status": "proposed",
|
|
"detail": detail,
|
|
}
|
|
)
|
|
if kind == "title_changed":
|
|
props.append(
|
|
{
|
|
"description": f"Chat title became {detail.get('to')!r}",
|
|
"kind": "title_equals",
|
|
"status": "proposed",
|
|
"detail": detail,
|
|
}
|
|
)
|
|
return props
|
|
|
|
|
|
wecom_adapter = WeComAdapter()
|
|
register_adapter(wecom_adapter)
|