shennian 0.2.112 → 0.2.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -261,8 +261,8 @@
261
261
  },
262
262
  {
263
263
  "file": "src/channels/wechat-channel/observer.js",
264
- "beforeBytes": 102627,
265
- "afterBytes": 47836
264
+ "beforeBytes": 102787,
265
+ "afterBytes": 47933
266
266
  },
267
267
  {
268
268
  "file": "src/channels/wechat-channel/outbound-ledger.js",
@@ -271,8 +271,8 @@
271
271
  },
272
272
  {
273
273
  "file": "src/channels/wechat-channel/outbound-sender.js",
274
- "beforeBytes": 21306,
275
- "afterBytes": 10998
274
+ "beforeBytes": 21342,
275
+ "afterBytes": 11027
276
276
  },
277
277
  {
278
278
  "file": "src/channels/wechat-channel/pacing.js",
@@ -1,7 +1,7 @@
1
- import W from"node:fs";import U from"node:path";import{WeChatChannelApiError as Re}from"./client.js";import{defaultWeChatChannelAttachmentDir as Fe,resolveVisibleWeChatChannelMedia as Ae}from"./media-resolver.js";import{updateWeChatChannelBindingLedger as Oe}from"./ledger.js";import{defaultWeChatChannelVectorStorePath as Le,loadWeChatChannelVectorStore as De,saveWeChatChannelVectorStore as Ke,upsertWeChatChannelVectorReferences as $e}from"./vector-store.js";import{normalizeWeChatChannelAttachmentAvailability as X,normalizeWeChatChannelMessageKind as ze}from"./core/schema.js";import{waitForWeChatChannelPacing as J,weChatChannelPacingDelayMs as Ve}from"./pacing.js";import{matchWeChatConversationFingerprints as qe}from"./fingerprint.js";import{normalizeWeChatAnchorText as v,weChatTextSimilarity as Z}from"./anchor.js";import{decideWeChatChannelActivityGate as je,normalizeWeChatChannelActivitySnapshot as Ge}from"./human-coordination.js";const He=3,Ye=5,Ue="wechat_login_required",Xe=5500;class N extends Error{reasonCode;stage;action;constructor(t){super(`user_active:${t.reasonCode}:${t.stage}:${t.action}`),this.name="WeChatChannelUserActivityAbort",this.reasonCode=t.reasonCode,this.stage=t.stage,this.action=t.action}}async function Tn(e){return await ct(e.helper,e.activityGuard,e.traceId).withLease("observe","observe-binding",async n=>Je({...e,helper:n}))}async function Je(e){const t=e.foregroundMode??"required";let n=await Ze(e,{foregroundMode:t});if(t!=="background"&&(n=await ve(e.helper,n,e.traceId)),t==="background"){const{capture:s,ocr:a}=await p({helper:e.helper,window:n,traceId:e.traceId}),c=B({capture:s,ocr:a,window:n});if(c)throw new Error(c);if(!O(a,s,e.binding.conversationDisplayName))throw new Error("conversation_not_visible_background");if(G({capture:s,ocr:a,binding:e.binding}))throw new Error("wechat_window_obstructed_background");return e.onObservationEvidence?.({window:n,capture:s,ocr:a}),se(e)?ce({...e,window:n,capture:s,ocr:a}):K({...e,window:n,capture:s,ocr:a})}const r=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!r.opened){const s=await oe({...e,fallback:n,requireTargetConversation:!1,force:!0});if(s.windowId!==n.windowId){n=await ve(e.helper,s,e.traceId);const a=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!a.opened)throw new Error(a.reason||r.reason||"conversation_not_opened")}else throw new Error(r.reason||"conversation_not_opened")}let{capture:i,ocr:o}=await p({helper:e.helper,window:n,traceId:e.traceId});if(G({capture:i,ocr:o,binding:e.binding})){n=await $t(e.helper,e.traceId);const s=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!s.opened)throw new Error(s.reason||"wechat_window_obstructed");if({capture:i,ocr:o}=await p({helper:e.helper,window:n,traceId:e.traceId}),G({capture:i,ocr:o,binding:e.binding}))throw new Error("wechat_window_obstructed")}return e.onObservationEvidence?.({window:n,capture:i,ocr:o}),se(e)?ce({...e,window:n,capture:i,ocr:o}):K({...e,window:n,capture:i,ocr:o})}async function Ze(e,t={}){const n=t.foregroundMode??e.foregroundMode??"required",r=await Dt(e.helper,e.traceId,{foreground:n});return n==="background"?r:oe({...e,fallback:r,requireTargetConversation:!1,force:t.forceVision})}const k=new Map;async function Bn(e){const t=await Q(e,"messageInputPoint");if(!t.messageInputPoint)throw new Error("wechat_message_input_not_found:vision_rect_missing");return t.messageInputPoint}async function Qe(e){const t=await Q(e,"searchInputPoint");if(!t.searchInputPoint)throw new Error("wechat_search_input_not_found:vision_rect_missing");return t.searchInputPoint}async function Q(e,t){const n=t==="searchInputPoint"?"wechat_search_input":"wechat_message_input";if(!e.api.classifyWindow)throw new Error(`${n}_detector_unavailable`);const r=e.window.windowId,i=tt(e.window),o=`${e.runtime.runtimeId}:${e.binding.bindingId}:${r||"unknown"}`,s=`${e.runtime.runtimeId}:window:${r||"unknown"}:${i}`,a=k.get(o)??k.get(s)??te(e,o)??te(e,s);if(a&&a.windowId===r&&a.boundsKey===i&&(!t||a[t]))return k.set(o,a),k.set(s,a),a;const c=e.screenshot??await F(e.helper,r,e.traceId,e.window.bounds),u=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:c.mimeType,dataBase64:c.dataBase64,width:c.width,height:c.height,windowId:r},traceId:e.traceId});if(u.windowKind!=="chat_main")throw new Error(`${n}_not_found:${u.windowKind||"unknown_window"}`);const w=ie(u.layout?.messageInputRect,c,e.window),l=ie(u.layout?.searchInputRect,c,e.window),d={windowId:r||"",boundsKey:i,messageInputPoint:w,searchInputPoint:l,updatedAt:new Date().toISOString()};return k.set(o,d),k.set(s,d),ne(e,o,d),ne(e,s,d),d}function ee(e){const t=e.workDir;return t?U.join(t,"wechat-channel",e.runtime.runtimeId,"vision-layout-point-cache.json"):null}function te(e,t){const n=ee(e);if(!n)return null;try{const r=JSON.parse(W.readFileSync(n,"utf8"));return et(r[t])}catch{return null}}function ne(e,t,n){const r=ee(e);if(r)try{let i={};try{i=JSON.parse(W.readFileSync(r,"utf8"))}catch{i={}}i[t]=n,W.mkdirSync(U.dirname(r),{recursive:!0}),W.writeFileSync(r,`${JSON.stringify(i,null,2)}
2
- `,"utf8")}catch{}}function et(e){if(!e||typeof e!="object")return null;const t=e,n=typeof t.windowId=="string"?t.windowId:"",r=typeof t.boundsKey=="string"?t.boundsKey:"";if(!r)return null;const i=re(t.messageInputPoint??t.point),o=re(t.searchInputPoint);return{windowId:n,boundsKey:r,messageInputPoint:i,searchInputPoint:o,...typeof t.updatedAt=="string"?{updatedAt:t.updatedAt}:{}}}function re(e){if(!e||typeof e!="object")return null;const t=e,n=Number(t.x),r=Number(t.y);return!Number.isFinite(n)||!Number.isFinite(r)?null:{x:Math.round(n),y:Math.round(r),coordinateSpace:"screen"}}function tt(e){const t=e.bounds;return[Math.round(Number(t?.x??0)),Math.round(Number(t?.y??0)),Math.round(Number(t?.width??0)),Math.round(Number(t?.height??0))].join(",")}function ie(e,t,n){const r=Number(e?.x),i=Number(e?.y),o=Number(e?.width),s=Number(e?.height);if(![r,i,o,s].every(Number.isFinite)||o<=0||s<=0)return null;const a=e?.coordinateSpace==="screen"?{x:r,y:i,width:o,height:s,coordinateSpace:"screen"}:{x:r/999*t.width,y:i/999*t.height,width:o/999*t.width,height:s/999*t.height,coordinateSpace:"screenshotPixel"},c=nt(a,t,n);return c?{x:Math.round(c.x),y:Math.round(c.y),coordinateSpace:"screen"}:null}function nt(e,t,n){const r=rt({x:e.x+e.width*.54,y:e.y+e.height*.55,coordinateSpace:e.coordinateSpace},t,n);return r?{x:r.x,y:r.y,coordinateSpace:"screen"}:null}function rt(e,t,n){if(![e.x,e.y].every(Number.isFinite))return null;if(e.coordinateSpace==="screen"||!n.bounds)return{x:e.x,y:e.y};const r=t.width&&n.bounds.width?t.width/n.bounds.width:1,i=t.height&&n.bounds.height?t.height/n.bounds.height:r,o=Math.max(0,(t.width-n.bounds.width*r)/2),s=Math.max(0,(t.height-n.bounds.height*i)/2);return{x:n.bounds.x+(e.x-o)/r,y:n.bounds.y+(e.y-s)/i}}async function oe(e){if(!e.api.classifyWindow)throw new Error("wechat_window_classifier_unavailable");const t=await e.helper.request("windows.list",{},e.traceId);m(t,"windows.list");const n=(t.result?.windows??[]).filter(q).filter(s=>s.visible!==!1&&s.minimized!==!0&&!!s.windowId),r=at(n.length?n:[e.fallback],e.fallback);if(!r.length)throw new Error("wechat_window_not_found");const i=[];for(const s of r)try{const a=await F(e.helper,s.windowId,e.traceId,s.bounds),c=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:a.mimeType,dataBase64:a.dataBase64,width:a.width,height:a.height,windowId:s.windowId},traceId:e.traceId});i.push({window:s,classification:c,score:st(c,e.requireTargetConversation===!0)})}catch(a){if(it(a))throw a;i.push({window:s,classification:null,errorSummary:a instanceof Error?a.message:String(a||"window classification failed"),score:-1})}const o=i.filter(s=>s.score>0).sort((s,a)=>a.score-s.score)[0];if(!o){const s=i.map(a=>({windowId:a.window.windowId,appName:a.window.appName,title:a.window.title,score:a.score,errorSummary:a.errorSummary,classification:a.classification?{windowKind:a.classification.windowKind,reasonCode:a.classification.reasonCode,confidence:a.classification.confidence,conversationTitle:a.classification.conversationTitle,isTargetConversation:a.classification.isTargetConversation}:null}));throw new Error(`wechat_chat_main_window_not_found: ${JSON.stringify(s)}`)}return o.window}function it(e){const t=ot(e);return t==="insufficient_credits"||t==="entitlement_required"||t==="manual_review_required"||t==="wechat_channel_network_failed"||t==="wechat_channel_invalid_response"}function ot(e){if(e instanceof Re||e&&typeof e=="object"&&typeof e.reasonCode=="string")return e.reasonCode.trim().toLowerCase();const t=e instanceof Error?e.message:String(e||"");return/classify-window (?:network )?failed:\s*([a-z][a-z0-9_]*)/i.exec(t)?.[1]?.trim().toLowerCase()||""}function at(e,t){const n=[],r=i=>{i?.windowId&&(n.some(o=>o.windowId===i.windowId)||n.push(i))};r(e.find(i=>i.windowId===t.windowId));for(const i of e)r(i);return n}function st(e,t){if(!e||e.windowKind!=="chat_main")return 0;const n=Number(e.confidence??0);return t&&e.isTargetConversation!==!0?0:100+(e.isTargetConversation?50:0)+Math.round(Math.max(0,Math.min(1,n))*100)}function ct(e,t,n){if(!t)return{helper:e,withLease:async(a,c,u)=>await u(e)};let r=null;const i=a=>{t.onEvent?.({...a,at:new Date().toISOString()})},o=async(a,c,u={})=>{if(r){const l=await e.request("automation.lease.status",{},n),d=l.result??{},f=l.ok&&d.interrupted?ae(d.interruptReason):l.ok?void 0:l.errorCode||"user_activity_unknown";if(i({phase:"lease-status",stage:a,action:c,ok:l.ok===!0&&!d.interrupted,...f?{reasonCode:f}:{}}),!l.ok)throw new N({reasonCode:l.errorCode||"user_activity_unknown",stage:a,action:c});if(d.active===!1||d.leaseId!==r||!d.interrupted)return;throw new N({reasonCode:ae(d.interruptReason),stage:a,action:c})}const w=Date.now()+lt(t.preflightIdleSettleTimeoutMs);for(;;){const l=await e.request("activity.snapshot",{},n);if(!l.ok)throw i({phase:"snapshot",stage:a,action:c,ok:!1,reasonCode:l.errorCode||"user_activity_unknown"}),new N({reasonCode:l.errorCode||"user_activity_unknown",stage:a,action:c});const d=je({snapshot:Ge(l.result),stage:a,policy:t.policy});if(i({phase:"snapshot",stage:a,action:c,ok:d.ok,...d.ok?{}:{reasonCode:d.reasonCode,waitMs:d.waitMs}}),d.ok)return;const f=new N({reasonCode:d.reasonCode,stage:a,action:c});if(!u.settle)throw f;const Y=w-Date.now();if(Y<=0)throw f;await j(Math.max(50,Math.min(d.waitMs,Y)))}},s={request:async(a,c,u)=>{const w=dt(a);w&&await o(w.stage,`${a}:before`);const l=await e.request(a,c,u);return w&&l.ok&&await o(w.stage,`${a}:after`),l}};return{helper:s,async withLease(a,c,u){if(await Ft(e,n),await o(a,`${c}:preflight`,{settle:!0}),t.useAutomationLease===!1)return await u(s);const w=await e.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`observe:${c}`,ttlMs:12e4},n);if(r=typeof w.result?.leaseId=="string"?w.result.leaseId:null,i({phase:"lease-acquire",stage:a,action:c,ok:w.ok===!0,...w.ok?{}:{reasonCode:w.errorCode||"user_activity_unknown"}}),!w.ok)throw r=null,new N({reasonCode:w.errorCode||"user_activity_unknown",stage:a,action:c});try{const l=await u(s);return await o(a,`${c}:complete`),l}finally{const l=r;if(r=null,l){const d=await e.request("automation.lease.release",{leaseId:l},n).catch(f=>({ok:!1,errorCode:"automation_lease_release_failed",errorSummary:f instanceof Error?f.message:String(f)}));i({phase:"lease-release",stage:a,action:c,ok:d.ok===!0,...d.ok?{}:{reasonCode:d.errorCode||"automation_lease_release_failed"}})}}}}}function dt(e){return e==="windows.ensureReady"||e==="windows.focus"||e==="wechat.searchConversation"?{stage:"open_conversation"}:e==="keyboard.shortcut"||e==="mouse.click"||e==="mouse.rightClick"||e==="mouse.scroll"||e==="clipboard.snapshot"||e==="clipboard.readAttachment"||e==="menu.pickItem"?{stage:"dangerous_action"}:null}function ae(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function lt(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:Xe}function se(e){return e.observePipeline==="edge-structure"?!0:e.observePipeline==="server-observe"?!1:!!e.api.structureWindow}async function K(e){const t=await _e(e),n=await e.api.observe(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height}],edgeOcrBlocks:e.ocr.blocks??[],visibleConversationFingerprints:e.ocr.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId}),r=await we({helper:e.helper,runtime:e.runtime,binding:e.binding,messages:n.observedMessages??[],workDir:e.workDir,attachmentsDir:e.attachmentsDir,window:e.window,screenshot:t,windowId:e.window.windowId,traceId:e.traceId,mediaAnchorText:e.mediaAnchorText});return Be(r,Te({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}))}async function ce(e){if(!e.api.structureWindow)throw new Error("wechat_structure_window_unavailable");const t=await _e(e);let n;try{n=await e.api.structureWindow(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height}],edgeOcrBlocks:e.ocr.blocks??[],visibleConversationFingerprints:e.ocr.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId})}catch(c){if(ut(c))return K(e);throw c}const r=vt(n.structuredMessages??n.observedMessages??[]),i=await wt({...e,messages:r,screenshot:t}),o=await we({helper:e.helper,runtime:e.runtime,binding:e.binding,messages:i.messages,workDir:e.workDir,attachmentsDir:e.attachmentsDir,window:e.window,screenshot:t,windowId:e.window.windowId,traceId:e.traceId,mediaAnchorText:e.mediaAnchorText}),s=Be(o,Te({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}));return e.localLedger?Oe({ledger:e.localLedger,bindingId:e.binding.bindingId,observedMessages:s,baselineOnly:e.baselineOnly,vectorReferences:i.vectorReferences}).newMessages:s}function ut(e){return e instanceof Error&&/\bedge_runtime_disabled\b/.test(e.message)}async function wt(e){const t=ht(e.messages);if(!t.length)return{messages:e.messages,vectorReferences:[]};const n=e.api.embedVisual?await mt({...e,seedBlocks:t}):t.filter(s=>h(s.vectorBase64)||h(s.signature));if(!n.length)return{messages:e.messages,vectorReferences:[]};const r=e.vectorStorePath??Le(e.workDir||process.cwd(),e.runtime.runtimeId),i=De(r,e.runtime.runtimeId),o=$e({store:i,bindingId:e.binding.bindingId,blocks:n});return o.length?(Ke(r,i),{messages:yt(e.messages,o),vectorReferences:o}):{messages:e.messages,vectorReferences:[]}}function ht(e){const t=[];for(const n of e)for(const[r,i]of(n.visualBlocks??[]).entries()){const o=h(i.blockId)||`${n.stableMessageKey}:visual-${r}`,s=h(i.blockKind)||n.kind||"visual";t.push({...i,stableMessageKey:n.stableMessageKey,blockId:o,blockKind:s,...i.bbox!==void 0?{bbox:i.bbox}:n.bbox!==void 0?{bbox:n.bbox}:{}})}return t}async function ft(e){if(!e.api.embedVisual)return[];const t=await e.api.embedVisual(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:e.screenshot.mimeType,dataBase64:e.screenshot.dataBase64,width:e.screenshot.width,height:e.screenshot.height}],visualBlocks:e.seedBlocks,traceId:e.traceId});return gt(t.visualBlocks??t.embeddedBlocks??[],e.seedBlocks)}async function mt(e){try{return await ft(e)}catch(t){if(bt(t))throw t;return[]}}function bt(e){return!e||typeof e!="object"?!1:e.reasonCode==="insufficient_credits"?!0:e instanceof Error&&/\binsufficient_credits\b/.test(e.message)}function gt(e,t){return e.map((n,r)=>{const i=t[r];return{...n,stableMessageKey:h(n.stableMessageKey)||h(i?.stableMessageKey),blockId:h(n.blockId)||h(i?.blockId),blockKind:h(n.blockKind)||h(i?.blockKind)||"visual",...n.bbox!==void 0?{bbox:n.bbox}:i?.bbox!==void 0?{bbox:i.bbox}:{}}}).filter(n=>h(n.stableMessageKey)&&h(n.blockId))}function yt(e,t){const n=new Map;for(const r of t){const i=n.get(r.stableMessageKey)??[];i.push(r),n.set(r.stableMessageKey,i)}return e.map(r=>{const i=n.get(r.stableMessageKey);return i?.length?{...r,visualBlocks:xt(r,i)}:r})}function xt(e,t){const r=(e.visualBlocks??[]).map((o,s)=>{const a=h(o.blockId)||`${e.stableMessageKey}:visual-${s}`,c=t.find(u=>u.blockId===a);return c?de(c,o):le(o)}),i=new Set(r.map(o=>o.blockId));for(const o of t)i.has(o.blockId)||r.push(de(o));return r}function de(e,t){return{...t?le(t):{},stableMessageKey:e.stableMessageKey,blockId:e.blockId,blockKind:e.blockKind,vectorStoreKey:e.vectorStoreKey,model:e.model,...e.modelVersion!==void 0?{modelVersion:e.modelVersion}:{},dims:e.dims,...e.signature?{signature:e.signature}:{},...e.bbox!==void 0?{bbox:e.bbox}:{}}}function le(e){const{vectorBase64:t,...n}=e;return n}function vt(e){return e.map((t,n)=>pt(t,n)).filter(t=>t!=null)}function pt(e,t){if(!b(e))return null;const n=ze(e.kind),r=It(e.senderRole),i=g(e.normalizedText),o=g(e.anchorText)??i??g(e.textExcerpt),s=h(e.stableMessageKey)||Ct({message:e,index:t,senderRole:r,kind:n,anchorText:o});return{stableMessageKey:s,senderRole:r,...g(e.senderName)!==null?{senderName:g(e.senderName)}:{},kind:n,...i!==null?{normalizedText:i}:{},...o!==null?{anchorText:o}:{},...S(e,"anchorMetadata")?{anchorMetadata:e.anchorMetadata}:{},...S(e,"neighborContext")?{neighborContext:e.neighborContext}:{},...g(e.textExcerpt)!==null?{textExcerpt:g(e.textExcerpt)}:{},...S(e,"bbox")?{bbox:e.bbox}:{},...S(e,"mediaMetadata")?{mediaMetadata:_t(e.mediaMetadata)}:{},...typeof e.isBaseline=="boolean"?{isBaseline:e.isBaseline}:{},...g(e.deliveryStatus)!==null?{deliveryStatus:g(e.deliveryStatus)??void 0}:{},...g(e.observedAt)!==null?{observedAt:g(e.observedAt)??void 0}:{},...Array.isArray(e.visualBlocks)?{visualBlocks:e.visualBlocks}:{},...o?{}:{anchorText:s}}}function Ct(e){const t=b(e.message.bbox)?JSON.stringify(e.message.bbox):"";return`structured-window:${[e.index,e.senderRole,e.kind,e.anchorText||h(e.message.textExcerpt)||"",t].join(":").slice(0,180)}`}function _t(e){if(!b(e))return e;const t={...e};return S(t,"availability")&&(t.availability=X(t.availability)),b(t.attachment)&&(t.attachment=ue(t.attachment)),Array.isArray(t.attachments)&&(t.attachments=t.attachments.map(n=>b(n)?ue(n):n)),t}function ue(e){const t={...e};return S(t,"availability")&&(t.availability=X(t.availability)),t}function It(e){return e==="self"||e==="contact"||e==="system"||e==="unknown"?e:"unknown"}async function we(e){if(e.binding.downloadMedia===!1)return e.messages;const t=e.messages.map((o,s)=>Et(o,e.screenshot,e.window,Bt(e.messages,s))).filter((o,s)=>kt(e.messages,s,e.mediaAnchorText)).filter(o=>o!=null);if(!t.length)return e.messages;const n=e.attachmentsDir??Fe(e.workDir||process.cwd(),e.runtime.runtimeId,e.binding.bindingId),r=await Ae({helper:e.helper,candidates:t,attachmentsDir:n,screenshot:e.screenshot,windowId:e.windowId,window:e.window,traceId:e.traceId,platform:e.runtime.policy.platform,stabilityCheck:async()=>{const o=await _({helper:e.helper,window:e.window,binding:e.binding,traceId:e.traceId});return o.ok?{ok:!0}:{ok:!1,reasonCode:o.reason}}});if(!r.length)return e.messages;const i=new Map(r.map(o=>[o.messageKey,o]));return e.messages.map(o=>{const s=i.get(o.stableMessageKey);return s?{...o,mediaMetadata:Pt(o.mediaMetadata,s.attachment,s.reasonCode,s.attemptReasonCodes,s.resolveTrace)}:o})}function kt(e,t,n){const r=fe(n);if(!r)return!0;const i=St(r),o=e.map((s,a)=>fe(Tt(s)).includes(r)?a:-1).filter(s=>s>=0);if(!o.length)return t===Mt(e,i);for(const s of o)if(t>=s&&t<=s+8||t===s-1&&!e.slice(s+1,Math.min(e.length,s+9)).some(he))return!0;return!1}function St(e){return e.includes("video")||e.includes("vide0")?"video":e.includes("image")||e.includes("photo")||e.includes("ph0t0")||e.includes("picture")?"image":e.includes("file")||e.includes("document")?"file":null}function Mt(e,t=null){for(let n=e.length-1;n>=0;n-=1)if(he(e[n]))return Nt(e[n],t)?n:-1;return-1}function he(e){if(!e)return!1;const t=String(e.kind||"").toLowerCase(),n=b(e.mediaMetadata)?e.mediaMetadata:{},r=b(n.attachment)?n.attachment:{};return me(t,n,r)}function Nt(e,t){if(!e||!t)return!0;const n=String(e.kind||"").toLowerCase(),r=b(e.mediaMetadata)?e.mediaMetadata:{},i=b(r.attachment)?r.attachment:{},o=String(i.type||"").toLowerCase(),s=String(i.mimeType||"").toLowerCase(),a=String(i.name||i.localPath||e.anchorText||e.textExcerpt||"").toLowerCase();return t==="video"?n.includes("video")||o==="video"||s.startsWith("video/")||/\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(a):t==="image"?/image|photo|picture/.test(n)||o==="image"||s.startsWith("image/")||/\.(png|jpe?g|gif|webp|heic|tiff?|bmp)$/i.test(a):/file|document/.test(n)||o==="file"||!/image|photo|picture|video/.test(n)&&o!=="image"&&o!=="video"&&!s.startsWith("image/")&&!s.startsWith("video/")}function Tt(e){if(!e)return"";const t=e;return[e.normalizedText,e.anchorText,e.textExcerpt,t.text].map(n=>String(n||"")).join(`
1
+ import R from"node:fs";import U from"node:path";import{WeChatChannelApiError as We}from"./client.js";import{defaultWeChatChannelAttachmentDir as Fe,resolveVisibleWeChatChannelMedia as Ae}from"./media-resolver.js";import{updateWeChatChannelBindingLedger as Oe}from"./ledger.js";import{defaultWeChatChannelVectorStorePath as Le,loadWeChatChannelVectorStore as De,saveWeChatChannelVectorStore as Ke,upsertWeChatChannelVectorReferences as $e}from"./vector-store.js";import{normalizeWeChatChannelAttachmentAvailability as X,normalizeWeChatChannelMessageKind as ze}from"./core/schema.js";import{waitForWeChatChannelPacing as J,weChatChannelPacingDelayMs as Ve}from"./pacing.js";import{matchWeChatConversationFingerprints as qe}from"./fingerprint.js";import{normalizeWeChatAnchorText as v,weChatTextSimilarity as Z}from"./anchor.js";import{decideWeChatChannelActivityGate as je,normalizeWeChatChannelActivitySnapshot as Ge}from"./human-coordination.js";const He=3,Ye=5,Ue="wechat_login_required",Xe=5500;class N extends Error{reasonCode;stage;action;constructor(t){super(`user_active:${t.reasonCode}:${t.stage}:${t.action}`),this.name="WeChatChannelUserActivityAbort",this.reasonCode=t.reasonCode,this.stage=t.stage,this.action=t.action}}async function Tn(e){return await ct(e.helper,e.activityGuard,e.traceId).withLease("observe","observe-binding",async n=>Je({...e,helper:n}))}async function Je(e){const t=e.foregroundMode??"required";let n=await Ze(e,{foregroundMode:t});if(t!=="background"&&(n=await ve(e.helper,n,e.traceId)),t==="background"){const{capture:s,ocr:a}=await p({helper:e.helper,window:n,traceId:e.traceId}),c=B({capture:s,ocr:a,window:n});if(c)throw new Error(c);if(!O(a,s,e.binding.conversationDisplayName))throw new Error("conversation_not_visible_background");if(G({capture:s,ocr:a,binding:e.binding}))throw new Error("wechat_window_obstructed_background");return e.onObservationEvidence?.({window:n,capture:s,ocr:a}),se(e)?ce({...e,window:n,capture:s,ocr:a}):K({...e,window:n,capture:s,ocr:a})}const r=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!r.opened){const s=await oe({...e,fallback:n,requireTargetConversation:!1,force:!0});if(s.windowId!==n.windowId){n=await ve(e.helper,s,e.traceId);const a=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!a.opened)throw new Error(a.reason||r.reason||"conversation_not_opened")}else throw new Error(r.reason||"conversation_not_opened")}let{capture:i,ocr:o}=await p({helper:e.helper,window:n,traceId:e.traceId});if(G({capture:i,ocr:o,binding:e.binding})){n=await $t(e.helper,e.traceId);const s=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!s.opened)throw new Error(s.reason||"wechat_window_obstructed");if({capture:i,ocr:o}=await p({helper:e.helper,window:n,traceId:e.traceId}),G({capture:i,ocr:o,binding:e.binding}))throw new Error("wechat_window_obstructed")}return e.onObservationEvidence?.({window:n,capture:i,ocr:o}),se(e)?ce({...e,window:n,capture:i,ocr:o}):K({...e,window:n,capture:i,ocr:o})}async function Ze(e,t={}){const n=t.foregroundMode??e.foregroundMode??"required",r=await Dt(e.helper,e.traceId,{foreground:n});return n==="background"?r:oe({...e,fallback:r,requireTargetConversation:!1,force:t.forceVision})}const k=new Map;async function Bn(e){const t=await Q(e,"messageInputPoint");if(!t.messageInputPoint)throw new Error("wechat_message_input_not_found:vision_rect_missing");return t.messageInputPoint}async function Qe(e){const t=await Q(e,"searchInputPoint");if(!t.searchInputPoint)throw new Error("wechat_search_input_not_found:vision_rect_missing");return t.searchInputPoint}async function Q(e,t){const n=t==="searchInputPoint"?"wechat_search_input":"wechat_message_input";if(!e.api.classifyWindow)throw new Error(`${n}_detector_unavailable`);const r=e.window.windowId,i=tt(e.window),o=`${e.runtime.runtimeId}:${e.binding.bindingId}:${r||"unknown"}`,s=`${e.runtime.runtimeId}:window:${r||"unknown"}:${i}`,a=k.get(o)??k.get(s)??te(e,o)??te(e,s);if(a&&a.windowId===r&&a.boundsKey===i&&(!t||a[t]))return k.set(o,a),k.set(s,a),a;const c=e.screenshot??await F(e.helper,r,e.traceId,e.window.bounds),l=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:c.mimeType,dataBase64:c.dataBase64,width:c.width,height:c.height,windowId:r},traceId:e.traceId});if(l.windowKind!=="chat_main")throw new Error(`${n}_not_found:${l.windowKind||"unknown_window"}`);const w=ie(l.layout?.messageInputRect,c,e.window,"message-input"),u=ie(l.layout?.searchInputRect,c,e.window,"search-input"),d={windowId:r||"",boundsKey:i,messageInputPoint:w,searchInputPoint:u,updatedAt:new Date().toISOString()};return k.set(o,d),k.set(s,d),ne(e,o,d),ne(e,s,d),d}function ee(e){const t=e.workDir;return t?U.join(t,"wechat-channel",e.runtime.runtimeId,"vision-layout-point-cache.json"):null}function te(e,t){const n=ee(e);if(!n)return null;try{const r=JSON.parse(R.readFileSync(n,"utf8"));return et(r[t])}catch{return null}}function ne(e,t,n){const r=ee(e);if(r)try{let i={};try{i=JSON.parse(R.readFileSync(r,"utf8"))}catch{i={}}i[t]=n,R.mkdirSync(U.dirname(r),{recursive:!0}),R.writeFileSync(r,`${JSON.stringify(i,null,2)}
2
+ `,"utf8")}catch{}}function et(e){if(!e||typeof e!="object")return null;const t=e,n=typeof t.windowId=="string"?t.windowId:"",r=typeof t.boundsKey=="string"?t.boundsKey:"";if(!r)return null;const i=re(t.messageInputPoint??t.point),o=re(t.searchInputPoint);return{windowId:n,boundsKey:r,messageInputPoint:i,searchInputPoint:o,...typeof t.updatedAt=="string"?{updatedAt:t.updatedAt}:{}}}function re(e){if(!e||typeof e!="object")return null;const t=e,n=Number(t.x),r=Number(t.y);return!Number.isFinite(n)||!Number.isFinite(r)?null:{x:Math.round(n),y:Math.round(r),coordinateSpace:"screen"}}function tt(e){const t=e.bounds;return[Math.round(Number(t?.x??0)),Math.round(Number(t?.y??0)),Math.round(Number(t?.width??0)),Math.round(Number(t?.height??0))].join(",")}function ie(e,t,n,r="message-input"){const i=Number(e?.x),o=Number(e?.y),s=Number(e?.width),a=Number(e?.height);if(![i,o,s,a].every(Number.isFinite)||s<=0||a<=0)return null;const c=e?.coordinateSpace==="screen"?{x:i,y:o,width:s,height:a,coordinateSpace:"screen"}:{x:i/999*t.width,y:o/999*t.height,width:s/999*t.width,height:a/999*t.height,coordinateSpace:"screenshotPixel"},l=nt(c,t,n,r);return l?{x:Math.round(l.x),y:Math.round(l.y),coordinateSpace:"screen"}:null}function nt(e,t,n,r="message-input"){const i=r==="message-input"?.28:.55,o=rt({x:e.x+e.width*.54,y:e.y+e.height*i,coordinateSpace:e.coordinateSpace},t,n);return o?{x:o.x,y:o.y,coordinateSpace:"screen"}:null}function rt(e,t,n){if(![e.x,e.y].every(Number.isFinite))return null;if(e.coordinateSpace==="screen"||!n.bounds)return{x:e.x,y:e.y};const r=t.width&&n.bounds.width?t.width/n.bounds.width:1,i=t.height&&n.bounds.height?t.height/n.bounds.height:r,o=Math.max(0,(t.width-n.bounds.width*r)/2),s=Math.max(0,(t.height-n.bounds.height*i)/2);return{x:n.bounds.x+(e.x-o)/r,y:n.bounds.y+(e.y-s)/i}}async function oe(e){if(!e.api.classifyWindow)throw new Error("wechat_window_classifier_unavailable");const t=await e.helper.request("windows.list",{},e.traceId);m(t,"windows.list");const n=(t.result?.windows??[]).filter(q).filter(s=>s.visible!==!1&&s.minimized!==!0&&!!s.windowId),r=at(n.length?n:[e.fallback],e.fallback);if(!r.length)throw new Error("wechat_window_not_found");const i=[];for(const s of r)try{const a=await F(e.helper,s.windowId,e.traceId,s.bounds),c=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:a.mimeType,dataBase64:a.dataBase64,width:a.width,height:a.height,windowId:s.windowId},traceId:e.traceId});i.push({window:s,classification:c,score:st(c,e.requireTargetConversation===!0)})}catch(a){if(it(a))throw a;i.push({window:s,classification:null,errorSummary:a instanceof Error?a.message:String(a||"window classification failed"),score:-1})}const o=i.filter(s=>s.score>0).sort((s,a)=>a.score-s.score)[0];if(!o){const s=i.map(a=>({windowId:a.window.windowId,appName:a.window.appName,title:a.window.title,score:a.score,errorSummary:a.errorSummary,classification:a.classification?{windowKind:a.classification.windowKind,reasonCode:a.classification.reasonCode,confidence:a.classification.confidence,conversationTitle:a.classification.conversationTitle,isTargetConversation:a.classification.isTargetConversation}:null}));throw new Error(`wechat_chat_main_window_not_found: ${JSON.stringify(s)}`)}return o.window}function it(e){const t=ot(e);return t==="insufficient_credits"||t==="entitlement_required"||t==="manual_review_required"||t==="wechat_channel_network_failed"||t==="wechat_channel_invalid_response"}function ot(e){if(e instanceof We||e&&typeof e=="object"&&typeof e.reasonCode=="string")return e.reasonCode.trim().toLowerCase();const t=e instanceof Error?e.message:String(e||"");return/classify-window (?:network )?failed:\s*([a-z][a-z0-9_]*)/i.exec(t)?.[1]?.trim().toLowerCase()||""}function at(e,t){const n=[],r=i=>{i?.windowId&&(n.some(o=>o.windowId===i.windowId)||n.push(i))};r(e.find(i=>i.windowId===t.windowId));for(const i of e)r(i);return n}function st(e,t){if(!e||e.windowKind!=="chat_main")return 0;const n=Number(e.confidence??0);return t&&e.isTargetConversation!==!0?0:100+(e.isTargetConversation?50:0)+Math.round(Math.max(0,Math.min(1,n))*100)}function ct(e,t,n){if(!t)return{helper:e,withLease:async(a,c,l)=>await l(e)};let r=null;const i=a=>{t.onEvent?.({...a,at:new Date().toISOString()})},o=async(a,c,l={})=>{if(r){const u=await e.request("automation.lease.status",{},n),d=u.result??{},f=u.ok&&d.interrupted?ae(d.interruptReason):u.ok?void 0:u.errorCode||"user_activity_unknown";if(i({phase:"lease-status",stage:a,action:c,ok:u.ok===!0&&!d.interrupted,...f?{reasonCode:f}:{}}),!u.ok)throw new N({reasonCode:u.errorCode||"user_activity_unknown",stage:a,action:c});if(d.active===!1||d.leaseId!==r||!d.interrupted)return;throw new N({reasonCode:ae(d.interruptReason),stage:a,action:c})}const w=Date.now()+lt(t.preflightIdleSettleTimeoutMs);for(;;){const u=await e.request("activity.snapshot",{},n);if(!u.ok)throw i({phase:"snapshot",stage:a,action:c,ok:!1,reasonCode:u.errorCode||"user_activity_unknown"}),new N({reasonCode:u.errorCode||"user_activity_unknown",stage:a,action:c});const d=je({snapshot:Ge(u.result),stage:a,policy:t.policy});if(i({phase:"snapshot",stage:a,action:c,ok:d.ok,...d.ok?{}:{reasonCode:d.reasonCode,waitMs:d.waitMs}}),d.ok)return;const f=new N({reasonCode:d.reasonCode,stage:a,action:c});if(!l.settle)throw f;const Y=w-Date.now();if(Y<=0)throw f;await j(Math.max(50,Math.min(d.waitMs,Y)))}},s={request:async(a,c,l)=>{const w=dt(a);w&&await o(w.stage,`${a}:before`);const u=await e.request(a,c,l);return w&&u.ok&&await o(w.stage,`${a}:after`),u}};return{helper:s,async withLease(a,c,l){if(await Ft(e,n),await o(a,`${c}:preflight`,{settle:!0}),t.useAutomationLease===!1)return await l(s);const w=await e.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`observe:${c}`,ttlMs:12e4},n);if(r=typeof w.result?.leaseId=="string"?w.result.leaseId:null,i({phase:"lease-acquire",stage:a,action:c,ok:w.ok===!0,...w.ok?{}:{reasonCode:w.errorCode||"user_activity_unknown"}}),!w.ok)throw r=null,new N({reasonCode:w.errorCode||"user_activity_unknown",stage:a,action:c});try{const u=await l(s);return await o(a,`${c}:complete`),u}finally{const u=r;if(r=null,u){const d=await e.request("automation.lease.release",{leaseId:u},n).catch(f=>({ok:!1,errorCode:"automation_lease_release_failed",errorSummary:f instanceof Error?f.message:String(f)}));i({phase:"lease-release",stage:a,action:c,ok:d.ok===!0,...d.ok?{}:{reasonCode:d.errorCode||"automation_lease_release_failed"}})}}}}}function dt(e){return e==="windows.ensureReady"||e==="windows.focus"||e==="wechat.searchConversation"?{stage:"open_conversation"}:e==="keyboard.shortcut"||e==="mouse.click"||e==="mouse.rightClick"||e==="mouse.scroll"||e==="clipboard.snapshot"||e==="clipboard.readAttachment"||e==="menu.pickItem"?{stage:"dangerous_action"}:null}function ae(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function lt(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:Xe}function se(e){return e.observePipeline==="edge-structure"?!0:e.observePipeline==="server-observe"?!1:!!e.api.structureWindow}async function K(e){const t=await _e(e),n=await e.api.observe(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height}],edgeOcrBlocks:e.ocr.blocks??[],visibleConversationFingerprints:e.ocr.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId}),r=await we({helper:e.helper,runtime:e.runtime,binding:e.binding,messages:n.observedMessages??[],workDir:e.workDir,attachmentsDir:e.attachmentsDir,window:e.window,screenshot:t,windowId:e.window.windowId,traceId:e.traceId,mediaAnchorText:e.mediaAnchorText});return Be(r,Te({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}))}async function ce(e){if(!e.api.structureWindow)throw new Error("wechat_structure_window_unavailable");const t=await _e(e);let n;try{n=await e.api.structureWindow(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height}],edgeOcrBlocks:e.ocr.blocks??[],visibleConversationFingerprints:e.ocr.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId})}catch(c){if(ut(c))return K(e);throw c}const r=vt(n.structuredMessages??n.observedMessages??[]),i=await wt({...e,messages:r,screenshot:t}),o=await we({helper:e.helper,runtime:e.runtime,binding:e.binding,messages:i.messages,workDir:e.workDir,attachmentsDir:e.attachmentsDir,window:e.window,screenshot:t,windowId:e.window.windowId,traceId:e.traceId,mediaAnchorText:e.mediaAnchorText}),s=Be(o,Te({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}));return e.localLedger?Oe({ledger:e.localLedger,bindingId:e.binding.bindingId,observedMessages:s,baselineOnly:e.baselineOnly,vectorReferences:i.vectorReferences}).newMessages:s}function ut(e){return e instanceof Error&&/\bedge_runtime_disabled\b/.test(e.message)}async function wt(e){const t=ht(e.messages);if(!t.length)return{messages:e.messages,vectorReferences:[]};const n=e.api.embedVisual?await mt({...e,seedBlocks:t}):t.filter(s=>h(s.vectorBase64)||h(s.signature));if(!n.length)return{messages:e.messages,vectorReferences:[]};const r=e.vectorStorePath??Le(e.workDir||process.cwd(),e.runtime.runtimeId),i=De(r,e.runtime.runtimeId),o=$e({store:i,bindingId:e.binding.bindingId,blocks:n});return o.length?(Ke(r,i),{messages:yt(e.messages,o),vectorReferences:o}):{messages:e.messages,vectorReferences:[]}}function ht(e){const t=[];for(const n of e)for(const[r,i]of(n.visualBlocks??[]).entries()){const o=h(i.blockId)||`${n.stableMessageKey}:visual-${r}`,s=h(i.blockKind)||n.kind||"visual";t.push({...i,stableMessageKey:n.stableMessageKey,blockId:o,blockKind:s,...i.bbox!==void 0?{bbox:i.bbox}:n.bbox!==void 0?{bbox:n.bbox}:{}})}return t}async function ft(e){if(!e.api.embedVisual)return[];const t=await e.api.embedVisual(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:e.screenshot.mimeType,dataBase64:e.screenshot.dataBase64,width:e.screenshot.width,height:e.screenshot.height}],visualBlocks:e.seedBlocks,traceId:e.traceId});return gt(t.visualBlocks??t.embeddedBlocks??[],e.seedBlocks)}async function mt(e){try{return await ft(e)}catch(t){if(bt(t))throw t;return[]}}function bt(e){return!e||typeof e!="object"?!1:e.reasonCode==="insufficient_credits"?!0:e instanceof Error&&/\binsufficient_credits\b/.test(e.message)}function gt(e,t){return e.map((n,r)=>{const i=t[r];return{...n,stableMessageKey:h(n.stableMessageKey)||h(i?.stableMessageKey),blockId:h(n.blockId)||h(i?.blockId),blockKind:h(n.blockKind)||h(i?.blockKind)||"visual",...n.bbox!==void 0?{bbox:n.bbox}:i?.bbox!==void 0?{bbox:i.bbox}:{}}}).filter(n=>h(n.stableMessageKey)&&h(n.blockId))}function yt(e,t){const n=new Map;for(const r of t){const i=n.get(r.stableMessageKey)??[];i.push(r),n.set(r.stableMessageKey,i)}return e.map(r=>{const i=n.get(r.stableMessageKey);return i?.length?{...r,visualBlocks:xt(r,i)}:r})}function xt(e,t){const r=(e.visualBlocks??[]).map((o,s)=>{const a=h(o.blockId)||`${e.stableMessageKey}:visual-${s}`,c=t.find(l=>l.blockId===a);return c?de(c,o):le(o)}),i=new Set(r.map(o=>o.blockId));for(const o of t)i.has(o.blockId)||r.push(de(o));return r}function de(e,t){return{...t?le(t):{},stableMessageKey:e.stableMessageKey,blockId:e.blockId,blockKind:e.blockKind,vectorStoreKey:e.vectorStoreKey,model:e.model,...e.modelVersion!==void 0?{modelVersion:e.modelVersion}:{},dims:e.dims,...e.signature?{signature:e.signature}:{},...e.bbox!==void 0?{bbox:e.bbox}:{}}}function le(e){const{vectorBase64:t,...n}=e;return n}function vt(e){return e.map((t,n)=>pt(t,n)).filter(t=>t!=null)}function pt(e,t){if(!b(e))return null;const n=ze(e.kind),r=It(e.senderRole),i=g(e.normalizedText),o=g(e.anchorText)??i??g(e.textExcerpt),s=h(e.stableMessageKey)||Ct({message:e,index:t,senderRole:r,kind:n,anchorText:o});return{stableMessageKey:s,senderRole:r,...g(e.senderName)!==null?{senderName:g(e.senderName)}:{},kind:n,...i!==null?{normalizedText:i}:{},...o!==null?{anchorText:o}:{},...S(e,"anchorMetadata")?{anchorMetadata:e.anchorMetadata}:{},...S(e,"neighborContext")?{neighborContext:e.neighborContext}:{},...g(e.textExcerpt)!==null?{textExcerpt:g(e.textExcerpt)}:{},...S(e,"bbox")?{bbox:e.bbox}:{},...S(e,"mediaMetadata")?{mediaMetadata:_t(e.mediaMetadata)}:{},...typeof e.isBaseline=="boolean"?{isBaseline:e.isBaseline}:{},...g(e.deliveryStatus)!==null?{deliveryStatus:g(e.deliveryStatus)??void 0}:{},...g(e.observedAt)!==null?{observedAt:g(e.observedAt)??void 0}:{},...Array.isArray(e.visualBlocks)?{visualBlocks:e.visualBlocks}:{},...o?{}:{anchorText:s}}}function Ct(e){const t=b(e.message.bbox)?JSON.stringify(e.message.bbox):"";return`structured-window:${[e.index,e.senderRole,e.kind,e.anchorText||h(e.message.textExcerpt)||"",t].join(":").slice(0,180)}`}function _t(e){if(!b(e))return e;const t={...e};return S(t,"availability")&&(t.availability=X(t.availability)),b(t.attachment)&&(t.attachment=ue(t.attachment)),Array.isArray(t.attachments)&&(t.attachments=t.attachments.map(n=>b(n)?ue(n):n)),t}function ue(e){const t={...e};return S(t,"availability")&&(t.availability=X(t.availability)),t}function It(e){return e==="self"||e==="contact"||e==="system"||e==="unknown"?e:"unknown"}async function we(e){if(e.binding.downloadMedia===!1)return e.messages;const t=e.messages.map((o,s)=>Et(o,e.screenshot,e.window,Bt(e.messages,s))).filter((o,s)=>kt(e.messages,s,e.mediaAnchorText)).filter(o=>o!=null);if(!t.length)return e.messages;const n=e.attachmentsDir??Fe(e.workDir||process.cwd(),e.runtime.runtimeId,e.binding.bindingId),r=await Ae({helper:e.helper,candidates:t,attachmentsDir:n,screenshot:e.screenshot,windowId:e.windowId,window:e.window,traceId:e.traceId,platform:e.runtime.policy.platform,stabilityCheck:async()=>{const o=await _({helper:e.helper,window:e.window,binding:e.binding,traceId:e.traceId});return o.ok?{ok:!0}:{ok:!1,reasonCode:o.reason}}});if(!r.length)return e.messages;const i=new Map(r.map(o=>[o.messageKey,o]));return e.messages.map(o=>{const s=i.get(o.stableMessageKey);return s?{...o,mediaMetadata:Pt(o.mediaMetadata,s.attachment,s.reasonCode,s.attemptReasonCodes,s.resolveTrace)}:o})}function kt(e,t,n){const r=fe(n);if(!r)return!0;const i=St(r),o=e.map((s,a)=>fe(Tt(s)).includes(r)?a:-1).filter(s=>s>=0);if(!o.length)return t===Mt(e,i);for(const s of o)if(t>=s&&t<=s+8||t===s-1&&!e.slice(s+1,Math.min(e.length,s+9)).some(he))return!0;return!1}function St(e){return e.includes("video")||e.includes("vide0")?"video":e.includes("image")||e.includes("photo")||e.includes("ph0t0")||e.includes("picture")?"image":e.includes("file")||e.includes("document")?"file":null}function Mt(e,t=null){for(let n=e.length-1;n>=0;n-=1)if(he(e[n]))return Nt(e[n],t)?n:-1;return-1}function he(e){if(!e)return!1;const t=String(e.kind||"").toLowerCase(),n=b(e.mediaMetadata)?e.mediaMetadata:{},r=b(n.attachment)?n.attachment:{};return me(t,n,r)}function Nt(e,t){if(!e||!t)return!0;const n=String(e.kind||"").toLowerCase(),r=b(e.mediaMetadata)?e.mediaMetadata:{},i=b(r.attachment)?r.attachment:{},o=String(i.type||"").toLowerCase(),s=String(i.mimeType||"").toLowerCase(),a=String(i.name||i.localPath||e.anchorText||e.textExcerpt||"").toLowerCase();return t==="video"?n.includes("video")||o==="video"||s.startsWith("video/")||/\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(a):t==="image"?/image|photo|picture/.test(n)||o==="image"||s.startsWith("image/")||/\.(png|jpe?g|gif|webp|heic|tiff?|bmp)$/i.test(a):/file|document/.test(n)||o==="file"||!/image|photo|picture|video/.test(n)&&o!=="image"&&o!=="video"&&!s.startsWith("image/")&&!s.startsWith("video/")}function Tt(e){if(!e)return"";const t=e;return[e.normalizedText,e.anchorText,e.textExcerpt,t.text].map(n=>String(n||"")).join(`
3
3
  `)}function fe(e){return String(e||"").normalize("NFKC").replace(/[o]/giu,"0").replace(/[^\p{L}\p{N}]/gu,"").toLowerCase()}function Bt(e,t){return[e[t-1],e[t],e[t+1]].map(r=>r&&(r.normalizedText||r.anchorText||r.textExcerpt)||"").map(r=>String(r||"").trim()).filter(Boolean).join(`
4
- `)||null}function Et(e,t,n,r){const i=String(e.kind||"").toLowerCase(),o=b(e.mediaMetadata)?e.mediaMetadata:{},s=b(o.attachment)?o.attachment:{},a=h(s.availability)||h(o.availability),c=h(s.localPath)||h(o.localPath);if(a==="edge-local"&&c||!me(i,o,s))return null;const u=R(e.bbox)??R(o.bbox)??R(o.downloadActionBbox),w=R(o.downloadActionBbox),l=be(u,t,n),d=Rt(u,t,n),f=be(w,t,n);return{messageKey:e.stableMessageKey,kind:h(s.type)||h(s.kind)||h(o.messageType)||i,fileName:h(s.name)||h(s.fileName)||h(o.fileName)||null,mimeType:h(s.mimeType)||h(o.mimeType)||null,size:M(s.size)??M(o.size),mediaStatus:Wt(o,s),observedAt:e.observedAt??null,contextText:r??e.normalizedText??e.anchorText??e.textExcerpt??null,...l?{bbox:l}:{},...d?{screenshotBbox:d}:{},...f?{downloadActionBbox:f}:{}}}function Pt(e,t,n,r,i){const o=b(e)?{...e}:{};return{...o,availability:b(t)?t.availability:o.availability,mediaStatus:b(t)&&t.availability==="edge-local"?"downloaded":o.mediaStatus,attachment:t,edgeResolveReasonCode:n,...r?.length?{edgeResolveAttempts:r}:{},...i?{edgeResolveTrace:i}:{}}}function Wt(e,t){const n=h(e.mediaStatus);if(n==="not_downloaded")return"not_downloaded";if(n==="downloaded"||n==="available")return"available";const r=h(t.availability)||h(e.availability);return r==="pending-download"?"not_downloaded":r==="metadata-only"?"metadata_only":n||null}function me(e,t,n){const r=`${e} ${h(t.messageType)} ${h(n.type)} ${h(n.kind)}`.toLowerCase();return/image|photo|video|file|document/.test(r)}function R(e){if(!b(e))return null;const t=M(e.x),n=M(e.y),r=M(e.width),i=M(e.height);return t==null||n==null||r==null||i==null?null:{x:t,y:n,width:r,height:i,...typeof e.coordinateSpace=="string"?{coordinateSpace:e.coordinateSpace}:{}}}function be(e,t,n){if(!e)return null;if(e.coordinateSpace==="screen")return e;const r=L(e,t,n);if(!r)return e;const i=n.bounds;if(!i?.width||!i?.height)return{...e,x:r.x-e.width/2,y:r.y-e.height/2,coordinateSpace:"screen"};const o=i.width/t.width,s=i.height/t.height,a=r.x,c=r.y;return{x:a-e.width*o/2,y:c-e.height*s/2,width:e.width*o,height:e.height*s,coordinateSpace:"screen"}}function Rt(e,t,n){if(!e)return null;if(e.coordinateSpace!=="screen")return{...e,coordinateSpace:"screenshotPixel"};const r=n.bounds;if(!r?.width||!r?.height)return null;const i=t.width/r.width,o=t.height/r.height;return{x:(e.x-r.x)*i,y:(e.y-r.y)*o,width:e.width*i,height:e.height*o,coordinateSpace:"screenshotPixel"}}function b(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function S(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function h(e){return typeof e=="string"?e.trim():""}function g(e){return h(e)||null}function M(e){const t=Number(e);return Number.isFinite(t)?t:null}async function En(e,t){await ye(e,t)}async function Ft(e,t){await ge(e,t)}async function ge(e,t){const n=await e.request("permissions.check",{},t);m(n,"permissions.check");const r=n.result??{},i=await At(e,r,t);if(i==="screen-recording")throw new Error("permission_screen_recording_missing");if(i==="accessibility")throw new Error("permission_accessibility_missing");if(i==="input-monitoring")throw new Error("permission_input_monitoring_missing");if(r.automation===!1)throw new Error("permission_automation_missing");return r}async function ye(e,t,n={}){const r=await ge(e,t);if(r.wechatRunning===!1)throw new Error("wechat_not_running");if(Kt(r))throw new Error("windows_visible_desktop_unavailable");if(r.dpiMappingAvailable===!1||r.displayTopologySupported===!1)throw new Error("dpi_mapping_failed");if(r.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(r.wechatWindowAvailable===!1&&String(r.platform??"").toLowerCase()!=="win32"&&n.allowUnavailableWindow!==!0)throw new Error("wechat_window_unavailable");return r}async function At(e,t,n){const r=Ot(t);if(!r||process.platform!=="darwin")return r;const i=Lt(r);try{await e.request(i,{},n)}catch{}return r}function Ot(e){return e.screenRecording===!1?"screen-recording":e.accessibility===!1?"accessibility":e.inputMonitoring===!1?"input-monitoring":null}function Lt(e){return e==="screen-recording"?"permissions.requestScreenRecording":e==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring"}async function Dt(e,t,n={}){const i=(n.foreground??"required")!=="background",o=await ye(e,t,{allowUnavailableWindow:i});if(String(o.platform??"").toLowerCase()==="win32"){const c=await e.request("windows.ensureReady",{activate:i,allowRecovery:!1,allowLaunch:!1},t);m(c,"windows.ensureReady");const u=c.result;if(!u?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return u}const s=await e.request("windows.ensureReady",{restore:i,focus:i},t);m(s,"windows.ensureReady");const a=s.result;if(!a?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return a}function Kt(e){return e.windowsVisibleDesktopAvailable===!1||e.rdpVisibleDesktopAvailable===!1||e.desktopSessionVisible===!1||e.screenLocked===!0||e.rdpDisconnected===!0}function xe(e){const t=e.filter(q),n=t.filter(i=>i.visible!==!1&&i.minimized!==!0);return(n.length?n:t)[0]??null}async function Pn(e,t){let n=await e.request("windows.list",{},t);m(n,"windows.list");let r=n.result?.windows??[],i=xe(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return m(o,"windows.focus"),await pe(e,i,t)}async function ve(e,t,n){if(!t.windowId)throw new Error("wechat_window_not_found");const r=await e.request("windows.focus",{windowId:t.windowId},n);return m(r,"windows.focus"),t}async function $t(e,t){const n=await e.request("windows.list",{},t);m(n,"windows.list");const r=n.result?.windows??[],i=xe(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return m(o,"windows.focus"),await pe(e,i,t)}async function pe(e,t,n){let r;try{r=await e.request("windows.list",{},n)}catch{return t}if(!r.ok)return t;const i=(r.result?.windows??[]).filter(q);return i.find(o=>o.windowId===t.windowId)??i[0]??t}async function $(e){const{capture:t,ocr:n}=e.observation??await p(e),r=B({capture:t,ocr:n,window:e.window});if(r)return{opened:!1,reason:r};const i=qe({visibleItems:Zt(n,t,e.allowOcrTitleRows!==!1),targets:[{bindingId:e.binding.bindingId,conversationDisplayName:e.binding.conversationDisplayName}]})[0];if(!i)return{opened:!1,reason:"conversation_not_visible"};const o=bn(i.item.bbox,t,e.window);if(!o)return{opened:!1,reason:"conversation_bbox_missing"};const s=await e.helper.request("mouse.click",{x:o.x,y:o.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return m(s,"mouse.click"),{opened:!0,reason:i.reason}}async function z(e){let t={opened:!1,reason:"conversation_not_opened"};for(let r=0;r<He;r+=1){if(t=await zt(e),t.opened||t.reason!=="conversation_title_not_confirmed")return t;await C(e,"open-retry",`retry:${r}`)}const n=await Ce(e);return n.opened?{opened:!0,reason:`${n.reason}:final-visible-recovery`}:t}async function zt(e){const t=await p(e),n=B({capture:t.capture,ocr:t.ocr,window:e.window});if(n)return{opened:!1,reason:n};let r=!1;if(O(t.ocr,t.capture,e.binding.conversationDisplayName)){e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId,observation:t});const l=await Vt(e,t);return l.ok?{opened:!0,reason:"current-conversation-title-confirmed"}:{opened:!1,reason:l.reason}}if(!r){const l=await $({...e,observation:t});if(l.opened){if(await C(e,"open-click-settle","visible-initial"),(await _(e)).ok)return{opened:!0,reason:l.reason};const f=await Ce(e);if(f.opened)return f}}const i=await Ut(e,t.capture);if(!i.ok)return{opened:!1,reason:i.reason};const o=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??A(e,"search-input-settle","search-input"),searchPoint:i.point},e.traceId);m(o,"wechat.searchConversation");const s=await qt(e);if(s.opened){await C(e,"open-click-settle","search-result-click");const l=await _(e);return l.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:s.reason}):{opened:!1,reason:l.reason}}let a=s.observation;const c=y(e.binding.conversationDisplayName)&&s.reason==="search_result_not_visible";if(!y(e.binding.conversationDisplayName)){await Jt(e.helper,e.traceId),await C(e,"open-click-settle","search-return");const l=await _(e);if(l.ok)return e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:l.reason};const d=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??A(e,"search-input-settle","search-input-retry-after-return"),searchPoint:i.point},e.traceId);m(d,"wechat.searchConversation"),a=void 0}const u=await $({...e,...a?{observation:a}:{},allowOcrTitleRows:!c});if(!u.opened)return u;await C(e,"open-click-settle","visible-final");const w=await _(e);return w.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:u.reason}):{opened:!1,reason:w.reason}}async function Vt(e,t){const n=t??await p(e);if(!rn(n.ocr))return{ok:!0};const r=await e.helper.request("keyboard.shortcut",{key:"escape",modifiers:[]},e.traceId);m(r,"keyboard.shortcut"),await C(e,"open-click-settle","escape-after-title-confirmed");const i=await _(e);return i.ok?{ok:!0}:{ok:!1,reason:`search_overlay_dismiss_failed:${i.reason}`}}async function Ce(e){const t=await $(e);if(!t.opened)return t;await C(e,"open-click-settle","visible-retry");const n=await _(e);return n.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:`${t.reason}:retry-visible-title-confirmed`}):{opened:!1,reason:n.reason}}async function qt(e){let t;const n=e.searchDelayMs===0?0:A(e,"search-result-probe","search-result-probe"),r=y(e.binding.conversationDisplayName)?Ye:1;for(let i=0;i<r;i+=1){i>0&&n>0&&await j(n);const o=await jt(e);t=o;const{capture:s,ocr:a}=o,c=B({capture:s,ocr:a,window:e.window});if(c)return{opened:!1,reason:c,observation:o};const u=tn(a,s,e.binding.conversationDisplayName);if(!u){if(nn(a)||on(a,e.binding.conversationDisplayName))break;continue}const w=L(u.bbox,s,Gt(s,e.window));if(!w)return{opened:!1,reason:"search_result_bbox_missing",observation:o};const l=await e.helper.request("mouse.click",{x:w.x,y:w.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return m(l,"mouse.click"),{opened:!0,reason:u.reason,observation:o}}return{opened:!1,reason:"search_result_not_visible",observation:t}}async function jt(e){if(e.window.bounds&&y(e.binding.conversationDisplayName)){const t=await e.helper.request("screen.capture",{bounds:e.window.bounds},e.traceId);if(t.ok&&t.result?.dataBase64&&t.result.width&&t.result.height){const n={...t.result,windowId:e.window.windowId,bounds:t.result.bounds??e.window.bounds},r=await Ie(e.helper,n,e.traceId);return{capture:n,ocr:r}}t.errorCode&&t.errorCode!=="helper_unknown_command"&&t.errorCode!=="helper_command_unsupported"&&m(t,"screen.capture")}return p(e)}function Gt(e,t){return e.bounds?{...t,bounds:e.bounds}:t}async function p(e){let{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds);return await Ht({helper:e.helper,window:e.window,capture:t,ocr:n,traceId:e.traceId})&&(await J("preview-dismiss-settle",`${e.traceId||""}:${e.window.windowId}:preview-dismiss`),{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds)),{capture:t,ocr:n}}async function Ht(e){const t=Yt(e.ocr,e.capture,e.window);if(!t)return!1;for(const n of[async()=>e.helper.request("keyboard.shortcut",{key:"escape",modifiers:[]},e.traceId),async()=>e.helper.request("mouse.click",{x:t.x,y:t.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId)])if((await n()).ok)return!0;return!1}function Yt(e,t,n){const r=e.blocks??[],i=r.find(c=>{const u=String(c.text||""),w=c.bbox;if(!w)return!1;const l=Number(w.x),d=Number(w.y);return Number.isFinite(l)&&Number.isFinite(d)&&d>t.height*.06&&d<t.height*.22&&l>t.width*.3&&/查看原视频|查看原图|原视频|原图|视频|图片|图像/.test(u)});if(!i)return null;const o=i.bbox,s=Number(o?.y);if(!Number.isFinite(s))return null;const a=r.filter(c=>{const u=String(c.text||"").trim(),w=c.bbox;if(!w||u!=="\xD7")return!1;const l=Number(w.x),d=Number(w.y);return Number.isFinite(l)&&Number.isFinite(d)&&l>t.width*.55&&l<t.width*.9&&Math.abs(d-s)<t.height*.08}).sort((c,u)=>Number(u.bbox?.x??0)-Number(c.bbox?.x??0))[0];return L(a?.bbox,t,n)}async function Ut(e,t){if(!e.runtime||!e.api?.classifyWindow)return{ok:!1,reason:"wechat_search_input_detector_unavailable"};try{return{ok:!0,point:await Qe({runtime:e.runtime,binding:e.binding,helper:e.helper,api:e.api,workDir:e.workDir,traceId:e.traceId,window:e.window,...t.dataBase64?{screenshot:t}:{}})}}catch(n){return{ok:!1,reason:n instanceof Error?n.message:"wechat_search_input_not_found"}}}async function F(e,t,n,r){const i=await e.request("windows.capture",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);m(i,"windows.capture");const o=i.result;if(!o?.dataBase64||!o.mimeType||!o.width||!o.height)throw new Error("helper_invalid_response: windows.capture missing screenshot data");return o}async function _e(e){return e.capture.dataBase64?e.capture:F(e.helper,e.window.windowId,e.traceId,e.window.bounds)}async function V(e,t,n,r){const i=await e.request("windows.captureAndOcr",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);if(i.ok&&i.result?.capture&&i.result?.ocr)return{capture:i.result.capture,ocr:i.result.ocr};!i.ok&&i.errorCode&&i.errorCode!=="helper_unknown_command"&&i.errorCode!=="helper_command_unsupported"&&m(i,"windows.captureAndOcr");const o=await F(e,t,n,r),s=await Ie(e,o,n);return{capture:o,ocr:s}}async function Ie(e,t,n){const r=await e.request("ocr.recognize",{mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height},n);return m(r,"ocr.recognize"),r.result??{}}function m(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}function q(e){const t=String(e.appName||"").toLowerCase();return t==="wechat"||t==="weixin"||t==="\u5FAE\u4FE1"}function j(e){return new Promise(t=>setTimeout(t,e))}function A(e,t,n){return e.searchDelayMs===0?0:Ve(t,Xt(e,n))}async function C(e,t,n){const r=A(e,t,n);r>0&&await j(r)}function Xt(e,t){return`${e.traceId||""}:${e.binding.conversationDisplayName}:${t}`}async function Jt(e,t){const n=await e.request("keyboard.shortcut",{key:"return",modifiers:[]},t);m(n,"keyboard.shortcut")}async function T(e){if(!e.window.bounds)return;const t=e.observation,n=gn(t?.ocr,t?.capture,e.window);if(n){const r=await e.helper.request("mouse.click",{x:n.x,y:n.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);m(r,"mouse.click"),await J("jump-latest-settle",`${e.traceId||""}:${e.window.windowId}:jump-latest`)}}async function _(e){const{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds),r=B({capture:t,ocr:n,window:e.window});return r?{ok:!1,reason:r}:O(n,t,e.binding.conversationDisplayName)?{ok:!0,reason:"target-conversation-title-confirmed"}:{ok:!1,reason:"conversation_title_not_confirmed"}}function B(e){const n=(e.ocr.blocks??[]).map(r=>sn(r.text)).filter(Boolean).join("");return/(扫码登录|仅传输文件|重新登录|为了安全|安全验证|登录微信|微信登录|该账号已登录|帐号已登录|账号已登录|当前账号已登录|当前帐号已登录|已登录|进入微信|進入微信)/u.test(n)?Ue:null}function Zt(e,t,n=!0){const r=n?Qt(e.blocks??[],t):[];return r.length?r:e.visibleConversationFingerprints??[]}function Qt(e,t){const n=e.map(i=>ke(i)).filter(i=>!!i).filter(i=>i.text.length>=2).filter(i=>i.x>t.width*.08&&i.x<t.width*.38).filter(i=>i.y>t.height*.06&&i.y<t.height*.96).filter(i=>!Se(i.text)),r=new Set;return n.filter(i=>!en(i,n,t)).sort((i,o)=>i.y-o.y||i.x-o.x).map(i=>{const o=i.text.trim();return{title:o,bbox:{x:Math.max(0,i.x-24),y:Math.max(0,i.y-Math.max(24,i.height)),width:Math.max(120,t.width*.3),height:Math.max(48,i.height+40),coordinateSpace:"screenshotPixel"},fingerprint:o.toLowerCase()}}).filter(i=>{const o=P(i.title);return!o||r.has(o)?!1:(r.add(o),!0)})}function ke(e){const t=e.bbox,n=String(e.text||"").normalize("NFKC").trim(),r=Number(t?.x),i=Number(t?.y),o=Number(t?.width),s=Number(t?.height);return!n||![r,i,o,s].every(Number.isFinite)?null:{text:n,x:r,y:i,width:o,height:s}}function en(e,t,n){const r=Math.max(36,Math.min(64,n.height*.058));return t.some(i=>i!==e&&i.y<e.y&&e.y-i.y<=r&&Math.abs(i.x-e.x)<=16&&i.height>=e.height*.85)}function Se(e){const t=x(e);return/^(搜索|微信|通讯录|收藏|设置|文件传输助手|search)$/iu.test(t)||E(t)||an(t)||/^包含[::]?/u.test(t)||/搜索网络结果/u.test(t)}function tn(e,t,n){const r=(e.blocks??[]).map(a=>ke(a)).filter(a=>!!a),i=r.filter(a=>E(x(a.text))).sort((a,c)=>a.y-c.y||a.x-c.x),o=["\u7FA4\u804A","GroupChats","\u8054\u7CFB\u4EBA","Contacts"];for(const a of o){const c=i.findIndex(d=>x(d.text)===a);if(c<0)continue;const u=i[c],w=i[c+1]?.y??Number.POSITIVE_INFINITY,l=r.filter(d=>d.y>u.y&&d.y<w).filter(d=>d.x<t.width*.7).filter(d=>d.text.length>=2).filter(d=>!E(x(d.text))).filter(d=>!Ne(d,r)).filter(d=>H(d.text,n)).sort((d,f)=>d.y-f.y||d.x-f.x)[0];if(l)return{bbox:Me(l,t),reason:"search-result-title"}}const s=r.filter(a=>a.y>t.height*.12&&a.y<t.height*.82).filter(a=>a.x>t.width*.08&&a.x<t.width*.45).filter(a=>a.text.length>=2).filter(a=>!Se(a.text)).filter(a=>!Ne(a,r)).filter(a=>H(a.text,n)).sort((a,c)=>a.y-c.y||a.x-c.x)[0];return y(n)?null:s?{bbox:Me(s,t),reason:"search-result-title"}:null}function Me(e,t){return{x:Math.max(0,e.x-24),y:Math.max(0,e.y-12),width:Math.max(e.width+t.width*.18,160),height:Math.max(e.height+28,44),coordinateSpace:"screenshotPixel"}}function E(e){return/^(群聊|联系人|聊天记录|公众号|小程序|GroupChats|Contacts|ChatHistory|OfficialAccounts|MiniPrograms)$/u.test(e)}function nn(e){return(e.blocks??[]).some(t=>E(x(t.text)))}function rn(e){return(e.blocks??[]).some(t=>{const n=x(t.text);return E(n)||n==="\u641C\u7D22\u7F51\u7EDC\u7ED3\u679C"})}function on(e,t){return(e.visibleConversationFingerprints??[]).some(n=>H(n.title,t))}function x(e){return String(e||"").normalize("NFKC").replace(/[^\p{L}\p{N}_-]/gu,"").trim()}function Ne(e,t){return/^包含[::]?/u.test(e.text.trim())?!0:t.some(n=>n!==e&&Math.abs(n.y-e.y)<=Math.max(18,e.height)&&n.x<e.x&&/^包含[::]?/u.test(n.text.trim()))}function an(e){const t=String(e||"").trim();return!!(/^(星期[一二三四五六日天]|周[一二三四五六日天])\s*\d{1,2}:\d{2}$/u.test(t)||/^\d{1,2}:\d{2}(?::\d{2})?$/u.test(t)||/^\d{4}[-/.年]\d{1,2}(?:[-/.月]\d{1,2}日?)?$/u.test(t)||/^\d{1,2}[-/.月]\d{1,2}日?$/u.test(t))}function sn(e){return String(e||"").normalize("NFKC").replace(/\s+/g,"").trim()}function O(e,t,n){const r=y(n)?P(n):D(n);return r?(e.blocks??[]).some(i=>{const o=y(n)?P(i.text):D(i.text);if(!o||!Ee(o,r))return!1;const s=i.bbox;if(!s)return!1;const a=Number(s.x),c=Number(s.y);if(!Number.isFinite(a)||!Number.isFinite(c))return!1;const u=a>t.width*.32&&a<t.width*.78&&c<t.height*.16,w=a<t.width*.18&&c<t.height*.12;return u||w}):!1}function G(e){if(O(e.ocr,e.capture,e.binding.conversationDisplayName))return!1;const t=(e.ocr.blocks??[]).map(a=>String(a.text||"").normalize("NFKC").replace(/\s+/g," ").trim()).filter(Boolean),n=t.join(`
5
- `),i=[{pattern:/UTF-?8/iu,source:n},{pattern:/Unix\s*\(LF\)/iu,source:n},{pattern:/纯文本/u,source:n},{pattern:/\d+\s*个字符/u,source:n},{pattern:/\bH1\b/u,source:n},{pattern:/^查看$/u,source:t}].reduce((a,c)=>{const u=Array.isArray(c.source)?c.source.some(w=>c.pattern.test(w)):c.pattern.test(c.source);return a+(u?1:0)},0);if(i>=2)return!0;const o=(e.ocr.blocks??[]).filter(a=>Number(a.bbox?.y)<e.capture.height*.14).map(a=>String(a.text||"")).join(`
6
- `);return/\.(txt|md|rtf|docx?|pdf)\b/i.test(o)&&i>=1||/\.(png|jpe?g|gif|webp|bmp|heic|mp4|mov|m4v|avi|mkv|webm)\b/i.test(o)&&cn(e.capture,e.ocr)?!0:((e.ocr.visibleConversationFingerprints??[]).some(a=>{const c=y(e.binding.conversationDisplayName)?P(a.title):D(a.title),u=y(e.binding.conversationDisplayName)?P(e.binding.conversationDisplayName):D(e.binding.conversationDisplayName);return!!(c&&u&&Ee(c,u))}),!1)}function cn(e,t){const n=(t.blocks??[]).map(o=>String(o.text||"").normalize("NFKC").trim()).filter(Boolean),r=n.join(`
7
- `);if(/\b\d+\s*x\s*\d+\b/i.test(r)&&/\b\d+(\.\d+)?\s*(B|KB|MB|GB)\b/i.test(r)||/\b100%\b/.test(r)&&n.length<=20)return!0;const i=n.filter(o=>!/^(□|×|\+|…|\.\.\.|100%|\d+|发送)$/u.test(o));return e.width>600&&e.height>500&&i.length<=6}function Te(e){const t=e.anchors.map(o=>({...o,normalized:v(o.expectedEchoAnchor)})).filter(o=>o.normalized);if(!t.length)return[];const n=[],r=new Set,i=dn(e.ocr,e.screenshot).sort((o,s)=>v(s.text).length-v(o.text).length);for(const o of i){const s=v(o.text);if(!s)continue;const a=t.find(u=>ln(u.normalized,s));if(!a)continue;const c=`local-outbound-echo:${e.binding.bindingId}:${a.idempotencyKey||a.replyId||a.normalized}`;r.has(c)||(r.add(c),n.push({stableMessageKey:c,senderRole:"self",kind:"text",normalizedText:s,anchorText:s,textExcerpt:o.text.trim(),bbox:o.bbox??null,observedAt:new Date().toISOString(),deliveryStatus:"suppressed"}))}return n}function dn(e,t){const n=(e.blocks??[]).filter(i=>mn(i,t)&&v(i.text)).sort((i,o)=>I(i.bbox,"y")-I(o.bbox,"y")),r=n.map(i=>({text:String(i.text||"").trim(),bbox:i.bbox}));for(let i=0;i<n.length;i+=1){const o=[n[i]];for(let s=i+1;s<n.length&&o.length<5;s+=1){const a=n[s];if(!un(o[o.length-1],a,t))break;o.push(a),r.push({text:wn(o.map(c=>String(c.text||"").trim())),bbox:fn(o.map(c=>c.bbox))})}}return r}function ln(e,t){if(!e||!t)return!1;if(Z(e,t)>=.88)return!0;const n=e.replace(/\s+/g,""),r=t.replace(/\s+/g,"");return r.length>=8&&n.includes(r)}function un(e,t,n){const r=I(e.bbox,"x"),i=I(e.bbox,"y"),o=I(e.bbox,"height"),s=I(t.bbox,"x"),a=I(t.bbox,"y");if(![r,i,o,s,a].every(Number.isFinite)||r<n.width*.5||s<n.width*.5)return!1;const c=a-(i+o);return c>=-8&&c<=Math.max(64,n.height*.04)&&Math.abs(s-r)<=120}function wn(e){return e.reduce((t,n)=>t?n?`${t}${hn(t,n)?" ":""}${n}`:t:n,"")}function hn(e,t){return/[A-Za-z0-9]$/u.test(e)&&/^[A-Za-z0-9]/u.test(t)}function fn(e){const t=e.filter(c=>!!c);if(!t.length)return;const n=t.map(c=>Number(c.x)).filter(Number.isFinite),r=t.map(c=>Number(c.y)).filter(Number.isFinite),i=t.map(c=>Number(c.x)+Number(c.width)).filter(Number.isFinite),o=t.map(c=>Number(c.y)+Number(c.height)).filter(Number.isFinite);if(!n.length||!r.length||!i.length||!o.length)return t[0];const s=Math.min(...n),a=Math.min(...r);return{x:s,y:a,width:Math.max(...i)-s,height:Math.max(...o)-a,coordinateSpace:t.find(c=>c.coordinateSpace)?.coordinateSpace}}function I(e,t){const n=Number(e?.[t]);return Number.isFinite(n)?n:Number.NaN}function Be(e,t){if(!t.length)return e;const n=[...e];for(const r of t){const i=v(r.anchorText||r.normalizedText||r.textExcerpt);n.some(s=>{if(s.senderRole!=="self")return!1;const a=v(s.anchorText||s.normalizedText||s.textExcerpt);return a&&i&&Z(a,i)>=.9})||n.push(r)}return n}function mn(e,t){const n=e.bbox;if(!n)return!1;const r=Number(n.x),i=Number(n.y);return!Number.isFinite(r)||!Number.isFinite(i)?!1:r>t.width*.34&&r<t.width*.96&&i>t.height*.12&&i<t.height*.86}function bn(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),s=Number(r.width),a=Number(r.height);if(![i,o,s,a].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,u=t.width&&n.bounds?.width?t.width/n.bounds.width:1,w=t.height&&n.bounds?.height?t.height/n.bounds.height:u,l={x:i+Math.min(s*.35,110*u),y:o+Math.min(a-8*w,Math.max(18*w,a/2))};if(c==="screen"||!n.bounds)return l;const d=Math.max(0,(t.width-n.bounds.width*u)/2),f=Math.max(0,(t.height-n.bounds.height*w)/2);return{x:n.bounds.x+(l.x-d)/u,y:n.bounds.y+(l.y-f)/w}}function L(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),s=Number(r.width),a=Number(r.height);if(![i,o,s,a].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,u={x:i+s/2,y:o+a/2};if(c==="screen"||!n.bounds)return u;const w=t.width&&n.bounds.width?t.width/n.bounds.width:1,l=t.height&&n.bounds.height?t.height/n.bounds.height:w,d=Math.max(0,(t.width-n.bounds.width*w)/2),f=Math.max(0,(t.height-n.bounds.height*l)/2);return{x:n.bounds.x+(u.x-d)/w,y:n.bounds.y+(u.y-f)/l}}function gn(e,t,n){if(!e?.blocks?.length||!t)return null;const r=e.blocks.find(i=>{const o=String(i.text||"").trim(),s=i.bbox;if(!s||!o)return!1;const a=Number(s.x),c=Number(s.y);return!Number.isFinite(a)||!Number.isFinite(c)||!/跳转到最新消息|回到最新消息|jump\s+to\s+latest/i.test(o)?!1:a>t.width*.55&&c>t.height*.45&&c<t.height*.92});return L(r?.bbox,t,n)}function Ee(e,t){return y(t)?We(e,t):e===t||e.includes(t)||t.includes(e)}function H(e,t){if(y(t))return We(e,t);const n=Pe(x(e)),r=Pe(x(t));return!n||!r?!1:n===r?!0:n.replace(/\d+$/u,"")===r}function Pe(e){return e.toLowerCase().replace(/[l1]/g,"i")}function D(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").replace(/[l1]/gi,"i").toLowerCase().trim()}function P(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim()}function y(e){const t=String(e||"").trim();return/^[A-Z0-9_-]{1,6}$/.test(t)&&/[A-Z]/.test(t)}function We(e,t){const n=String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim(),r=String(t||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim();return!!(n&&r&&(n===r||n.replace(/\d+$/u,"")===r))}export{N as WeChatChannelUserActivityAbort,V as captureAndRecognizeWeChatWindow,F as captureWeChatWindow,Bn as detectWeChatMessageInputPointByServerVision,Qe as detectWeChatSearchInputPointByServerVision,Ft as ensureHelperPermissionPreflight,En as ensureHelperPreflight,Dt as ensureWeChatWindowReady,$t as focusExistingWeChatWindow,ve as focusKnownWeChatWindow,Pn as focusWeChatWindow,Tn as observeWeChatChannelBindingViaHelper,z as openConversationBySearch,$ as openConversationInVisibleList,Ie as recognizeWeChatScreenshot,Ze as selectWeChatWindowForBinding};
4
+ `)||null}function Et(e,t,n,r){const i=String(e.kind||"").toLowerCase(),o=b(e.mediaMetadata)?e.mediaMetadata:{},s=b(o.attachment)?o.attachment:{},a=h(s.availability)||h(o.availability),c=h(s.localPath)||h(o.localPath);if(a==="edge-local"&&c||!me(i,o,s))return null;const l=W(e.bbox)??W(o.bbox)??W(o.downloadActionBbox),w=W(o.downloadActionBbox),u=be(l,t,n),d=Wt(l,t,n),f=be(w,t,n);return{messageKey:e.stableMessageKey,kind:h(s.type)||h(s.kind)||h(o.messageType)||i,fileName:h(s.name)||h(s.fileName)||h(o.fileName)||null,mimeType:h(s.mimeType)||h(o.mimeType)||null,size:M(s.size)??M(o.size),mediaStatus:Rt(o,s),observedAt:e.observedAt??null,contextText:r??e.normalizedText??e.anchorText??e.textExcerpt??null,...u?{bbox:u}:{},...d?{screenshotBbox:d}:{},...f?{downloadActionBbox:f}:{}}}function Pt(e,t,n,r,i){const o=b(e)?{...e}:{};return{...o,availability:b(t)?t.availability:o.availability,mediaStatus:b(t)&&t.availability==="edge-local"?"downloaded":o.mediaStatus,attachment:t,edgeResolveReasonCode:n,...r?.length?{edgeResolveAttempts:r}:{},...i?{edgeResolveTrace:i}:{}}}function Rt(e,t){const n=h(e.mediaStatus);if(n==="not_downloaded")return"not_downloaded";if(n==="downloaded"||n==="available")return"available";const r=h(t.availability)||h(e.availability);return r==="pending-download"?"not_downloaded":r==="metadata-only"?"metadata_only":n||null}function me(e,t,n){const r=`${e} ${h(t.messageType)} ${h(n.type)} ${h(n.kind)}`.toLowerCase();return/image|photo|video|file|document/.test(r)}function W(e){if(!b(e))return null;const t=M(e.x),n=M(e.y),r=M(e.width),i=M(e.height);return t==null||n==null||r==null||i==null?null:{x:t,y:n,width:r,height:i,...typeof e.coordinateSpace=="string"?{coordinateSpace:e.coordinateSpace}:{}}}function be(e,t,n){if(!e)return null;if(e.coordinateSpace==="screen")return e;const r=L(e,t,n);if(!r)return e;const i=n.bounds;if(!i?.width||!i?.height)return{...e,x:r.x-e.width/2,y:r.y-e.height/2,coordinateSpace:"screen"};const o=i.width/t.width,s=i.height/t.height,a=r.x,c=r.y;return{x:a-e.width*o/2,y:c-e.height*s/2,width:e.width*o,height:e.height*s,coordinateSpace:"screen"}}function Wt(e,t,n){if(!e)return null;if(e.coordinateSpace!=="screen")return{...e,coordinateSpace:"screenshotPixel"};const r=n.bounds;if(!r?.width||!r?.height)return null;const i=t.width/r.width,o=t.height/r.height;return{x:(e.x-r.x)*i,y:(e.y-r.y)*o,width:e.width*i,height:e.height*o,coordinateSpace:"screenshotPixel"}}function b(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function S(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function h(e){return typeof e=="string"?e.trim():""}function g(e){return h(e)||null}function M(e){const t=Number(e);return Number.isFinite(t)?t:null}async function En(e,t){await ye(e,t)}async function Ft(e,t){await ge(e,t)}async function ge(e,t){const n=await e.request("permissions.check",{},t);m(n,"permissions.check");const r=n.result??{},i=await At(e,r,t);if(i==="screen-recording")throw new Error("permission_screen_recording_missing");if(i==="accessibility")throw new Error("permission_accessibility_missing");if(i==="input-monitoring")throw new Error("permission_input_monitoring_missing");if(r.automation===!1)throw new Error("permission_automation_missing");return r}async function ye(e,t,n={}){const r=await ge(e,t);if(r.wechatRunning===!1)throw new Error("wechat_not_running");if(Kt(r))throw new Error("windows_visible_desktop_unavailable");if(r.dpiMappingAvailable===!1||r.displayTopologySupported===!1)throw new Error("dpi_mapping_failed");if(r.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(r.wechatWindowAvailable===!1&&String(r.platform??"").toLowerCase()!=="win32"&&n.allowUnavailableWindow!==!0)throw new Error("wechat_window_unavailable");return r}async function At(e,t,n){const r=Ot(t);if(!r||process.platform!=="darwin")return r;const i=Lt(r);try{await e.request(i,{},n)}catch{}return r}function Ot(e){return e.screenRecording===!1?"screen-recording":e.accessibility===!1?"accessibility":e.inputMonitoring===!1?"input-monitoring":null}function Lt(e){return e==="screen-recording"?"permissions.requestScreenRecording":e==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring"}async function Dt(e,t,n={}){const i=(n.foreground??"required")!=="background",o=await ye(e,t,{allowUnavailableWindow:i});if(String(o.platform??"").toLowerCase()==="win32"){const c=await e.request("windows.ensureReady",{activate:i,allowRecovery:!1,allowLaunch:!1},t);m(c,"windows.ensureReady");const l=c.result;if(!l?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return l}const s=await e.request("windows.ensureReady",{restore:i,focus:i},t);m(s,"windows.ensureReady");const a=s.result;if(!a?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return a}function Kt(e){return e.windowsVisibleDesktopAvailable===!1||e.rdpVisibleDesktopAvailable===!1||e.desktopSessionVisible===!1||e.screenLocked===!0||e.rdpDisconnected===!0}function xe(e){const t=e.filter(q),n=t.filter(i=>i.visible!==!1&&i.minimized!==!0);return(n.length?n:t)[0]??null}async function Pn(e,t){let n=await e.request("windows.list",{},t);m(n,"windows.list");let r=n.result?.windows??[],i=xe(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return m(o,"windows.focus"),await pe(e,i,t)}async function ve(e,t,n){if(!t.windowId)throw new Error("wechat_window_not_found");const r=await e.request("windows.focus",{windowId:t.windowId},n);return m(r,"windows.focus"),t}async function $t(e,t){const n=await e.request("windows.list",{},t);m(n,"windows.list");const r=n.result?.windows??[],i=xe(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return m(o,"windows.focus"),await pe(e,i,t)}async function pe(e,t,n){let r;try{r=await e.request("windows.list",{},n)}catch{return t}if(!r.ok)return t;const i=(r.result?.windows??[]).filter(q);return i.find(o=>o.windowId===t.windowId)??i[0]??t}async function $(e){const{capture:t,ocr:n}=e.observation??await p(e),r=B({capture:t,ocr:n,window:e.window});if(r)return{opened:!1,reason:r};const i=qe({visibleItems:Zt(n,t,e.allowOcrTitleRows!==!1),targets:[{bindingId:e.binding.bindingId,conversationDisplayName:e.binding.conversationDisplayName}]})[0];if(!i)return{opened:!1,reason:"conversation_not_visible"};const o=bn(i.item.bbox,t,e.window);if(!o)return{opened:!1,reason:"conversation_bbox_missing"};const s=await e.helper.request("mouse.click",{x:o.x,y:o.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return m(s,"mouse.click"),{opened:!0,reason:i.reason}}async function z(e){let t={opened:!1,reason:"conversation_not_opened"};for(let r=0;r<He;r+=1){if(t=await zt(e),t.opened||t.reason!=="conversation_title_not_confirmed")return t;await C(e,"open-retry",`retry:${r}`)}const n=await Ce(e);return n.opened?{opened:!0,reason:`${n.reason}:final-visible-recovery`}:t}async function zt(e){const t=await p(e),n=B({capture:t.capture,ocr:t.ocr,window:e.window});if(n)return{opened:!1,reason:n};let r=!1;if(O(t.ocr,t.capture,e.binding.conversationDisplayName)){e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId,observation:t});const u=await Vt(e,t);return u.ok?{opened:!0,reason:"current-conversation-title-confirmed"}:{opened:!1,reason:u.reason}}if(!r){const u=await $({...e,observation:t});if(u.opened){if(await C(e,"open-click-settle","visible-initial"),(await _(e)).ok)return{opened:!0,reason:u.reason};const f=await Ce(e);if(f.opened)return f}}const i=await Ut(e,t.capture);if(!i.ok)return{opened:!1,reason:i.reason};const o=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??A(e,"search-input-settle","search-input"),searchPoint:i.point},e.traceId);m(o,"wechat.searchConversation");const s=await qt(e);if(s.opened){await C(e,"open-click-settle","search-result-click");const u=await _(e);return u.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:s.reason}):{opened:!1,reason:u.reason}}let a=s.observation;const c=y(e.binding.conversationDisplayName)&&s.reason==="search_result_not_visible";if(!y(e.binding.conversationDisplayName)){await Jt(e.helper,e.traceId),await C(e,"open-click-settle","search-return");const u=await _(e);if(u.ok)return e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:u.reason};const d=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??A(e,"search-input-settle","search-input-retry-after-return"),searchPoint:i.point},e.traceId);m(d,"wechat.searchConversation"),a=void 0}const l=await $({...e,...a?{observation:a}:{},allowOcrTitleRows:!c});if(!l.opened)return l;await C(e,"open-click-settle","visible-final");const w=await _(e);return w.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:l.reason}):{opened:!1,reason:w.reason}}async function Vt(e,t){const n=t??await p(e);if(!rn(n.ocr))return{ok:!0};const r=await e.helper.request("keyboard.shortcut",{key:"escape",modifiers:[]},e.traceId);m(r,"keyboard.shortcut"),await C(e,"open-click-settle","escape-after-title-confirmed");const i=await _(e);return i.ok?{ok:!0}:{ok:!1,reason:`search_overlay_dismiss_failed:${i.reason}`}}async function Ce(e){const t=await $(e);if(!t.opened)return t;await C(e,"open-click-settle","visible-retry");const n=await _(e);return n.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:`${t.reason}:retry-visible-title-confirmed`}):{opened:!1,reason:n.reason}}async function qt(e){let t;const n=e.searchDelayMs===0?0:A(e,"search-result-probe","search-result-probe"),r=y(e.binding.conversationDisplayName)?Ye:1;for(let i=0;i<r;i+=1){i>0&&n>0&&await j(n);const o=await jt(e);t=o;const{capture:s,ocr:a}=o,c=B({capture:s,ocr:a,window:e.window});if(c)return{opened:!1,reason:c,observation:o};const l=tn(a,s,e.binding.conversationDisplayName);if(!l){if(nn(a)||on(a,e.binding.conversationDisplayName))break;continue}const w=L(l.bbox,s,Gt(s,e.window));if(!w)return{opened:!1,reason:"search_result_bbox_missing",observation:o};const u=await e.helper.request("mouse.click",{x:w.x,y:w.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return m(u,"mouse.click"),{opened:!0,reason:l.reason,observation:o}}return{opened:!1,reason:"search_result_not_visible",observation:t}}async function jt(e){if(e.window.bounds&&y(e.binding.conversationDisplayName)){const t=await e.helper.request("screen.capture",{bounds:e.window.bounds},e.traceId);if(t.ok&&t.result?.dataBase64&&t.result.width&&t.result.height){const n={...t.result,windowId:e.window.windowId,bounds:t.result.bounds??e.window.bounds},r=await Ie(e.helper,n,e.traceId);return{capture:n,ocr:r}}t.errorCode&&t.errorCode!=="helper_unknown_command"&&t.errorCode!=="helper_command_unsupported"&&m(t,"screen.capture")}return p(e)}function Gt(e,t){return e.bounds?{...t,bounds:e.bounds}:t}async function p(e){let{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds);return await Ht({helper:e.helper,window:e.window,capture:t,ocr:n,traceId:e.traceId})&&(await J("preview-dismiss-settle",`${e.traceId||""}:${e.window.windowId}:preview-dismiss`),{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds)),{capture:t,ocr:n}}async function Ht(e){const t=Yt(e.ocr,e.capture,e.window);if(!t)return!1;for(const n of[async()=>e.helper.request("keyboard.shortcut",{key:"escape",modifiers:[]},e.traceId),async()=>e.helper.request("mouse.click",{x:t.x,y:t.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId)])if((await n()).ok)return!0;return!1}function Yt(e,t,n){const r=e.blocks??[],i=r.find(c=>{const l=String(c.text||""),w=c.bbox;if(!w)return!1;const u=Number(w.x),d=Number(w.y);return Number.isFinite(u)&&Number.isFinite(d)&&d>t.height*.06&&d<t.height*.22&&u>t.width*.3&&/查看原视频|查看原图|原视频|原图|视频|图片|图像/.test(l)});if(!i)return null;const o=i.bbox,s=Number(o?.y);if(!Number.isFinite(s))return null;const a=r.filter(c=>{const l=String(c.text||"").trim(),w=c.bbox;if(!w||l!=="\xD7")return!1;const u=Number(w.x),d=Number(w.y);return Number.isFinite(u)&&Number.isFinite(d)&&u>t.width*.55&&u<t.width*.9&&Math.abs(d-s)<t.height*.08}).sort((c,l)=>Number(l.bbox?.x??0)-Number(c.bbox?.x??0))[0];return L(a?.bbox,t,n)}async function Ut(e,t){if(!e.runtime||!e.api?.classifyWindow)return{ok:!1,reason:"wechat_search_input_detector_unavailable"};try{return{ok:!0,point:await Qe({runtime:e.runtime,binding:e.binding,helper:e.helper,api:e.api,workDir:e.workDir,traceId:e.traceId,window:e.window,...t.dataBase64?{screenshot:t}:{}})}}catch(n){return{ok:!1,reason:n instanceof Error?n.message:"wechat_search_input_not_found"}}}async function F(e,t,n,r){const i=await e.request("windows.capture",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);m(i,"windows.capture");const o=i.result;if(!o?.dataBase64||!o.mimeType||!o.width||!o.height)throw new Error("helper_invalid_response: windows.capture missing screenshot data");return o}async function _e(e){return e.capture.dataBase64?e.capture:F(e.helper,e.window.windowId,e.traceId,e.window.bounds)}async function V(e,t,n,r){const i=await e.request("windows.captureAndOcr",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);if(i.ok&&i.result?.capture&&i.result?.ocr)return{capture:i.result.capture,ocr:i.result.ocr};!i.ok&&i.errorCode&&i.errorCode!=="helper_unknown_command"&&i.errorCode!=="helper_command_unsupported"&&m(i,"windows.captureAndOcr");const o=await F(e,t,n,r),s=await Ie(e,o,n);return{capture:o,ocr:s}}async function Ie(e,t,n){const r=await e.request("ocr.recognize",{mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height},n);return m(r,"ocr.recognize"),r.result??{}}function m(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}function q(e){const t=String(e.appName||"").toLowerCase();return t==="wechat"||t==="weixin"||t==="\u5FAE\u4FE1"}function j(e){return new Promise(t=>setTimeout(t,e))}function A(e,t,n){return e.searchDelayMs===0?0:Ve(t,Xt(e,n))}async function C(e,t,n){const r=A(e,t,n);r>0&&await j(r)}function Xt(e,t){return`${e.traceId||""}:${e.binding.conversationDisplayName}:${t}`}async function Jt(e,t){const n=await e.request("keyboard.shortcut",{key:"return",modifiers:[]},t);m(n,"keyboard.shortcut")}async function T(e){if(!e.window.bounds)return;const t=e.observation,n=gn(t?.ocr,t?.capture,e.window);if(n){const r=await e.helper.request("mouse.click",{x:n.x,y:n.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);m(r,"mouse.click"),await J("jump-latest-settle",`${e.traceId||""}:${e.window.windowId}:jump-latest`)}}async function _(e){const{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds),r=B({capture:t,ocr:n,window:e.window});return r?{ok:!1,reason:r}:O(n,t,e.binding.conversationDisplayName)?{ok:!0,reason:"target-conversation-title-confirmed"}:{ok:!1,reason:"conversation_title_not_confirmed"}}function B(e){const n=(e.ocr.blocks??[]).map(r=>sn(r.text)).filter(Boolean).join("");return/(扫码登录|仅传输文件|重新登录|为了安全|安全验证|登录微信|微信登录|该账号已登录|帐号已登录|账号已登录|当前账号已登录|当前帐号已登录|已登录|进入微信|進入微信)/u.test(n)?Ue:null}function Zt(e,t,n=!0){const r=n?Qt(e.blocks??[],t):[];return r.length?r:e.visibleConversationFingerprints??[]}function Qt(e,t){const n=e.map(i=>ke(i)).filter(i=>!!i).filter(i=>i.text.length>=2).filter(i=>i.x>t.width*.08&&i.x<t.width*.38).filter(i=>i.y>t.height*.06&&i.y<t.height*.96).filter(i=>!Se(i.text)),r=new Set;return n.filter(i=>!en(i,n,t)).sort((i,o)=>i.y-o.y||i.x-o.x).map(i=>{const o=i.text.trim();return{title:o,bbox:{x:Math.max(0,i.x-24),y:Math.max(0,i.y-Math.max(24,i.height)),width:Math.max(120,t.width*.3),height:Math.max(48,i.height+40),coordinateSpace:"screenshotPixel"},fingerprint:o.toLowerCase()}}).filter(i=>{const o=P(i.title);return!o||r.has(o)?!1:(r.add(o),!0)})}function ke(e){const t=e.bbox,n=String(e.text||"").normalize("NFKC").trim(),r=Number(t?.x),i=Number(t?.y),o=Number(t?.width),s=Number(t?.height);return!n||![r,i,o,s].every(Number.isFinite)?null:{text:n,x:r,y:i,width:o,height:s}}function en(e,t,n){const r=Math.max(36,Math.min(64,n.height*.058));return t.some(i=>i!==e&&i.y<e.y&&e.y-i.y<=r&&Math.abs(i.x-e.x)<=16&&i.height>=e.height*.85)}function Se(e){const t=x(e);return/^(搜索|微信|通讯录|收藏|设置|文件传输助手|search)$/iu.test(t)||E(t)||an(t)||/^包含[::]?/u.test(t)||/搜索网络结果/u.test(t)}function tn(e,t,n){const r=(e.blocks??[]).map(a=>ke(a)).filter(a=>!!a),i=r.filter(a=>E(x(a.text))).sort((a,c)=>a.y-c.y||a.x-c.x),o=["\u7FA4\u804A","GroupChats","\u8054\u7CFB\u4EBA","Contacts"];for(const a of o){const c=i.findIndex(d=>x(d.text)===a);if(c<0)continue;const l=i[c],w=i[c+1]?.y??Number.POSITIVE_INFINITY,u=r.filter(d=>d.y>l.y&&d.y<w).filter(d=>d.x<t.width*.7).filter(d=>d.text.length>=2).filter(d=>!E(x(d.text))).filter(d=>!Ne(d,r)).filter(d=>H(d.text,n)).sort((d,f)=>d.y-f.y||d.x-f.x)[0];if(u)return{bbox:Me(u,t),reason:"search-result-title"}}const s=r.filter(a=>a.y>t.height*.12&&a.y<t.height*.82).filter(a=>a.x>t.width*.08&&a.x<t.width*.45).filter(a=>a.text.length>=2).filter(a=>!Se(a.text)).filter(a=>!Ne(a,r)).filter(a=>H(a.text,n)).sort((a,c)=>a.y-c.y||a.x-c.x)[0];return y(n)?null:s?{bbox:Me(s,t),reason:"search-result-title"}:null}function Me(e,t){return{x:Math.max(0,e.x-24),y:Math.max(0,e.y-12),width:Math.max(e.width+t.width*.18,160),height:Math.max(e.height+28,44),coordinateSpace:"screenshotPixel"}}function E(e){return/^(群聊|联系人|聊天记录|公众号|小程序|GroupChats|Contacts|ChatHistory|OfficialAccounts|MiniPrograms)$/u.test(e)}function nn(e){return(e.blocks??[]).some(t=>E(x(t.text)))}function rn(e){return(e.blocks??[]).some(t=>{const n=x(t.text);return E(n)||n==="\u641C\u7D22\u7F51\u7EDC\u7ED3\u679C"})}function on(e,t){return(e.visibleConversationFingerprints??[]).some(n=>H(n.title,t))}function x(e){return String(e||"").normalize("NFKC").replace(/[^\p{L}\p{N}_-]/gu,"").trim()}function Ne(e,t){return/^包含[::]?/u.test(e.text.trim())?!0:t.some(n=>n!==e&&Math.abs(n.y-e.y)<=Math.max(18,e.height)&&n.x<e.x&&/^包含[::]?/u.test(n.text.trim()))}function an(e){const t=String(e||"").trim();return!!(/^(星期[一二三四五六日天]|周[一二三四五六日天])\s*\d{1,2}:\d{2}$/u.test(t)||/^\d{1,2}:\d{2}(?::\d{2})?$/u.test(t)||/^\d{4}[-/.年]\d{1,2}(?:[-/.月]\d{1,2}日?)?$/u.test(t)||/^\d{1,2}[-/.月]\d{1,2}日?$/u.test(t))}function sn(e){return String(e||"").normalize("NFKC").replace(/\s+/g,"").trim()}function O(e,t,n){const r=y(n)?P(n):D(n);return r?(e.blocks??[]).some(i=>{const o=y(n)?P(i.text):D(i.text);if(!o||!Ee(o,r))return!1;const s=i.bbox;if(!s)return!1;const a=Number(s.x),c=Number(s.y);if(!Number.isFinite(a)||!Number.isFinite(c))return!1;const l=a>t.width*.32&&a<t.width*.78&&c<t.height*.16,w=a<t.width*.18&&c<t.height*.12;return l||w}):!1}function G(e){if(O(e.ocr,e.capture,e.binding.conversationDisplayName))return!1;const t=(e.ocr.blocks??[]).map(a=>String(a.text||"").normalize("NFKC").replace(/\s+/g," ").trim()).filter(Boolean),n=t.join(`
5
+ `),i=[{pattern:/UTF-?8/iu,source:n},{pattern:/Unix\s*\(LF\)/iu,source:n},{pattern:/纯文本/u,source:n},{pattern:/\d+\s*个字符/u,source:n},{pattern:/\bH1\b/u,source:n},{pattern:/^查看$/u,source:t}].reduce((a,c)=>{const l=Array.isArray(c.source)?c.source.some(w=>c.pattern.test(w)):c.pattern.test(c.source);return a+(l?1:0)},0);if(i>=2)return!0;const o=(e.ocr.blocks??[]).filter(a=>Number(a.bbox?.y)<e.capture.height*.14).map(a=>String(a.text||"")).join(`
6
+ `);return/\.(txt|md|rtf|docx?|pdf)\b/i.test(o)&&i>=1||/\.(png|jpe?g|gif|webp|bmp|heic|mp4|mov|m4v|avi|mkv|webm)\b/i.test(o)&&cn(e.capture,e.ocr)?!0:((e.ocr.visibleConversationFingerprints??[]).some(a=>{const c=y(e.binding.conversationDisplayName)?P(a.title):D(a.title),l=y(e.binding.conversationDisplayName)?P(e.binding.conversationDisplayName):D(e.binding.conversationDisplayName);return!!(c&&l&&Ee(c,l))}),!1)}function cn(e,t){const n=(t.blocks??[]).map(o=>String(o.text||"").normalize("NFKC").trim()).filter(Boolean),r=n.join(`
7
+ `);if(/\b\d+\s*x\s*\d+\b/i.test(r)&&/\b\d+(\.\d+)?\s*(B|KB|MB|GB)\b/i.test(r)||/\b100%\b/.test(r)&&n.length<=20)return!0;const i=n.filter(o=>!/^(□|×|\+|…|\.\.\.|100%|\d+|发送)$/u.test(o));return e.width>600&&e.height>500&&i.length<=6}function Te(e){const t=e.anchors.map(o=>({...o,normalized:v(o.expectedEchoAnchor)})).filter(o=>o.normalized);if(!t.length)return[];const n=[],r=new Set,i=dn(e.ocr,e.screenshot).sort((o,s)=>v(s.text).length-v(o.text).length);for(const o of i){const s=v(o.text);if(!s)continue;const a=t.find(l=>ln(l.normalized,s));if(!a)continue;const c=`local-outbound-echo:${e.binding.bindingId}:${a.idempotencyKey||a.replyId||a.normalized}`;r.has(c)||(r.add(c),n.push({stableMessageKey:c,senderRole:"self",kind:"text",normalizedText:s,anchorText:s,textExcerpt:o.text.trim(),bbox:o.bbox??null,observedAt:new Date().toISOString(),deliveryStatus:"suppressed"}))}return n}function dn(e,t){const n=(e.blocks??[]).filter(i=>mn(i,t)&&v(i.text)).sort((i,o)=>I(i.bbox,"y")-I(o.bbox,"y")),r=n.map(i=>({text:String(i.text||"").trim(),bbox:i.bbox}));for(let i=0;i<n.length;i+=1){const o=[n[i]];for(let s=i+1;s<n.length&&o.length<5;s+=1){const a=n[s];if(!un(o[o.length-1],a,t))break;o.push(a),r.push({text:wn(o.map(c=>String(c.text||"").trim())),bbox:fn(o.map(c=>c.bbox))})}}return r}function ln(e,t){if(!e||!t)return!1;if(Z(e,t)>=.88)return!0;const n=e.replace(/\s+/g,""),r=t.replace(/\s+/g,"");return r.length>=8&&n.includes(r)}function un(e,t,n){const r=I(e.bbox,"x"),i=I(e.bbox,"y"),o=I(e.bbox,"height"),s=I(t.bbox,"x"),a=I(t.bbox,"y");if(![r,i,o,s,a].every(Number.isFinite)||r<n.width*.5||s<n.width*.5)return!1;const c=a-(i+o);return c>=-8&&c<=Math.max(64,n.height*.04)&&Math.abs(s-r)<=120}function wn(e){return e.reduce((t,n)=>t?n?`${t}${hn(t,n)?" ":""}${n}`:t:n,"")}function hn(e,t){return/[A-Za-z0-9]$/u.test(e)&&/^[A-Za-z0-9]/u.test(t)}function fn(e){const t=e.filter(c=>!!c);if(!t.length)return;const n=t.map(c=>Number(c.x)).filter(Number.isFinite),r=t.map(c=>Number(c.y)).filter(Number.isFinite),i=t.map(c=>Number(c.x)+Number(c.width)).filter(Number.isFinite),o=t.map(c=>Number(c.y)+Number(c.height)).filter(Number.isFinite);if(!n.length||!r.length||!i.length||!o.length)return t[0];const s=Math.min(...n),a=Math.min(...r);return{x:s,y:a,width:Math.max(...i)-s,height:Math.max(...o)-a,coordinateSpace:t.find(c=>c.coordinateSpace)?.coordinateSpace}}function I(e,t){const n=Number(e?.[t]);return Number.isFinite(n)?n:Number.NaN}function Be(e,t){if(!t.length)return e;const n=[...e];for(const r of t){const i=v(r.anchorText||r.normalizedText||r.textExcerpt);n.some(s=>{if(s.senderRole!=="self")return!1;const a=v(s.anchorText||s.normalizedText||s.textExcerpt);return a&&i&&Z(a,i)>=.9})||n.push(r)}return n}function mn(e,t){const n=e.bbox;if(!n)return!1;const r=Number(n.x),i=Number(n.y);return!Number.isFinite(r)||!Number.isFinite(i)?!1:r>t.width*.34&&r<t.width*.96&&i>t.height*.12&&i<t.height*.86}function bn(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),s=Number(r.width),a=Number(r.height);if(![i,o,s,a].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,l=t.width&&n.bounds?.width?t.width/n.bounds.width:1,w=t.height&&n.bounds?.height?t.height/n.bounds.height:l,u={x:i+Math.min(s*.35,110*l),y:o+Math.min(a-8*w,Math.max(18*w,a/2))};if(c==="screen"||!n.bounds)return u;const d=Math.max(0,(t.width-n.bounds.width*l)/2),f=Math.max(0,(t.height-n.bounds.height*w)/2);return{x:n.bounds.x+(u.x-d)/l,y:n.bounds.y+(u.y-f)/w}}function L(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),s=Number(r.width),a=Number(r.height);if(![i,o,s,a].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,l={x:i+s/2,y:o+a/2};if(c==="screen"||!n.bounds)return l;const w=t.width&&n.bounds.width?t.width/n.bounds.width:1,u=t.height&&n.bounds.height?t.height/n.bounds.height:w,d=Math.max(0,(t.width-n.bounds.width*w)/2),f=Math.max(0,(t.height-n.bounds.height*u)/2);return{x:n.bounds.x+(l.x-d)/w,y:n.bounds.y+(l.y-f)/u}}function gn(e,t,n){if(!e?.blocks?.length||!t)return null;const r=e.blocks.find(i=>{const o=String(i.text||"").trim(),s=i.bbox;if(!s||!o)return!1;const a=Number(s.x),c=Number(s.y);return!Number.isFinite(a)||!Number.isFinite(c)||!/跳转到最新消息|回到最新消息|jump\s+to\s+latest/i.test(o)?!1:a>t.width*.55&&c>t.height*.45&&c<t.height*.92});return L(r?.bbox,t,n)}function Ee(e,t){return y(t)?Re(e,t):e===t||e.includes(t)||t.includes(e)}function H(e,t){if(y(t))return Re(e,t);const n=Pe(x(e)),r=Pe(x(t));return!n||!r?!1:n===r?!0:n.replace(/\d+$/u,"")===r}function Pe(e){return e.toLowerCase().replace(/[l1]/g,"i")}function D(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").replace(/[l1]/gi,"i").toLowerCase().trim()}function P(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim()}function y(e){const t=String(e||"").trim();return/^[A-Z0-9_-]{1,6}$/.test(t)&&/[A-Z]/.test(t)}function Re(e,t){const n=String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim(),r=String(t||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim();return!!(n&&r&&(n===r||n.replace(/\d+$/u,"")===r))}export{N as WeChatChannelUserActivityAbort,V as captureAndRecognizeWeChatWindow,F as captureWeChatWindow,Bn as detectWeChatMessageInputPointByServerVision,Qe as detectWeChatSearchInputPointByServerVision,Ft as ensureHelperPermissionPreflight,En as ensureHelperPreflight,Dt as ensureWeChatWindowReady,$t as focusExistingWeChatWindow,ve as focusKnownWeChatWindow,Pn as focusWeChatWindow,Tn as observeWeChatChannelBindingViaHelper,z as openConversationBySearch,$ as openConversationInVisibleList,Ie as recognizeWeChatScreenshot,Ze as selectWeChatWindowForBinding};
@@ -1 +1 @@
1
- import g from"node:fs";import A from"node:path";import{waitForWeChatChannelPacing as d}from"./pacing.js";import{guardWeChatOutboundRevision as v,markWeChatOutboundFailed as C,markWeChatOutboundManualReview as x,markWeChatOutboundCommitStage as o,markWeChatOutboundSending as P,markWeChatOutboundSentUnconfirmed as S,markWeChatOutboundUserActiveTimeout as h,markWeChatOutboundWaitingUserIdle as _,shouldFailWeChatOutboundForUserActiveTimeout as l}from"./outbound-ledger.js";import{decideWeChatChannelActivityGate as I,nextWeChatChannelActivityRetryAt as b,normalizeWeChatChannelActivitySnapshot as k}from"./human-coordination.js";const W=600*1e3,f=520;async function Y(e){const t={sentRecords:[],staleRecords:[],failedRecords:[],waitingRecords:[],manualReviewRecords:[]},s=e.now??new Date,a=e.maxUserActivityWaitMs??W,n=e.ledger.records.filter(i=>i.bindingId===e.bindingId&&i.sendStatus==="queued");for(const i of n){if(l({record:i,now:s,maxWaitMs:a})){h(i,s),t.failedRecords.push(i);continue}if(!v({record:i,currentLastInboundRevision:e.currentLastInboundRevision,now:s}).ok){t.staleRecords.push(i);continue}try{const r=await e.sender.canStart(i,s);if(r.ok===!1){_({record:i,reasonCode:r.reasonCode,nextAttemptAt:r.nextAttemptAt,now:s}),l({record:i,now:s,maxWaitMs:a})?(h(i,s),t.failedRecords.push(i)):t.waitingRecords.push(i);continue}P(i),await e.sender.send(i),S(i,s),t.sentRecords.push(i)}catch(r){if(r instanceof m){if(H(r)){x(i,"user_takeover_before_return","User activity was detected after paste and before Return; manual WeChat inspection is required",r.stage),t.manualReviewRecords.push(i);continue}_({record:i,reasonCode:r.reasonCode,nextAttemptAt:r.nextAttemptAt,now:s}),l({record:i,now:s,maxWaitMs:a})?(h(i,s),t.failedRecords.push(i)):t.waitingRecords.push(i);continue}C(i,z(r),r instanceof Error?r.message:String(r)),t.failedRecords.push(i)}}return t}class J{options;activeAutomationLeaseId=null;focus;windowsTextClipboardPrimed=!1;constructor(t){this.options=t}async canStart(t,s=new Date){const a=await this.activitySnapshot();await $(this.options.helper,a,this.options.platform,this.options.traceId);const n=I({snapshot:a,stage:"send_start",policy:this.options.activityGatePolicy});return n.ok===!1?{ok:!1,reasonCode:n.reasonCode,nextAttemptAt:b(s,n.waitMs)}:{ok:!0}}async send(t){await this.withAutomationLease(t,()=>this.sendWithLease(t))}async sendWithLease(t){await this.ensureStageIdle(t,"open_conversation"),o(t,"open_conversation");const s=await this.options.openConversation(t.conversationName);if(!s.opened)throw new Error(s.reason||"conversation_not_opened");if(D(this.options.platform)&&!s.inputPoint)throw new Error("wechat_message_input_point_required: Windows send requires a vision-detected message input point");o(t,"focus_input"),this.focus={windowId:s.windowId??void 0,inputPoint:s.inputPoint??void 0},await this.focusMessageInputWithRetry(t),await this.ensureStageIdle(t,"clipboard_snapshot"),o(t,"clipboard_snapshot");const a=await this.options.helper.request("clipboard.snapshot",{},this.options.traceId);u(a,"clipboard.snapshot");let n=!1;try{await this.sendTextIfPresent(t,()=>{n=!0}),await this.sendAttachmentsIfPresent(t,()=>{n=!0})}finally{const i=a.result&&typeof a.result=="object"?a.result:{},c=await this.options.helper.request("clipboard.restore",i,this.options.traceId);n||u(c,"clipboard.restore")}}async sendTextIfPresent(t,s){if(!t.text)return;if(F(this.options.platform)){await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set"),await this.ensureStageIdle(t,"paste"),o(t,"paste");const n=await this.options.helper.request("wechat.pasteAndSubmit",{text:t.text,waitMs:f,pasteWaitMs:this.options.postPasteSettleMs??900,...this.focus?.windowId?{windowId:this.focus.windowId}:{},...this.focus?.inputPoint?{inputPoint:this.focus.inputPoint}:{}},this.options.traceId);u(n,"wechat.pasteAndSubmit"),s(),o(t,"after_return");return}await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set"),O(this.options.platform)||(await p(this.options.helper,"a",w(this.options.platform),this.options.traceId),await p(this.options.helper,"backspace",[],this.options.traceId));const a=await this.options.helper.request("clipboard.setText",{text:t.text},this.options.traceId);u(a,"clipboard.setText"),U(this.options.platform)&&await this.focusMessageInputWithRetry(t,"clipboard_set"),await this.ensureStageIdle(t,"paste"),o(t,"paste"),await this.primeWindowsTextPasteIfNeeded(t),await p(this.options.helper,"v",w(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.options.onAfterPaste?.({record:t,kind:"text"}),await this.ensureStageIdle(t,"before_return"),o(t,"before_return"),await p(this.options.helper,"return",[],this.options.traceId),s(),o(t,"after_return")}async primeWindowsTextPasteIfNeeded(t){if(!E(this.options.platform)||this.windowsTextClipboardPrimed)return;const s=await this.options.helper.request("keyboard.primeTextPaste",{},this.options.traceId);u(s,"keyboard.primeTextPaste"),this.windowsTextClipboardPrimed=!0,await this.ensureStageIdle(t,"paste")}async sendAttachmentsIfPresent(t,s){for(const a of t.attachmentLocalRefs??[]){M(a),await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set");const n=q(a),i=n==="image"&&y(this.options.platform)?await this.options.helper.request("clipboard.setImage",{filePath:a},this.options.traceId):await this.options.helper.request("clipboard.setFiles",{filePaths:[a]},this.options.traceId);u(i,n==="image"&&y(this.options.platform)?"clipboard.setImage":"clipboard.setFiles"),await this.ensureStageIdle(t,"paste"),o(t,"paste"),await p(this.options.helper,"v",w(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.options.onAfterPaste?.({record:t,kind:"attachment"}),await this.ensureStageIdle(t,"before_return"),o(t,"before_return"),await p(this.options.helper,"return",[],this.options.traceId),s(),o(t,"after_return")}}async withAutomationLease(t,s){const a=await this.options.helper.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`send:${t.bindingId}`,ttlMs:6e4},this.options.traceId);u(a,"automation.lease.acquire");const n=typeof a.result?.leaseId=="string"?a.result.leaseId:"";try{this.activeAutomationLeaseId=n||null,await s()}finally{this.activeAutomationLeaseId=null,n&&await this.releaseAutomationLease(n)}}async releaseAutomationLease(t){try{await this.options.helper.request("automation.lease.release",{leaseId:t},this.options.traceId)}catch{}}async waitAfterPaste(t){const s=(this.options.platform??process.platform)==="win32"?1e3:void 0;await d("send-post-paste",`${this.options.traceId||""}:${t.replyId}:post-paste`,this.options.postPasteSettleMs??s)}async focusMessageInputWithRetry(t,s="focus_input"){await T(this.options.helper,this.options.traceId,L(this.focus)),await this.ensureStageIdle(t,s)}async ensureStageIdle(t,s){if(this.options.takeoverCheck===!1)return;if(this.activeAutomationLeaseId){const i=await this.automationLeaseDecision();if(i.ok===!1)throw new m({reasonCode:i.reasonCode,nextAttemptAt:i.nextAttemptAt,stage:s,replyId:t.replyId});return}const a=await this.activitySnapshot(),n=I({snapshot:a,stage:R(s),policy:this.options.activityGatePolicy});if(!n.ok)throw new m({reasonCode:n.reasonCode,nextAttemptAt:b(new Date,n.waitMs),stage:s,replyId:t.replyId})}async activitySnapshot(){const t=await this.options.helper.request("activity.snapshot",{},this.options.traceId);return u(t,"activity.snapshot"),k(t.result)}async automationLeaseDecision(){if(!this.activeAutomationLeaseId)return{ok:!0};const t=await this.options.helper.request("automation.lease.status",{},this.options.traceId);u(t,"automation.lease.status");const s=t.result??{};return s.active===!1||s.leaseId!==this.activeAutomationLeaseId||!s.interrupted?{ok:!0}:{ok:!1,reasonCode:G(s.interruptReason),nextAttemptAt:new Date(Date.now()+1e3)}}}class m extends Error{reasonCode;nextAttemptAt;stage;replyId;constructor(t){super(`user_takeover_aborted:${t.reasonCode}:${t.stage}`),this.name="WeChatChannelUserTakeoverAbort",this.reasonCode=t.reasonCode,this.nextAttemptAt=t.nextAttemptAt,this.stage=t.stage,this.replyId=t.replyId}}function R(e){return e==="open_conversation"?"open_conversation":e==="queued"?"send_start":"dangerous_action"}async function T(e,t,s){const a={waitMs:f,...s?.windowId?{windowId:s.windowId}:{},...s?.inputPoint?{inputPoint:s.inputPoint}:{}};if((await e.request("wechat.focusMessageInput",a,t)).ok){await d("send-focus-stabilize",`${t||""}:focus-stabilize`);const c=await e.request("wechat.focusMessageInput",a,t);u(c,"wechat.focusMessageInput");return}await d("send-focus-retry",`${t||""}:focus-retry`);const i=await e.request("wechat.focusMessageInput",{...a,waitMs:Math.max(f,700)},t);u(i,"wechat.focusMessageInput")}async function p(e,t,s,a){const n=await e.request("keyboard.shortcut",{key:t,modifiers:s},a);u(n,"keyboard.shortcut")}function M(e){if(!g.statSync(e).isFile())throw new Error(`wechat_channel_attachment_not_file:${e}`)}function q(e){const t=A.extname(e).toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".heic",".tiff",".bmp"].includes(t)?"image":[".mp4",".mov",".m4v",".avi",".mkv",".webm"].includes(t)?"video":"file"}function y(e){return(e??process.platform)==="win32"}function w(e){return(e??process.platform)==="win32"?["control"]:["command"]}function L(e){if(e)return{...e.windowId?{windowId:e.windowId}:{},...e.inputPoint?{inputPoint:e.inputPoint}:{}}}function O(e){return(e??process.platform)==="win32"}function U(e){return(e??process.platform)==="win32"}function E(e){return(e??process.platform)==="win32"}function F(e){return!1}function D(e){return(e??process.platform)==="win32"}async function $(e,t,s,a){if((s??process.platform)!=="darwin")return;const n=t?.permissions;if(!n)return;const i=n.accessibilityTrusted===!1?"accessibility":n.iohidListenGranted===!1?"input-monitoring":null;if(i)throw await N(e,i==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring",a),new Error(`permission_missing:mac_input:${i}`)}async function N(e,t,s){try{await e.request(t,{},s)}catch{}}function z(e){const t=e instanceof Error?e.message:String(e);return/conversation_not|conversation.*visible|conversation.*open/i.test(t)?"conversation_not_opened":/wechat_message_input_point_required|wechat_message_input_not_found/i.test(t)?"wechat_message_input_not_found":/permission|accessibility|screen|automation/i.test(t)?"permission_missing":/clipboard/i.test(t)?"clipboard_failed":/attachment|not_file|ENOENT|no such file/i.test(t)?"attachment_unavailable":"send_failed"}function G(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function H(e){return e.stage==="before_return"}function u(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}export{J as WeChatChannelOutboundSender,m as WeChatChannelUserTakeoverAbort,Y as sendQueuedWeChatOutboundRecords};
1
+ import g from"node:fs";import A from"node:path";import{waitForWeChatChannelPacing as d}from"./pacing.js";import{guardWeChatOutboundRevision as v,markWeChatOutboundFailed as C,markWeChatOutboundManualReview as x,markWeChatOutboundCommitStage as o,markWeChatOutboundSending as P,markWeChatOutboundSentUnconfirmed as S,markWeChatOutboundUserActiveTimeout as h,markWeChatOutboundWaitingUserIdle as _,shouldFailWeChatOutboundForUserActiveTimeout as l}from"./outbound-ledger.js";import{decideWeChatChannelActivityGate as I,nextWeChatChannelActivityRetryAt as b,normalizeWeChatChannelActivitySnapshot as k}from"./human-coordination.js";const W=600*1e3,f=520;async function Y(e){const t={sentRecords:[],staleRecords:[],failedRecords:[],waitingRecords:[],manualReviewRecords:[]},s=e.now??new Date,a=e.maxUserActivityWaitMs??W,n=e.ledger.records.filter(i=>i.bindingId===e.bindingId&&i.sendStatus==="queued");for(const i of n){if(l({record:i,now:s,maxWaitMs:a})){h(i,s),t.failedRecords.push(i);continue}if(!v({record:i,currentLastInboundRevision:e.currentLastInboundRevision,now:s}).ok){t.staleRecords.push(i);continue}try{const r=await e.sender.canStart(i,s);if(r.ok===!1){_({record:i,reasonCode:r.reasonCode,nextAttemptAt:r.nextAttemptAt,now:s}),l({record:i,now:s,maxWaitMs:a})?(h(i,s),t.failedRecords.push(i)):t.waitingRecords.push(i);continue}P(i),await e.sender.send(i),S(i,s),t.sentRecords.push(i)}catch(r){if(r instanceof m){if(H(r)){x(i,"user_takeover_before_return","User activity was detected after paste and before Return; manual WeChat inspection is required",r.stage),t.manualReviewRecords.push(i);continue}_({record:i,reasonCode:r.reasonCode,nextAttemptAt:r.nextAttemptAt,now:s}),l({record:i,now:s,maxWaitMs:a})?(h(i,s),t.failedRecords.push(i)):t.waitingRecords.push(i);continue}C(i,z(r),r instanceof Error?r.message:String(r)),t.failedRecords.push(i)}}return t}class J{options;activeAutomationLeaseId=null;focus;windowsTextClipboardPrimed=!1;constructor(t){this.options=t}async canStart(t,s=new Date){const a=await this.activitySnapshot();await $(this.options.helper,a,this.options.platform,this.options.traceId);const n=I({snapshot:a,stage:"send_start",policy:this.options.activityGatePolicy});return n.ok===!1?{ok:!1,reasonCode:n.reasonCode,nextAttemptAt:b(s,n.waitMs)}:{ok:!0}}async send(t){await this.withAutomationLease(t,()=>this.sendWithLease(t))}async sendWithLease(t){await this.ensureStageIdle(t,"open_conversation"),o(t,"open_conversation");const s=await this.options.openConversation(t.conversationName);if(!s.opened)throw new Error(s.reason||"conversation_not_opened");if(D(this.options.platform)&&!s.inputPoint)throw new Error("wechat_message_input_point_required: Windows send requires a vision-detected message input point");o(t,"focus_input"),this.focus={windowId:s.windowId??void 0,inputPoint:s.inputPoint??void 0},await this.focusMessageInputWithRetry(t),await this.ensureStageIdle(t,"clipboard_snapshot"),o(t,"clipboard_snapshot");const a=await this.options.helper.request("clipboard.snapshot",{},this.options.traceId);u(a,"clipboard.snapshot");let n=!1;try{await this.sendTextIfPresent(t,()=>{n=!0}),await this.sendAttachmentsIfPresent(t,()=>{n=!0})}finally{const i=a.result&&typeof a.result=="object"?a.result:{},c=await this.options.helper.request("clipboard.restore",i,this.options.traceId);n||u(c,"clipboard.restore")}}async sendTextIfPresent(t,s){if(!t.text)return;if(F(this.options.platform)){await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set"),await this.ensureStageIdle(t,"paste"),o(t,"paste");const n=await this.options.helper.request("wechat.pasteAndSubmit",{text:t.text,waitMs:f,pasteWaitMs:this.options.postPasteSettleMs??900,...this.focus?.windowId?{windowId:this.focus.windowId}:{},...this.focus?.inputPoint?{inputPoint:this.focus.inputPoint}:{}},this.options.traceId);u(n,"wechat.pasteAndSubmit"),s(),o(t,"after_return");return}await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set"),O(this.options.platform)||(await p(this.options.helper,"a",w(this.options.platform),this.options.traceId),await p(this.options.helper,"backspace",[],this.options.traceId));const a=await this.options.helper.request("clipboard.setText",{text:t.text},this.options.traceId);u(a,"clipboard.setText"),U(this.options.platform)&&await this.focusMessageInputWithRetry(t,"clipboard_set"),await this.ensureStageIdle(t,"paste"),o(t,"paste"),await this.primeWindowsTextPasteIfNeeded(t),await p(this.options.helper,"v",w(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.options.onAfterPaste?.({record:t,kind:"text"}),await this.ensureStageIdle(t,"before_return"),o(t,"before_return"),await p(this.options.helper,"return",[],this.options.traceId),s(),o(t,"after_return")}async primeWindowsTextPasteIfNeeded(t){if(!E(this.options.platform)||this.windowsTextClipboardPrimed)return;const s=await this.options.helper.request("keyboard.primeTextPaste",{},this.options.traceId);u(s,"keyboard.primeTextPaste"),this.windowsTextClipboardPrimed=!0,await this.ensureStageIdle(t,"paste")}async sendAttachmentsIfPresent(t,s){for(const a of t.attachmentLocalRefs??[]){M(a),await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set");const n=q(a),i=n==="image"&&y(this.options.platform)?await this.options.helper.request("clipboard.setImage",{filePath:a},this.options.traceId):await this.options.helper.request("clipboard.setFiles",{filePaths:[a]},this.options.traceId);u(i,n==="image"&&y(this.options.platform)?"clipboard.setImage":"clipboard.setFiles"),await this.ensureStageIdle(t,"paste"),o(t,"paste"),await p(this.options.helper,"v",w(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.options.onAfterPaste?.({record:t,kind:"attachment"}),await this.ensureStageIdle(t,"before_return"),o(t,"before_return"),await p(this.options.helper,"return",[],this.options.traceId),s(),o(t,"after_return")}}async withAutomationLease(t,s){const a=await this.options.helper.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`send:${t.bindingId}`,ttlMs:6e4},this.options.traceId);u(a,"automation.lease.acquire");const n=typeof a.result?.leaseId=="string"?a.result.leaseId:"";try{this.activeAutomationLeaseId=n||null,await s()}finally{this.activeAutomationLeaseId=null,n&&await this.releaseAutomationLease(n)}}async releaseAutomationLease(t){try{await this.options.helper.request("automation.lease.release",{leaseId:t},this.options.traceId)}catch{}}async waitAfterPaste(t){const s=(this.options.platform??process.platform)==="win32"?1e3:void 0;await d("send-post-paste",`${this.options.traceId||""}:${t.replyId}:post-paste`,this.options.postPasteSettleMs??s)}async focusMessageInputWithRetry(t,s="focus_input"){await T(this.options.helper,this.options.traceId,L(this.focus)),await this.ensureStageIdle(t,s)}async ensureStageIdle(t,s){if(this.options.takeoverCheck===!1)return;if(this.activeAutomationLeaseId){const i=await this.automationLeaseDecision();if(i.ok===!1)throw new m({reasonCode:i.reasonCode,nextAttemptAt:i.nextAttemptAt,stage:s,replyId:t.replyId});return}const a=await this.activitySnapshot(),n=I({snapshot:a,stage:R(s),policy:this.options.activityGatePolicy});if(!n.ok)throw new m({reasonCode:n.reasonCode,nextAttemptAt:b(new Date,n.waitMs),stage:s,replyId:t.replyId})}async activitySnapshot(){const t=await this.options.helper.request("activity.snapshot",{},this.options.traceId);return u(t,"activity.snapshot"),k(t.result)}async automationLeaseDecision(){if(!this.activeAutomationLeaseId)return{ok:!0};const t=await this.options.helper.request("automation.lease.status",{},this.options.traceId);u(t,"automation.lease.status");const s=t.result??{};return s.active===!1||s.leaseId!==this.activeAutomationLeaseId||!s.interrupted?{ok:!0}:{ok:!1,reasonCode:G(s.interruptReason),nextAttemptAt:new Date(Date.now()+1e3)}}}class m extends Error{reasonCode;nextAttemptAt;stage;replyId;constructor(t){super(`user_takeover_aborted:${t.reasonCode}:${t.stage}`),this.name="WeChatChannelUserTakeoverAbort",this.reasonCode=t.reasonCode,this.nextAttemptAt=t.nextAttemptAt,this.stage=t.stage,this.replyId=t.replyId}}function R(e){return e==="open_conversation"?"open_conversation":e==="queued"?"send_start":"dangerous_action"}async function T(e,t,s){const a={waitMs:f,...s?.windowId?{windowId:s.windowId}:{},...s?.inputPoint?{inputPoint:s.inputPoint}:{}};if((await e.request("wechat.focusMessageInput",a,t)).ok){await d("send-focus-stabilize",`${t||""}:focus-stabilize`);const c=await e.request("wechat.focusMessageInput",a,t);u(c,"wechat.focusMessageInput");return}await d("send-focus-retry",`${t||""}:focus-retry`);const i=await e.request("wechat.focusMessageInput",{...a,waitMs:Math.max(f,700)},t);u(i,"wechat.focusMessageInput")}async function p(e,t,s,a){const n=await e.request("keyboard.shortcut",{key:t,modifiers:s},a);u(n,"keyboard.shortcut")}function M(e){if(!g.statSync(e).isFile())throw new Error(`wechat_channel_attachment_not_file:${e}`)}function q(e){const t=A.extname(e).toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".heic",".tiff",".bmp"].includes(t)?"image":[".mp4",".mov",".m4v",".avi",".mkv",".webm"].includes(t)?"video":"file"}function y(e){return(e??process.platform)==="win32"}function w(e){return(e??process.platform)==="win32"?["control"]:["command"]}function L(e){if(e)return{...e.windowId?{windowId:e.windowId}:{},...e.inputPoint?{inputPoint:e.inputPoint}:{}}}function O(e){return(e??process.platform)==="win32"}function U(e){return(e??process.platform)==="win32"}function E(e){return(e??process.platform)==="win32"}function F(e){return(e??process.platform)==="win32"}function D(e){return(e??process.platform)==="win32"}async function $(e,t,s,a){if((s??process.platform)!=="darwin")return;const n=t?.permissions;if(!n)return;const i=n.accessibilityTrusted===!1?"accessibility":n.iohidListenGranted===!1?"input-monitoring":null;if(i)throw await N(e,i==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring",a),new Error(`permission_missing:mac_input:${i}`)}async function N(e,t,s){try{await e.request(t,{},s)}catch{}}function z(e){const t=e instanceof Error?e.message:String(e);return/conversation_not|conversation.*visible|conversation.*open/i.test(t)?"conversation_not_opened":/wechat_message_input_point_required|wechat_message_input_not_found/i.test(t)?"wechat_message_input_not_found":/permission|accessibility|screen|automation/i.test(t)?"permission_missing":/clipboard/i.test(t)?"clipboard_failed":/attachment|not_file|ENOENT|no such file/i.test(t)?"attachment_unavailable":"send_failed"}function G(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function H(e){return e.stage==="before_return"}function u(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}export{J as WeChatChannelOutboundSender,m as WeChatChannelUserTakeoverAbort,Y as sendQueuedWeChatOutboundRecords};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.2.112",
3
+ "version": "0.2.114",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {