shennian 0.2.97 → 0.2.99

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.
@@ -266,8 +266,8 @@
266
266
  },
267
267
  {
268
268
  "file": "src/channels/wechat-channel/observer.js",
269
- "beforeBytes": 80918,
270
- "afterBytes": 37541
269
+ "beforeBytes": 81300,
270
+ "afterBytes": 37693
271
271
  },
272
272
  {
273
273
  "file": "src/channels/wechat-channel/outbound-ledger.js",
@@ -321,8 +321,8 @@
321
321
  },
322
322
  {
323
323
  "file": "src/channels/wechat-rpa/product-channel.js",
324
- "beforeBytes": 13524,
325
- "afterBytes": 7360
324
+ "beforeBytes": 13531,
325
+ "afterBytes": 7396
326
326
  },
327
327
  {
328
328
  "file": "src/channels/wechat-rpa.js",
@@ -386,8 +386,8 @@
386
386
  },
387
387
  {
388
388
  "file": "src/commands/wechat.js",
389
- "beforeBytes": 33293,
390
- "afterBytes": 18694
389
+ "beforeBytes": 37003,
390
+ "afterBytes": 20262
391
391
  },
392
392
  {
393
393
  "file": "src/config/index.js",
@@ -401,8 +401,8 @@
401
401
  },
402
402
  {
403
403
  "file": "src/devtools/wechat-channel-action-smoke.js",
404
- "beforeBytes": 67091,
405
- "afterBytes": 35476
404
+ "beforeBytes": 67181,
405
+ "afterBytes": 35507
406
406
  },
407
407
  {
408
408
  "file": "src/devtools/wechat-channel-download-report.js",
@@ -466,8 +466,8 @@
466
466
  },
467
467
  {
468
468
  "file": "src/manager/runtime.js",
469
- "beforeBytes": 54318,
470
- "afterBytes": 27932
469
+ "beforeBytes": 57340,
470
+ "afterBytes": 29445
471
471
  },
472
472
  {
473
473
  "file": "src/native-fusion/config.js",
@@ -104,6 +104,7 @@ export declare function openConversationInVisibleList(input: {
104
104
  binding: WeChatChannelBindingConfig;
105
105
  traceId?: string;
106
106
  observation?: WeChatChannelWindowObservation;
107
+ allowOcrTitleRows?: boolean;
107
108
  }): Promise<{
108
109
  opened: boolean;
109
110
  reason: string;
@@ -1,6 +1,6 @@
1
- import{defaultWeChatChannelAttachmentDir as pe,resolveVisibleWeChatChannelMedia as Ce}from"./media-resolver.js";import{updateWeChatChannelBindingLedger as Ne}from"./ledger.js";import{defaultWeChatChannelVectorStorePath as Ie,loadWeChatChannelVectorStore as Se,saveWeChatChannelVectorStore as Me,upsertWeChatChannelVectorReferences as ke}from"./vector-store.js";import{normalizeWeChatChannelAttachmentAvailability as $,normalizeWeChatChannelMessageKind as Te}from"./core/schema.js";import{matchWeChatConversationFingerprints as _e}from"./fingerprint.js";import{normalizeWeChatAnchorText as p,weChatTextSimilarity as V}from"./anchor.js";const Be=3,We=5,Fe=420,q="wechat_login_required",F="wechat_duplicate_instance";async function jt(e){let t=await ot(e.helper,e.traceId);t=await lt(e.helper,t,e.traceId);const n=await ae({helper:e.helper,window:t,binding:e.binding,traceId:e.traceId});if(!n.opened)throw new Error(n.reason||"conversation_not_opened");let{capture:r,ocr:i}=await T({helper:e.helper,window:t,traceId:e.traceId});if(be({capture:r,ocr:i,binding:e.binding})){t=await ie(e.helper,e.traceId);const o=await ae({helper:e.helper,window:t,binding:e.binding,traceId:e.traceId});if(!o.opened)throw new Error(o.reason||"wechat_window_obstructed");if({capture:r,ocr:i}=await T({helper:e.helper,window:t,traceId:e.traceId}),be({capture:r,ocr:i,binding:e.binding}))throw new Error("wechat_window_obstructed")}return e.onObservationEvidence?.({window:t,capture:r,ocr:i}),Ee(e)?Ae({...e,window:t,capture:r,ocr:i}):j({...e,window:t,capture:r,ocr:i})}function Ee(e){return e.observePipeline==="edge-structure"?!0:e.observePipeline==="server-observe"?!1:!!e.api.structureWindow}async function j(e){const t=await de(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??[]}),r=await G({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 ge(r,me({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}))}async function Ae(e){if(!e.api.structureWindow)throw new Error("wechat_structure_window_unavailable");const t=await de(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??[]})}catch(c){if(Re(c))return j(e);throw c}const r=qe(n.structuredMessages??n.observedMessages??[]),i=await Oe({...e,messages:r,screenshot:t}),o=await G({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}),a=ge(o,me({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}));return e.localLedger?Ne({ledger:e.localLedger,bindingId:e.binding.bindingId,observedMessages:a,baselineOnly:e.baselineOnly,vectorReferences:i.vectorReferences}).newMessages:a}function Re(e){return e instanceof Error&&/\bedge_runtime_disabled\b/.test(e.message)}async function Oe(e){const t=Le(e.messages);if(!t.length)return{messages:e.messages,vectorReferences:[]};const n=e.api.embedVisual?await Pe({...e,seedBlocks:t}):t.filter(a=>h(a.vectorBase64)||h(a.signature));if(!n.length)return{messages:e.messages,vectorReferences:[]};const r=e.vectorStorePath??Ie(e.workDir||process.cwd(),e.runtime.runtimeId),i=Se(r,e.runtime.runtimeId),o=ke({store:i,bindingId:e.binding.bindingId,blocks:n});return o.length?(Me(r,i),{messages:$e(e.messages,o),vectorReferences:o}):{messages:e.messages,vectorReferences:[]}}function Le(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}`,a=h(i.blockKind)||n.kind||"visual";t.push({...i,stableMessageKey:n.stableMessageKey,blockId:o,blockKind:a,...i.bbox!==void 0?{bbox:i.bbox}:n.bbox!==void 0?{bbox:n.bbox}:{}})}return t}async function ze(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 De(t.visualBlocks??t.embeddedBlocks??[],e.seedBlocks)}async function Pe(e){try{return await ze(e)}catch(t){if(Ke(t))throw t;return[]}}function Ke(e){return!e||typeof e!="object"?!1:e.reasonCode==="insufficient_credits"?!0:e instanceof Error&&/\binsufficient_credits\b/.test(e.message)}function De(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 $e(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:Ve(r,i)}:r})}function Ve(e,t){const r=(e.visualBlocks??[]).map((o,a)=>{const s=h(o.blockId)||`${e.stableMessageKey}:visual-${a}`,c=t.find(d=>d.blockId===s);return c?Y(c,o):H(o)}),i=new Set(r.map(o=>o.blockId));for(const o of t)i.has(o.blockId)||r.push(Y(o));return r}function Y(e,t){return{...t?H(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 H(e){const{vectorBase64:t,...n}=e;return n}function qe(e){return e.map((t,n)=>je(t,n)).filter(t=>t!=null)}function je(e,t){if(!b(e))return null;const n=Te(e.kind),r=Ue(e.senderRole),i=g(e.normalizedText),o=g(e.anchorText)??i??g(e.textExcerpt),a=h(e.stableMessageKey)||Ye({message:e,index:t,senderRole:r,kind:n,anchorText:o});return{stableMessageKey:a,senderRole:r,...g(e.senderName)!==null?{senderName:g(e.senderName)}:{},kind:n,...i!==null?{normalizedText:i}:{},...o!==null?{anchorText:o}:{},...I(e,"anchorMetadata")?{anchorMetadata:e.anchorMetadata}:{},...I(e,"neighborContext")?{neighborContext:e.neighborContext}:{},...g(e.textExcerpt)!==null?{textExcerpt:g(e.textExcerpt)}:{},...I(e,"bbox")?{bbox:e.bbox}:{},...I(e,"mediaMetadata")?{mediaMetadata:He(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:a}}}function Ye(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 He(e){if(!b(e))return e;const t={...e};return I(t,"availability")&&(t.availability=$(t.availability)),b(t.attachment)&&(t.attachment=U(t.attachment)),Array.isArray(t.attachments)&&(t.attachments=t.attachments.map(n=>b(n)?U(n):n)),t}function U(e){const t={...e};return I(t,"availability")&&(t.availability=$(t.availability)),t}function Ue(e){return e==="self"||e==="contact"||e==="system"||e==="unknown"?e:"unknown"}async function G(e){if(e.binding.downloadMedia===!1)return e.messages;const t=e.messages.map((o,a)=>tt(o,e.screenshot,e.window,et(e.messages,a))).filter((o,a)=>Ge(e.messages,a,e.mediaAnchorText)).filter(o=>o!=null);if(!t.length)return e.messages;const n=e.attachmentsDir??pe(e.workDir||process.cwd(),e.runtime.runtimeId,e.binding.bindingId),r=await Ce({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 k({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 a=i.get(o.stableMessageKey);return a?{...o,mediaMetadata:nt(o.mediaMetadata,a.attachment,a.reasonCode,a.attemptReasonCodes,a.resolveTrace)}:o})}function Ge(e,t,n){const r=Z(n);if(!r)return!0;const i=Xe(r),o=e.map((a,s)=>Z(Qe(a)).includes(r)?s:-1).filter(a=>a>=0);if(!o.length)return t===Ze(e,i);for(const a of o)if(t>=a&&t<=a+8||t===a-1&&!e.slice(a+1,Math.min(e.length,a+9)).some(X))return!0;return!1}function Xe(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 Ze(e,t=null){for(let n=e.length-1;n>=0;n-=1)if(X(e[n]))return Je(e[n],t)?n:-1;return-1}function X(e){if(!e)return!1;const t=String(e.kind||"").toLowerCase(),n=b(e.mediaMetadata)?e.mediaMetadata:{},r=b(n.attachment)?n.attachment:{};return J(t,n,r)}function Je(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(),a=String(i.mimeType||"").toLowerCase(),s=String(i.name||i.localPath||e.anchorText||e.textExcerpt||"").toLowerCase();return t==="video"?n.includes("video")||o==="video"||a.startsWith("video/")||/\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(s):t==="image"?/image|photo|picture/.test(n)||o==="image"||a.startsWith("image/")||/\.(png|jpe?g|gif|webp|heic|tiff?|bmp)$/i.test(s):/file|document/.test(n)||o==="file"||!/image|photo|picture|video/.test(n)&&o!=="image"&&o!=="video"&&!a.startsWith("image/")&&!a.startsWith("video/")}function Qe(e){if(!e)return"";const t=e;return[e.normalizedText,e.anchorText,e.textExcerpt,t.text].map(n=>String(n||"")).join(`
1
+ import{defaultWeChatChannelAttachmentDir as pe,resolveVisibleWeChatChannelMedia as Ce}from"./media-resolver.js";import{updateWeChatChannelBindingLedger as Ne}from"./ledger.js";import{defaultWeChatChannelVectorStorePath as Ie,loadWeChatChannelVectorStore as Se,saveWeChatChannelVectorStore as Me,upsertWeChatChannelVectorReferences as ke}from"./vector-store.js";import{normalizeWeChatChannelAttachmentAvailability as $,normalizeWeChatChannelMessageKind as Te}from"./core/schema.js";import{matchWeChatConversationFingerprints as _e}from"./fingerprint.js";import{normalizeWeChatAnchorText as p,weChatTextSimilarity as V}from"./anchor.js";const Be=3,We=5,Fe=420,q="wechat_login_required",F="wechat_duplicate_instance";async function jt(e){let t=await ot(e.helper,e.traceId);t=await lt(e.helper,t,e.traceId);const n=await ae({helper:e.helper,window:t,binding:e.binding,traceId:e.traceId});if(!n.opened)throw new Error(n.reason||"conversation_not_opened");let{capture:r,ocr:i}=await T({helper:e.helper,window:t,traceId:e.traceId});if(be({capture:r,ocr:i,binding:e.binding})){t=await ie(e.helper,e.traceId);const o=await ae({helper:e.helper,window:t,binding:e.binding,traceId:e.traceId});if(!o.opened)throw new Error(o.reason||"wechat_window_obstructed");if({capture:r,ocr:i}=await T({helper:e.helper,window:t,traceId:e.traceId}),be({capture:r,ocr:i,binding:e.binding}))throw new Error("wechat_window_obstructed")}return e.onObservationEvidence?.({window:t,capture:r,ocr:i}),Ee(e)?Re({...e,window:t,capture:r,ocr:i}):j({...e,window:t,capture:r,ocr:i})}function Ee(e){return e.observePipeline==="edge-structure"?!0:e.observePipeline==="server-observe"?!1:!!e.api.structureWindow}async function j(e){const t=await de(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??[]}),r=await G({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 ge(r,me({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}))}async function Re(e){if(!e.api.structureWindow)throw new Error("wechat_structure_window_unavailable");const t=await de(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??[]})}catch(c){if(Ae(c))return j(e);throw c}const r=qe(n.structuredMessages??n.observedMessages??[]),i=await Oe({...e,messages:r,screenshot:t}),o=await G({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}),a=ge(o,me({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}));return e.localLedger?Ne({ledger:e.localLedger,bindingId:e.binding.bindingId,observedMessages:a,baselineOnly:e.baselineOnly,vectorReferences:i.vectorReferences}).newMessages:a}function Ae(e){return e instanceof Error&&/\bedge_runtime_disabled\b/.test(e.message)}async function Oe(e){const t=Le(e.messages);if(!t.length)return{messages:e.messages,vectorReferences:[]};const n=e.api.embedVisual?await Pe({...e,seedBlocks:t}):t.filter(a=>u(a.vectorBase64)||u(a.signature));if(!n.length)return{messages:e.messages,vectorReferences:[]};const r=e.vectorStorePath??Ie(e.workDir||process.cwd(),e.runtime.runtimeId),i=Se(r,e.runtime.runtimeId),o=ke({store:i,bindingId:e.binding.bindingId,blocks:n});return o.length?(Me(r,i),{messages:$e(e.messages,o),vectorReferences:o}):{messages:e.messages,vectorReferences:[]}}function Le(e){const t=[];for(const n of e)for(const[r,i]of(n.visualBlocks??[]).entries()){const o=u(i.blockId)||`${n.stableMessageKey}:visual-${r}`,a=u(i.blockKind)||n.kind||"visual";t.push({...i,stableMessageKey:n.stableMessageKey,blockId:o,blockKind:a,...i.bbox!==void 0?{bbox:i.bbox}:n.bbox!==void 0?{bbox:n.bbox}:{}})}return t}async function ze(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 De(t.visualBlocks??t.embeddedBlocks??[],e.seedBlocks)}async function Pe(e){try{return await ze(e)}catch(t){if(Ke(t))throw t;return[]}}function Ke(e){return!e||typeof e!="object"?!1:e.reasonCode==="insufficient_credits"?!0:e instanceof Error&&/\binsufficient_credits\b/.test(e.message)}function De(e,t){return e.map((n,r)=>{const i=t[r];return{...n,stableMessageKey:u(n.stableMessageKey)||u(i?.stableMessageKey),blockId:u(n.blockId)||u(i?.blockId),blockKind:u(n.blockKind)||u(i?.blockKind)||"visual",...n.bbox!==void 0?{bbox:n.bbox}:i?.bbox!==void 0?{bbox:i.bbox}:{}}}).filter(n=>u(n.stableMessageKey)&&u(n.blockId))}function $e(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:Ve(r,i)}:r})}function Ve(e,t){const r=(e.visualBlocks??[]).map((o,a)=>{const s=u(o.blockId)||`${e.stableMessageKey}:visual-${a}`,c=t.find(d=>d.blockId===s);return c?Y(c,o):H(o)}),i=new Set(r.map(o=>o.blockId));for(const o of t)i.has(o.blockId)||r.push(Y(o));return r}function Y(e,t){return{...t?H(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 H(e){const{vectorBase64:t,...n}=e;return n}function qe(e){return e.map((t,n)=>je(t,n)).filter(t=>t!=null)}function je(e,t){if(!b(e))return null;const n=Te(e.kind),r=Ue(e.senderRole),i=x(e.normalizedText),o=x(e.anchorText)??i??x(e.textExcerpt),a=u(e.stableMessageKey)||Ye({message:e,index:t,senderRole:r,kind:n,anchorText:o});return{stableMessageKey:a,senderRole:r,...x(e.senderName)!==null?{senderName:x(e.senderName)}:{},kind:n,...i!==null?{normalizedText:i}:{},...o!==null?{anchorText:o}:{},...I(e,"anchorMetadata")?{anchorMetadata:e.anchorMetadata}:{},...I(e,"neighborContext")?{neighborContext:e.neighborContext}:{},...x(e.textExcerpt)!==null?{textExcerpt:x(e.textExcerpt)}:{},...I(e,"bbox")?{bbox:e.bbox}:{},...I(e,"mediaMetadata")?{mediaMetadata:He(e.mediaMetadata)}:{},...typeof e.isBaseline=="boolean"?{isBaseline:e.isBaseline}:{},...x(e.deliveryStatus)!==null?{deliveryStatus:x(e.deliveryStatus)??void 0}:{},...x(e.observedAt)!==null?{observedAt:x(e.observedAt)??void 0}:{},...Array.isArray(e.visualBlocks)?{visualBlocks:e.visualBlocks}:{},...o?{}:{anchorText:a}}}function Ye(e){const t=b(e.message.bbox)?JSON.stringify(e.message.bbox):"";return`structured-window:${[e.index,e.senderRole,e.kind,e.anchorText||u(e.message.textExcerpt)||"",t].join(":").slice(0,180)}`}function He(e){if(!b(e))return e;const t={...e};return I(t,"availability")&&(t.availability=$(t.availability)),b(t.attachment)&&(t.attachment=U(t.attachment)),Array.isArray(t.attachments)&&(t.attachments=t.attachments.map(n=>b(n)?U(n):n)),t}function U(e){const t={...e};return I(t,"availability")&&(t.availability=$(t.availability)),t}function Ue(e){return e==="self"||e==="contact"||e==="system"||e==="unknown"?e:"unknown"}async function G(e){if(e.binding.downloadMedia===!1)return e.messages;const t=e.messages.map((o,a)=>tt(o,e.screenshot,e.window,et(e.messages,a))).filter((o,a)=>Ge(e.messages,a,e.mediaAnchorText)).filter(o=>o!=null);if(!t.length)return e.messages;const n=e.attachmentsDir??pe(e.workDir||process.cwd(),e.runtime.runtimeId,e.binding.bindingId),r=await Ce({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 k({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 a=i.get(o.stableMessageKey);return a?{...o,mediaMetadata:nt(o.mediaMetadata,a.attachment,a.reasonCode,a.attemptReasonCodes,a.resolveTrace)}:o})}function Ge(e,t,n){const r=Z(n);if(!r)return!0;const i=Xe(r),o=e.map((a,s)=>Z(Qe(a)).includes(r)?s:-1).filter(a=>a>=0);if(!o.length)return t===Ze(e,i);for(const a of o)if(t>=a&&t<=a+8||t===a-1&&!e.slice(a+1,Math.min(e.length,a+9)).some(X))return!0;return!1}function Xe(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 Ze(e,t=null){for(let n=e.length-1;n>=0;n-=1)if(X(e[n]))return Je(e[n],t)?n:-1;return-1}function X(e){if(!e)return!1;const t=String(e.kind||"").toLowerCase(),n=b(e.mediaMetadata)?e.mediaMetadata:{},r=b(n.attachment)?n.attachment:{};return J(t,n,r)}function Je(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(),a=String(i.mimeType||"").toLowerCase(),s=String(i.name||i.localPath||e.anchorText||e.textExcerpt||"").toLowerCase();return t==="video"?n.includes("video")||o==="video"||a.startsWith("video/")||/\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(s):t==="image"?/image|photo|picture/.test(n)||o==="image"||a.startsWith("image/")||/\.(png|jpe?g|gif|webp|heic|tiff?|bmp)$/i.test(s):/file|document/.test(n)||o==="file"||!/image|photo|picture|video/.test(n)&&o!=="image"&&o!=="video"&&!a.startsWith("image/")&&!a.startsWith("video/")}function Qe(e){if(!e)return"";const t=e;return[e.normalizedText,e.anchorText,e.textExcerpt,t.text].map(n=>String(n||"")).join(`
2
2
  `)}function Z(e){return String(e||"").normalize("NFKC").replace(/[o]/giu,"0").replace(/[^\p{L}\p{N}]/gu,"").toLowerCase()}function et(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(`
3
- `)||null}function tt(e,t,n,r){const i=String(e.kind||"").toLowerCase(),o=b(e.mediaMetadata)?e.mediaMetadata:{},a=b(o.attachment)?o.attachment:{},s=h(a.availability)||h(o.availability),c=h(a.localPath)||h(o.localPath);if(s==="edge-local"&&c||!J(i,o,a))return null;const d=E(e.bbox)??E(o.bbox)??E(o.downloadActionBbox),l=E(o.downloadActionBbox),f=Q(d,t,n),u=it(d,t,n),x=Q(l,t,n);return{messageKey:e.stableMessageKey,kind:h(a.type)||h(a.kind)||h(o.messageType)||i,fileName:h(a.name)||h(a.fileName)||h(o.fileName)||null,mimeType:h(a.mimeType)||h(o.mimeType)||null,size:S(a.size)??S(o.size),mediaStatus:rt(o,a),observedAt:e.observedAt??null,contextText:r??e.normalizedText??e.anchorText??e.textExcerpt??null,...f?{bbox:f}:{},...u?{screenshotBbox:u}:{},...x?{downloadActionBbox:x}:{}}}function nt(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 J(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 E(e){if(!b(e))return null;const t=S(e.x),n=S(e.y),r=S(e.width),i=S(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 Q(e,t,n){if(!e)return null;if(e.coordinateSpace==="screen")return e;const r=B(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,a=i.height/t.height,s=r.x,c=r.y;return{x:s-e.width*o/2,y:c-e.height*a/2,width:e.width*o,height:e.height*a,coordinateSpace:"screen"}}function it(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 I(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 S(e){const t=Number(e);return Number.isFinite(t)?t:null}async function Yt(e,t){await ee(e,t)}async function ee(e,t){let n=await e.request("permissions.check",{},t);w(n,"permissions.check");const r=n.result??{};if(r.screenRecording===!1)throw new Error("permission_screen_recording_missing");if(r.automation===!1)throw new Error("permission_automation_missing");if(r.wechatRunning===!1)throw new Error("wechat_not_running");if(at(r))throw new Error(F);if(r.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(te([...r.captureCandidates??[],...r.restoreCandidates??[],...r.hiddenRestoreCandidates??[],...r.duplicateMainWindows??[],...r.unsafeAuxiliaryWindows??[]]))throw new Error(F);if(r.wechatWindowAvailable===!1&&String(r.platform??"").toLowerCase()!=="win32")throw new Error("wechat_window_unavailable");return r}async function ot(e,t){const n=await ee(e,t);if(String(n.platform??"").toLowerCase()==="win32"){const i=await e.request("windows.ensureReady",{activate:!0,allowRecovery:!1,allowLaunch:!1},t);w(i,"windows.ensureReady");const o=i.result;if(!o?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return o}const r=await ie(e,t);if(!r?.windowId)throw new Error("helper_invalid_response: windows.list missing WeChat window data");return r}function te(e,t){const n=e.filter(v).filter(i=>i.visible!==!1&&i.minimized!==!0),r=t??n.slice().sort((i,o)=>M(o)-M(i))[0];return n.find(i=>st(i,r))??null}function at(e){return e.duplicateInstanceBlocked===!0||Number(e.duplicateMainWindowCount??0)>0||Number(e.unsafeAuxiliaryWindowCount??0)>0||(e.duplicateMainWindows??[]).some(v)||(e.unsafeAuxiliaryWindows??[]).some(v)}function L(e){const t=e.filter(v).filter(i=>i.visible!==!1&&i.minimized!==!0),n=t.filter(re);if(n.length>1)throw new Error(F);const r=n.slice().sort((i,o)=>M(o)-M(i))[0];if(te(t,r))throw new Error(F)}function ne(e){const t=e.filter(v),n=t.filter(o=>o.visible!==!1&&o.minimized!==!0),r=n.filter(re);return(r.length?r:n.length?n:t).slice().sort((o,a)=>M(a)-M(o))[0]??null}function st(e,t){if(!v(e)||t&&dt(e,t)||e.visible===!1||e.minimized===!0)return!1;const n=Number(e.bounds?.width),r=Number(e.bounds?.height);if(!Number.isFinite(n)||!Number.isFinite(r))return!1;const i=n>=360&&n<=720&&r>=420&&r<=840&&r>n,o=n>=420&&n<=680&&r>=260&&r<=460;return!(!i&&!o||t&&ct(e,t))}function ct(e,t){const n=Number(e.rootProcessId),r=Number(t.rootProcessId);if(!Number.isFinite(n)||!Number.isFinite(r)||n!==r)return!1;const i=Number(e.zOrder),o=Number(t.zOrder);return!Number.isFinite(i)||!Number.isFinite(o)?!1:i>o}function re(e){const t=Number(e.bounds?.width),n=Number(e.bounds?.height);return Number.isFinite(t)&&Number.isFinite(n)&&t>=760&&n>=600}function M(e){const t=Number(e.bounds?.width),n=Number(e.bounds?.height);return Number.isFinite(t)&&Number.isFinite(n)?t*n:0}function dt(e,t){return!!(e.windowId&&t.windowId&&e.windowId===t.windowId)}async function Ht(e,t){let n=await e.request("windows.list",{},t);w(n,"windows.list");let r=n.result?.windows??[];L(r);let i=ne(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return w(o,"windows.focus"),await oe(e,i,t)}async function lt(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 w(r,"windows.focus"),t}async function ie(e,t){const n=await e.request("windows.list",{},t);w(n,"windows.list");const r=n.result?.windows??[];L(r);const i=ne(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return w(o,"windows.focus"),await oe(e,i,t)}async function oe(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(v);return L(i),i.find(o=>o.windowId===t.windowId)??i[0]??t}async function z(e){const{capture:t,ocr:n}=e.observation??await T(e),r=A({capture:t,ocr:n,window:e.window});if(r)return{opened:!1,reason:r};const i=_e({visibleItems:yt(n,t),targets:[{bindingId:e.binding.bindingId,conversationDisplayName:e.binding.conversationDisplayName}]})[0];if(!i)return{opened:!1,reason:"conversation_not_visible"};const o=Ot(i.item.bbox,t,e.window);if(!o)return{opened:!1,reason:"conversation_bbox_missing"};const a=await e.helper.request("mouse.click",{x:o.x,y:o.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return w(a,"mouse.click"),{opened:!0,reason:i.reason}}async function ae(e){let t={opened:!1,reason:"conversation_not_opened"};for(let r=0;r<Be;r+=1){if(t=await ut(e),t.opened||t.reason!=="conversation_title_not_confirmed")return t;await m(350)}const n=await se(e);return n.opened?{opened:!0,reason:`${n.reason}:final-visible-recovery`}:t}async function ut(e){const t=await T(e),n=A({capture:t.capture,ocr:t.ocr,window:e.window});if(n)return{opened:!1,reason:n};let r=!1;if(K(t.ocr,t.capture,e.binding.conversationDisplayName))return e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId,observation:t}),{opened:!0,reason:"current-conversation-title-confirmed"};if(!r){const l=await z({...e,observation:t});if(l.opened){if(await m(900),(await k(e)).ok)return{opened:!0,reason:l.reason};const u=await se(e);if(u.opened)return u}}const i=gt(e,t),o=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,waitMs:e.searchDelayMs??700,...i?{searchPoint:i}:{}},e.traceId);w(o,"wechat.searchConversation");const a=await ht(e);if(a.opened){if(await m(900),(await k(e)).ok)return e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:a.reason};const f=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,waitMs:e.searchDelayMs??700,...i?{searchPoint:i}:{}},e.traceId);w(f,"wechat.searchConversation")}let s=a.observation;if(!y(e.binding.conversationDisplayName)){await xt(e.helper,e.traceId),await m(900);const l=await k(e);if(l.ok)return e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:l.reason};const f=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,waitMs:e.searchDelayMs??700,...i?{searchPoint:i}:{}},e.traceId);w(f,"wechat.searchConversation"),s=void 0}const c=await z({...e,...s?{observation:s}:{}});if(!c.opened)return c;await m(900);const d=await k(e);return d.ok?(e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:c.reason}):{opened:!1,reason:d.reason}}async function se(e){const t=await z(e);if(!t.opened)return t;await m(900);const n=await k(e);return n.ok?(e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:`${t.reason}:retry-visible-title-confirmed`}):{opened:!1,reason:n.reason}}function Ut(e){const t=e.bounds,n=Number(t?.x),r=Number(t?.y),i=Number(t?.width),o=Number(t?.height);if(![n,r,i,o].every(Number.isFinite)||i<=0||o<=0)return null;const a=Math.max(520,Math.min(i-160,i*.68)),s=Math.max(48,Math.min(88,o*.08));return{x:Math.round(n+a),y:Math.round(r+o-s),coordinateSpace:"screen"}}async function ht(e){let t;const n=e.searchDelayMs===0?0:Fe,r=y(e.binding.conversationDisplayName)?We:1;for(let i=0;i<r;i+=1){i>0&&n>0&&await m(n);const o=await ft(e);t=o;const{capture:a,ocr:s}=o,c=A({capture:a,ocr:s,window:e.window});if(c)return{opened:!1,reason:c,observation:o};const d=Ct(s,a,e.binding.conversationDisplayName);if(!d){if(Nt(s)||It(s,e.binding.conversationDisplayName))break;continue}const l=B(d.bbox,a,wt(a,e.window));if(!l)return{opened:!1,reason:"search_result_bbox_missing",observation:o};const f=await e.helper.request("mouse.click",{x:l.x,y:l.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return w(f,"mouse.click"),{opened:!0,reason:d.reason,observation:o}}return{opened:!1,reason:"search_result_not_visible",observation:t}}async function ft(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 le(e.helper,n,e.traceId);return{capture:n,ocr:r}}t.errorCode&&t.errorCode!=="helper_unknown_command"&&t.errorCode!=="helper_command_unsupported"&&w(t,"screen.capture")}return T(e)}function wt(e,t){return e.bounds?{...t,bounds:e.bounds}:t}async function T(e){let{capture:t,ocr:n}=await P(e.helper,e.window.windowId,e.traceId,e.window.bounds);return await bt({helper:e.helper,window:e.window,capture:t,ocr:n,traceId:e.traceId})&&(await m(350),{capture:t,ocr:n}=await P(e.helper,e.window.windowId,e.traceId,e.window.bounds)),{capture:t,ocr:n}}async function bt(e){const t=mt(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 mt(e,t,n){const r=e.blocks??[],i=r.find(c=>{const d=String(c.text||""),l=c.bbox;if(!l)return!1;const f=Number(l.x),u=Number(l.y);return Number.isFinite(f)&&Number.isFinite(u)&&u>t.height*.06&&u<t.height*.22&&f>t.width*.3&&/查看原视频|查看原图|原视频|原图|视频|图片|图像/.test(d)});if(!i)return null;const o=i.bbox,a=Number(o?.y);if(!Number.isFinite(a))return null;const s=r.filter(c=>{const d=String(c.text||"").trim(),l=c.bbox;if(!l||d!=="\xD7")return!1;const f=Number(l.x),u=Number(l.y);return Number.isFinite(f)&&Number.isFinite(u)&&f>t.width*.55&&f<t.width*.9&&Math.abs(u-a)<t.height*.08}).sort((c,d)=>Number(d.bbox?.x??0)-Number(c.bbox?.x??0))[0];return B(s?.bbox,t,n)}function gt(e,t){const{capture:n,ocr:r}=t,i=(r.blocks??[]).find(o=>{const a=String(o.text||"").trim().toLowerCase(),s=o.bbox;if(!s||!/^(搜索|search)$/.test(a))return!1;const c=Number(s.x),d=Number(s.y);return Number.isFinite(c)&&Number.isFinite(d)&&c<n.width*.22&&d<n.height*.12});return B(i?.bbox,n,e.window)}async function ce(e,t,n,r){const i=await e.request("windows.capture",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);w(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 de(e){return e.capture.dataBase64?e.capture:ce(e.helper,e.window.windowId,e.traceId,e.window.bounds)}async function P(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"&&w(i,"windows.captureAndOcr");const o=await ce(e,t,n,r),a=await le(e,o,n);return{capture:o,ocr:a}}async function le(e,t,n){const r=await e.request("ocr.recognize",{mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height},n);return w(r,"ocr.recognize"),r.result??{}}function w(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}function v(e){const t=`${e.appName||""} ${e.title||""} ${e.className||""}`.toLowerCase();return t.includes("wechat")||t.includes("weixin")||t.includes("\u5FAE\u4FE1")||t.includes("qwindowicon")}function m(e){return new Promise(t=>setTimeout(t,e))}async function xt(e,t){const n=await e.request("keyboard.shortcut",{key:"return",modifiers:[]},t);w(n,"keyboard.shortcut")}async function _(e){if(!e.window.bounds)return;const t=e.observation,n=Lt(t?.ocr,t?.capture,e.window);if(n){const i=await e.helper.request("mouse.click",{x:n.x,y:n.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);w(i,"mouse.click"),await m(700)}const r=zt(e.window);if(r){const i=await e.helper.request("mouse.click",{x:r.x,y:r.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);w(i,"mouse.click"),await m(150)}for(let i=0;i<6;i+=1){const o=await e.helper.request("keyboard.shortcut",{key:"pagedown",modifiers:[]},e.traceId);w(o,"keyboard.shortcut"),await m(260)}for(let i=0;i<2;i+=1){const o=await e.helper.request("keyboard.shortcut",{key:"end",modifiers:[]},e.traceId);w(o,"keyboard.shortcut"),await m(180)}for(let i=0;i<3;i+=1){const o=await e.helper.request("mouse.scroll",{deltaY:-2400,windowId:e.window.windowId,...r?{point:{...r,coordinateSpace:"screen"}}:{}},e.traceId);w(o,"mouse.scroll"),await m(180)}await m(220)}async function k(e){const{capture:t,ocr:n}=await P(e.helper,e.window.windowId,e.traceId,e.window.bounds),r=A({capture:t,ocr:n,window:e.window});return r?{ok:!1,reason:r}:K(n,t,e.binding.conversationDisplayName)?{ok:!0,reason:"target-conversation-title-confirmed"}:{ok:!1,reason:"conversation_title_not_confirmed"}}function A(e){const t=(e.ocr.blocks??[]).map(r=>kt(r.text)).filter(Boolean),n=t.join("");return/(扫码登录|仅传输文件|重新登录|为了安全|安全验证|登录微信|微信登录|该账号已登录|帐号已登录|账号已登录|当前账号已登录|当前帐号已登录|已登录|进入微信|進入微信)/u.test(n)||Mt(e,t)?q:null}function yt(e,t){const n=vt(e.blocks??[],t);return n.length?n:e.visibleConversationFingerprints??[]}function vt(e,t){const n=e.map(i=>ue(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=>!he(i.text)),r=new Set;return n.filter(i=>!pt(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=W(i.title);return!o||r.has(o)?!1:(r.add(o),!0)})}function ue(e){const t=e.bbox,n=String(e.text||"").normalize("NFKC").trim(),r=Number(t?.x),i=Number(t?.y),o=Number(t?.width),a=Number(t?.height);return!n||![r,i,o,a].every(Number.isFinite)?null:{text:n,x:r,y:i,width:o,height:a}}function pt(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 he(e){const t=C(e);return/^(搜索|微信|通讯录|收藏|设置|文件传输助手|search)$/iu.test(t)||R(t)||St(t)||/^包含[::]?/u.test(t)||/搜索网络结果/u.test(t)}function Ct(e,t,n){const r=(e.blocks??[]).map(s=>ue(s)).filter(s=>!!s),i=r.filter(s=>R(C(s.text))).sort((s,c)=>s.y-c.y||s.x-c.x),o=["\u7FA4\u804A","GroupChats","\u8054\u7CFB\u4EBA","Contacts"];for(const s of o){const c=i.findIndex(u=>C(u.text)===s);if(c<0)continue;const d=i[c],l=i[c+1]?.y??Number.POSITIVE_INFINITY,f=r.filter(u=>u.y>d.y&&u.y<l).filter(u=>u.x<t.width*.7).filter(u=>u.text.length>=2).filter(u=>!R(C(u.text))).filter(u=>!we(u,r)).filter(u=>D(u.text,n)).sort((u,x)=>u.y-x.y||u.x-x.x)[0];if(f)return{bbox:fe(f,t),reason:"search-result-title"}}const a=r.filter(s=>s.y>t.height*.12&&s.y<t.height*.82).filter(s=>s.x>t.width*.08&&s.x<t.width*.45).filter(s=>s.text.length>=2).filter(s=>!he(s.text)).filter(s=>!we(s,r)).filter(s=>D(s.text,n)).sort((s,c)=>s.y-c.y||s.x-c.x)[0];return a?{bbox:fe(a,t),reason:"search-result-title"}:null}function fe(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 R(e){return/^(群聊|联系人|聊天记录|公众号|小程序|GroupChats|Contacts|ChatHistory|OfficialAccounts|MiniPrograms)$/u.test(e)}function Nt(e){return(e.blocks??[]).some(t=>R(C(t.text)))}function It(e,t){return(e.visibleConversationFingerprints??[]).some(n=>D(n.title,t))}function C(e){return String(e||"").normalize("NFKC").replace(/[^\p{L}\p{N}_-]/gu,"").trim()}function we(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 St(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 Mt(e,t){if(!v(e.window)||(e.ocr.visibleConversationFingerprints??[]).length>0)return!1;const n=Number(e.window.bounds?.width||e.capture.width),r=Number(e.window.bounds?.height||e.capture.height);if(![n,r].every(Number.isFinite)||!(n>=360&&n<=720&&r>=420&&r<=840&&r>n))return!1;const o=t.filter(a=>a&&!/^[x*×]+$/iu.test(a));return o.length<=4&&!o.some(a=>/搜索|search/u.test(a))}function kt(e){return String(e||"").normalize("NFKC").replace(/\s+/g,"").trim()}function K(e,t,n){const r=y(n)?W(n):O(n);return r?(e.blocks??[]).some(i=>{const o=y(n)?W(i.text):O(i.text);if(!o||!xe(o,r))return!1;const a=i.bbox;if(!a)return!1;const s=Number(a.x),c=Number(a.y);if(!Number.isFinite(s)||!Number.isFinite(c))return!1;const d=s>t.width*.32&&s<t.width*.78&&c<t.height*.16,l=s<t.width*.18&&c<t.height*.12;return d||l}):!1}function be(e){if(K(e.ocr,e.capture,e.binding.conversationDisplayName))return!1;const t=(e.ocr.blocks??[]).map(s=>String(s.text||"").normalize("NFKC").replace(/\s+/g," ").trim()).filter(Boolean),n=t.join(`
4
- `),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((s,c)=>{const d=Array.isArray(c.source)?c.source.some(l=>c.pattern.test(l)):c.pattern.test(c.source);return s+(d?1:0)},0);if(i>=2)return!0;const o=(e.ocr.blocks??[]).filter(s=>Number(s.bbox?.y)<e.capture.height*.14).map(s=>String(s.text||"")).join(`
3
+ `)||null}function tt(e,t,n,r){const i=String(e.kind||"").toLowerCase(),o=b(e.mediaMetadata)?e.mediaMetadata:{},a=b(o.attachment)?o.attachment:{},s=u(a.availability)||u(o.availability),c=u(a.localPath)||u(o.localPath);if(s==="edge-local"&&c||!J(i,o,a))return null;const d=E(e.bbox)??E(o.bbox)??E(o.downloadActionBbox),h=E(o.downloadActionBbox),f=Q(d,t,n),l=it(d,t,n),g=Q(h,t,n);return{messageKey:e.stableMessageKey,kind:u(a.type)||u(a.kind)||u(o.messageType)||i,fileName:u(a.name)||u(a.fileName)||u(o.fileName)||null,mimeType:u(a.mimeType)||u(o.mimeType)||null,size:S(a.size)??S(o.size),mediaStatus:rt(o,a),observedAt:e.observedAt??null,contextText:r??e.normalizedText??e.anchorText??e.textExcerpt??null,...f?{bbox:f}:{},...l?{screenshotBbox:l}:{},...g?{downloadActionBbox:g}:{}}}function nt(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=u(e.mediaStatus);if(n==="not_downloaded")return"not_downloaded";if(n==="downloaded"||n==="available")return"available";const r=u(t.availability)||u(e.availability);return r==="pending-download"?"not_downloaded":r==="metadata-only"?"metadata_only":n||null}function J(e,t,n){const r=`${e} ${u(t.messageType)} ${u(n.type)} ${u(n.kind)}`.toLowerCase();return/image|photo|video|file|document/.test(r)}function E(e){if(!b(e))return null;const t=S(e.x),n=S(e.y),r=S(e.width),i=S(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 Q(e,t,n){if(!e)return null;if(e.coordinateSpace==="screen")return e;const r=B(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,a=i.height/t.height,s=r.x,c=r.y;return{x:s-e.width*o/2,y:c-e.height*a/2,width:e.width*o,height:e.height*a,coordinateSpace:"screen"}}function it(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 I(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function u(e){return typeof e=="string"?e.trim():""}function x(e){return u(e)||null}function S(e){const t=Number(e);return Number.isFinite(t)?t:null}async function Yt(e,t){await ee(e,t)}async function ee(e,t){let n=await e.request("permissions.check",{},t);w(n,"permissions.check");const r=n.result??{};if(r.screenRecording===!1)throw new Error("permission_screen_recording_missing");if(r.automation===!1)throw new Error("permission_automation_missing");if(r.wechatRunning===!1)throw new Error("wechat_not_running");if(at(r))throw new Error(F);if(r.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(te([...r.captureCandidates??[],...r.restoreCandidates??[],...r.hiddenRestoreCandidates??[],...r.duplicateMainWindows??[],...r.unsafeAuxiliaryWindows??[]]))throw new Error(F);if(r.wechatWindowAvailable===!1&&String(r.platform??"").toLowerCase()!=="win32")throw new Error("wechat_window_unavailable");return r}async function ot(e,t){const n=await ee(e,t);if(String(n.platform??"").toLowerCase()==="win32"){const i=await e.request("windows.ensureReady",{activate:!0,allowRecovery:!1,allowLaunch:!1},t);w(i,"windows.ensureReady");const o=i.result;if(!o?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return o}const r=await ie(e,t);if(!r?.windowId)throw new Error("helper_invalid_response: windows.list missing WeChat window data");return r}function te(e,t){const n=e.filter(v).filter(i=>i.visible!==!1&&i.minimized!==!0),r=t??n.slice().sort((i,o)=>M(o)-M(i))[0];return n.find(i=>st(i,r))??null}function at(e){return e.duplicateInstanceBlocked===!0||Number(e.duplicateMainWindowCount??0)>0||Number(e.unsafeAuxiliaryWindowCount??0)>0||(e.duplicateMainWindows??[]).some(v)||(e.unsafeAuxiliaryWindows??[]).some(v)}function L(e){const t=e.filter(v).filter(i=>i.visible!==!1&&i.minimized!==!0),n=t.filter(re);if(n.length>1)throw new Error(F);const r=n.slice().sort((i,o)=>M(o)-M(i))[0];if(te(t,r))throw new Error(F)}function ne(e){const t=e.filter(v),n=t.filter(o=>o.visible!==!1&&o.minimized!==!0),r=n.filter(re);return(r.length?r:n.length?n:t).slice().sort((o,a)=>M(a)-M(o))[0]??null}function st(e,t){if(!v(e)||t&&dt(e,t)||e.visible===!1||e.minimized===!0)return!1;const n=Number(e.bounds?.width),r=Number(e.bounds?.height);if(!Number.isFinite(n)||!Number.isFinite(r))return!1;const i=n>=360&&n<=720&&r>=420&&r<=840&&r>n,o=n>=420&&n<=680&&r>=260&&r<=460;return!(!i&&!o||t&&ct(e,t))}function ct(e,t){const n=Number(e.rootProcessId),r=Number(t.rootProcessId);if(!Number.isFinite(n)||!Number.isFinite(r)||n!==r)return!1;const i=Number(e.zOrder),o=Number(t.zOrder);return!Number.isFinite(i)||!Number.isFinite(o)?!1:i>o}function re(e){const t=Number(e.bounds?.width),n=Number(e.bounds?.height);return Number.isFinite(t)&&Number.isFinite(n)&&t>=760&&n>=600}function M(e){const t=Number(e.bounds?.width),n=Number(e.bounds?.height);return Number.isFinite(t)&&Number.isFinite(n)?t*n:0}function dt(e,t){return!!(e.windowId&&t.windowId&&e.windowId===t.windowId)}async function Ht(e,t){let n=await e.request("windows.list",{},t);w(n,"windows.list");let r=n.result?.windows??[];L(r);let i=ne(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return w(o,"windows.focus"),await oe(e,i,t)}async function lt(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 w(r,"windows.focus"),t}async function ie(e,t){const n=await e.request("windows.list",{},t);w(n,"windows.list");const r=n.result?.windows??[];L(r);const i=ne(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return w(o,"windows.focus"),await oe(e,i,t)}async function oe(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(v);return L(i),i.find(o=>o.windowId===t.windowId)??i[0]??t}async function z(e){const{capture:t,ocr:n}=e.observation??await T(e),r=R({capture:t,ocr:n,window:e.window});if(r)return{opened:!1,reason:r};const i=_e({visibleItems:yt(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=Ot(i.item.bbox,t,e.window);if(!o)return{opened:!1,reason:"conversation_bbox_missing"};const a=await e.helper.request("mouse.click",{x:o.x,y:o.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return w(a,"mouse.click"),{opened:!0,reason:i.reason}}async function ae(e){let t={opened:!1,reason:"conversation_not_opened"};for(let r=0;r<Be;r+=1){if(t=await ut(e),t.opened||t.reason!=="conversation_title_not_confirmed")return t;await m(350)}const n=await se(e);return n.opened?{opened:!0,reason:`${n.reason}:final-visible-recovery`}:t}async function ut(e){const t=await T(e),n=R({capture:t.capture,ocr:t.ocr,window:e.window});if(n)return{opened:!1,reason:n};let r=!1;if(K(t.ocr,t.capture,e.binding.conversationDisplayName))return e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId,observation:t}),{opened:!0,reason:"current-conversation-title-confirmed"};if(!r){const f=await z({...e,observation:t});if(f.opened){if(await m(900),(await k(e)).ok)return{opened:!0,reason:f.reason};const g=await se(e);if(g.opened)return g}}const i=gt(e,t),o=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,waitMs:e.searchDelayMs??700,...i?{searchPoint:i}:{}},e.traceId);w(o,"wechat.searchConversation");const a=await ht(e);if(a.opened){if(await m(900),(await k(e)).ok)return e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:a.reason};const l=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,waitMs:e.searchDelayMs??700,...i?{searchPoint:i}:{}},e.traceId);w(l,"wechat.searchConversation")}let s=a.observation;const c=y(e.binding.conversationDisplayName)&&a.reason==="search_result_not_visible";if(!y(e.binding.conversationDisplayName)){await xt(e.helper,e.traceId),await m(900);const f=await k(e);if(f.ok)return e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:f.reason};const l=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,waitMs:e.searchDelayMs??700,...i?{searchPoint:i}:{}},e.traceId);w(l,"wechat.searchConversation"),s=void 0}const d=await z({...e,...s?{observation:s}:{},allowOcrTitleRows:!c});if(!d.opened)return d;await m(900);const h=await k(e);return h.ok?(e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:d.reason}):{opened:!1,reason:h.reason}}async function se(e){const t=await z(e);if(!t.opened)return t;await m(900);const n=await k(e);return n.ok?(e.settleToBottom!==!1&&await _({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:`${t.reason}:retry-visible-title-confirmed`}):{opened:!1,reason:n.reason}}function Ut(e){const t=e.bounds,n=Number(t?.x),r=Number(t?.y),i=Number(t?.width),o=Number(t?.height);if(![n,r,i,o].every(Number.isFinite)||i<=0||o<=0)return null;const a=Math.max(520,Math.min(i-160,i*.68)),s=Math.max(48,Math.min(88,o*.08));return{x:Math.round(n+a),y:Math.round(r+o-s),coordinateSpace:"screen"}}async function ht(e){let t;const n=e.searchDelayMs===0?0:Fe,r=y(e.binding.conversationDisplayName)?We:1;for(let i=0;i<r;i+=1){i>0&&n>0&&await m(n);const o=await ft(e);t=o;const{capture:a,ocr:s}=o,c=R({capture:a,ocr:s,window:e.window});if(c)return{opened:!1,reason:c,observation:o};const d=Ct(s,a,e.binding.conversationDisplayName);if(!d){if(Nt(s)||It(s,e.binding.conversationDisplayName))break;continue}const h=B(d.bbox,a,wt(a,e.window));if(!h)return{opened:!1,reason:"search_result_bbox_missing",observation:o};const f=await e.helper.request("mouse.click",{x:h.x,y:h.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return w(f,"mouse.click"),{opened:!0,reason:d.reason,observation:o}}return{opened:!1,reason:"search_result_not_visible",observation:t}}async function ft(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 le(e.helper,n,e.traceId);return{capture:n,ocr:r}}t.errorCode&&t.errorCode!=="helper_unknown_command"&&t.errorCode!=="helper_command_unsupported"&&w(t,"screen.capture")}return T(e)}function wt(e,t){return e.bounds?{...t,bounds:e.bounds}:t}async function T(e){let{capture:t,ocr:n}=await P(e.helper,e.window.windowId,e.traceId,e.window.bounds);return await bt({helper:e.helper,window:e.window,capture:t,ocr:n,traceId:e.traceId})&&(await m(350),{capture:t,ocr:n}=await P(e.helper,e.window.windowId,e.traceId,e.window.bounds)),{capture:t,ocr:n}}async function bt(e){const t=mt(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 mt(e,t,n){const r=e.blocks??[],i=r.find(c=>{const d=String(c.text||""),h=c.bbox;if(!h)return!1;const f=Number(h.x),l=Number(h.y);return Number.isFinite(f)&&Number.isFinite(l)&&l>t.height*.06&&l<t.height*.22&&f>t.width*.3&&/查看原视频|查看原图|原视频|原图|视频|图片|图像/.test(d)});if(!i)return null;const o=i.bbox,a=Number(o?.y);if(!Number.isFinite(a))return null;const s=r.filter(c=>{const d=String(c.text||"").trim(),h=c.bbox;if(!h||d!=="\xD7")return!1;const f=Number(h.x),l=Number(h.y);return Number.isFinite(f)&&Number.isFinite(l)&&f>t.width*.55&&f<t.width*.9&&Math.abs(l-a)<t.height*.08}).sort((c,d)=>Number(d.bbox?.x??0)-Number(c.bbox?.x??0))[0];return B(s?.bbox,t,n)}function gt(e,t){const{capture:n,ocr:r}=t,i=(r.blocks??[]).find(o=>{const a=String(o.text||"").trim().toLowerCase(),s=o.bbox;if(!s||!/^(搜索|search)$/.test(a))return!1;const c=Number(s.x),d=Number(s.y);return Number.isFinite(c)&&Number.isFinite(d)&&c<n.width*.22&&d<n.height*.12});return B(i?.bbox,n,e.window)}async function ce(e,t,n,r){const i=await e.request("windows.capture",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);w(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 de(e){return e.capture.dataBase64?e.capture:ce(e.helper,e.window.windowId,e.traceId,e.window.bounds)}async function P(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"&&w(i,"windows.captureAndOcr");const o=await ce(e,t,n,r),a=await le(e,o,n);return{capture:o,ocr:a}}async function le(e,t,n){const r=await e.request("ocr.recognize",{mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height},n);return w(r,"ocr.recognize"),r.result??{}}function w(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}function v(e){const t=`${e.appName||""} ${e.title||""} ${e.className||""}`.toLowerCase();return t.includes("wechat")||t.includes("weixin")||t.includes("\u5FAE\u4FE1")||t.includes("qwindowicon")}function m(e){return new Promise(t=>setTimeout(t,e))}async function xt(e,t){const n=await e.request("keyboard.shortcut",{key:"return",modifiers:[]},t);w(n,"keyboard.shortcut")}async function _(e){if(!e.window.bounds)return;const t=e.observation,n=Lt(t?.ocr,t?.capture,e.window);if(n){const i=await e.helper.request("mouse.click",{x:n.x,y:n.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);w(i,"mouse.click"),await m(700)}const r=zt(e.window);if(r){const i=await e.helper.request("mouse.click",{x:r.x,y:r.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);w(i,"mouse.click"),await m(150)}for(let i=0;i<6;i+=1){const o=await e.helper.request("keyboard.shortcut",{key:"pagedown",modifiers:[]},e.traceId);w(o,"keyboard.shortcut"),await m(260)}for(let i=0;i<2;i+=1){const o=await e.helper.request("keyboard.shortcut",{key:"end",modifiers:[]},e.traceId);w(o,"keyboard.shortcut"),await m(180)}for(let i=0;i<3;i+=1){const o=await e.helper.request("mouse.scroll",{deltaY:-2400,windowId:e.window.windowId,...r?{point:{...r,coordinateSpace:"screen"}}:{}},e.traceId);w(o,"mouse.scroll"),await m(180)}await m(220)}async function k(e){const{capture:t,ocr:n}=await P(e.helper,e.window.windowId,e.traceId,e.window.bounds),r=R({capture:t,ocr:n,window:e.window});return r?{ok:!1,reason:r}:K(n,t,e.binding.conversationDisplayName)?{ok:!0,reason:"target-conversation-title-confirmed"}:{ok:!1,reason:"conversation_title_not_confirmed"}}function R(e){const t=(e.ocr.blocks??[]).map(r=>kt(r.text)).filter(Boolean),n=t.join("");return/(扫码登录|仅传输文件|重新登录|为了安全|安全验证|登录微信|微信登录|该账号已登录|帐号已登录|账号已登录|当前账号已登录|当前帐号已登录|已登录|进入微信|進入微信)/u.test(n)||Mt(e,t)?q:null}function yt(e,t,n=!0){const r=n?vt(e.blocks??[],t):[];return r.length?r:e.visibleConversationFingerprints??[]}function vt(e,t){const n=e.map(i=>ue(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=>!he(i.text)),r=new Set;return n.filter(i=>!pt(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=W(i.title);return!o||r.has(o)?!1:(r.add(o),!0)})}function ue(e){const t=e.bbox,n=String(e.text||"").normalize("NFKC").trim(),r=Number(t?.x),i=Number(t?.y),o=Number(t?.width),a=Number(t?.height);return!n||![r,i,o,a].every(Number.isFinite)?null:{text:n,x:r,y:i,width:o,height:a}}function pt(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 he(e){const t=C(e);return/^(搜索|微信|通讯录|收藏|设置|文件传输助手|search)$/iu.test(t)||A(t)||St(t)||/^包含[::]?/u.test(t)||/搜索网络结果/u.test(t)}function Ct(e,t,n){const r=(e.blocks??[]).map(s=>ue(s)).filter(s=>!!s),i=r.filter(s=>A(C(s.text))).sort((s,c)=>s.y-c.y||s.x-c.x),o=["\u7FA4\u804A","GroupChats","\u8054\u7CFB\u4EBA","Contacts"];for(const s of o){const c=i.findIndex(l=>C(l.text)===s);if(c<0)continue;const d=i[c],h=i[c+1]?.y??Number.POSITIVE_INFINITY,f=r.filter(l=>l.y>d.y&&l.y<h).filter(l=>l.x<t.width*.7).filter(l=>l.text.length>=2).filter(l=>!A(C(l.text))).filter(l=>!we(l,r)).filter(l=>D(l.text,n)).sort((l,g)=>l.y-g.y||l.x-g.x)[0];if(f)return{bbox:fe(f,t),reason:"search-result-title"}}const a=r.filter(s=>s.y>t.height*.12&&s.y<t.height*.82).filter(s=>s.x>t.width*.08&&s.x<t.width*.45).filter(s=>s.text.length>=2).filter(s=>!he(s.text)).filter(s=>!we(s,r)).filter(s=>D(s.text,n)).sort((s,c)=>s.y-c.y||s.x-c.x)[0];return y(n)?null:a?{bbox:fe(a,t),reason:"search-result-title"}:null}function fe(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 A(e){return/^(群聊|联系人|聊天记录|公众号|小程序|GroupChats|Contacts|ChatHistory|OfficialAccounts|MiniPrograms)$/u.test(e)}function Nt(e){return(e.blocks??[]).some(t=>A(C(t.text)))}function It(e,t){return(e.visibleConversationFingerprints??[]).some(n=>D(n.title,t))}function C(e){return String(e||"").normalize("NFKC").replace(/[^\p{L}\p{N}_-]/gu,"").trim()}function we(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 St(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 Mt(e,t){if(!v(e.window)||(e.ocr.visibleConversationFingerprints??[]).length>0)return!1;const n=Number(e.window.bounds?.width||e.capture.width),r=Number(e.window.bounds?.height||e.capture.height);if(![n,r].every(Number.isFinite)||!(n>=360&&n<=720&&r>=420&&r<=840&&r>n))return!1;const o=t.filter(a=>a&&!/^[x*×]+$/iu.test(a));return o.length<=4&&!o.some(a=>/搜索|search/u.test(a))}function kt(e){return String(e||"").normalize("NFKC").replace(/\s+/g,"").trim()}function K(e,t,n){const r=y(n)?W(n):O(n);return r?(e.blocks??[]).some(i=>{const o=y(n)?W(i.text):O(i.text);if(!o||!xe(o,r))return!1;const a=i.bbox;if(!a)return!1;const s=Number(a.x),c=Number(a.y);if(!Number.isFinite(s)||!Number.isFinite(c))return!1;const d=s>t.width*.32&&s<t.width*.78&&c<t.height*.16,h=s<t.width*.18&&c<t.height*.12;return d||h}):!1}function be(e){if(K(e.ocr,e.capture,e.binding.conversationDisplayName))return!1;const t=(e.ocr.blocks??[]).map(s=>String(s.text||"").normalize("NFKC").replace(/\s+/g," ").trim()).filter(Boolean),n=t.join(`
4
+ `),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((s,c)=>{const d=Array.isArray(c.source)?c.source.some(h=>c.pattern.test(h)):c.pattern.test(c.source);return s+(d?1:0)},0);if(i>=2)return!0;const o=(e.ocr.blocks??[]).filter(s=>Number(s.bbox?.y)<e.capture.height*.14).map(s=>String(s.text||"")).join(`
5
5
  `);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)&&Tt(e.capture,e.ocr)?!0:((e.ocr.visibleConversationFingerprints??[]).some(s=>{const c=y(e.binding.conversationDisplayName)?W(s.title):O(s.title),d=y(e.binding.conversationDisplayName)?W(e.binding.conversationDisplayName):O(e.binding.conversationDisplayName);return!!(c&&d&&xe(c,d))}),!1)}function Tt(e,t){const n=(t.blocks??[]).map(o=>String(o.text||"").normalize("NFKC").trim()).filter(Boolean),r=n.join(`
6
- `);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 me(e){const t=e.anchors.map(o=>({...o,normalized:p(o.expectedEchoAnchor)})).filter(o=>o.normalized);if(!t.length)return[];const n=[],r=new Set,i=_t(e.ocr,e.screenshot).sort((o,a)=>p(a.text).length-p(o.text).length);for(const o of i){const a=p(o.text);if(!a)continue;const s=t.find(d=>Bt(d.normalized,a));if(!s)continue;const c=`local-outbound-echo:${e.binding.bindingId}:${s.idempotencyKey||s.replyId||s.normalized}`;r.has(c)||(r.add(c),n.push({stableMessageKey:c,senderRole:"self",kind:"text",normalizedText:a,anchorText:a,textExcerpt:o.text.trim(),bbox:o.bbox??null,observedAt:new Date().toISOString(),deliveryStatus:"suppressed"}))}return n}function _t(e,t){const n=(e.blocks??[]).filter(i=>Rt(i,t)&&p(i.text)).sort((i,o)=>N(i.bbox,"y")-N(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 a=i+1;a<n.length&&o.length<5;a+=1){const s=n[a];if(!Wt(o[o.length-1],s,t))break;o.push(s),r.push({text:Ft(o.map(c=>String(c.text||"").trim())),bbox:At(o.map(c=>c.bbox))})}}return r}function Bt(e,t){if(!e||!t)return!1;if(V(e,t)>=.88)return!0;const n=e.replace(/\s+/g,""),r=t.replace(/\s+/g,"");return r.length>=8&&n.includes(r)}function Wt(e,t,n){const r=N(e.bbox,"x"),i=N(e.bbox,"y"),o=N(e.bbox,"height"),a=N(t.bbox,"x"),s=N(t.bbox,"y");if(![r,i,o,a,s].every(Number.isFinite)||r<n.width*.5||a<n.width*.5)return!1;const c=s-(i+o);return c>=-8&&c<=Math.max(64,n.height*.04)&&Math.abs(a-r)<=120}function Ft(e){return e.reduce((t,n)=>t?n?`${t}${Et(t,n)?" ":""}${n}`:t:n,"")}function Et(e,t){return/[A-Za-z0-9]$/u.test(e)&&/^[A-Za-z0-9]/u.test(t)}function At(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 a=Math.min(...n),s=Math.min(...r);return{x:a,y:s,width:Math.max(...i)-a,height:Math.max(...o)-s,coordinateSpace:t.find(c=>c.coordinateSpace)?.coordinateSpace}}function N(e,t){const n=Number(e?.[t]);return Number.isFinite(n)?n:Number.NaN}function ge(e,t){if(!t.length)return e;const n=[...e];for(const r of t){const i=p(r.anchorText||r.normalizedText||r.textExcerpt);n.some(a=>{if(a.senderRole!=="self")return!1;const s=p(a.anchorText||a.normalizedText||a.textExcerpt);return s&&i&&V(s,i)>=.9})||n.push(r)}return n}function Rt(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 Ot(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),a=Number(r.width),s=Number(r.height);if(![i,o,a,s].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,d=t.width&&n.bounds?.width?t.width/n.bounds.width:1,l=t.height&&n.bounds?.height?t.height/n.bounds.height:d,f={x:i+Math.min(a*.35,110*d),y:o+Math.min(s-8*l,Math.max(18*l,s/2))};if(c==="screen"||!n.bounds)return f;const u=Math.max(0,(t.width-n.bounds.width*d)/2),x=Math.max(0,(t.height-n.bounds.height*l)/2);return{x:n.bounds.x+(f.x-u)/d,y:n.bounds.y+(f.y-x)/l}}function B(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),a=Number(r.width),s=Number(r.height);if(![i,o,a,s].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,d={x:i+a/2,y:o+s/2};if(c==="screen"||!n.bounds)return d;const l=t.width&&n.bounds.width?t.width/n.bounds.width:1,f=t.height&&n.bounds.height?t.height/n.bounds.height:l,u=Math.max(0,(t.width-n.bounds.width*l)/2),x=Math.max(0,(t.height-n.bounds.height*f)/2);return{x:n.bounds.x+(d.x-u)/l,y:n.bounds.y+(d.y-x)/f}}function Lt(e,t,n){if(!e?.blocks?.length||!t)return null;const r=e.blocks.find(i=>{const o=String(i.text||"").trim(),a=i.bbox;if(!a||!o)return!1;const s=Number(a.x),c=Number(a.y);return!Number.isFinite(s)||!Number.isFinite(c)||!/跳转到最新消息|回到最新消息|jump\s+to\s+latest/i.test(o)?!1:s>t.width*.55&&c>t.height*.45&&c<t.height*.92});return B(r?.bbox,t,n)}function zt(e){const t=e.bounds;return!t?.width||!t?.height?null:{x:t.x+t.width*.54,y:t.y+t.height*.7}}function xe(e,t){return y(t)?ve(e,t):e===t||e.includes(t)||t.includes(e)}function D(e,t){if(y(t))return ve(e,t);const n=ye(C(e)),r=ye(C(t));return!n||!r?!1:n===r?!0:n.replace(/\d+$/u,"")===r}function ye(e){return e.toLowerCase().replace(/[l1]/g,"i")}function O(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").replace(/[l1]/gi,"i").toLowerCase().trim()}function W(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 ve(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{P as captureAndRecognizeWeChatWindow,ce as captureWeChatWindow,Yt as ensureHelperPreflight,ot as ensureWeChatWindowReady,Ut as fallbackWeChatMessageInputPointForWindow,ie as focusExistingWeChatWindow,lt as focusKnownWeChatWindow,Ht as focusWeChatWindow,jt as observeWeChatChannelBindingViaHelper,ae as openConversationBySearch,z as openConversationInVisibleList,le as recognizeWeChatScreenshot};
6
+ `);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 me(e){const t=e.anchors.map(o=>({...o,normalized:p(o.expectedEchoAnchor)})).filter(o=>o.normalized);if(!t.length)return[];const n=[],r=new Set,i=_t(e.ocr,e.screenshot).sort((o,a)=>p(a.text).length-p(o.text).length);for(const o of i){const a=p(o.text);if(!a)continue;const s=t.find(d=>Bt(d.normalized,a));if(!s)continue;const c=`local-outbound-echo:${e.binding.bindingId}:${s.idempotencyKey||s.replyId||s.normalized}`;r.has(c)||(r.add(c),n.push({stableMessageKey:c,senderRole:"self",kind:"text",normalizedText:a,anchorText:a,textExcerpt:o.text.trim(),bbox:o.bbox??null,observedAt:new Date().toISOString(),deliveryStatus:"suppressed"}))}return n}function _t(e,t){const n=(e.blocks??[]).filter(i=>At(i,t)&&p(i.text)).sort((i,o)=>N(i.bbox,"y")-N(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 a=i+1;a<n.length&&o.length<5;a+=1){const s=n[a];if(!Wt(o[o.length-1],s,t))break;o.push(s),r.push({text:Ft(o.map(c=>String(c.text||"").trim())),bbox:Rt(o.map(c=>c.bbox))})}}return r}function Bt(e,t){if(!e||!t)return!1;if(V(e,t)>=.88)return!0;const n=e.replace(/\s+/g,""),r=t.replace(/\s+/g,"");return r.length>=8&&n.includes(r)}function Wt(e,t,n){const r=N(e.bbox,"x"),i=N(e.bbox,"y"),o=N(e.bbox,"height"),a=N(t.bbox,"x"),s=N(t.bbox,"y");if(![r,i,o,a,s].every(Number.isFinite)||r<n.width*.5||a<n.width*.5)return!1;const c=s-(i+o);return c>=-8&&c<=Math.max(64,n.height*.04)&&Math.abs(a-r)<=120}function Ft(e){return e.reduce((t,n)=>t?n?`${t}${Et(t,n)?" ":""}${n}`:t:n,"")}function Et(e,t){return/[A-Za-z0-9]$/u.test(e)&&/^[A-Za-z0-9]/u.test(t)}function Rt(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 a=Math.min(...n),s=Math.min(...r);return{x:a,y:s,width:Math.max(...i)-a,height:Math.max(...o)-s,coordinateSpace:t.find(c=>c.coordinateSpace)?.coordinateSpace}}function N(e,t){const n=Number(e?.[t]);return Number.isFinite(n)?n:Number.NaN}function ge(e,t){if(!t.length)return e;const n=[...e];for(const r of t){const i=p(r.anchorText||r.normalizedText||r.textExcerpt);n.some(a=>{if(a.senderRole!=="self")return!1;const s=p(a.anchorText||a.normalizedText||a.textExcerpt);return s&&i&&V(s,i)>=.9})||n.push(r)}return n}function At(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 Ot(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),a=Number(r.width),s=Number(r.height);if(![i,o,a,s].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,d=t.width&&n.bounds?.width?t.width/n.bounds.width:1,h=t.height&&n.bounds?.height?t.height/n.bounds.height:d,f={x:i+Math.min(a*.35,110*d),y:o+Math.min(s-8*h,Math.max(18*h,s/2))};if(c==="screen"||!n.bounds)return f;const l=Math.max(0,(t.width-n.bounds.width*d)/2),g=Math.max(0,(t.height-n.bounds.height*h)/2);return{x:n.bounds.x+(f.x-l)/d,y:n.bounds.y+(f.y-g)/h}}function B(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),a=Number(r.width),s=Number(r.height);if(![i,o,a,s].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,d={x:i+a/2,y:o+s/2};if(c==="screen"||!n.bounds)return d;const h=t.width&&n.bounds.width?t.width/n.bounds.width:1,f=t.height&&n.bounds.height?t.height/n.bounds.height:h,l=Math.max(0,(t.width-n.bounds.width*h)/2),g=Math.max(0,(t.height-n.bounds.height*f)/2);return{x:n.bounds.x+(d.x-l)/h,y:n.bounds.y+(d.y-g)/f}}function Lt(e,t,n){if(!e?.blocks?.length||!t)return null;const r=e.blocks.find(i=>{const o=String(i.text||"").trim(),a=i.bbox;if(!a||!o)return!1;const s=Number(a.x),c=Number(a.y);return!Number.isFinite(s)||!Number.isFinite(c)||!/跳转到最新消息|回到最新消息|jump\s+to\s+latest/i.test(o)?!1:s>t.width*.55&&c>t.height*.45&&c<t.height*.92});return B(r?.bbox,t,n)}function zt(e){const t=e.bounds;return!t?.width||!t?.height?null:{x:t.x+t.width*.68,y:t.y+t.height*.58}}function xe(e,t){return y(t)?ve(e,t):e===t||e.includes(t)||t.includes(e)}function D(e,t){if(y(t))return ve(e,t);const n=ye(C(e)),r=ye(C(t));return!n||!r?!1:n===r?!0:n.replace(/\d+$/u,"")===r}function ye(e){return e.toLowerCase().replace(/[l1]/g,"i")}function O(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").replace(/[l1]/gi,"i").toLowerCase().trim()}function W(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 ve(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{P as captureAndRecognizeWeChatWindow,ce as captureWeChatWindow,Yt as ensureHelperPreflight,ot as ensureWeChatWindowReady,Ut as fallbackWeChatMessageInputPointForWindow,ie as focusExistingWeChatWindow,lt as focusKnownWeChatWindow,Ht as focusWeChatWindow,jt as observeWeChatChannelBindingViaHelper,ae as openConversationBySearch,z as openConversationInVisibleList,le as recognizeWeChatScreenshot};
@@ -1,7 +1,8 @@
1
1
  import type { ExternalChannelConfig, ExternalMessageEvent, ExternalReply } from '../base.js';
2
2
  import type { WeChatRpaPendingReplyProjection } from '@shennian/wire';
3
3
  import { type WeChatChannelProductRunnerOptions } from '../wechat-channel/runner.js';
4
- import { type WeChatChannelRuntime } from '../wechat-channel/runtime.js';
4
+ import { type WeChatChannelBindingConfig, type WeChatChannelRuntime } from '../wechat-channel/runtime.js';
5
+ import type { WeChatChannelObservedMessage } from '../wechat-channel/client.js';
5
6
  import { type WeChatChannelOutboundRecord } from '../wechat-channel/outbound-ledger.js';
6
7
  export declare const WECHAT_RPA_PRODUCT_SOURCE: "wechat-channel";
7
8
  export type WeChatRpaProductSourceSecret = {
@@ -67,3 +68,4 @@ export declare function weChatChannelBindingId(channelId: string, conversationNa
67
68
  export declare function weChatChannelLedgerPath(workDir: string, runtimeId: string): string;
68
69
  export declare function weChatChannelOutboundLedgerPath(workDir: string, runtimeId: string): string;
69
70
  export declare function safeWeChatChannelRuntimePathSegment(runtimeId: string): string;
71
+ export declare function observedMessageToExternalEvent(config: ExternalChannelConfig, binding: WeChatChannelBindingConfig, message: WeChatChannelObservedMessage): ExternalMessageEvent | null;
@@ -5,4 +5,4 @@ ${s.join(`
5
5
  `)}`),bindingId:r,runtimeId:n,sessionId:e.config.sessionId||e.config.managerSessionId,conversationName:e.conversationName,replyBaseRevision:a.bindings[r]?.revision??0,text:e.reply.text,attachmentLocalRefs:s});return p(t,o),c}function Y(e){return m(u(e.config.workDir,e.config.id),e.config.id).records.filter(r=>["queued","sending","sent_unconfirmed"].includes(r.sendStatus)).length}function ee(e){return m(u(e.config.workDir,e.config.id),e.config.id).records.filter(r=>["queued","sending","sent_unconfirmed"].includes(r.sendStatus)).slice(0,100).map(r=>({replyId:r.replyId,idempotencyKey:r.idempotencyKey,status:r.sendStatus,conversationName:r.conversationName,reasonCode:r.deferReason||r.failureCode||null,nextAttemptAt:r.nextAttemptAt??null,queuedAt:r.queuedAt??r.createdAt,lastAttemptAt:r.lastAttemptAt??null,attemptCount:r.attemptCount??0,commitStage:r.commitStage??null}))}function ne(e){const n=q(e.limit,20,1,100),r=y(e.product.ledgerPath,e.product.runtime.runtimeId),a=[];for(const t of e.product.runtime.bindings){const o=r.bindings[t.bindingId]?.recent??[];for(const s of o.slice(-n)){const c=w(e.config,t,s);c&&a.push(c)}}return a}function te(e){const n=u(e.config.workDir,e.config.id),r=m(n,e.config.id),a=String(e.idempotencyKey??"").trim(),t=String(e.replyId??"").trim();if(!a&&!t)return{cancelled:!1};const o=r.records.find(c=>a&&c.idempotencyKey===a||t&&c.replyId===t);if(!o)return{cancelled:!1};const s=o.sendStatus;return M(o,e.reason||"user_cancelled"),o.sendStatus!==s?(p(n,r),{cancelled:!0,status:o.sendStatus,record:o}):{cancelled:!1,status:o.sendStatus,record:o}}function re(e){return e===W}function D(e){return d("wechat-conversation",i(e))}function b(e,n){return d("wechat-channel-binding",`${e}
6
6
  ${i(n)}`)}function I(e,n){return g.join(e,"wechat-channel",`${C(n)}.ledger.json`)}function u(e,n){return g.join(e,"wechat-channel",`${C(n)}.outbound-ledger.json`)}function C(e){return String(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"wechat-channel-runtime"}function $(e,n){return L(n).map(r=>({bindingId:b(e.id,r),sessionId:e.sessionId||e.managerSessionId,conversationDisplayName:r,enabled:!0,allowReply:n.canReply!==!1,downloadMedia:n.downloadAttachments!==!1}))}function w(e,n,r){const a=i(r.normalizedText||r.anchorText||r.textExcerpt||""),t=K(r);if(!a&&t.length===0)return null;const o=i(r.senderName||"");return{type:"external.message",channelId:e.id,channelType:"wechat-rpa",conversationId:D(n.conversationDisplayName),conversationName:n.conversationDisplayName,messageId:d("wechat-message",`${n.bindingId}
7
7
  ${r.stableMessageKey}`),sender:{id:d("wechat-sender",`${n.bindingId}
8
- ${o||r.senderRole}`),name:o||null},text:a,attachments:t,receivedAt:j(r.observedAt),isMentioned:!1,replyTarget:"",rawRef:r.stableMessageKey}}function K(e){const n=e.mediaMetadata;return z(n).map(a=>{const t=a,o=typeof t.localPath=="string"?i(t.localPath):"",s=typeof t.thumbnailPath=="string"?i(t.thumbnailPath):"",c=typeof t.url=="string"?i(t.url):"",l=Number(t.size??t.sizeBytes??0);return{type:i(String(t.type||t.kind||e.kind||"file"))||"file",...t.name||t.fileName?{name:i(String(t.name||t.fileName))}:{},...c?{url:c}:{},...typeof t.mimeType=="string"?{mimeType:i(t.mimeType)}:{},...typeof t.extension=="string"?{extension:i(t.extension)}:{},...Number.isFinite(l)&&l>0?{size:l}:{},...o?{localPath:o}:{},...s?{thumbnailPath:s}:{},...typeof t.hash=="string"||typeof t.sha256=="string"?{hash:i(String(t.hash||t.sha256))}:{},availability:E(t.availability,{localPath:o,url:c}),...typeof t.providerError=="string"?{providerError:i(t.providerError)}:{},...typeof t.sourceAction=="string"?{sourceAction:i(t.sourceAction)}:{},...k(t.materializationKind)?{materializationKind:t.materializationKind}:{},...typeof t.isOriginal=="boolean"?{isOriginal:t.isOriginal}:{},...typeof t.mimeKindMatches=="boolean"?{mimeKindMatches:t.mimeKindMatches}:{}}})}function z(e){if(!e||typeof e!="object")return[];const n=e;return Array.isArray(n.attachments)?n.attachments:n.attachment&&typeof n.attachment=="object"?[n.attachment]:n.localPath||n.url||n.name||n.fileName||n.availability?[n]:[]}function E(e,n){return e==="edge-local"||e==="server-url"||e==="pending-download"||e==="metadata-only"||e==="unavailable-large"?e:n.localPath?"edge-local":n.url?"server-url":"metadata-only"}function k(e){return e==="original-file"||e==="clipboard-image"||e==="preview-crop"||e==="metadata"}function T(e){const n=i(e.localPath||"");if(!n)throw new Error("WeChat channel product send requires a local attachment path on this machine");if(!S.statSync(n).isFile())throw new Error(`WeChat channel product attachment is not a file: ${n}`);return n}function L(e){return Array.isArray(e.groups)?e.groups.map(n=>i(n?.name||"")).filter(Boolean):[]}function _(){return process.env.SHENNIAN_MACHINE_ID?.trim()||A().machineId||"local"}function j(e){if(!e)return new Date().toISOString();const n=new Date(e);return Number.isNaN(n.getTime())?new Date().toISOString():n.toISOString()}function i(e){return e.replace(/\s+/g," ").trim()}function q(e,n,r,a){const t=Number(e);return Number.isFinite(t)?Math.max(r,Math.min(a,Math.floor(t))):n}function d(e,n){return`${e}:${P.createHash("sha256").update(n).digest("hex").slice(0,24)}`}export{W as WECHAT_RPA_PRODUCT_SOURCE,te as cancelWeChatRpaProductOutboundReply,Y as countPendingWeChatRpaProductOutbound,V as createWeChatRpaProductSourceConnection,X as enqueueWeChatRpaProductOutboundReply,re as isWeChatRpaProductSource,ee as listPendingWeChatRpaProductOutbound,ne as listWeChatRpaProductRecentMessages,C as safeWeChatChannelRuntimePathSegment,b as weChatChannelBindingId,D as weChatChannelConversationId,I as weChatChannelLedgerPath,u as weChatChannelOutboundLedgerPath};
8
+ ${o||r.senderRole}`),name:o||null},text:a,attachments:t,receivedAt:j(r.observedAt),isMentioned:!1,replyTarget:"",rawRef:r.stableMessageKey}}function K(e){const n=e.mediaMetadata;return z(n).map(a=>{const t=a,o=typeof t.localPath=="string"?i(t.localPath):"",s=typeof t.thumbnailPath=="string"?i(t.thumbnailPath):"",c=typeof t.url=="string"?i(t.url):"",l=Number(t.size??t.sizeBytes??0);return{type:i(String(t.type||t.kind||e.kind||"file"))||"file",...t.name||t.fileName?{name:i(String(t.name||t.fileName))}:{},...c?{url:c}:{},...typeof t.mimeType=="string"?{mimeType:i(t.mimeType)}:{},...typeof t.extension=="string"?{extension:i(t.extension)}:{},...Number.isFinite(l)&&l>0?{size:l}:{},...o?{localPath:o}:{},...s?{thumbnailPath:s}:{},...typeof t.hash=="string"||typeof t.sha256=="string"?{hash:i(String(t.hash||t.sha256))}:{},availability:E(t.availability,{localPath:o,url:c}),...typeof t.providerError=="string"?{providerError:i(t.providerError)}:{},...typeof t.sourceAction=="string"?{sourceAction:i(t.sourceAction)}:{},...k(t.materializationKind)?{materializationKind:t.materializationKind}:{},...typeof t.isOriginal=="boolean"?{isOriginal:t.isOriginal}:{},...typeof t.mimeKindMatches=="boolean"?{mimeKindMatches:t.mimeKindMatches}:{}}})}function z(e){if(!e||typeof e!="object")return[];const n=e;return Array.isArray(n.attachments)?n.attachments:n.attachment&&typeof n.attachment=="object"?[n.attachment]:n.localPath||n.url||n.name||n.fileName||n.availability?[n]:[]}function E(e,n){return e==="edge-local"||e==="server-url"||e==="pending-download"||e==="metadata-only"||e==="unavailable-large"?e:n.localPath?"edge-local":n.url?"server-url":"metadata-only"}function k(e){return e==="original-file"||e==="clipboard-image"||e==="preview-crop"||e==="metadata"}function T(e){const n=i(e.localPath||"");if(!n)throw new Error("WeChat channel product send requires a local attachment path on this machine");if(!S.statSync(n).isFile())throw new Error(`WeChat channel product attachment is not a file: ${n}`);return n}function L(e){return Array.isArray(e.groups)?e.groups.map(n=>i(n?.name||"")).filter(Boolean):[]}function _(){return process.env.SHENNIAN_MACHINE_ID?.trim()||A().machineId||"local"}function j(e){if(!e)return new Date().toISOString();const n=new Date(e);return Number.isNaN(n.getTime())?new Date().toISOString():n.toISOString()}function i(e){return e.replace(/\s+/g," ").trim()}function q(e,n,r,a){const t=Number(e);return Number.isFinite(t)?Math.max(r,Math.min(a,Math.floor(t))):n}function d(e,n){return`${e}:${P.createHash("sha256").update(n).digest("hex").slice(0,24)}`}export{W as WECHAT_RPA_PRODUCT_SOURCE,te as cancelWeChatRpaProductOutboundReply,Y as countPendingWeChatRpaProductOutbound,V as createWeChatRpaProductSourceConnection,X as enqueueWeChatRpaProductOutboundReply,re as isWeChatRpaProductSource,ee as listPendingWeChatRpaProductOutbound,ne as listWeChatRpaProductRecentMessages,w as observedMessageToExternalEvent,C as safeWeChatChannelRuntimePathSegment,b as weChatChannelBindingId,D as weChatChannelConversationId,I as weChatChannelLedgerPath,u as weChatChannelOutboundLedgerPath};
@@ -23,19 +23,21 @@ type IpcContext = {
23
23
  url: string;
24
24
  token: string;
25
25
  };
26
- type WeChatToolBinding = {
26
+ export type WeChatToolBinding = {
27
27
  sessionId: string;
28
28
  channelId: string;
29
29
  conversationId: string;
30
30
  conversationName: string;
31
31
  workDir: string;
32
32
  };
33
+ export type WeChatToolTransport = 'auto' | 'daemon' | 'direct';
33
34
  export type WeChatToolOptions = {
34
35
  conversation: string;
35
36
  sessionId?: string;
36
37
  workDir?: string;
37
38
  source?: string;
38
39
  download?: 'auto' | 'never';
40
+ transport?: WeChatToolTransport;
39
41
  traceId?: string;
40
42
  timeoutMs?: number;
41
43
  recentLimit?: number;
@@ -49,6 +51,8 @@ export type WeChatDirectToolRuntime = {
49
51
  send(binding: WeChatToolBinding, options: WeChatSendOptions): Promise<{
50
52
  pending?: boolean;
51
53
  sendStatus?: WeChatSendResult['sendStatus'];
54
+ outDir?: string;
55
+ helperTracePath?: string | null;
52
56
  }>;
53
57
  };
54
58
  export type WeChatSendOptions = WeChatToolOptions & {
@@ -96,9 +100,28 @@ export type WeChatReadLatestResult = {
96
100
  reasonCode?: null;
97
101
  message?: string;
98
102
  };
103
+ export type WeChatToolErrorResult = {
104
+ ok: false;
105
+ operation: 'read' | 'write';
106
+ conversation?: string;
107
+ reasonCode: string;
108
+ message: string;
109
+ };
99
110
  export declare function runWeChatDoctor(options?: WeChatDoctorOptions): Promise<WeChatDoctorResult>;
100
111
  export declare function runWeChatSend(options: WeChatSendOptions): Promise<WeChatSendResult>;
101
112
  export declare function runWeChatReadLatest(options: WeChatReadLatestOptions): Promise<WeChatReadLatestResult>;
113
+ export declare function sendDirectWeChatMessageOnce(binding: WeChatToolBinding, options: WeChatSendOptions): Promise<{
114
+ pending?: boolean;
115
+ sendStatus?: WeChatSendResult['sendStatus'];
116
+ outDir?: string;
117
+ helperTracePath?: string | null;
118
+ }>;
119
+ export declare function readDirectWeChatLatestOnce(binding: WeChatToolBinding, options: WeChatReadLatestOptions): Promise<{
120
+ messages: ExternalMessageEvent[];
121
+ outDir: string;
122
+ helperTracePath: string | null;
123
+ }>;
102
124
  export declare function registerWeChatCommand(program: Command): void;
125
+ export declare function buildWeChatToolErrorResult(operation: 'read' | 'write', conversation: string | undefined, error: unknown): WeChatToolErrorResult;
103
126
  export declare function buildWeChatReadMarkdown(result: WeChatReadLatestResult): string;
104
127
  export {};
@@ -1,11 +1,7 @@
1
- import j from"node:crypto";import q from"node:fs";import W from"node:path";import{SERVERS as U}from"../region.js";import{loadConfig as B,resolveShennianPath as R}from"../config/index.js";import{createWeChatRpaProductSourceConnection as z,listWeChatRpaProductRecentMessages as F,weChatChannelConversationId as J}from"../channels/wechat-rpa/product-channel.js";import{createWeChatChannelProductRunner as H}from"../channels/wechat-channel/runner.js";import{createWeChatChannelApiClient as K}from"../channels/wechat-channel/client.js";import{readExternalAttachment as V}from"./external-attachments.js";import{resolveWeChatChannelHelperAsset as Q,WECHAT_CHANNEL_HELPER_VERSION as Z}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as G}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as X}from"../channels/wechat-channel/helper-protocol.js";import{ensureWeChatWindowReady as Y,fallbackWeChatMessageInputPointForWindow as ee,focusKnownWeChatWindow as ne,openConversationBySearch as te}from"../channels/wechat-channel/observer.js";import{enqueueWeChatOutboundReply as re}from"../channels/wechat-channel/outbound-ledger.js";import{sendQueuedWeChatOutboundRecords as _,WeChatChannelOutboundSender as ae}from"../channels/wechat-channel/outbound-sender.js";async function oe(e={}){const n=B(),t=he(e.serverUrl||n.serverUrl||U.cn.url),a=e.machineToken||n.machineToken,r=e.machineId||n.machineId,s=e.fetchImpl||fetch,o=[f("cli_installed","Shennian CLI is installed."),a?f("machine_paired","Machine token is configured."):v("machine_paired","machine_not_paired","Machine is not paired. Run shennian pair first.")];if(!a)return y({checks:o,serverUrl:t,machineId:r});try{const d=await s(`${t}/api/channels/wechat/runtime-policy`,{headers:{authorization:`Bearer ${a}`}}),i=await d.json().catch(()=>null);if(!d.ok||i?.ok===!1){const l=I(i?.reasonCode)||d.statusText||"request_failed";return o.push(v("server_policy",l,`WeChat runtime policy is blocked: ${l}`)),y({checks:o,serverUrl:t,machineId:r})}const c=g(i?.usagePolicy)?i.usagePolicy:{};o.push(f("server_policy","Server WeChat policy is reachable.")),o.push(f("entitlement","Account has Pro / Team external channel entitlement.")),o.push(f("credits",c.billingMode==="credits"?"Credit billing is enabled; balance is checked by server calls.":"Credits are not metered in current billing mode."));const h=g(i?.runtime)&&g(i.runtime.current)?i.runtime.current:null;o.push(h?f("runtime_registered","Local WeChat runtime is registered on the server."):me("runtime_registered","runtime_not_registered","Local WeChat runtime is not registered yet; open Shennian Desktop/daemon and enable Use WeChat."))}catch(d){o.push(v("server_policy","network_unavailable",d instanceof Error?d.message:"Unable to reach Shennian server."))}return y({checks:o,serverUrl:t,machineId:r})}async function ie(e){const n=e.text.trim();if(!n&&!e.attachment)throw new Error("Message text or attachment is required");const t=N(e),a=e.attachment?We(e.attachment):void 0;if(e.dryRun)return{ok:!0,operation:"write",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,sendStatus:"dry_run",pending:!1,attachment:a,attachments:a?[a]:[],dryRun:!0,reasonCode:null,message:"Dry run completed. No WeChat message was sent."};if(!M(e)){const c=await(e.directRuntime??b).send(t,e);return{ok:!0,operation:"write",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,sendStatus:c.sendStatus??(c.pending?"pending":"sent"),pending:c.pending===!0,attachment:a,attachments:a?[a]:[],reasonCode:null,message:c.pending?"WeChat message is queued or waiting for confirmation.":"WeChat message sent."}}const r=e.ipc??$();await x(r,t,e);const s=e.idempotencyKey||C("wechat-cli-send",`${t.channelId}
2
- ${t.conversationId}
3
- ${n}
4
- ${Date.now()}`),o=await p(r,"/external/reply",{managerSessionId:t.sessionId,channelId:t.channelId,conversationId:t.conversationId,text:n,attachment:e.attachment,idempotencyKey:s},e.fetchImpl,e.timeoutMs),d=await p(r,"/wechat-rpa/channel/sync",{managerSessionId:t.sessionId},e.fetchImpl,e.timeoutMs),i=Ie(d,s,o.pending===!0);return{ok:!0,operation:"write",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,sendStatus:i,pending:o.pending===!0&&(i==="queued"||i==="pending"),attachment:a,attachments:a?[a]:[],reasonCode:null,message:i==="confirmed_echo"?"WeChat message sent and confirmed.":i==="manual_review"?"WeChat message was submitted but needs manual review.":"WeChat message submitted to local daemon."}}async function se(e){const n=m(e.limit,10),t=N(e);if(!M(e)){const c=(await(e.directRuntime??b).readLatest(t,{...e,limit:n,recentLimit:e.recentLimit??n})).filter(l=>l.conversationId===t.conversationId||l.conversationName===t.conversationName).slice(-n),h=T(c);return{ok:!0,operation:"read",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,messages:c,attachments:h,count:c.length,reasonCode:null,message:`Read ${c.length} WeChat message(s).`}}const a=e.ipc??$();await x(a,t,{...e,recentLimit:e.recentLimit??n});const r=await p(a,"/wechat-rpa/channel/sync",{managerSessionId:t.sessionId},e.fetchImpl,e.timeoutMs),o=(Array.isArray(r.messages)?r.messages.filter(xe):[]).filter(i=>i.conversationId===t.conversationId||i.conversationName===t.conversationName).slice(-n),d=T(o);return{ok:!0,operation:"read",conversation:t.conversationName,conversationName:t.conversationName,conversationId:t.conversationId,sessionId:t.sessionId,channelId:t.channelId,traceId:e.traceId,outDir:t.workDir,helperTracePath:null,messages:o,attachments:d,count:o.length,reasonCode:null,message:`Read ${o.length} WeChat message(s).`}}const b={async readLatest(e,n){const{config:t,secret:a}=D(e,n),r=P(t,a,n);try{return await r.runner.tick(),F({config:t,product:r,limit:n.limit??n.recentLimit??10})}finally{await r.runner.stop().catch(()=>{})}},async send(e,n){return ce(e,n)}};async function ce(e,n){const{config:t,secret:a}=D(e,n),r=P(t,a,n),s=r.runtime.bindings.find(l=>l.conversationDisplayName===e.conversationName)??r.runtime.bindings[0];if(!s)throw new Error("wechat_direct_binding_missing");const o=r.runtime.policy.platform,d=Q({platform:o});if(!d.ok)throw new Error(`${d.reasonCode}: ${d.message}`);const i=new G({helperPath:d.helperPath,expectedHelperVersion:d.version||Z,requiredCapabilities:o==="win32"?X("send"):void 0,guardUnsafeWindowsCommands:o==="win32",cleanupWindowsOverlays:o==="win32"}),c={version:1,runtimeId:r.runtime.runtimeId,records:[]},h=n.idempotencyKey||C("wechat-cli-send",`${e.channelId}
5
- ${e.conversationId}
6
- ${n.text}
7
- ${n.attachment?.localPath||""}
8
- ${Date.now()}`);re({ledger:c,replyId:`wechat-cli:${h}`,idempotencyKey:h,bindingId:s.bindingId,runtimeId:r.runtime.runtimeId,sessionId:s.sessionId,conversationName:s.conversationDisplayName,replyBaseRevision:0,text:n.text,attachmentLocalRefs:n.attachment?.localPath?[n.attachment.localPath]:[]});try{await i.start();const l=new ae({helper:i,platform:o,traceId:n.traceId,openConversation:async L=>{const O=await Y(i,n.traceId),S=await ne(i,O,n.traceId);return{...await te({helper:i,window:S,settleToBottom:!1,binding:{...s,conversationDisplayName:L},traceId:n.traceId}),inputPoint:ee(S)}}}),u=await de({ledger:c,bindingId:s.bindingId,sender:l,maxWaitMs:n.timeoutMs??9e4}),k=c.records[0];if(u.sentRecords.length>0)return{pending:!0,sendStatus:"sent_unconfirmed"};if(u.manualReviewRecords.length>0)return{pending:!1,sendStatus:"manual_review"};if(u.waitingRecords.length>0)return{pending:!0,sendStatus:"pending"};if(u.staleRecords.length>0)throw new Error(u.staleRecords[0]?.failureCode||"reply_revision_stale");if(u.failedRecords.length>0)throw new Error(u.failedRecords[0]?.failureCode||u.failedRecords[0]?.lastErrorSummary||"wechat_direct_send_failed");return{pending:k?.sendStatus==="queued",sendStatus:k?.sendStatus==="queued"?"queued":"pending"}}finally{await i.stop().catch(()=>{}),await r.runner.stop().catch(()=>{})}}async function de(e){const n=e.maxAttempts??24,t=e.maxWaitMs??9e4,a=Date.now();let r=await _({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:t});for(let s=2;r.waitingRecords.length>0&&s<=n&&!(Date.now()-a>=t);s+=1){const o=le(r.waitingRecords[0]?.nextAttemptAt,a,t);await ue(o),r=await _({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:t})}return r}function le(e,n,t){const a=Math.max(0,n+t-Date.now());if(a<=0)return 0;if(!e)return Math.min(1200,a);const r=new Date(e).getTime();return Number.isFinite(r)?Math.max(250,Math.min(r-Date.now(),a)):Math.min(1200,a)}function ue(e){return new Promise(n=>setTimeout(n,Math.max(0,e)))}function He(e){const n=e.command("wechat").description("Use WeChat through Shennian local runtime");n.option("--conversation <name>","WeChat conversation/group name"),n.command("doctor").description("Check local Shennian, pairing, entitlement, credits, and WeChat runtime readiness").option("--json","Output JSON",!1).action(async a=>{const r=await oe();if(a.json)console.log(JSON.stringify(r,null,2));else for(const s of r.checks){const o=s.ok?"\u2713":s.status==="warning"?"!":"\u2717";console.log(`${o} ${s.id}: ${s.message}`)}r.ok||(process.exitCode=1)}),n.command("write").aliases(["send"]).description("Write a message to a local WeChat conversation through Shennian").argument("[text...]","Message text").option("--conversation <name>","WeChat conversation/group name").option("--text <text>","Message text").option("--file <path>","File attachment path").option("--image <path>","Image attachment path").option("--video <path>","Video attachment path").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--idempotency-key <key>","Idempotency key").option("--dry-run","Validate the request and output the planned write without sending",!1).option("--trace-id <id>","Trace id included in JSON output").option("--timeout <ms>","Manager IPC request timeout in milliseconds").option("--format <format>","Output format: json or text","text").option("--json","Output JSON",!1).action(async(a,r,s)=>{const o=A(s,r.conversation),d=r.text??a.join(" "),i=Ce(r),c=await ie({conversation:o,text:d,attachment:i,sessionId:r.sessionId,workDir:r.workDir,idempotencyKey:r.idempotencyKey,dryRun:r.dryRun,traceId:r.traceId,timeoutMs:r.timeout?m(r.timeout,24e4):void 0});ge(c,r.json||r.format==="json")}),n.command("read").aliases(["read-latest","read_latest","latest"]).description("Read recent messages from a local WeChat conversation through Shennian").argument("[count]","Number of latest messages","10").option("--conversation <name>","WeChat conversation/group name").option("--limit <n>","Number of latest messages").option("--format <format>","Output format: markdown or json","markdown").option("--download <mode>","Attachment download mode: auto or never","auto").option("--trace-id <id>","Trace id included in JSON output").option("--timeout <ms>","Manager IPC request timeout in milliseconds").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--json","Output JSON",!1).action(async(a,r,s)=>{const o=A(s,r.conversation),d=ke(r.json?"json":r.format),i=await se({conversation:o,limit:m(r.limit??a,10),download:Se(r.download),traceId:r.traceId,timeoutMs:r.timeout?m(r.timeout,24e4):void 0,sessionId:r.sessionId,workDir:r.workDir});pe(i,d)})}function y(e){return{ok:e.checks.every(n=>n.ok||n.status==="warning"),checks:e.checks,serverUrl:e.serverUrl,machineId:e.machineId}}function f(e,n){return{id:e,ok:!0,status:"ready",message:n}}function me(e,n,t){return{id:e,ok:!1,status:"warning",reasonCode:n,message:t}}function v(e,n,t){return{id:e,ok:!1,status:"blocked",reasonCode:n,message:t}}function he(e){return e.replace(/\/+$/,"")}function $(){const e=R("runtime","manager-ipc.json");let n;try{n=JSON.parse(q.readFileSync(e,"utf-8"))}catch{throw new Error("Manager IPC is not available. Open Shennian Desktop or run `shennian start` first.")}const t=Number(n.pid);if(Number.isInteger(t)&&t>0&&!be(t))throw new Error(`Manager IPC runtime file is stale for PID ${t}. Restart Shennian Desktop or run \`shennian restart\`.`);const a=typeof n.url=="string"?n.url.replace(/\/+$/,""):"",r=typeof n.token=="string"?n.token:"";if(!a||!r)throw new Error(`Manager IPC runtime file is incomplete: ${e}`);return{url:a,token:r}}async function x(e,n,t){return p(e,"/wechat-rpa/channel/upsert",{managerSessionId:n.sessionId,id:n.channelId,name:`WeChat ${n.conversationName}`,workDir:n.workDir,enabled:!0,groups:[{name:n.conversationName}],canReply:!0,source:t.source||"wechat-channel",recentLimit:m(t.recentLimit,20),pollIntervalMs:m(t.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:t.download!=="never",privacyConsentAccepted:!0},t.fetchImpl,t.timeoutMs)}async function p(e,n,t,a=fetch,r){const s=String(t.managerSessionId||"");if(!s)throw new Error("managerSessionId is required");const o=r?new AbortController:null,d=o?setTimeout(()=>o.abort(),r):null;try{const i=await a(`${e.url}${n}`,{method:"POST",headers:{authorization:`Bearer ${e.token}`,"content-type":"application/json","x-shennian-manager-session-id":s},body:JSON.stringify(t),signal:o?.signal}),c=await i.json().catch(()=>({ok:!1,error:i.statusText}));if(!i.ok||!c.ok)throw new Error(c.error||`Manager IPC failed: ${i.status}`);return c}finally{d&&clearTimeout(d)}}function N(e){const n=e.conversation.trim();if(!n)throw new Error("--conversation is required");const t=C("wechat-cli-conversation",n),a=e.sessionId?.trim()||`wechat-cli-${t.slice(-24)}`,r=`wechat-rpa:${a}`;return{sessionId:a,channelId:r,conversationId:J(n),conversationName:n,workDir:W.resolve(e.workDir||R("wechat-cli",$e(n)))}}function M(e){return e.directRuntime?!1:!!(e.sessionId?.trim()||e.ipc)}function D(e,n){return{config:{id:e.channelId,type:"wechat-rpa",name:`WeChat ${e.conversationName}`,sessionId:e.sessionId,managerSessionId:e.sessionId,workDir:e.workDir,enabled:!0,secretRef:`wechat-cli:${e.channelId}`},secret:{groups:[{name:e.conversationName}],pollIntervalMs:m(n.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:n.download!=="never",canReply:!0}}}function P(e,n,t){const a=fe(t);return z({config:e,secret:n,createRunner:r=>H({...r,api:a})})}function fe(e){return{...K({fetchImpl:e.fetchImpl}),upsertRuntime:async()=>({ok:!0,status:"local_direct_tool"}),ingest:async()=>({ok:!0,status:"local_direct_tool"}),reportRunStatus:async()=>({ok:!0,status:"local_direct_tool"}),reportOutboundStatus:async()=>({ok:!0,status:"local_direct_tool"})}}function A(e,n){const t=e.parent?.opts()??{},a=n||t.conversation||"";if(!a.trim())throw new Error("--conversation is required");return a}function ge(e,n){if(n){console.log(JSON.stringify(e,null,2));return}console.log(e.sendStatus)}function pe(e,n){if(n==="json"){console.log(JSON.stringify(e,null,2));return}console.log(we(e).trimEnd())}function we(e){const n=[];if(e.messages.length===0)return`\uFF08\u6CA1\u6709\u8BFB\u5230\uFF09
9
- `;for(const t of e.messages)n.push(`${ve(t)}: ${ye(t)}`);return`${n.join(`
1
+ import q from"node:crypto";import _ from"node:fs";import y from"node:path";import{SERVERS as z}from"../region.js";import{loadConfig as k,resolveShennianPath as $}from"../config/index.js";import{observedMessageToExternalEvent as B,weChatChannelConversationId as J,weChatChannelBindingId as F}from"../channels/wechat-rpa/product-channel.js";import{readExternalAttachment as K}from"./external-attachments.js";import{runWeChatChannelActionSmoke as D}from"../devtools/wechat-channel-action-smoke.js";async function H(e={}){const t=k(),n=ee(e.serverUrl||t.serverUrl||z.cn.url),a=e.machineToken||t.machineToken,r=e.machineId||t.machineId,o=e.fetchImpl||fetch,s=[g("cli_installed","Shennian CLI is installed."),a?g("machine_paired","Machine token is configured."):S("machine_paired","machine_not_paired","Machine is not paired. Run shennian pair first.")];if(!a)return C({checks:s,serverUrl:n,machineId:r});try{const i=await o(`${n}/api/channels/wechat/runtime-policy`,{headers:{authorization:`Bearer ${a}`}}),d=await i.json().catch(()=>null);if(!i.ok||d?.ok===!1){const u=h(d?.reasonCode)||i.statusText||"request_failed";return s.push(S("server_policy",u,`WeChat runtime policy is blocked: ${u}`)),C({checks:s,serverUrl:n,machineId:r})}const c=f(d?.usagePolicy)?d.usagePolicy:{};s.push(g("server_policy","Server WeChat policy is reachable.")),s.push(g("entitlement","Account has Pro / Team external channel entitlement.")),s.push(g("credits",c.billingMode==="credits"?"Credit billing is enabled; balance is checked by server calls.":"Credits are not metered in current billing mode."));const l=f(d?.runtime)&&f(d.runtime.current)?d.runtime.current:null;s.push(l?g("runtime_registered","Local WeChat runtime is registered on the server."):Y("runtime_registered","runtime_not_registered","Local WeChat runtime is not registered yet; open Shennian Desktop/daemon and enable Use WeChat."))}catch(i){s.push(S("server_policy","network_unavailable",i instanceof Error?i.message:"Unable to reach Shennian server."))}return C({checks:s,serverUrl:n,machineId:r})}async function V(e){const t=e.text.trim();if(!t&&!e.attachment)throw new Error("Message text or attachment is required");const n=R(e),a=e.attachment?we(e.attachment):void 0;if(e.dryRun)return{ok:!0,operation:"write",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:n.workDir,helperTracePath:null,sendStatus:"dry_run",pending:!1,attachment:a,attachments:a?[a]:[],dryRun:!0,reasonCode:null,message:"Dry run completed. No WeChat message was sent."};const r=P(e);if(!r){const l=e.directRuntime?await e.directRuntime.send(n,e):await G(n,e);return{ok:!0,operation:"write",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:l.outDir??n.workDir,helperTracePath:l.helperTracePath??null,sendStatus:l.sendStatus??(l.pending?"pending":"sent"),pending:l.pending===!0,attachment:a,attachments:a?[a]:[],reasonCode:null,message:l.pending?"WeChat message is queued or waiting for confirmation.":"WeChat message sent."}}if(r.mode==="tool"){const l=await w(r.ctx,"/wechat-rpa/tool/send",{managerSessionId:n.sessionId,binding:n,text:t,attachment:e.attachment,traceId:e.traceId,timeoutMs:e.timeoutMs},e.fetchImpl,e.timeoutMs),u=b(l.sendStatus)??(l.pending===!0?"pending":"sent");return{ok:!0,operation:"write",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:h(l.outDir)||n.workDir,helperTracePath:h(l.helperTracePath)||null,sendStatus:u,pending:l.pending===!0,attachment:a,attachments:a?[a]:[],reasonCode:null,message:l.pending?"WeChat message is queued or waiting for confirmation.":"WeChat message sent."}}const o=r.ctx;await W(o,n,e);const s=e.idempotencyKey||O("wechat-cli-send",`${n.channelId}
2
+ ${n.conversationId}
3
+ ${t}
4
+ ${Date.now()}`),i=await w(o,"/external/reply",{managerSessionId:n.sessionId,channelId:n.channelId,conversationId:n.conversationId,text:t,attachment:e.attachment,idempotencyKey:s},e.fetchImpl,e.timeoutMs),d=await te(o,n,e),c=d?ue(d,s,i.pending===!0):i.pending===!0?"queued":"ok";return{ok:!0,operation:"write",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:n.workDir,helperTracePath:null,sendStatus:c,pending:i.pending===!0&&(c==="queued"||c==="pending"),attachment:a,attachments:a?[a]:[],reasonCode:null,message:d?c==="confirmed_echo"?"WeChat message sent and confirmed.":c==="manual_review"?"WeChat message was submitted but needs manual review.":"WeChat message submitted to local daemon.":"WeChat message submitted to local daemon; confirmation sync timed out."}}async function Z(e){const t=v(e.limit,10),n=R(e),a=P(e);if(!a){const c=e.directRuntime?{messages:await e.directRuntime.readLatest(n,{...e,limit:t,recentLimit:e.recentLimit??t}),outDir:n.workDir,helperTracePath:null}:await X(n,{...e,limit:t,recentLimit:e.recentLimit??t}),l=c.messages.filter(p=>p.conversationId===n.conversationId||p.conversationName===n.conversationName).slice(-t),u=x(l);return{ok:!0,operation:"read",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:c.outDir,helperTracePath:c.helperTracePath,messages:l,attachments:u,count:l.length,reasonCode:null,message:`Read ${l.length} WeChat message(s).`}}if(a.mode==="tool"){const c=await w(a.ctx,"/wechat-rpa/tool/read",{managerSessionId:n.sessionId,binding:n,limit:t,download:e.download,traceId:e.traceId,timeoutMs:e.timeoutMs},e.fetchImpl,e.timeoutMs),u=(Array.isArray(c.messages)?c.messages.filter(U):[]).filter(m=>m.conversationId===n.conversationId||m.conversationName===n.conversationName).slice(-t),p=x(u);return{ok:!0,operation:"read",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:h(c.outDir)||n.workDir,helperTracePath:h(c.helperTracePath)||null,messages:u,attachments:p,count:u.length,reasonCode:null,message:`Read ${u.length} WeChat message(s).`}}const r=a.ctx;await W(r,n,{...e,recentLimit:e.recentLimit??t});const o=await w(r,"/wechat-rpa/channel/sync",{managerSessionId:n.sessionId},e.fetchImpl,e.timeoutMs),i=(Array.isArray(o.messages)?o.messages.filter(U):[]).filter(c=>c.conversationId===n.conversationId||c.conversationName===n.conversationName).slice(-t),d=x(i);return{ok:!0,operation:"read",conversation:n.conversationName,conversationName:n.conversationName,conversationId:n.conversationId,sessionId:n.sessionId,channelId:n.channelId,traceId:e.traceId,outDir:n.workDir,helperTracePath:null,messages:i,attachments:d,count:i.length,reasonCode:null,message:`Read ${i.length} WeChat message(s).`}}async function G(e,t){const n=Q(t.attachment),a=M(e,t,{kind:"send",steps:["open-read",n],text:t.text,attachment:t.attachment}),r=await D(a),o=r.steps.find(i=>i.step===n);if(!r.ok||!o?.ok){const i=o?.reasonCode||r.steps.find(c=>!c.ok&&!c.skipped)?.reasonCode||"wechat_direct_send_failed",d=o?.errorSummary||r.steps.find(c=>!c.ok&&!c.skipped)?.errorSummary||i;throw new Error(`${i}: ${d}`)}const s=b(o.details?.sendStatus)??"sent_unconfirmed";return{pending:s==="queued"||s==="pending"||s==="sent_unconfirmed",sendStatus:s,outDir:r.outDir,helperTracePath:r.helperTracePath}}function Q(e){return e?e.kind==="image"?"send-image":e.kind==="video"?"send-video":"send-file":"send-text"}async function X(e,t){const n=t.download!=="never",a=n?"download-visible-media":"structure-window",r=M(e,t,{kind:"read",steps:[a],allowEmptyMedia:n}),o=await D(r),s=o.steps.find(u=>u.step===a);if(!o.ok&&s?.reasonCode!=="no_observed_messages"){const u=s?.reasonCode||o.steps.find(m=>!m.ok&&!m.skipped)?.reasonCode||"wechat_direct_read_failed",p=s?.errorSummary||o.steps.find(m=>!m.ok&&!m.skipped)?.errorSummary||u;throw new Error(`${u}: ${p}`)}const i=y.join(o.outDir,n?"download-visible-messages.json":"structure-window-messages.json"),d=oe(i),c=re(e,t),l=ae(e);return{messages:d.map(u=>B(c,l,u)).filter(u=>u!=null),outDir:o.outDir,helperTracePath:o.helperTracePath}}function We(e){const t=e.command("wechat").description("Use WeChat through Shennian local runtime");t.option("--conversation <name>","WeChat conversation/group name"),t.command("doctor").description("Check local Shennian, pairing, entitlement, credits, and WeChat runtime readiness").option("--json","Output JSON",!1).action(async a=>{const r=await H();if(a.json)console.log(JSON.stringify(r,null,2));else for(const o of r.checks){const s=o.ok?"\u2713":o.status==="warning"?"!":"\u2717";console.log(`${s} ${o.id}: ${o.message}`)}r.ok||(process.exitCode=1)}),t.command("write").aliases(["send"]).description("Write a message to a local WeChat conversation through Shennian").argument("[text...]","Message text").option("--conversation <name>","WeChat conversation/group name").option("--text <text>","Message text").option("--file <path>","File attachment path").option("--image <path>","Image attachment path").option("--video <path>","Video attachment path").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--idempotency-key <key>","Idempotency key").option("--dry-run","Validate the request and output the planned write without sending",!1).option("--trace-id <id>","Trace id included in JSON output").option("--timeout <ms>","Manager IPC request timeout in milliseconds").option("--transport <mode>","Execution transport: auto, daemon, or direct","auto").option("--format <format>","Output format: json or text","text").option("--json","Output JSON",!1).action(async(a,r,o)=>{let s;try{s=T(o,r.conversation);const i=r.text??a.join(" "),d=fe(r),c=await V({conversation:s,text:i,attachment:d,sessionId:r.sessionId,workDir:r.workDir,idempotencyKey:r.idempotencyKey,dryRun:r.dryRun,traceId:r.traceId,timeoutMs:r.timeout?v(r.timeout,24e4):void 0,transport:A(r.transport)});ie(c,r.json||r.format==="json")}catch(i){E("write",s||r.conversation,i,r.json||r.format==="json")}}),t.command("read").aliases(["read-latest","read_latest","latest"]).description("Read recent messages from a local WeChat conversation through Shennian").argument("[count]","Number of latest messages","10").option("--conversation <name>","WeChat conversation/group name").option("--limit <n>","Number of latest messages").option("--format <format>","Output format: markdown or json","markdown").option("--download <mode>","Attachment download mode: auto or never","auto").option("--trace-id <id>","Trace id included in JSON output").option("--timeout <ms>","Manager IPC request timeout in milliseconds").option("--session-id <id>","Bind to an existing Shennian chat/session; omit for direct local WeChat tool mode").option("--work-dir <path>","Local tool work dir; defaults under ~/.shennian/wechat-cli").option("--transport <mode>","Execution transport: auto, daemon, or direct","auto").option("--json","Output JSON",!1).action(async(a,r,o)=>{let s,i="markdown";try{s=T(o,r.conversation),i=pe(r.json?"json":r.format);const d=await Z({conversation:s,limit:v(r.limit??a,10),download:ge(r.download),traceId:r.traceId,timeoutMs:r.timeout?v(r.timeout,24e4):void 0,sessionId:r.sessionId,workDir:r.workDir,transport:A(r.transport)});ce(d,i)}catch(d){E("read",s||r.conversation,d,r.json||i==="json")}})}function C(e){return{ok:e.checks.every(t=>t.ok||t.status==="warning"),checks:e.checks,serverUrl:e.serverUrl,machineId:e.machineId}}function g(e,t){return{id:e,ok:!0,status:"ready",message:t}}function Y(e,t,n){return{id:e,ok:!1,status:"warning",reasonCode:t,message:n}}function S(e,t,n){return{id:e,ok:!1,status:"blocked",reasonCode:t,message:n}}function ee(e){return e.replace(/\/+$/,"")}function N(){const e=$("runtime","manager-ipc.json");let t;try{t=JSON.parse(_.readFileSync(e,"utf-8"))}catch{throw new Error("Manager IPC is not available. Open Shennian Desktop or run `shennian start` first.")}const n=Number(t.pid);if(Number.isInteger(n)&&n>0&&!ye(n))throw new Error(`Manager IPC runtime file is stale for PID ${n}. Restart Shennian Desktop or run \`shennian restart\`.`);const a=typeof t.url=="string"?t.url.replace(/\/+$/,""):"",r=typeof t.token=="string"?t.token:"";if(!a||!r)throw new Error(`Manager IPC runtime file is incomplete: ${e}`);return{url:a,token:r}}function ne(){try{return N()}catch{return null}}function P(e){if(e.directRuntime)return null;const t=e.transport??"auto";if(t==="direct")return null;if(e.ipc)return{ctx:e.ipc,mode:"session"};if(e.sessionId?.trim())return{ctx:N(),mode:"session"};if(t==="daemon")return{ctx:N(),mode:"tool"};const n=ne();return n?{ctx:n,mode:"tool"}:null}async function W(e,t,n){return w(e,"/wechat-rpa/channel/upsert",{managerSessionId:t.sessionId,id:t.channelId,name:`WeChat ${t.conversationName}`,workDir:t.workDir,enabled:!0,groups:[{name:t.conversationName}],canReply:!0,source:n.source||"wechat-channel",recentLimit:v(n.recentLimit,20),pollIntervalMs:v(n.pollIntervalMs,3e4),forceForeground:!0,downloadAttachments:n.download!=="never",privacyConsentAccepted:!0},n.fetchImpl,n.timeoutMs)}async function w(e,t,n,a=fetch,r){const o=String(n.managerSessionId||"");if(!o)throw new Error("managerSessionId is required");const s=r?new AbortController:null,i=s?setTimeout(()=>s.abort(),r):null;try{const d=await a(`${e.url}${t}`,{method:"POST",headers:{authorization:`Bearer ${e.token}`,"content-type":"application/json","x-shennian-manager-session-id":o},body:JSON.stringify(n),signal:s?.signal}),c=await d.json().catch(()=>({ok:!1,error:d.statusText}));if(!d.ok||!c.ok)throw new Error(c.error||`Manager IPC failed: ${d.status}`);return c}finally{i&&clearTimeout(i)}}function R(e){const t=e.conversation.trim();if(!t)throw new Error("--conversation is required");const n=O("wechat-cli-conversation",t),a=e.sessionId?.trim()||`wechat-cli-${n.slice(-24)}`,r=`wechat-rpa:${a}`;return{sessionId:a,channelId:r,conversationId:J(t),conversationName:t,workDir:y.resolve(e.workDir||$("wechat-cli",L(t)))}}async function te(e,t,n){try{return await w(e,"/wechat-rpa/channel/sync",{managerSessionId:t.sessionId},n.fetchImpl,n.timeoutMs)}catch(a){if(ke(a))return null;throw a}}function M(e,t,n){const a=t.traceId||`wechat-cli-${n.kind}-${Date.now().toString(36)}`,r=y.join(e.workDir,"runs",L(a)),o=n.attachment;return{conversation:e.conversationName,mode:"custom",steps:n.steps,outDir:r,workDir:e.workDir,traceId:a,runtimeId:e.channelId,machineId:process.env.SHENNIAN_MACHINE_ID||k().machineId||"local",sessionId:e.sessionId,serverUrl:k().serverUrl,platform:se(),text:n.text,...o?.localPath&&o.kind==="image"?{imagePath:o.localPath}:{},...o?.localPath&&o.kind==="video"?{videoPath:o.localPath}:{},...o?.localPath&&o.kind!=="image"&&o.kind!=="video"?{filePath:o.localPath}:{},allowEmptyMedia:n.allowEmptyMedia,skipRuntimeUpsert:!0,requireServer:!1}}function re(e,t){return{id:e.channelId,type:"wechat-rpa",name:`WeChat ${e.conversationName}`,sessionId:e.sessionId,managerSessionId:e.sessionId,workDir:e.workDir,enabled:!0,secretRef:`wechat-cli:${e.channelId}`}}function ae(e){return{bindingId:F(e.channelId,e.conversationName),sessionId:e.sessionId,conversationDisplayName:e.conversationName,enabled:!0,allowReply:!0,downloadMedia:!0}}function oe(e){try{const t=JSON.parse(_.readFileSync(e,"utf-8"));return Array.isArray(t)?t.filter(f):[]}catch{return[]}}function b(e){return e==="dry_run"||e==="queued"||e==="sent"||e==="sent_unconfirmed"||e==="confirmed_echo"||e==="manual_review"||e==="pending"||e==="ok"?e:null}function se(){if(process.platform==="darwin")return"darwin";if(process.platform==="win32")return"win32"}function T(e,t){const n=e.parent?.opts()??{},a=t||n.conversation||"";if(!a.trim())throw new Error("--conversation is required");return a}function ie(e,t){if(t){console.log(JSON.stringify(e,null,2));return}console.log(e.sendStatus)}function ce(e,t){if(t==="json"){console.log(JSON.stringify(e,null,2));return}console.log(le(e).trimEnd())}function E(e,t,n,a){const r=de(e,t,n);a?console.log(JSON.stringify(r,null,2)):console.error(`${r.reasonCode}: ${r.message}`),process.exitCode=1}function de(e,t,n){const a=n instanceof Error?n.message:String(n||"wechat_tool_failed"),r=I(a)||"wechat_tool_failed",o=/^([a-z][a-z0-9_]*)(?::\s*(.*))?$/i.exec(r),s=o?.[1]||"wechat_tool_failed",i=I(o?.[2]||r),d=i&&i!==s?i:s;return{ok:!1,operation:e,...t?.trim()?{conversation:t.trim()}:{},reasonCode:s,message:d}}function le(e){const t=[];if(e.messages.length===0)return`\uFF08\u6CA1\u6709\u8BFB\u5230\uFF09
5
+ `;for(const n of e.messages)t.push(`${he(n)}: ${me(n)}`);return`${t.join(`
10
6
  `)}
11
- `}function Ie(e,n,t){const a=g(e.channel)?e.channel:{},s=(Array.isArray(a.wechatRpaPendingReplies)?a.wechatRpaPendingReplies:[]).filter(g).find(c=>I(c.idempotencyKey)===n),o=I(s?.status);if(o==="confirmed_echo"||o==="sent_unconfirmed"||o==="manual_review"||o==="queued")return o;const i=(Array.isArray(a.wechatRpaRecentTaskSummaries)?a.wechatRpaRecentTaskSummaries:[]).filter(g).map(c=>I(c.status)).find(Boolean);return i==="sent"?"sent":i==="confirmed_echo"?"confirmed_echo":i==="manual_review"?"manual_review":t?"pending":"ok"}function ye(e){const n=e.attachments||[],t=w(e.text);return t&&n.length===0?t:t&&n.length>0?`${t} ${n.map(E).join("\u3001")}`:n.length>0?n.map(E).join("\u3001"):"\uFF08\u6D88\u606F\uFF09"}function ve(e){return w(e.sender.name||e.sender.id||"\u5BF9\u65B9")}function E(e){const n=w(e.name||W.basename(e.localPath||"")||e.type||"\u9644\u4EF6"),t=e.localPath||e.url||"",a=e.availability&&e.availability!=="edge-local"?` (${e.availability})`:"";return t?`[${_e(n)}](${Re(t)})${a}`:`${n}${a}`}function Ce(e){const n=[e.file?{kind:"file",path:e.file}:null,e.image?{kind:"image",path:e.image}:null,e.video?{kind:"video",path:e.video}:null].filter(t=>!!t);if(n.length>1)throw new Error("Pass only one of --file, --image, or --video");if(n.length!==0)return V(n[0].path,n[0].kind)}function ke(e){const n=String(e||"markdown").trim().toLowerCase();if(n==="json")return"json";if(n==="markdown"||n==="md"||n==="text")return"markdown";throw new Error(`Unsupported --format: ${e}. Use markdown or json.`)}function Se(e){const n=String(e||"auto").trim().toLowerCase();if(n==="auto"||n==="never")return n;throw new Error(`Unsupported --download: ${e}. Use auto or never.`)}function We(e){return{kind:e.kind,name:e.name,mimeType:e.mimeType,size:e.size,localPath:e.localPath}}function T(e){return e.flatMap(n=>n.attachments??[])}function Re(e){const n=e.replace(/\\/g,"/");return/[\s()<>]/.test(n)?`<${n.replace(/[<>]/g,"")}>`:n}function _e(e){return w(e).replace(/([\\\]])/g,"\\$1")}function w(e){return String(e||"").replace(/\s+/g," ").trim()}function be(e){try{return process.kill(e,0),!0}catch{return!1}}function C(e,n){return`${e}:${j.createHash("sha256").update(n).digest("hex").slice(0,32)}`}function $e(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"conversation"}function m(e,n){const t=Number(e);return!Number.isFinite(t)||t<=0?n:Math.floor(t)}function xe(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.type==="external.message"&&typeof e.channelId=="string"&&typeof e.conversationId=="string"&&typeof e.messageId=="string"&&typeof e.text=="string"}function g(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function I(e){return typeof e=="string"&&e?e:void 0}export{we as buildWeChatReadMarkdown,He as registerWeChatCommand,oe as runWeChatDoctor,se as runWeChatReadLatest,ie as runWeChatSend};
7
+ `}function ue(e,t,n){const a=f(e.channel)?e.channel:{},o=(Array.isArray(a.wechatRpaPendingReplies)?a.wechatRpaPendingReplies:[]).filter(f).find(c=>h(c.idempotencyKey)===t),s=h(o?.status);if(s==="confirmed_echo"||s==="sent_unconfirmed"||s==="manual_review"||s==="queued")return s;const d=(Array.isArray(a.wechatRpaRecentTaskSummaries)?a.wechatRpaRecentTaskSummaries:[]).filter(f).map(c=>h(c.status)).find(Boolean);return d==="sent"?"sent":d==="confirmed_echo"?"confirmed_echo":d==="manual_review"?"manual_review":n?"pending":"ok"}function me(e){const t=e.attachments||[],n=I(e.text);return n&&t.length===0?n:n&&t.length>0?`${n} ${t.map(j).join("\u3001")}`:t.length>0?t.map(j).join("\u3001"):"\uFF08\u6D88\u606F\uFF09"}function he(e){return I(e.sender.name||e.sender.id||"\u5BF9\u65B9")}function j(e){const t=I(e.name||y.basename(e.localPath||"")||e.type||"\u9644\u4EF6"),n=e.localPath||e.url||"",a=e.availability&&e.availability!=="edge-local"?` (${e.availability})`:"";return n?`[${ve(t)}](${Ie(n)})${a}`:`${t}${a}`}function fe(e){const t=[e.file?{kind:"file",path:e.file}:null,e.image?{kind:"image",path:e.image}:null,e.video?{kind:"video",path:e.video}:null].filter(n=>!!n);if(t.length>1)throw new Error("Pass only one of --file, --image, or --video");if(t.length!==0)return K(t[0].path,t[0].kind)}function pe(e){const t=String(e||"markdown").trim().toLowerCase();if(t==="json")return"json";if(t==="markdown"||t==="md"||t==="text")return"markdown";throw new Error(`Unsupported --format: ${e}. Use markdown or json.`)}function ge(e){const t=String(e||"auto").trim().toLowerCase();if(t==="auto"||t==="never")return t;throw new Error(`Unsupported --download: ${e}. Use auto or never.`)}function A(e){const t=String(e||"auto").trim().toLowerCase();if(t==="auto"||t==="daemon"||t==="direct")return t;throw new Error(`Unsupported --transport: ${e}. Use auto, daemon, or direct.`)}function we(e){return{kind:e.kind,name:e.name,mimeType:e.mimeType,size:e.size,localPath:e.localPath}}function x(e){return e.flatMap(t=>t.attachments??[])}function Ie(e){const t=e.replace(/\\/g,"/");return/[\s()<>]/.test(t)?`<${t.replace(/[<>]/g,"")}>`:t}function ve(e){return I(e).replace(/([\\\]])/g,"\\$1")}function I(e){return String(e||"").replace(/\s+/g," ").trim()}function ye(e){try{return process.kill(e,0),!0}catch{return!1}}function ke(e){if(!e||typeof e!="object")return!1;const t=e,n=typeof t.name=="string"?t.name:"",a=typeof t.message=="string"?t.message:"";return n==="AbortError"||t.code==="ABORT_ERR"||/aborted|abort/i.test(a)}function O(e,t){return`${e}:${q.createHash("sha256").update(t).digest("hex").slice(0,32)}`}function L(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"conversation"}function v(e,t){const n=Number(e);return!Number.isFinite(n)||n<=0?t:Math.floor(n)}function U(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&e.type==="external.message"&&typeof e.channelId=="string"&&typeof e.conversationId=="string"&&typeof e.messageId=="string"&&typeof e.text=="string"}function f(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function h(e){return typeof e=="string"&&e?e:void 0}export{le as buildWeChatReadMarkdown,de as buildWeChatToolErrorResult,X as readDirectWeChatLatestOnce,We as registerWeChatCommand,H as runWeChatDoctor,Z as runWeChatReadLatest,V as runWeChatSend,G as sendDirectWeChatMessageOnce};
@@ -19,6 +19,7 @@ export type WeChatChannelActionSmokeOptions = {
19
19
  videoPath?: string;
20
20
  downloadAnchorText?: string;
21
21
  allowEmptyMedia?: boolean;
22
+ skipRuntimeUpsert?: boolean;
22
23
  requireServer: boolean;
23
24
  };
24
25
  export type WeChatChannelActionSmokeResult = {
@@ -1,6 +1,6 @@
1
1
  import D from"node:crypto";import{spawnSync as ne}from"node:child_process";import w from"node:fs";import i from"node:path";import{fileURLToPath as oe}from"node:url";import{buildBottomPageReport as M,buildDownloadVisibleMediaReport as q}from"./wechat-channel-download-report.js";import{buildWeChatMessagesMarkdown as y}from"./wechat-channel-markdown-report.js";import{loadConfig as re}from"../config/index.js";import{createWeChatChannelApiClient as se}from"../channels/wechat-channel/client.js";import{resolveWeChatChannelHelperAsset as ae,WECHAT_CHANNEL_HELPER_VERSION as ie}from"../channels/wechat-channel/helper-assets.js";import{WeChatChannelHelperClient as de}from"../channels/wechat-channel/helper-client.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as j}from"../channels/wechat-channel/helper-protocol.js";import{classifyWeChatOutboundEchoes as ce,enqueueWeChatOutboundReply as K}from"../channels/wechat-channel/outbound-ledger.js";import{loadWeChatChannelLedger as le,saveWeChatChannelLedger as ue,updateWeChatChannelBindingLedger as me}from"../channels/wechat-channel/ledger.js";import{WeChatChannelOutboundSender as U,sendQueuedWeChatOutboundRecords as S}from"../channels/wechat-channel/outbound-sender.js";import{captureWeChatWindow as W,ensureWeChatWindowReady as C,fallbackWeChatMessageInputPointForWindow as he,focusKnownWeChatWindow as k,observeWeChatChannelBindingViaHelper as fe,openConversationBySearch as I,recognizeWeChatScreenshot as E}from"../channels/wechat-channel/observer.js";import{createWeChatChannelRuntime as ge}from"../channels/wechat-channel/runtime.js";function pe(e){const t=!e.sessionId&&e.observePipeline==="edge-structure";if(!e.sessionId&&!t)throw new Error("session_id_required: pass --session-id <existing Shennian session id> for server observe steps");return t?"direct-edge-structure":"session-bound"}const we="ABC",be="wechat-channel-action-smoke";function ve(e){const t=e.filter(l=>l!=="--"),n=st(t),o=it(t,"--step").map(at).filter(l=>l!=null),r=re(),s=g(t,"--trace-id")||`wechat-action-smoke-${Date.now().toString(36)}`,a=i.resolve(g(t,"--out")||g(t,"--output")||i.join(process.cwd(),".dev-runtime","wechat-channel","action-smoke",s)),d=o.length?dt(o):ye(n);return{conversation:g(t,"--conversation")||g(t,"--group")||we,mode:o.length?"custom":n,steps:d,outDir:a,workDir:i.resolve(g(t,"--work-dir")||process.cwd()),traceId:s,runtimeId:g(t,"--runtime-id")||be,machineId:g(t,"--machine-id")||process.env.SHENNIAN_MACHINE_ID||r.machineId||"local",sessionId:g(t,"--session-id")||process.env.SHENNIAN_EXTERNAL_SESSION_ID||process.env.SHENNIAN_MANAGER_SESSION_ID,serverUrl:g(t,"--server-url")||r.serverUrl,platform:nt(g(t,"--platform")),text:g(t,"--text"),filePath:F(g(t,"--file")),imagePath:F(g(t,"--image")),videoPath:F(g(t,"--video")),downloadAnchorText:g(t,"--download-anchor-text")||g(t,"--media-anchor-text"),allowEmptyMedia:t.includes("--allow-empty-media"),requireServer:t.includes("--require-server")}}function ye(e){return e==="send"?["open-read","send-text","send-file","send-image","send-video"]:e==="observe"?["structure-window"]:e==="all"?["open-read","send-text","send-file","send-image","send-video","structure-window"]:["open-read"]}async function Se(e){const t=Date.now(),n=new Date(t).toISOString();w.mkdirSync(e.outDir,{recursive:!0});const o=i.join(e.outDir,"helper-trace.jsonl");w.writeFileSync(o,"");const r=Qe(e),s=r.bindings[0],a=Ze(e,o);await a.start();const d={ok:!1,conversation:e.conversation,outDir:e.outDir,helperTracePath:o,traceId:e.traceId,runtimeId:e.runtimeId,machineId:e.machineId,startedAt:n,finishedAt:n,durationMs:0,steps:[]};try{for(const l of e.steps){if(Ce(l)&&d.steps.some(c=>c.step==="open-read"&&!c.ok&&!c.skipped)){d.steps.push({step:l,ok:!1,reasonCode:"open_read_required",errorSummary:"open-read failed; refusing to run send step against the current WeChat window"});continue}d.steps.push(await ke({step:l,options:e,runtime:r,binding:s,helper:a}))}}finally{await a.stop().catch(()=>{}),d.finishedAt=new Date().toISOString(),d.durationMs=Date.now()-t,d.ok=d.steps.every(l=>l.ok||l.skipped),f(i.join(e.outDir,"summary.json"),d)}return d}function Ce(e){return e==="send-text"||e==="send-file"||e==="send-image"||e==="send-video"||e==="send-and-confirm"}async function ke(e){try{return e.step==="open-read"?await Re(e):e.step==="structure-window"?await Le(e):e.step==="server-observe"?await Oe(e):e.step==="read-bottom-page"?await Ne(e):e.step==="download-visible-media"?await Fe(e):e.step==="send-and-confirm"?await Ee(e):e.step.startsWith("human-")?await Ae(e):await V(e)}catch(t){const n=ft(t),o=await Ie(e,n,t);return{step:e.step,ok:!1,reasonCode:n,errorSummary:t instanceof Error?t.message:String(t),userAction:gt(n),...o?{details:o}:{}}}}async function Ie(e,t,n){if(!xe(t))return;const o=i.join(e.options.outDir,`${e.step}-failure-diagnostics.json`),r={step:e.step,reasonCode:t,errorSummary:n instanceof Error?n.message:String(n),capturedAt:new Date().toISOString()};try{r.permissions=await e.helper.request("permissions.check",{},e.options.traceId)}catch(s){r.permissionsError=s instanceof Error?s.message:String(s)}try{r.windows=await e.helper.request("windows.list",{},e.options.traceId)}catch(s){r.windowsError=s instanceof Error?s.message:String(s)}return f(o,r),{failureDiagnosticsPath:o}}function xe(e){return e.startsWith("wechat_")||e.startsWith("permission_")||e.startsWith("user_active")}async function Ae(e){if(e.step==="human-observe-deferred")return await _e(e);const t=e.step,n=`human-${_(`${e.options.traceId}:${t}:${Date.now()}`)}`,o={version:1,runtimeId:e.runtime.runtimeId,records:[]},r=K({ledger:o,replyId:`human:${t}:${n}`,idempotencyKey:`human:${n}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:`${n} ${e.options.text||"Shennian WeChat human coordination smoke"}`}),s=G(e.helper,J(t)),a=s.actionLog,d=async H=>{a.push(`openConversation:${H}`);const ee=await C(s,e.options.traceId),te=await k(s,ee,e.options.traceId);return I({helper:s,window:te,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:H},traceId:e.options.traceId})},l=new U({helper:s,platform:e.runtime.policy.platform,openConversation:d,traceId:e.options.traceId,activityGatePolicy:e.step==="human-send-user-active-timeout"?{keyDownThresholdMs:3e4,mouseMovedThresholdMs:3e4,mouseClickThresholdMs:3e4,scrollWheelThresholdMs:3e4}:void 0});let h=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:l,now:new Date("2026-06-15T00:00:00.000Z"),maxUserActivityWaitMs:e.step==="human-send-user-active-timeout"?1e3:void 0});e.step==="human-send-user-active-timeout"&&(h=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:l,now:new Date("2026-06-15T00:00:02.000Z"),maxUserActivityWaitMs:1e3})),(e.step==="human-send-preflight-busy-then-idle"||e.step==="human-send-takeover-then-idle")&&(s.setScenario(Ue()),h=await S({ledger:o,bindingId:e.binding.bindingId,currentLastInboundRevision:0,sender:l,now:new Date("2026-06-15T00:00:06.000Z")}));const m=Ve(e.step,r)?await N({helper:s,binding:e.binding,marker:n,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:e.step}):0,p=m>0?ce({ledger:o,bindingId:e.binding.bindingId,messages:[{stableMessageKey:`human-echo:${n}`,senderRole:"self",kind:"text",anchorText:r.text,normalizedText:r.text,textExcerpt:r.text,observedAt:new Date().toISOString()}]}):{confirmedRecords:[],manualReviewRecords:[],remainingMessages:[]},u=o.records[0],b=Ge(u,h,p.confirmedRecords),v={case:e.step,marker:n,runStatus:b,reasonCode:u.deferReason||u.failureCode||null,outboundStatus:u.sendStatus,attemptCount:u.attemptCount??0,nextAttemptAt:u.nextAttemptAt??null,observedMarkerCount:m,actionLog:a,clipboardRestore:a.includes("clipboard.restore")?"attempted":"not_needed",commitStage:u.commitStage??null};return f(i.join(e.options.outDir,`${e.step}-summary.json`),v),{step:e.step,ok:Je(e.step,v),reasonCode:v.reasonCode||void 0,details:v}}async function _e(e){const t=G(e.helper,J("human-observe-deferred")),n=await t.request("activity.snapshot",{},e.options.traceId),o=!!(n.ok&&n.result&&typeof n.result=="object"&&Number(n.result.keyDownSecondsAgo)<5),r={case:e.step,marker:null,runStatus:o?"observe_deferred_user_active":"baseline_or_no_change",reasonCode:o?"recent_keyboard_activity":null,outboundStatus:null,attemptCount:0,nextAttemptAt:null,observedMarkerCount:0,actionLog:t.actionLog,clipboardRestore:"not_needed"};return f(i.join(e.options.outDir,`${e.step}-summary.json`),r),{step:e.step,ok:o&&!t.actionLog.some(s=>s.startsWith("windows.")||s.startsWith("wechat.")||s.startsWith("clipboard.")),reasonCode:r.reasonCode||void 0,details:r}}async function Re(e){const t=await C(e.helper,e.options.traceId),n=await k(e.helper,t,e.options.traceId),o=await I({helper:e.helper,window:n,binding:e.binding,traceId:e.options.traceId});if(!o.opened)throw await De({helper:e.helper,window:n,outDir:e.options.outDir,traceId:e.options.traceId,reason:o.reason||"conversation_not_opened"}),new Error(o.reason||"conversation_not_opened");const r=await W(e.helper,n.windowId,e.options.traceId),s=T(e.options.outDir,"open-read-full-window",r),a=await E(e.helper,r,e.options.traceId);return f(i.join(e.options.outDir,"open-read-ocr.json"),a),{step:"open-read",ok:!0,details:{openedReason:o.reason,windowId:n.windowId,screenshotPath:s,screenshot:{width:r.width,height:r.height,mimeType:r.mimeType},ocrBlockCount:a.blocks?.length??0,visibleConversationFingerprintCount:a.visibleConversationFingerprints?.length??0}}}async function De(e){try{const t=await W(e.helper,e.window.windowId,e.traceId,e.window.bounds),n=T(e.outDir,"open-read-failure-window",t),o=await E(e.helper,t,e.traceId);f(i.join(e.outDir,"open-read-failure-ocr.json"),o),f(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,windowId:e.window.windowId,screenshotPath:n,screenshot:{width:t.width,height:t.height,mimeType:t.mimeType},ocrBlockCount:o.blocks?.length??0,visibleConversationFingerprintCount:o.visibleConversationFingerprints?.length??0,topTexts:(o.blocks??[]).slice(0,30).map(r=>({text:r.text,bbox:r.bbox}))})}catch(t){f(i.join(e.outDir,"open-read-failure-summary.json"),{reason:e.reason,captureError:t instanceof Error?t.message:String(t)})}}async function V(e){return await Me(e,ot(e.step,e.options))}async function Me(e,t){if(t.skipped)return{step:e.step,ok:!0,skipped:!0,reasonCode:t.reasonCode};const n={version:1,runtimeId:e.runtime.runtimeId,records:[]},o=`${e.options.traceId}:${e.step}:${t.text}:${t.attachmentPath||""}`,r=t.text?await N({helper:e.helper,binding:e.binding,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-before-send`,settleToBottom:!1}).catch(()=>null):null;K({ledger:n,replyId:`action-smoke:${e.step}:${_(o)}`,idempotencyKey:`action-smoke:${_(o)}`,bindingId:e.binding.bindingId,runtimeId:e.runtime.runtimeId,sessionId:e.binding.sessionId,conversationName:e.binding.conversationDisplayName,replyBaseRevision:0,text:t.text,attachmentLocalRefs:t.attachmentPath?[t.attachmentPath]:[]});const s=new U({helper:e.helper,platform:e.runtime.policy.platform,traceId:e.options.traceId,openConversation:async p=>{const u=await C(e.helper,e.options.traceId),b=await k(e.helper,u,e.options.traceId);return{...await I({helper:e.helper,window:b,settleToBottom:!1,binding:{...e.binding,conversationDisplayName:p},traceId:e.options.traceId}),inputPoint:he(b)}}}),a=await Te({ledger:n,bindingId:e.binding.bindingId,sender:s});await R(900);const d=n.records[0],l=a.failedRecords[0]?.failureCode||a.manualReviewRecords[0]?.failureCode||a.waitingRecords[0]?.deferReason||a.staleRecords[0]?.failureCode,c=a.sentRecords.length===1&&a.failedRecords.length===0&&a.waitingRecords.length===0&&a.manualReviewRecords.length===0&&a.staleRecords.length===0,h=c&&t.text?await ze({helper:e.helper,binding:e.binding,marker:t.text,traceId:e.options.traceId,outDir:e.options.outDir,filePrefix:`${e.step}-after-send`,settleToBottom:!1,attempts:3,targetGreaterThan:r}):null,m=Pe({sendAccepted:c,text:t.text,beforeTextCount:r,afterTextCount:h});return{step:e.step,ok:m.ok,reasonCode:l||m.reasonCode,errorSummary:a.failedRecords[0]?.lastErrorSummary||a.manualReviewRecords[0]?.lastErrorSummary,details:{text:t.text,attachmentPath:t.attachmentPath??null,helperTracePath:i.join(e.options.outDir,"helper-trace.jsonl"),confirmationRequired:m.confirmationRequired,sendAccepted:m.sendAccepted,beforeTextCount:r,afterTextCount:h,sentRecords:a.sentRecords.length,failedRecords:a.failedRecords.length,waitingRecords:a.waitingRecords.length,manualReviewRecords:a.manualReviewRecords.length,staleRecords:a.staleRecords.length,sendStatus:d?.sendStatus,failureCode:d?.failureCode??null,lastErrorSummary:d?.lastErrorSummary??null,deferReason:d?.deferReason,commitStage:d?.commitStage??null,attemptCount:d?.attemptCount??0,nextAttemptAt:d?.nextAttemptAt??null}}}function Pe(e){const t=!!(e.text&&e.text.trim());if(!e.sendAccepted)return{ok:!1,reasonCode:void 0,sendAccepted:!1,confirmationRequired:t};if(!t)return{ok:!0,sendAccepted:!0,confirmationRequired:t};const n=typeof e.beforeTextCount=="number"&&Number.isFinite(e.beforeTextCount)?e.beforeTextCount:null,o=typeof e.afterTextCount=="number"&&Number.isFinite(e.afterTextCount)?e.afterTextCount:0,r=n==null?o>0:o>n;return{ok:r,reasonCode:r?void 0:"sent_text_not_observed",sendAccepted:!0,confirmationRequired:t}}async function Te(e){const t=e.maxAttempts??24,n=e.maxWaitMs??9e4,o=Date.now();let r=await S({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n});for(let s=2;r.waitingRecords.length>0&&s<=t&&!(Date.now()-o>=n);s+=1){const a=je(r.waitingRecords[0]?.nextAttemptAt,o,n);await R(a),r=await S({ledger:e.ledger,bindingId:e.bindingId,currentLastInboundRevision:0,sender:e.sender,maxUserActivityWaitMs:n})}return r}function je(e,t,n){const o=Math.max(0,n-(Date.now()-t));if(o<=0)return 0;const r=e?new Date(e).getTime():Number.NaN,s=Number.isFinite(r)?r-Date.now():1e3;return Math.max(500,Math.min(Math.max(500,s),Math.min(5e3,o)))}function We(e){const t=e.sendResults.filter(u=>!z(u)),n=e.sendResults.filter(u=>!u.skipped).map(u=>u.details?.text&&typeof u.details.text=="string"?u.details.text:"").filter(Boolean),o=e.observedMessages.map(u=>[u.normalizedText||"",u.anchorText||"",u.textExcerpt||""].join(`
2
2
  `)).join(`
3
- `),r=n.filter(u=>o.includes(u)),s=e.sendResults.map(u=>typeof u.details?.sendStatus=="string"?u.details.sendStatus:"").filter(Boolean),a=e.sendResults.filter(z).length,d=$(t,"waitingRecords"),l=$(t,"failedRecords"),c=$(t,"manualReviewRecords"),h=t.find(u=>!u.ok||u.skipped),m=s.length===n.length&&s.every(u=>u==="sent_unconfirmed"||u==="confirmed_echo"),p=!h&&n.length>0&&r.length>0&&m&&d===0&&l===0&&c===0;return{ok:p,reasonCode:p?void 0:h?.reasonCode||(d>0?"outbound_send_waiting":void 0)||(l>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(m?void 0:"outbound_status_not_accepted")||(r.length?"partial_sent_messages_observed":"sent_messages_not_observed"),sentTexts:n,confirmedTexts:r,outboundStatuses:s,skippedFixtureCount:a,pendingOutboundCount:d,failedOutboundCount:l,manualReviewCount:c}}function z(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function $(e,t){return e.reduce((n,o)=>{const r=o.details?.[t];return n+(typeof r=="number"&&Number.isFinite(r)?r:0)},0)}async function Ee(e){const t=["send-text","send-file","send-image","send-video"],n=[];for(const c of t)n.push(await V({...e,step:c}));await R(1200);const o=await $e(e,3),r=M(o.messages),s=i.join(e.options.outDir,"bottom-page.md"),a=y(o.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(o.attachmentsDir)});f(i.join(e.options.outDir,"bottom-page-summary.json"),r),f(i.join(e.options.outDir,"server-observe-messages.json"),o.messages),A(s,a);const d=We({sendResults:n,observedMessages:o.messages}),l=d.ok&&o.messages.length>0;return{step:"send-and-confirm",ok:l,reasonCode:l?void 0:d.reasonCode,errorSummary:n.find(c=>!c.ok||c.skipped)?.errorSummary,details:{sent:n.map(c=>({step:c.step,ok:c.ok,skipped:c.skipped,reasonCode:c.reasonCode,errorSummary:c.errorSummary,text:c.details?.text,attachmentPath:c.details?.attachmentPath,sendStatus:c.details?.sendStatus,deferReason:c.details?.deferReason,failureCode:c.details?.failureCode,commitStage:c.details?.commitStage,attemptCount:c.details?.attemptCount,nextAttemptAt:c.details?.nextAttemptAt,waitingRecords:c.details?.waitingRecords,failedRecords:c.details?.failedRecords,manualReviewRecords:c.details?.manualReviewRecords})),sentTexts:d.sentTexts,confirmedTexts:d.confirmedTexts,outboundStatuses:d.outboundStatuses,skippedFixtureCount:d.skippedFixtureCount,pendingOutboundCount:d.pendingOutboundCount,failedOutboundCount:d.failedOutboundCount,manualReviewCount:d.manualReviewCount,observedCount:o.messages.length,byKind:r.byKind,attachmentSummary:r.attachmentSummary,attachmentsDir:o.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:s,markdown:a}}}async function $e(e,t){let n;for(let o=1;o<=t;o+=1)try{return await x(e)}catch(r){if(n=r,o>=t||!Be(r))break;try{const s=await C(e.helper,e.options.traceId),a=await k(e.helper,s,e.options.traceId);await I({helper:e.helper,window:a,binding:e.binding,traceId:e.options.traceId})}catch{}await R(1500*o)}throw n}function Be(e){const t=e instanceof Error?e.message:String(e||"");return/conversation_not_visible|wechat_window_unavailable|wechat_window_not_found|title_not_confirmed|server_observe_failed|timeout/i.test(t)}async function Ne(e){const t=await x(e),n=M(t.messages),o=i.join(e.options.outDir,"bottom-page.md"),r=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});return f(i.join(e.options.outDir,"bottom-page-summary.json"),n),f(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),A(o,r),{step:"read-bottom-page",ok:n.messageCount>0,reasonCode:n.messageCount>0?void 0:"no_observed_messages",details:{messageCount:n.messageCount,byKind:n.byKind,attachmentSummary:n.attachmentSummary,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:o,markdown:r}}}async function Fe(e){const t=await x(e,{observePipeline:"edge-structure",persistLocalLedger:!0});B(e.options.outDir,"download-visible",t.observationEvidence);const n=M(t.messages),o=i.join(e.options.outDir,"download-visible.md"),r=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)}),s=q(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});f(i.join(e.options.outDir,"bottom-page-summary.json"),n),f(i.join(e.options.outDir,"download-visible-summary.json"),s),f(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),A(o,r);const a=!!(e.options.allowEmptyMedia&&s.reasonCode==="no_visible_media_candidates"&&t.messages.length>0),d=s.ok||a;return{step:"download-visible-media",ok:d,reasonCode:d?void 0:s.reasonCode,details:{mediaCandidateCount:s.mediaCandidateCount,localAttachmentCount:s.localAttachmentCount,originalLocalAttachmentCount:s.originalLocalAttachmentCount,previewAttachmentCount:s.previewAttachmentCount,missingLocalPathCount:s.missingLocalPathCount,pendingAttachmentCount:s.pendingAttachmentCount,byKind:s.byKind,byAvailability:s.byAvailability,reasonCodes:s.reasonCodes,mediaReasonCode:s.reasonCode,allowEmptyMediaRead:a,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"download-visible-summary.json"),markdownPath:o,markdown:r,phases:s.phases,observePipeline:s.observePipeline,ledgerPath:s.ledgerPath,ledgerRevision:s.ledger?.revision,traceHashes:s.traceHashes,traceEvents:s.traceEvents}}}async function Oe(e){const t=await x(e,{observePipeline:"server-observe"});B(e.options.outDir,"server-observe",t.observationEvidence),f(i.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=i.join(e.options.outDir,"server-observe.md"),o=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,o);const r=Q(t.messages);return{step:"server-observe",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:O(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function Le(e){const t=await x(e,{observePipeline:"edge-structure",downloadMedia:!1});B(e.options.outDir,"structure-window",t.observationEvidence),f(i.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=i.join(e.options.outDir,"structure-window.md"),o=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,o);const r=Q(t.messages);return{step:"structure-window",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:O(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function x(e,t={}){const n=pe({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),o=se({serverUrl:e.options.serverUrl});n==="direct-edge-structure"?await o.upsertRuntime(e.runtime):await o.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1});const r=i.join(e.options.outDir,"inbound-attachments"),s=t.persistLocalLedger?ct(e.options):void 0,a=s?le(s,e.runtime.runtimeId):void 0;let d,l,c;const h=await fe({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:o,workDir:e.options.workDir,attachmentsDir:r,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,observePipeline:t.observePipeline,localLedgerTailAnchors:a?lt(a.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:u,ocr:b})=>{d=qe(u),l=Ke(b),c=He(u,b,{captureHash:d,ocrHash:l})}});let m,p;if(a&&s){const u=me({ledger:a,bindingId:e.binding.bindingId,observedMessages:h});m=u.binding,p=Y({bindingId:e.binding.bindingId,revision:m.revision,messages:u.newMessages}),ue(s,a)}return{messages:h,attachmentsDir:r,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...m?{ledgerBinding:m}:{},traceHashes:{...d?{captureHash:d}:{},...l?{ocrHash:l}:{},...p?{ingestPayloadHash:p}:{}},...c?{observationEvidence:c}:{}}}function He(e,t,n){return{capture:e,report:{screenshot:{width:e.width,height:e.height,mimeType:e.mimeType,...e.windowId?{windowId:e.windowId}:{}},hashes:n,ocrBlockCount:t.blocks?.length??0,visibleConversationFingerprintCount:t.visibleConversationFingerprints?.length??0,topTexts:(t.blocks??[]).slice(0,40).map(o=>({text:o.text,...o.bbox?{bbox:o.bbox}:{},...typeof o.confidence=="number"?{confidence:o.confidence}:{}}))}}}function B(e,t,n){if(!n)return;const o=n.capture.dataBase64?T(e,`${t}-observation-window`,n.capture):void 0;f(i.join(e,`${t}-observation-evidence.json`),{...n.report,...o?{screenshotPath:o}:{}})}function qe(e){if(e.dataBase64)return`sha256:${D.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function Ke(e){return Y({blocks:(e.blocks??[]).map(t=>({text:t.text??"",bbox:t.bbox??null,confidence:typeof t.confidence=="number"?Number(t.confidence.toFixed(4)):null})),visibleConversationFingerprints:e.visibleConversationFingerprints??[]})}function G(e,t){let n=t,o=0,r=0,s="";const a=[];return{actionLog:a,setScenario(l){n=l,o=0,r=0},async request(l,c,h){if(a.push(l),l==="activity.snapshot"){if(o+=1,o<=n.preflightBusySnapshots)return{id:`human-${o}`,ok:!0,result:{keyDownSecondsAgo:.2,mouseMovedSecondsAgo:.2,scrollWheelSecondsAgo:.2,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:h};if(n.forceIdleAfterBusy)return{id:`human-${o}`,ok:!0,result:{keyDownSecondsAgo:60,mouseMovedSecondsAgo:60,leftMouseDownSecondsAgo:60,rightMouseDownSecondsAgo:60,scrollWheelSecondsAgo:60,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:h}}if(l==="automation.lease.acquire"){const m=await e.request(l,c,h),p=m.result&&typeof m.result=="object"?m.result:{};return s=typeof p.leaseId=="string"?p.leaseId:"",m}return l==="automation.lease.status"?(r+=1,n.simulateInterruptionAtLeaseStatus===r?(a.push("automation.lease.simulateInterruption"),{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!0,interruptReason:n.interruptionReason||"recent_mouse_activity"},latencyMs:0,traceId:h}):{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:h}):e.request(l,c,h)}}}function J(e){return e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-observe-deferred"?{preflightBusySnapshots:100}:e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"?{preflightBusySnapshots:0,forceIdleAfterBusy:!0,simulateInterruptionAtLeaseStatus:2,interruptionReason:"recent_mouse_activity"}:{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Ue(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Ve(e,t){return t.sendStatus!=="sent_unconfirmed"?!1:e==="human-send-normal"||e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"}async function N(e){const t=await C(e.helper,e.traceId),n=await k(e.helper,t,e.traceId);if(!(await I({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId,settleToBottom:e.settleToBottom})).opened)return 0;const r=await W(e.helper,n.windowId,e.traceId),s=T(e.outDir,`${e.filePrefix}-observe-marker`,r),a=await E(e.helper,r,e.traceId);return f(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:a}),(a.blocks||[]).map(l=>l.text||"").join(`
3
+ `),r=n.filter(u=>o.includes(u)),s=e.sendResults.map(u=>typeof u.details?.sendStatus=="string"?u.details.sendStatus:"").filter(Boolean),a=e.sendResults.filter(z).length,d=$(t,"waitingRecords"),l=$(t,"failedRecords"),c=$(t,"manualReviewRecords"),h=t.find(u=>!u.ok||u.skipped),m=s.length===n.length&&s.every(u=>u==="sent_unconfirmed"||u==="confirmed_echo"),p=!h&&n.length>0&&r.length>0&&m&&d===0&&l===0&&c===0;return{ok:p,reasonCode:p?void 0:h?.reasonCode||(d>0?"outbound_send_waiting":void 0)||(l>0?"outbound_send_failed":void 0)||(c>0?"outbound_manual_review":void 0)||(m?void 0:"outbound_status_not_accepted")||(r.length?"partial_sent_messages_observed":"sent_messages_not_observed"),sentTexts:n,confirmedTexts:r,outboundStatuses:s,skippedFixtureCount:a,pendingOutboundCount:d,failedOutboundCount:l,manualReviewCount:c}}function z(e){return e.skipped===!0&&e.reasonCode==="ffmpeg_unavailable_for_video_fixture"}function $(e,t){return e.reduce((n,o)=>{const r=o.details?.[t];return n+(typeof r=="number"&&Number.isFinite(r)?r:0)},0)}async function Ee(e){const t=["send-text","send-file","send-image","send-video"],n=[];for(const c of t)n.push(await V({...e,step:c}));await R(1200);const o=await $e(e,3),r=M(o.messages),s=i.join(e.options.outDir,"bottom-page.md"),a=y(o.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(o.attachmentsDir)});f(i.join(e.options.outDir,"bottom-page-summary.json"),r),f(i.join(e.options.outDir,"server-observe-messages.json"),o.messages),A(s,a);const d=We({sendResults:n,observedMessages:o.messages}),l=d.ok&&o.messages.length>0;return{step:"send-and-confirm",ok:l,reasonCode:l?void 0:d.reasonCode,errorSummary:n.find(c=>!c.ok||c.skipped)?.errorSummary,details:{sent:n.map(c=>({step:c.step,ok:c.ok,skipped:c.skipped,reasonCode:c.reasonCode,errorSummary:c.errorSummary,text:c.details?.text,attachmentPath:c.details?.attachmentPath,sendStatus:c.details?.sendStatus,deferReason:c.details?.deferReason,failureCode:c.details?.failureCode,commitStage:c.details?.commitStage,attemptCount:c.details?.attemptCount,nextAttemptAt:c.details?.nextAttemptAt,waitingRecords:c.details?.waitingRecords,failedRecords:c.details?.failedRecords,manualReviewRecords:c.details?.manualReviewRecords})),sentTexts:d.sentTexts,confirmedTexts:d.confirmedTexts,outboundStatuses:d.outboundStatuses,skippedFixtureCount:d.skippedFixtureCount,pendingOutboundCount:d.pendingOutboundCount,failedOutboundCount:d.failedOutboundCount,manualReviewCount:d.manualReviewCount,observedCount:o.messages.length,byKind:r.byKind,attachmentSummary:r.attachmentSummary,attachmentsDir:o.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:s,markdown:a}}}async function $e(e,t){let n;for(let o=1;o<=t;o+=1)try{return await x(e)}catch(r){if(n=r,o>=t||!Be(r))break;try{const s=await C(e.helper,e.options.traceId),a=await k(e.helper,s,e.options.traceId);await I({helper:e.helper,window:a,binding:e.binding,traceId:e.options.traceId})}catch{}await R(1500*o)}throw n}function Be(e){const t=e instanceof Error?e.message:String(e||"");return/conversation_not_visible|wechat_window_unavailable|wechat_window_not_found|title_not_confirmed|server_observe_failed|timeout/i.test(t)}async function Ne(e){const t=await x(e),n=M(t.messages),o=i.join(e.options.outDir,"bottom-page.md"),r=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});return f(i.join(e.options.outDir,"bottom-page-summary.json"),n),f(i.join(e.options.outDir,"server-observe-messages.json"),t.messages),A(o,r),{step:"read-bottom-page",ok:n.messageCount>0,reasonCode:n.messageCount>0?void 0:"no_observed_messages",details:{messageCount:n.messageCount,byKind:n.byKind,attachmentSummary:n.attachmentSummary,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"bottom-page-summary.json"),markdownPath:o,markdown:r}}}async function Fe(e){const t=await x(e,{observePipeline:"edge-structure",persistLocalLedger:!0});B(e.options.outDir,"download-visible",t.observationEvidence);const n=M(t.messages),o=i.join(e.options.outDir,"download-visible.md"),r=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)}),s=q(t.messages,t.attachmentsDir,{observePipeline:t.observePipeline,downloadAnchorText:e.options.downloadAnchorText,ledgerPath:t.ledgerPath,ledgerBinding:t.ledgerBinding,traceHashes:t.traceHashes});f(i.join(e.options.outDir,"bottom-page-summary.json"),n),f(i.join(e.options.outDir,"download-visible-summary.json"),s),f(i.join(e.options.outDir,"download-visible-messages.json"),t.messages),A(o,r);const a=!!(e.options.allowEmptyMedia&&s.reasonCode==="no_visible_media_candidates"&&t.messages.length>0),d=s.ok||a;return{step:"download-visible-media",ok:d,reasonCode:d?void 0:s.reasonCode,details:{mediaCandidateCount:s.mediaCandidateCount,localAttachmentCount:s.localAttachmentCount,originalLocalAttachmentCount:s.originalLocalAttachmentCount,previewAttachmentCount:s.previewAttachmentCount,missingLocalPathCount:s.missingLocalPathCount,pendingAttachmentCount:s.pendingAttachmentCount,byKind:s.byKind,byAvailability:s.byAvailability,reasonCodes:s.reasonCodes,mediaReasonCode:s.reasonCode,allowEmptyMediaRead:a,attachmentsDir:t.attachmentsDir,reportPath:i.join(e.options.outDir,"download-visible-summary.json"),markdownPath:o,markdown:r,phases:s.phases,observePipeline:s.observePipeline,ledgerPath:s.ledgerPath,ledgerRevision:s.ledger?.revision,traceHashes:s.traceHashes,traceEvents:s.traceEvents}}}async function Oe(e){const t=await x(e,{observePipeline:"server-observe"});B(e.options.outDir,"server-observe",t.observationEvidence),f(i.join(e.options.outDir,"server-observe-messages.json"),t.messages);const n=i.join(e.options.outDir,"server-observe.md"),o=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,o);const r=Q(t.messages);return{step:"server-observe",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:O(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function Le(e){const t=await x(e,{observePipeline:"edge-structure",downloadMedia:!1});B(e.options.outDir,"structure-window",t.observationEvidence),f(i.join(e.options.outDir,"structure-window-messages.json"),t.messages);const n=i.join(e.options.outDir,"structure-window.md"),o=y(t.messages,{conversation:e.options.conversation,attachmentsDirName:i.basename(t.attachmentsDir)});A(n,o);const r=Q(t.messages);return{step:"structure-window",ok:t.messages.length>0,reasonCode:t.messages.length>0?void 0:"no_observed_messages",details:{observedCount:t.messages.length,byKind:O(t.messages.map(s=>s.kind||"unknown")),attachmentSummary:r,attachmentsDir:t.attachmentsDir,markdownPath:n,markdown:o}}}async function x(e,t={}){const n=pe({sessionId:e.options.sessionId,observePipeline:t.observePipeline}),o=se({serverUrl:e.options.serverUrl});e.options.skipRuntimeUpsert||(n==="direct-edge-structure"?await o.upsertRuntime(e.runtime):await o.upsertRuntime(e.runtime,{...e.binding,enabled:!1,allowReply:!1}));const r=i.join(e.options.outDir,"inbound-attachments"),s=t.persistLocalLedger?ct(e.options):void 0,a=s?le(s,e.runtime.runtimeId):void 0;let d,l,c;const h=await fe({runtime:e.runtime,binding:{...e.binding,downloadMedia:t.downloadMedia??e.binding.downloadMedia},helper:e.helper,api:o,workDir:e.options.workDir,attachmentsDir:r,traceId:e.options.traceId,mediaAnchorText:e.options.downloadAnchorText,observePipeline:t.observePipeline,localLedgerTailAnchors:a?lt(a.bindings[e.binding.bindingId]):void 0,onObservationEvidence:({capture:u,ocr:b})=>{d=qe(u),l=Ke(b),c=He(u,b,{captureHash:d,ocrHash:l})}});let m,p;if(a&&s){const u=me({ledger:a,bindingId:e.binding.bindingId,observedMessages:h});m=u.binding,p=Y({bindingId:e.binding.bindingId,revision:m.revision,messages:u.newMessages}),ue(s,a)}return{messages:h,attachmentsDir:r,observePipeline:t.observePipeline,...s?{ledgerPath:s}:{},...m?{ledgerBinding:m}:{},traceHashes:{...d?{captureHash:d}:{},...l?{ocrHash:l}:{},...p?{ingestPayloadHash:p}:{}},...c?{observationEvidence:c}:{}}}function He(e,t,n){return{capture:e,report:{screenshot:{width:e.width,height:e.height,mimeType:e.mimeType,...e.windowId?{windowId:e.windowId}:{}},hashes:n,ocrBlockCount:t.blocks?.length??0,visibleConversationFingerprintCount:t.visibleConversationFingerprints?.length??0,topTexts:(t.blocks??[]).slice(0,40).map(o=>({text:o.text,...o.bbox?{bbox:o.bbox}:{},...typeof o.confidence=="number"?{confidence:o.confidence}:{}}))}}}function B(e,t,n){if(!n)return;const o=n.capture.dataBase64?T(e,`${t}-observation-window`,n.capture):void 0;f(i.join(e,`${t}-observation-evidence.json`),{...n.report,...o?{screenshotPath:o}:{}})}function qe(e){if(e.dataBase64)return`sha256:${D.createHash("sha256").update(Buffer.from(e.dataBase64,"base64")).digest("hex")}`}function Ke(e){return Y({blocks:(e.blocks??[]).map(t=>({text:t.text??"",bbox:t.bbox??null,confidence:typeof t.confidence=="number"?Number(t.confidence.toFixed(4)):null})),visibleConversationFingerprints:e.visibleConversationFingerprints??[]})}function G(e,t){let n=t,o=0,r=0,s="";const a=[];return{actionLog:a,setScenario(l){n=l,o=0,r=0},async request(l,c,h){if(a.push(l),l==="activity.snapshot"){if(o+=1,o<=n.preflightBusySnapshots)return{id:`human-${o}`,ok:!0,result:{keyDownSecondsAgo:.2,mouseMovedSecondsAgo:.2,scrollWheelSecondsAgo:.2,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:h};if(n.forceIdleAfterBusy)return{id:`human-${o}`,ok:!0,result:{keyDownSecondsAgo:60,mouseMovedSecondsAgo:60,leftMouseDownSecondsAgo:60,rightMouseDownSecondsAgo:60,scrollWheelSecondsAgo:60,privacy:{capturesKeyContent:!1,capturesMousePath:!1}},latencyMs:0,traceId:h}}if(l==="automation.lease.acquire"){const m=await e.request(l,c,h),p=m.result&&typeof m.result=="object"?m.result:{};return s=typeof p.leaseId=="string"?p.leaseId:"",m}return l==="automation.lease.status"?(r+=1,n.simulateInterruptionAtLeaseStatus===r?(a.push("automation.lease.simulateInterruption"),{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!0,interruptReason:n.interruptionReason||"recent_mouse_activity"},latencyMs:0,traceId:h}):{id:`human-lease-${r}`,ok:!0,result:{active:!0,leaseId:s,interrupted:!1},latencyMs:0,traceId:h}):e.request(l,c,h)}}}function J(e){return e==="human-send-preflight-busy"||e==="human-send-preflight-busy-then-idle"||e==="human-send-user-active-timeout"||e==="human-observe-deferred"?{preflightBusySnapshots:100}:e==="human-send-takeover-during-run"||e==="human-send-takeover-then-idle"?{preflightBusySnapshots:0,forceIdleAfterBusy:!0,simulateInterruptionAtLeaseStatus:2,interruptionReason:"recent_mouse_activity"}:{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Ue(){return{preflightBusySnapshots:0,forceIdleAfterBusy:!0}}function Ve(e,t){return t.sendStatus!=="sent_unconfirmed"?!1:e==="human-send-normal"||e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"}async function N(e){const t=await C(e.helper,e.traceId),n=await k(e.helper,t,e.traceId);if(!(await I({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId,settleToBottom:e.settleToBottom})).opened)return 0;const r=await W(e.helper,n.windowId,e.traceId),s=T(e.outDir,`${e.filePrefix}-observe-marker`,r),a=await E(e.helper,r,e.traceId);return f(i.join(e.outDir,`${e.filePrefix}-observe-marker-ocr.json`),{screenshotPath:s,marker:e.marker,ocr:a}),(a.blocks||[]).map(l=>l.text||"").join(`
4
4
  `).split(e.marker).length-1}async function ze(e){const t=Math.max(1,e.attempts??3),n=typeof e.targetGreaterThan=="number"&&Number.isFinite(e.targetGreaterThan)?e.targetGreaterThan:null;let o=0;for(let r=0;r<t;r+=1){if(o=await N({helper:e.helper,binding:e.binding,marker:e.marker,traceId:e.traceId,outDir:e.outDir,filePrefix:`${e.filePrefix}-${r+1}`,settleToBottom:e.settleToBottom}),n==null?o>0:o>n)return o;r<t-1&&await R(800)}return o}function Ge(e,t,n){return n.length>0||e.sendStatus==="confirmed_echo"?"confirmed_echo":t.waitingRecords.length>0?"send_waiting_user_idle":t.failedRecords.length>0?e.failureCode==="user_active_timeout"?"failed:user_active_timeout":"outbound_send_failed":t.manualReviewRecords.length>0||e.sendStatus==="manual_review"?"manual_review":e.sendStatus==="sent_unconfirmed"?"sent_unconfirmed":e.sendStatus}function Je(e,t){return e==="human-send-preflight-busy"?t.outboundStatus==="queued"&&t.observedMarkerCount===0&&!t.actionLog.includes("clipboard.setText")&&!t.actionLog.includes("keyboard.shortcut"):e==="human-send-user-active-timeout"?t.outboundStatus==="failed"&&t.runStatus==="failed:user_active_timeout"&&t.observedMarkerCount===0&&!t.actionLog.includes("clipboard.setText")&&!t.actionLog.includes("keyboard.shortcut"):e==="human-send-takeover-during-run"?(t.outboundStatus==="queued"||t.outboundStatus==="manual_review")&&t.observedMarkerCount===0:e==="human-send-preflight-busy-then-idle"||e==="human-send-takeover-then-idle"||e==="human-send-normal"?t.outboundStatus==="confirmed_echo"||t.outboundStatus==="sent_unconfirmed"&&t.observedMarkerCount===1:t.runStatus==="observe_deferred_user_active"}function Qe(e){return ge({runtimeId:e.runtimeId,machineId:e.machineId,pollIntervalMs:6e4,platform:e.platform,foregroundPolicy:"work",bindings:[{bindingId:`action-smoke:${_(e.conversation)}`,sessionId:e.sessionId||`action-smoke:${_(e.runtimeId)}`,conversationDisplayName:e.conversation,enabled:!0,allowReply:!0,downloadMedia:!0}]})}function Ze(e,t){const n=ae({platform:e.platform});if(!n.ok)throw new Error(`${n.reasonCode}: ${n.message}`);return new de({helperPath:n.helperPath,expectedHelperVersion:n.version||ie,requiredCapabilities:tt(e),guardUnsafeWindowsCommands:(e.platform??process.platform)==="win32",cleanupWindowsOverlays:(e.platform??process.platform)==="win32",requestLogger:Xe(t)})}function Xe(e){return t=>{w.appendFileSync(e,`${JSON.stringify(Ye(t))}
5
5
  `)}}function Ye(e){const t={phase:e.phase,at:e.at,id:e.id,command:e.command};return e.traceId&&(t.traceId=e.traceId),e.timeoutMs!=null&&(t.timeoutMs=e.timeoutMs),e.durationMs!=null&&(t.durationMs=e.durationMs),e.params!==void 0&&(t.params=P(e.params)),e.ok!==void 0&&(t.ok=e.ok),e.errorCode&&(t.errorCode=e.errorCode),e.errorSummary&&(t.errorSummary=e.errorSummary),e.latencyMs!=null&&(t.latencyMs=e.latencyMs),e.result!==void 0&&(t.result=P(e.result)),t}function P(e,t="",n=0){if(e==null||typeof e=="number"||typeof e=="boolean")return e;if(typeof e=="string")return et(t,e)?{type:"string",length:e.length,sha256:D.createHash("sha256").update(e).digest("hex").slice(0,16),preview:e.slice(0,120)}:e;if(Array.isArray(e)){const s=e.slice(0,10).map(a=>P(a,t,n+1));return e.length>s.length?{type:"array",length:e.length,items:s}:s}if(typeof e!="object")return String(e);if(n>=5)return{type:"object",truncated:!0};const o=e,r={};for(const[s,a]of Object.entries(o))r[s]=P(a,s,n+1);return r}function et(e,t){return t.length>240?!0:/(base64|bytes|data|image|screenshot|png|jpeg|jpg|buffer)/i.test(e)&&t.length>48}function tt(e){if((e.platform??process.platform)==="win32")return e.steps.some(t=>t.startsWith("send")||t.startsWith("human-send"))?j("send"):e.steps.some(t=>t==="download-visible-media")?j("download"):j("observe")}function nt(e){const t=String(e||"").trim().toLowerCase();if(t){if(t==="windows"||t==="win32")return"win32";if(t==="macos"||t==="darwin")return"darwin";throw new Error(`unsupported_wechat_smoke_platform:${e}`)}}function ot(e,t){const n=i.join(t.outDir,"fixtures");w.mkdirSync(n,{recursive:!0});const o=new Date().toISOString().replace(/[-:.TZ]/g,"").slice(0,14);if(e==="send-text")return{text:t.text||`codex-product-action text ${o}`};if(e==="send-file"){const r=t.filePath||i.join(n,`wechat-action-smoke-${o}.txt`);return t.filePath||w.writeFileSync(r,`Shennian WeChat product action smoke
6
6
  ${o}
@@ -1,24 +1,24 @@
1
- import F from"node:http";import{randomBytes as q,randomUUID as g}from"node:crypto";import k from"node:fs";import T from"node:os";import f from"node:path";import{AVAILABLE_BUILTIN_AGENT_TYPES as U,extractPayloadText as L,formatExternalConversationText as O,formatExternalMessageLine as K,formatExternalAttachmentReference as H,isAgentHiddenPayload as j,isToolPayload as G}from"@shennian/wire";import{ManagerRegistry as z}from"./registry.js";import{readMessages as J}from"../session/store.js";import{ChannelRuntime as Y}from"../channels/runtime.js";import{splitExternalReplyText as V}from"../channels/reply-split.js";import{resolveShennianPath as Q}from"../config/index.js";import{buildExternalChannelInstructions as X}from"../agents/external-channel-instructions.js";const A=Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES||2*1024*1024);let x=null;function Te(r){x=r}function xe(){return x}function S(r){return f.resolve(r||T.homedir())}function u(r,e,a){r.writeHead(e,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify(a))}function Z(r){return/^agent-(.+)-\d+$/.exec(r)?.[1]??null}function ee(r){return r==="manager"?!1:r.startsWith("custom:")?!0:U.includes(r)}function te(r){const e=/^agent-.+-(\d+)$/.exec(r);if(!e)return null;const a=Number(e[1]);return Number.isInteger(a)&&a>=0?a:null}function N(r){return r.replace(/\r\n/g,`
2
- `).trim()}function ne(r){try{const e=JSON.parse(r),a=e.type==="tool_result"||e.result?"tool_result":"tool_call",t=e.name||"tool",n=typeof e.result=="string"?e.result.replace(/\s+/g," ").trim():"",s=n.length>220?`${n.slice(0,220)}...`:n;return s?`[${a}] ${t}: ${s}`:`[${a}] ${t}`}catch{return"[tool]"}}function re(r){if(!r||typeof r!="object")return;const e=r,a=String(e.kind||""),t=String(e.name||""),n=String(e.mimeType||""),s=String(e.dataBase64||""),o=String(e.localPath||""),i=String(e.url||""),l=Number(e.size||0);if(s)throw new Error("Manager IPC external attachments must use localPath or url; dataBase64 is not accepted");if(!(a!=="image"&&a!=="video"&&a!=="file")&&!(!t||!n||!Number.isFinite(l)||l<0)&&!(!o&&!i))return{kind:a,name:t,mimeType:n,size:l,...o?{localPath:o}:{},...i?{url:i}:{}}}function ae(r,e){const a=[...r].sort((c,d)=>c.ts-d.ts),t=[];let n=null,s=null,o=null,i="";const l=()=>{if(!n)return;const c=i.trim();c&&t.push({...n,id:`${n.id}-compact`,payload:c}),n=null,s=null,o=null,i=""};for(const c of a){if(j(c.payload)){l();continue}if(c.role==="user"){l(),t.push(c);continue}if(G(c.payload)){l(),t.push({...c,payload:ne(c.payload)});continue}const d=L(c.payload);if(!d.trim())continue;const h=Z(c.id),p=te(c.id);n&&n.role===c.role&&s===h&&h&&p!==null&&o!==null&&p===o+1?(i+=d,n.ts=c.ts,o=p):(l(),n=c,s=h,o=p,i=d)}return l(),t.slice(-e).sort((c,d)=>d.ts-c.ts)}async function se(r){const e=[];let a=0;for await(const n of r){const s=Buffer.from(n);if(a+=s.byteLength,Number.isFinite(A)&&A>0&&a>A)throw new Error(`Manager IPC request body is too large. Max: ${A} bytes.`);e.push(s)}const t=Buffer.concat(e).toString("utf-8");return t?JSON.parse(t):{}}function y(r,e,a,t){r.client.sendRes({type:"res",id:e,ok:a,...a?{payload:t}:{error:String(t.error||"unknown error")}})}function D(r){return/binding not found|unknown method|not supported|relay is not connected|no external channel/i.test(r)}function P(){return ie()?f.join(T.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):Q("runtime","manager-ipc.json")}function ie(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class Ne{opts;registry=new z;channelRuntime=new Y((e,a)=>{this.handleExternalMessage(e,a)},e=>this.registry.createReplyTarget(e).replyTarget);server=null;ipcUrl=null;ipcToken=q(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;constructor(e){this.opts=e}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=F.createServer((a,t)=>{this.handleIpc(a,t)}),await new Promise((a,t)=>{this.server.once("error",t),this.server.listen(0,"127.0.0.1",()=>a())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.broadcastConfiguredChannelStatuses(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=P();k.mkdirSync(f.dirname(e),{recursive:!0}),k.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),k.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=P(),a=JSON.parse(k.readFileSync(e,"utf-8"));(a.url===this.ipcUrl||a.token===this.ipcToken)&&k.unlinkSync(e)}catch{}}getInjectedEnv(e,a,t,n){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:a??"",SHENNIAN_MANAGER_WORKDIR:S(t),SHENNIAN_MANAGER_MODEL:n,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:S(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null})}setManagerWorkerDefaults(e,a,t){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,defaultWorkerAgentType:a??null,defaultWorkerModelId:t??null})}getManagerWorkerDefaults(e){const a=this.registry.getManager(e);return{agentType:a?.defaultWorkerAgentType??null,modelId:a?.defaultWorkerModelId??null}}noteManagerAgentSession(e,a,t,n){this.registry.upsertManager({sessionId:e,agentSessionId:a,workDir:S(t),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:n})}noteAgentEvent(e,a){if(!this.findWorker(e))return;const n={lastActivityAt:new Date().toISOString(),runId:a.runId};a.agentSessionId&&(n.agentSessionId=a.agentSessionId);const s=`${e}:${a.runId}`;if(a.state==="delta"&&a.text&&!a.thinking){const i=(this.workerTextAcc.get(s)??"")+a.text;this.workerTextAcc.set(s,i);const l=N(i);l&&(n.summary=l.length>160?`${l.slice(0,160)}...`:l)}if(a.state==="final"||a.state==="error"||a.state==="aborted"){n.status=a.state;const i=N(this.workerTextAcc.get(s)??"");i&&(n.summary=i.length>240?`${i.slice(0,240)}...`:i),this.workerTextAcc.delete(s)}else a.state==="start"&&(n.status="running");const o=this.registry.updateWorker(e,n);o&&(a.state==="final"||a.state==="error"||a.state==="aborted")&&this.wakeManagerForWorker(o.managedBy,o,a.state,a.message)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){const a=this.opts.getRuntime(),t=e.params??{};try{const n=String(t.managerSessionId||t.sessionId||"");if(!n)throw new Error("sessionId is required");const s=this.registry.getManager(n),o=e.method==="session.wechat-rpa.channel.get"||e.method==="manager.wechat-rpa.channel.get",i=e.method==="session.wechat-rpa.channel.upsert"||e.method==="manager.wechat-rpa.channel.upsert",l=e.method==="session.wechat-rpa.channel.sync"||e.method==="manager.wechat-rpa.channel.sync",c=e.method==="session.wechat-rpa.outbound.cancel"||e.method==="manager.wechat-rpa.outbound.cancel";if(e.method==="manager.channel.get"){y(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(n,"websocket",{includeSecret:!0})});return}if(e.method==="manager.channel.upsert"){const d=await this.channelRuntime.upsertManagerChannel({id:String(t.id||`websocket:${n}`),managerSessionId:n,sessionId:n,workDir:String(t.workDir||s?.workDir||""),type:"websocket",name:typeof t.name=="string"?t.name:void 0,agentType:typeof t.agentType=="string"?t.agentType:void 0,agentSessionId:typeof t.agentSessionId=="string"?t.agentSessionId:null,modelId:typeof t.modelId=="string"?t.modelId:null,enabled:!!t.enabled,wsUrl:typeof t.wsUrl=="string"?t.wsUrl:void 0,token:typeof t.token=="string"?t.token:void 0,canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0});this.broadcastManagerChannelStatus(n),y(a,e.id,!0,{channel:d});return}if(o){y(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(n,"wechat-rpa",{includeSecret:!0})});return}if(i){const d=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(t.id||`wechat-rpa:${n}`),managerSessionId:n,sessionId:n,workDir:S(String(t.workDir||s?.workDir||"")),name:typeof t.name=="string"?t.name:void 0,agentType:typeof t.agentType=="string"?t.agentType:void 0,agentSessionId:typeof t.agentSessionId=="string"?t.agentSessionId:null,modelId:typeof t.modelId=="string"?t.modelId:null,enabled:!!t.enabled,groups:W(t.groups),canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0,source:$(t.source),pollIntervalMs:I(t.pollIntervalMs),recentLimit:I(t.recentLimit),idleSeconds:I(t.idleSeconds),forceForeground:t.forceForeground===void 0?void 0:!!t.forceForeground,noRestore:t.noRestore===void 0?void 0:!!t.noRestore,downloadAttachments:t.downloadAttachments===void 0?void 0:!!t.downloadAttachments,downloadAttachmentsDir:typeof t.downloadAttachmentsDir=="string"?t.downloadAttachmentsDir:void 0,selfNickname:typeof t.selfNickname=="string"?t.selfNickname:void 0,privacyConsentAccepted:t.privacyConsentAccepted===void 0?void 0:!!t.privacyConsentAccepted,flowScriptPath:typeof t.flowScriptPath=="string"?t.flowScriptPath:void 0});this.broadcastManagerChannelStatus(n),y(a,e.id,!0,{channel:d});return}if(l){const d=await this.channelRuntime.syncManagerWeChatRpaChannel(n);this.broadcastManagerChannelStatus(n),y(a,e.id,!0,d);return}if(c){const d=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:n,idempotencyKey:typeof t.idempotencyKey=="string"?t.idempotencyKey:null,replyId:typeof t.replyId=="string"?t.replyId:null,reason:typeof t.reason=="string"?t.reason:"user_cancelled"});this.broadcastManagerChannelStatus(n),y(a,e.id,!0,d);return}throw new Error(`Unsupported manager app method: ${e.method}`)}catch(n){y(a,e.id,!1,{error:n instanceof Error?n.message:String(n)})}}broadcastConfiguredChannelStatuses(){for(const e of this.channelRuntime.listManagerChannelStatuses())this.broadcastManagerChannelStatus(e.managerSessionId)}broadcastManagerChannelStatus(e){const a=this.opts.getRuntime();if(!a.client?.sendEvent)return;const t=this.registry.getManager(e),n=this.channelRuntime.getManagerChannelStatus(e),s=this.channelRuntime.getManagerChannel(e,"wechat-rpa")??this.channelRuntime.getManagerChannel(e,"websocket");a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:t?"manager":s?.agentType,agentSessionId:t?.agentSessionId??s?.agentSessionId??null,modelId:t?.modelId??s?.modelId??null,workDir:t?.workDir??s?.workDir,externalChannel:n}}})}async handleIpc(e,a){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){u(a,401,{ok:!1,error:"Unauthorized"});return}try{const t=new URL(e.url??"/","http://127.0.0.1"),n=await se(e),s=String(n.managerSessionId||e.headers["x-shennian-manager-session-id"]||"");if(!s)throw new Error("managerSessionId is required");const o=this.registry.getManager(s);if(t.pathname==="/sessions/list"){if(!o)throw new Error("Manager runtime is not registered");const i=new Set(this.opts.getRuntime().sessions.keys());u(a,200,{ok:!0,sessions:this.registry.listWorkers(s,{runningSessionIds:i})});return}if(t.pathname==="/sessions/start"){if(!o)throw new Error("Manager runtime is not registered");const i=String(n.agentType||n.agent||o.defaultWorkerAgentType||"codex");if(!ee(i))throw new Error(`Unsupported manager worker agent: ${i}`);const l=S(String(n.workDir||o.workDir));if(l!==o.workDir)throw new Error("Manager can only start workers in the same workDir");const c=String(n.message||"");if(!c)throw new Error("message is required");const d=this.registry.addWorker({managerSessionId:s,agentType:i,workDir:l,summary:c.slice(0,120)}),h=String(n.modelId||(i===o.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));await this.dispatchChatSend(d.sessionId,i,l,c,null,h),u(a,200,{ok:!0,session:d});return}if(t.pathname==="/sessions/send"){const i=String(n.sessionId||""),l=String(n.message||""),c=n.enqueue===void 0?!0:!!n.enqueue,d=this.registry.getWorkerForManager(s,i);if(!d)throw new Error("Worker not found in this manager scope");const h=String(n.modelId||(d.agentType===o?.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));c?await this.dispatchChatEnqueue(d.sessionId,d.agentType,d.workDir,l,d.agentSessionId??null,h):await this.dispatchChatSend(d.sessionId,d.agentType,d.workDir,l,d.agentSessionId??null,h),u(a,200,{ok:!0});return}if(t.pathname==="/sessions/queue"){const i=String(n.sessionId||"");if(!this.registry.getWorkerForManager(s,i))throw new Error("Worker not found in this manager scope");const c=this.opts.getRuntime().chatQueue?.getSnapshot(i);u(a,200,{ok:!0,queue:c});return}if(t.pathname==="/sessions/queue/edit"){const i=String(n.sessionId||"");if(!this.registry.getWorkerForManager(s,i))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-edit-${g()}`,method:"chat.queue.edit",params:{sessionId:i,queueMessageId:String(n.queueMessageId||n.messageId||""),text:String(n.message||n.text||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(i)});return}if(t.pathname==="/sessions/queue/delete"){const i=String(n.sessionId||"");if(!this.registry.getWorkerForManager(s,i))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-delete-${g()}`,method:"chat.queue.delete",params:{sessionId:i,queueMessageId:String(n.queueMessageId||n.messageId||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(i)});return}if(t.pathname==="/sessions/stop"||t.pathname==="/sessions/terminate"){const i=String(n.sessionId||"");if(!this.registry.getWorkerForManager(s,i))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-abort-${g()}`,method:"chat.abort",params:{sessionId:i}}),this.registry.updateWorker(i,{status:"aborted"}),u(a,200,{ok:!0});return}if(t.pathname==="/sessions/read"){const i=String(n.sessionId||""),l=Number(n.limit||200);if(!this.registry.getWorkerForManager(s,i))throw new Error("Worker not found in this manager scope");const d=J(i,{limit:Math.max(l*20,l)});u(a,200,{ok:!0,messages:ae(d,l),rawMessageCount:d.length});return}if(t.pathname==="/memory/path"){if(!o)throw new Error("Manager runtime is not registered");u(a,200,{ok:!0,path:f.join(o.workDir,".shennian")});return}if(t.pathname==="/external/reply"){const i=typeof n.replyTarget=="string"?this.registry.getReplyTarget(n.replyTarget):this.registry.getLatestReplyTargetForManager(s),l=String(n.text||""),c=re(n.attachment),d=String(n.idempotencyKey||g()),h=String(n.channelId||""),p=String(n.conversationId||""),R=!i&&(!h||!p)?await this.channelRuntime.getDefaultReplyTarget(s).catch(()=>null):null,M=i?.channelId||h||R?.channelId||"",C=i?.conversationId||p||R?.conversationId||"";if(M&&this.channelRuntime.getChannelById(M)){if(!C)throw new Error("No external channel target is available for this Manager");const m=await this.channelRuntime.reply({managerSessionId:s,channelId:M,conversationId:C,messageId:i?.messageId??void 0,text:l,attachment:c,idempotencyKey:d});u(a,m.ok?200:400,m);return}let w;try{w=await this.sendManagedWeComReply({managerSessionId:s,text:l,attachment:c,idempotencyKey:d})}catch(m){const E=m instanceof Error?m.message:String(m);if(!D(E))throw m;w={ok:!1,error:E}}if(w.ok){u(a,200,{ok:!0,payload:w.payload});return}if(!D(w.error||"")||!M||!C){u(a,400,{ok:!1,error:w.error||"External send failed"});return}u(a,400,{ok:!1,error:`No local external channel is configured for ${M}`});return}if(t.pathname==="/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(s,"websocket")});return}if(t.pathname==="/channel/upsert"){if(!o)throw new Error("Manager runtime is not registered");const i=await this.channelRuntime.upsertManagerChannel({id:String(n.id||`websocket:${s}`),managerSessionId:s,workDir:o.workDir,type:"websocket",name:typeof n.name=="string"?n.name:void 0,enabled:!!n.enabled,wsUrl:typeof n.wsUrl=="string"?n.wsUrl:void 0,token:typeof n.token=="string"?n.token:void 0,canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0});this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(s),u(a,200,{ok:!0,channel:i});return}if(t.pathname==="/wechat-rpa/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(s,"wechat-rpa",{includeSecret:!0})});return}if(t.pathname==="/wechat-rpa/channel/upsert"){const i=S(String(n.workDir||o?.workDir||""));if(!i)throw new Error("workDir is required");const l=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(n.id||`wechat-rpa:${s}`),managerSessionId:s,sessionId:s,workDir:i,name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,groups:W(n.groups),canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0,source:$(n.source),pollIntervalMs:I(n.pollIntervalMs),recentLimit:I(n.recentLimit),idleSeconds:I(n.idleSeconds),forceForeground:n.forceForeground===void 0?void 0:!!n.forceForeground,noRestore:n.noRestore===void 0?void 0:!!n.noRestore,downloadAttachments:n.downloadAttachments===void 0?void 0:!!n.downloadAttachments,downloadAttachmentsDir:typeof n.downloadAttachmentsDir=="string"?n.downloadAttachmentsDir:void 0,selfNickname:typeof n.selfNickname=="string"?n.selfNickname:void 0,privacyConsentAccepted:n.privacyConsentAccepted===void 0?void 0:!!n.privacyConsentAccepted,flowScriptPath:typeof n.flowScriptPath=="string"?n.flowScriptPath:void 0});o&&this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(s),u(a,200,{ok:!0,channel:l});return}if(t.pathname==="/wechat-rpa/channel/sync"){const{channel:i,messages:l}=await this.channelRuntime.syncManagerWeChatRpaChannel(s);this.broadcastManagerChannelStatus(s),u(a,200,{ok:!0,channel:i,messages:l});return}if(t.pathname==="/wechat-rpa/outbound/cancel"){const i=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:s,idempotencyKey:typeof n.idempotencyKey=="string"?n.idempotencyKey:null,replyId:typeof n.replyId=="string"?n.replyId:null,reason:typeof n.reason=="string"?n.reason:"user_cancelled"});this.broadcastManagerChannelStatus(s),u(a,200,{ok:!0,...i});return}u(a,404,{ok:!1,error:`Unknown manager IPC path: ${t.pathname}`})}catch(t){u(a,400,{ok:!1,error:t instanceof Error?t.message:String(t)})}}async dispatchChatSend(e,a,t,n,s,o){await this.opts.dispatchReq({type:"req",id:`manager-send-${g()}`,method:"chat.send",params:{sessionId:e,text:n,agentType:a,workDir:t,agentSessionId:s,modelId:o}})}async dispatchChatEnqueue(e,a,t,n,s,o){await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${g()}`,method:"chat.enqueue",params:{sessionId:e,text:n,agentType:a,workDir:t,agentSessionId:s,modelId:o}})}async sendManagedWeComReply(e){const a=V(e.text);if(!a.length&&!e.attachment)return{ok:!1,error:"text or attachment is required"};const t=this.opts.getRuntime().client;if(!t||typeof t.sendReq!="function")return{ok:!1,error:"Relay is not connected"};const n=[];for(const[s,o]of a.entries()){const i=await t.sendReq({type:"req",id:`external-send-${g()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,text:o,idempotencyKey:a.length>1?`${e.idempotencyKey}:${s+1}`:e.idempotencyKey}});if(!i.ok)return{ok:!1,error:i.error||"External send failed"};n.push(i.payload)}if(e.attachment){const s=await t.sendReq({type:"req",id:`external-send-${g()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,attachment:e.attachment,idempotencyKey:a.length?`${e.idempotencyKey}:attachment`:e.idempotencyKey}});if(!s.ok)return{ok:!1,error:s.error||"External send failed"};n.push(s.payload)}return{ok:!0,payload:n.length===1?n[0]:n}}wakeManagerForWorker(e,a,t,n){const s=this.registry.getManager(e);if(!s)return;const o=`\u4F60\u7BA1\u7406\u7684 worker \u5DF2\u7ED3\u675F\u3002
1
+ import L from"node:http";import{randomBytes as O,randomUUID as g}from"node:crypto";import k from"node:fs";import T from"node:os";import y from"node:path";import{AVAILABLE_BUILTIN_AGENT_TYPES as U,extractPayloadText as K,formatExternalConversationText as H,formatExternalMessageLine as j,formatExternalAttachmentReference as G,isAgentHiddenPayload as z,isToolPayload as J}from"@shennian/wire";import{ManagerRegistry as Y}from"./registry.js";import{readMessages as V}from"../session/store.js";import{ChannelRuntime as Q}from"../channels/runtime.js";import{splitExternalReplyText as X}from"../channels/reply-split.js";import{resolveShennianPath as Z}from"../config/index.js";import{buildExternalChannelInstructions as ee}from"../agents/external-channel-instructions.js";import{readDirectWeChatLatestOnce as te,sendDirectWeChatMessageOnce as ne}from"../commands/wechat.js";const A=Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES||2*1024*1024);let x=null;function We(r){x=r}function Pe(){return x}function S(r){return y.resolve(r||T.homedir())}function u(r,e,a){r.writeHead(e,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify(a))}function re(r){return/^agent-(.+)-\d+$/.exec(r)?.[1]??null}function ae(r){return r==="manager"?!1:r.startsWith("custom:")?!0:U.includes(r)}function se(r){const e=/^agent-.+-(\d+)$/.exec(r);if(!e)return null;const a=Number(e[1]);return Number.isInteger(a)&&a>=0?a:null}function N(r){return r.replace(/\r\n/g,`
2
+ `).trim()}function ie(r){try{const e=JSON.parse(r),a=e.type==="tool_result"||e.result?"tool_result":"tool_call",n=e.name||"tool",t=typeof e.result=="string"?e.result.replace(/\s+/g," ").trim():"",i=t.length>220?`${t.slice(0,220)}...`:t;return i?`[${a}] ${n}: ${i}`:`[${a}] ${n}`}catch{return"[tool]"}}function D(r){if(!r||typeof r!="object")return;const e=r,a=String(e.kind||""),n=String(e.name||""),t=String(e.mimeType||""),i=String(e.dataBase64||""),o=String(e.localPath||""),s=String(e.url||""),l=Number(e.size||0);if(i)throw new Error("Manager IPC external attachments must use localPath or url; dataBase64 is not accepted");if(!(a!=="image"&&a!=="video"&&a!=="file")&&!(!n||!t||!Number.isFinite(l)||l<0)&&!(!o&&!s))return{kind:a,name:n,mimeType:t,size:l,...o?{localPath:o}:{},...s?{url:s}:{}}}function W(r){const e=r.binding&&typeof r.binding=="object"&&!Array.isArray(r.binding)?r.binding:{},a=String(e.sessionId||r.managerSessionId||"").trim(),n=String(e.channelId||"").trim(),t=String(e.conversationId||"").trim(),i=String(e.conversationName||r.conversation||"").trim(),o=String(e.workDir||r.workDir||"").trim();if(!a)throw new Error("WeChat tool sessionId is required");if(!n)throw new Error("WeChat tool channelId is required");if(!t)throw new Error("WeChat tool conversationId is required");if(!i)throw new Error("WeChat tool conversationName is required");if(!o)throw new Error("WeChat tool workDir is required");return{sessionId:a,channelId:n,conversationId:t,conversationName:i,workDir:o}}function oe(r,e){const a=[...r].sort((c,d)=>c.ts-d.ts),n=[];let t=null,i=null,o=null,s="";const l=()=>{if(!t)return;const c=s.trim();c&&n.push({...t,id:`${t.id}-compact`,payload:c}),t=null,i=null,o=null,s=""};for(const c of a){if(z(c.payload)){l();continue}if(c.role==="user"){l(),n.push(c);continue}if(J(c.payload)){l(),n.push({...c,payload:ie(c.payload)});continue}const d=K(c.payload);if(!d.trim())continue;const h=re(c.id),p=se(c.id);t&&t.role===c.role&&i===h&&h&&p!==null&&o!==null&&p===o+1?(s+=d,t.ts=c.ts,o=p):(l(),t=c,i=h,o=p,s=d)}return l(),n.slice(-e).sort((c,d)=>d.ts-c.ts)}async function le(r){const e=[];let a=0;for await(const t of r){const i=Buffer.from(t);if(a+=i.byteLength,Number.isFinite(A)&&A>0&&a>A)throw new Error(`Manager IPC request body is too large. Max: ${A} bytes.`);e.push(i)}const n=Buffer.concat(e).toString("utf-8");return n?JSON.parse(n):{}}function w(r,e,a,n){r.client.sendRes({type:"res",id:e,ok:a,...a?{payload:n}:{error:String(n.error||"unknown error")}})}function P(r){return/binding not found|unknown method|not supported|relay is not connected|no external channel/i.test(r)}function v(){return ce()?y.join(T.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):Z("runtime","manager-ipc.json")}function ce(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class ve{opts;registry=new Y;channelRuntime=new Q((e,a)=>{this.handleExternalMessage(e,a)},e=>this.registry.createReplyTarget(e).replyTarget);server=null;ipcUrl=null;ipcToken=O(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;constructor(e){this.opts=e}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=L.createServer((a,n)=>{this.handleIpc(a,n)}),await new Promise((a,n)=>{this.server.once("error",n),this.server.listen(0,"127.0.0.1",()=>a())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.broadcastConfiguredChannelStatuses(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=v();k.mkdirSync(y.dirname(e),{recursive:!0}),k.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),k.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=v(),a=JSON.parse(k.readFileSync(e,"utf-8"));(a.url===this.ipcUrl||a.token===this.ipcToken)&&k.unlinkSync(e)}catch{}}getInjectedEnv(e,a,n,t){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:a??"",SHENNIAN_MANAGER_WORKDIR:S(n),SHENNIAN_MANAGER_MODEL:t,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:S(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null})}setManagerWorkerDefaults(e,a,n){const t=this.registry.getManager(e);t&&this.registry.upsertManager({...t,defaultWorkerAgentType:a??null,defaultWorkerModelId:n??null})}getManagerWorkerDefaults(e){const a=this.registry.getManager(e);return{agentType:a?.defaultWorkerAgentType??null,modelId:a?.defaultWorkerModelId??null}}noteManagerAgentSession(e,a,n,t){this.registry.upsertManager({sessionId:e,agentSessionId:a,workDir:S(n),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:t})}noteAgentEvent(e,a){if(!this.findWorker(e))return;const t={lastActivityAt:new Date().toISOString(),runId:a.runId};a.agentSessionId&&(t.agentSessionId=a.agentSessionId);const i=`${e}:${a.runId}`;if(a.state==="delta"&&a.text&&!a.thinking){const s=(this.workerTextAcc.get(i)??"")+a.text;this.workerTextAcc.set(i,s);const l=N(s);l&&(t.summary=l.length>160?`${l.slice(0,160)}...`:l)}if(a.state==="final"||a.state==="error"||a.state==="aborted"){t.status=a.state;const s=N(this.workerTextAcc.get(i)??"");s&&(t.summary=s.length>240?`${s.slice(0,240)}...`:s),this.workerTextAcc.delete(i)}else a.state==="start"&&(t.status="running");const o=this.registry.updateWorker(e,t);o&&(a.state==="final"||a.state==="error"||a.state==="aborted")&&this.wakeManagerForWorker(o.managedBy,o,a.state,a.message)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){const a=this.opts.getRuntime(),n=e.params??{};try{const t=String(n.managerSessionId||n.sessionId||"");if(!t)throw new Error("sessionId is required");const i=this.registry.getManager(t),o=e.method==="session.wechat-rpa.channel.get"||e.method==="manager.wechat-rpa.channel.get",s=e.method==="session.wechat-rpa.channel.upsert"||e.method==="manager.wechat-rpa.channel.upsert",l=e.method==="session.wechat-rpa.channel.sync"||e.method==="manager.wechat-rpa.channel.sync",c=e.method==="session.wechat-rpa.outbound.cancel"||e.method==="manager.wechat-rpa.outbound.cancel";if(e.method==="manager.channel.get"){w(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(t,"websocket",{includeSecret:!0})});return}if(e.method==="manager.channel.upsert"){const d=await this.channelRuntime.upsertManagerChannel({id:String(n.id||`websocket:${t}`),managerSessionId:t,sessionId:t,workDir:String(n.workDir||i?.workDir||""),type:"websocket",name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,wsUrl:typeof n.wsUrl=="string"?n.wsUrl:void 0,token:typeof n.token=="string"?n.token:void 0,canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,{channel:d});return}if(o){w(a,e.id,!0,{channel:this.channelRuntime.getManagerChannel(t,"wechat-rpa",{includeSecret:!0})});return}if(s){const d=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(n.id||`wechat-rpa:${t}`),managerSessionId:t,sessionId:t,workDir:S(String(n.workDir||i?.workDir||"")),name:typeof n.name=="string"?n.name:void 0,agentType:typeof n.agentType=="string"?n.agentType:void 0,agentSessionId:typeof n.agentSessionId=="string"?n.agentSessionId:null,modelId:typeof n.modelId=="string"?n.modelId:null,enabled:!!n.enabled,groups:$(n.groups),canReply:n.canReply===void 0?void 0:!!n.canReply,systemPrompt:typeof n.systemPrompt=="string"?n.systemPrompt:void 0,source:_(n.source),pollIntervalMs:m(n.pollIntervalMs),recentLimit:m(n.recentLimit),idleSeconds:m(n.idleSeconds),forceForeground:n.forceForeground===void 0?void 0:!!n.forceForeground,noRestore:n.noRestore===void 0?void 0:!!n.noRestore,downloadAttachments:n.downloadAttachments===void 0?void 0:!!n.downloadAttachments,downloadAttachmentsDir:typeof n.downloadAttachmentsDir=="string"?n.downloadAttachmentsDir:void 0,selfNickname:typeof n.selfNickname=="string"?n.selfNickname:void 0,privacyConsentAccepted:n.privacyConsentAccepted===void 0?void 0:!!n.privacyConsentAccepted,flowScriptPath:typeof n.flowScriptPath=="string"?n.flowScriptPath:void 0});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,{channel:d});return}if(l){const d=await this.channelRuntime.syncManagerWeChatRpaChannel(t);this.broadcastManagerChannelStatus(t),w(a,e.id,!0,d);return}if(c){const d=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:t,idempotencyKey:typeof n.idempotencyKey=="string"?n.idempotencyKey:null,replyId:typeof n.replyId=="string"?n.replyId:null,reason:typeof n.reason=="string"?n.reason:"user_cancelled"});this.broadcastManagerChannelStatus(t),w(a,e.id,!0,d);return}throw new Error(`Unsupported manager app method: ${e.method}`)}catch(t){w(a,e.id,!1,{error:t instanceof Error?t.message:String(t)})}}broadcastConfiguredChannelStatuses(){for(const e of this.channelRuntime.listManagerChannelStatuses())this.broadcastManagerChannelStatus(e.managerSessionId)}broadcastManagerChannelStatus(e){const a=this.opts.getRuntime();if(!a.client?.sendEvent)return;const n=this.registry.getManager(e),t=this.channelRuntime.getManagerChannelStatus(e),i=this.channelRuntime.getManagerChannel(e,"wechat-rpa")??this.channelRuntime.getManagerChannel(e,"websocket");a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:n?"manager":i?.agentType,agentSessionId:n?.agentSessionId??i?.agentSessionId??null,modelId:n?.modelId??i?.modelId??null,workDir:n?.workDir??i?.workDir,externalChannel:t}}})}async handleIpc(e,a){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){u(a,401,{ok:!1,error:"Unauthorized"});return}try{const n=new URL(e.url??"/","http://127.0.0.1"),t=await le(e),i=String(t.managerSessionId||e.headers["x-shennian-manager-session-id"]||"");if(!i)throw new Error("managerSessionId is required");const o=this.registry.getManager(i);if(n.pathname==="/sessions/list"){if(!o)throw new Error("Manager runtime is not registered");const s=new Set(this.opts.getRuntime().sessions.keys());u(a,200,{ok:!0,sessions:this.registry.listWorkers(i,{runningSessionIds:s})});return}if(n.pathname==="/sessions/start"){if(!o)throw new Error("Manager runtime is not registered");const s=String(t.agentType||t.agent||o.defaultWorkerAgentType||"codex");if(!ae(s))throw new Error(`Unsupported manager worker agent: ${s}`);const l=S(String(t.workDir||o.workDir));if(l!==o.workDir)throw new Error("Manager can only start workers in the same workDir");const c=String(t.message||"");if(!c)throw new Error("message is required");const d=this.registry.addWorker({managerSessionId:i,agentType:s,workDir:l,summary:c.slice(0,120)}),h=String(t.modelId||(s===o.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));await this.dispatchChatSend(d.sessionId,s,l,c,null,h),u(a,200,{ok:!0,session:d});return}if(n.pathname==="/sessions/send"){const s=String(t.sessionId||""),l=String(t.message||""),c=t.enqueue===void 0?!0:!!t.enqueue,d=this.registry.getWorkerForManager(i,s);if(!d)throw new Error("Worker not found in this manager scope");const h=String(t.modelId||(d.agentType===o?.defaultWorkerAgentType?o.defaultWorkerModelId??"":""));c?await this.dispatchChatEnqueue(d.sessionId,d.agentType,d.workDir,l,d.agentSessionId??null,h):await this.dispatchChatSend(d.sessionId,d.agentType,d.workDir,l,d.agentSessionId??null,h),u(a,200,{ok:!0});return}if(n.pathname==="/sessions/queue"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");const c=this.opts.getRuntime().chatQueue?.getSnapshot(s);u(a,200,{ok:!0,queue:c});return}if(n.pathname==="/sessions/queue/edit"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-edit-${g()}`,method:"chat.queue.edit",params:{sessionId:s,queueMessageId:String(t.queueMessageId||t.messageId||""),text:String(t.message||t.text||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(s)});return}if(n.pathname==="/sessions/queue/delete"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-queue-delete-${g()}`,method:"chat.queue.delete",params:{sessionId:s,queueMessageId:String(t.queueMessageId||t.messageId||"")}}),u(a,200,{ok:!0,queue:this.opts.getRuntime().chatQueue?.getSnapshot(s)});return}if(n.pathname==="/sessions/stop"||n.pathname==="/sessions/terminate"){const s=String(t.sessionId||"");if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");await this.opts.dispatchReq({type:"req",id:`manager-abort-${g()}`,method:"chat.abort",params:{sessionId:s}}),this.registry.updateWorker(s,{status:"aborted"}),u(a,200,{ok:!0});return}if(n.pathname==="/sessions/read"){const s=String(t.sessionId||""),l=Number(t.limit||200);if(!this.registry.getWorkerForManager(i,s))throw new Error("Worker not found in this manager scope");const d=V(s,{limit:Math.max(l*20,l)});u(a,200,{ok:!0,messages:oe(d,l),rawMessageCount:d.length});return}if(n.pathname==="/memory/path"){if(!o)throw new Error("Manager runtime is not registered");u(a,200,{ok:!0,path:y.join(o.workDir,".shennian")});return}if(n.pathname==="/external/reply"){const s=typeof t.replyTarget=="string"?this.registry.getReplyTarget(t.replyTarget):this.registry.getLatestReplyTargetForManager(i),l=String(t.text||""),c=D(t.attachment),d=String(t.idempotencyKey||g()),h=String(t.channelId||""),p=String(t.conversationId||""),R=!s&&(!h||!p)?await this.channelRuntime.getDefaultReplyTarget(i).catch(()=>null):null,M=s?.channelId||h||R?.channelId||"",C=s?.conversationId||p||R?.conversationId||"";if(M&&this.channelRuntime.getChannelById(M)){if(!C)throw new Error("No external channel target is available for this Manager");const f=await this.channelRuntime.reply({managerSessionId:i,channelId:M,conversationId:C,messageId:s?.messageId??void 0,text:l,attachment:c,idempotencyKey:d});u(a,f.ok?200:400,f);return}let I;try{I=await this.sendManagedWeComReply({managerSessionId:i,text:l,attachment:c,idempotencyKey:d})}catch(f){const E=f instanceof Error?f.message:String(f);if(!P(E))throw f;I={ok:!1,error:E}}if(I.ok){u(a,200,{ok:!0,payload:I.payload});return}if(!P(I.error||"")||!M||!C){u(a,400,{ok:!1,error:I.error||"External send failed"});return}u(a,400,{ok:!1,error:`No local external channel is configured for ${M}`});return}if(n.pathname==="/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(i,"websocket")});return}if(n.pathname==="/channel/upsert"){if(!o)throw new Error("Manager runtime is not registered");const s=await this.channelRuntime.upsertManagerChannel({id:String(t.id||`websocket:${i}`),managerSessionId:i,workDir:o.workDir,type:"websocket",name:typeof t.name=="string"?t.name:void 0,enabled:!!t.enabled,wsUrl:typeof t.wsUrl=="string"?t.wsUrl:void 0,token:typeof t.token=="string"?t.token:void 0,canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0});this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:s});return}if(n.pathname==="/wechat-rpa/tool/read"){const s=W(t),l=m(t.limit)??10,c=await te(s,{conversation:s.conversationName,workDir:s.workDir,sessionId:s.sessionId,limit:l,recentLimit:l,download:t.download==="never"?"never":"auto",traceId:typeof t.traceId=="string"?t.traceId:void 0,timeoutMs:m(t.timeoutMs)});u(a,200,{ok:!0,messages:c.messages,outDir:c.outDir,helperTracePath:c.helperTracePath});return}if(n.pathname==="/wechat-rpa/tool/send"){const s=W(t),l=String(t.text||""),c=D(t.attachment),d=await ne(s,{conversation:s.conversationName,workDir:s.workDir,sessionId:s.sessionId,text:l,attachment:c,traceId:typeof t.traceId=="string"?t.traceId:void 0,timeoutMs:m(t.timeoutMs)});u(a,200,{ok:!0,...d});return}if(n.pathname==="/wechat-rpa/channel/get"){u(a,200,{ok:!0,channel:this.channelRuntime.getManagerChannel(i,"wechat-rpa",{includeSecret:!0})});return}if(n.pathname==="/wechat-rpa/channel/upsert"){const s=S(String(t.workDir||o?.workDir||""));if(!s)throw new Error("workDir is required");const l=await this.channelRuntime.upsertManagerWeChatRpaChannel({id:String(t.id||`wechat-rpa:${i}`),managerSessionId:i,sessionId:i,workDir:s,name:typeof t.name=="string"?t.name:void 0,agentType:typeof t.agentType=="string"?t.agentType:void 0,agentSessionId:typeof t.agentSessionId=="string"?t.agentSessionId:null,modelId:typeof t.modelId=="string"?t.modelId:null,enabled:!!t.enabled,groups:$(t.groups),canReply:t.canReply===void 0?void 0:!!t.canReply,systemPrompt:typeof t.systemPrompt=="string"?t.systemPrompt:void 0,source:_(t.source),pollIntervalMs:m(t.pollIntervalMs),recentLimit:m(t.recentLimit),idleSeconds:m(t.idleSeconds),forceForeground:t.forceForeground===void 0?void 0:!!t.forceForeground,noRestore:t.noRestore===void 0?void 0:!!t.noRestore,downloadAttachments:t.downloadAttachments===void 0?void 0:!!t.downloadAttachments,downloadAttachmentsDir:typeof t.downloadAttachmentsDir=="string"?t.downloadAttachmentsDir:void 0,selfNickname:typeof t.selfNickname=="string"?t.selfNickname:void 0,privacyConsentAccepted:t.privacyConsentAccepted===void 0?void 0:!!t.privacyConsentAccepted,flowScriptPath:typeof t.flowScriptPath=="string"?t.flowScriptPath:void 0});o&&this.registry.upsertManager({...o,status:o.status}),this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:l});return}if(n.pathname==="/wechat-rpa/channel/sync"){const{channel:s,messages:l}=await this.channelRuntime.syncManagerWeChatRpaChannel(i);this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,channel:s,messages:l});return}if(n.pathname==="/wechat-rpa/outbound/cancel"){const s=await this.channelRuntime.cancelManagerWeChatRpaOutbound({managerSessionId:i,idempotencyKey:typeof t.idempotencyKey=="string"?t.idempotencyKey:null,replyId:typeof t.replyId=="string"?t.replyId:null,reason:typeof t.reason=="string"?t.reason:"user_cancelled"});this.broadcastManagerChannelStatus(i),u(a,200,{ok:!0,...s});return}u(a,404,{ok:!1,error:`Unknown manager IPC path: ${n.pathname}`})}catch(n){u(a,400,{ok:!1,error:n instanceof Error?n.message:String(n)})}}async dispatchChatSend(e,a,n,t,i,o){await this.opts.dispatchReq({type:"req",id:`manager-send-${g()}`,method:"chat.send",params:{sessionId:e,text:t,agentType:a,workDir:n,agentSessionId:i,modelId:o}})}async dispatchChatEnqueue(e,a,n,t,i,o){await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${g()}`,method:"chat.enqueue",params:{sessionId:e,text:t,agentType:a,workDir:n,agentSessionId:i,modelId:o}})}async sendManagedWeComReply(e){const a=X(e.text);if(!a.length&&!e.attachment)return{ok:!1,error:"text or attachment is required"};const n=this.opts.getRuntime().client;if(!n||typeof n.sendReq!="function")return{ok:!1,error:"Relay is not connected"};const t=[];for(const[i,o]of a.entries()){const s=await n.sendReq({type:"req",id:`external-send-${g()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,text:o,idempotencyKey:a.length>1?`${e.idempotencyKey}:${i+1}`:e.idempotencyKey}});if(!s.ok)return{ok:!1,error:s.error||"External send failed"};t.push(s.payload)}if(e.attachment){const i=await n.sendReq({type:"req",id:`external-send-${g()}`,method:"external.send",params:{managerSessionId:e.managerSessionId,attachment:e.attachment,idempotencyKey:a.length?`${e.idempotencyKey}:attachment`:e.idempotencyKey}});if(!i.ok)return{ok:!1,error:i.error||"External send failed"};t.push(i.payload)}return{ok:!0,payload:t.length===1?t[0]:t}}wakeManagerForWorker(e,a,n,t){const i=this.registry.getManager(e);if(!i)return;const o=`\u4F60\u7BA1\u7406\u7684 worker \u5DF2\u7ED3\u675F\u3002
3
3
 
4
4
  Worker: ${a.sessionId}
5
- \u72B6\u6001\uFF1A${t}
5
+ \u72B6\u6001\uFF1A${n}
6
6
  \u6700\u7EC8\u7ED3\u679C\uFF1A
7
- ${n||a.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}
7
+ ${t||a.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}
8
8
 
9
- \u8BF7\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF1A\u7EE7\u7EED\u7B49\u5F85\u3001\u521B\u5EFA/\u6307\u6D3E worker\u3001\u505C\u6B62 worker\u3001\u8BE2\u95EE\u7528\u6237\uFF0C\u6216\u5411\u7528\u6237\u6C47\u62A5\u3002`;this.interruptAndResumeManager(s,o,t==="final"?"worker.final":`worker.${t}`)}handleExternalMessage(e,a){const t=this.channelRuntime.getChannelById(a.channelId)??this.channelRuntime.getManagerChannel(e,a.channelType),n=this.channelRuntime.getChannelStatusById(a.channelId)??this.channelRuntime.getManagerChannelStatus(e),s=this.registry.getManager(e),o=t?.agentType||(s?"manager":"codex"),i=t?.workDir||s?.workDir||process.cwd(),l=t?.agentSessionId??s?.agentSessionId??null,c=t?.modelId||s?.modelId||"",d=oe(a.attachments,a.channelType),h=de(a);this.dispatchExternalMessage({sessionId:e,agentType:o,workDir:i,agentSessionId:l,modelId:c,text:h,attachments:d,externalChannel:he(n),replyTarget:a.replyTarget})}async dispatchExternalMessage(e){await this.opts.dispatchReq({type:"req",id:`external-enqueue-${g()}`,method:"chat.enqueue",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,origin:"external",attachments:e.attachments,externalChannel:e.externalChannel??null,replyTarget:e.replyTarget}})}scanWorkerHealth(){const e=Date.now(),a=this.registry.load();for(const t of Object.values(a.workers)){if(t.status!=="running")continue;const n=e-Date.parse(t.createdAt);if(n<10*6e4)continue;const s=t.healthNotifiedAt?Date.parse(t.healthNotifiedAt):0;if(s&&e-s<10*6e4)continue;const o=a.managers[t.managedBy];if(!o)continue;const i=Math.max(0,Math.floor((e-Date.parse(t.lastActivityAt))/6e4)),l=`Worker ${t.sessionId} \u5DF2\u8FD0\u884C ${Math.floor(n/6e4)} \u5206\u949F\uFF0C\u5C1A\u672A\u7ED3\u675F\u3002
9
+ \u8BF7\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF1A\u7EE7\u7EED\u7B49\u5F85\u3001\u521B\u5EFA/\u6307\u6D3E worker\u3001\u505C\u6B62 worker\u3001\u8BE2\u95EE\u7528\u6237\uFF0C\u6216\u5411\u7528\u6237\u6C47\u62A5\u3002`;this.interruptAndResumeManager(i,o,n==="final"?"worker.final":`worker.${n}`)}handleExternalMessage(e,a){const n=this.channelRuntime.getChannelById(a.channelId)??this.channelRuntime.getManagerChannel(e,a.channelType),t=this.channelRuntime.getChannelStatusById(a.channelId)??this.channelRuntime.getManagerChannelStatus(e),i=this.registry.getManager(e),o=n?.agentType||(i?"manager":"codex"),s=n?.workDir||i?.workDir||process.cwd(),l=n?.agentSessionId??i?.agentSessionId??null,c=n?.modelId||i?.modelId||"",d=de(a.attachments,a.channelType),h=he(a);this.dispatchExternalMessage({sessionId:e,agentType:o,workDir:s,agentSessionId:l,modelId:c,text:h,attachments:d,externalChannel:me(t),replyTarget:a.replyTarget})}async dispatchExternalMessage(e){await this.opts.dispatchReq({type:"req",id:`external-enqueue-${g()}`,method:"chat.enqueue",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,origin:"external",attachments:e.attachments,externalChannel:e.externalChannel??null,replyTarget:e.replyTarget}})}scanWorkerHealth(){const e=Date.now(),a=this.registry.load();for(const n of Object.values(a.workers)){if(n.status!=="running")continue;const t=e-Date.parse(n.createdAt);if(t<10*6e4)continue;const i=n.healthNotifiedAt?Date.parse(n.healthNotifiedAt):0;if(i&&e-i<10*6e4)continue;const o=a.managers[n.managedBy];if(!o)continue;const s=Math.max(0,Math.floor((e-Date.parse(n.lastActivityAt))/6e4)),l=`Worker ${n.sessionId} \u5DF2\u8FD0\u884C ${Math.floor(t/6e4)} \u5206\u949F\uFF0C\u5C1A\u672A\u7ED3\u675F\u3002
10
10
 
11
11
  \u5F53\u524D\u53EF\u89C1\u8FDB\u5C55\uFF1A
12
- - \u6700\u8FD1\u6587\u672C\u6458\u8981\uFF1A${t.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}
13
- - \u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4\uFF1A${t.lastActivityAt}
14
- - \u6700\u8FD1 ${i} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002
12
+ - \u6700\u8FD1\u6587\u672C\u6458\u8981\uFF1A${n.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}
13
+ - \u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4\uFF1A${n.lastActivityAt}
14
+ - \u6700\u8FD1 ${s} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002
15
15
 
16
- \u8BF7\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u3001\u8BE2\u95EE\u7528\u6237\u3001\u505C\u6B62 worker\u3001\u6216\u521B\u5EFA\u5176\u4ED6 worker \u534F\u52A9\u3002`;this.registry.updateWorker(t.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:l}),o.status==="idle"&&this.dispatchChatSend(o.sessionId,"manager",o.workDir,l,o.agentSessionId,o.modelId)}}async interruptAndResumeManager(e,a,t){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&(this.registry.upsertManager({...e,status:"interrupting"}),await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${g()}`,method:"chat.abort",params:{sessionId:e.sessionId}}));const o=t?`\u4E8B\u4EF6\u7C7B\u578B\uFF1A${t}
16
+ \u8BF7\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED\u7B49\u5F85\u3001\u8BE2\u95EE\u7528\u6237\u3001\u505C\u6B62 worker\u3001\u6216\u521B\u5EFA\u5176\u4ED6 worker \u534F\u52A9\u3002`;this.registry.updateWorker(n.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:l}),o.status==="idle"&&this.dispatchChatSend(o.sessionId,"manager",o.workDir,l,o.agentSessionId,o.modelId)}}async interruptAndResumeManager(e,a,n){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&(this.registry.upsertManager({...e,status:"interrupting"}),await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${g()}`,method:"chat.abort",params:{sessionId:e.sessionId}}));const o=n?`\u4E8B\u4EF6\u7C7B\u578B\uFF1A${n}
17
17
 
18
- ${a}`:a;await this.dispatchChatSend(e.sessionId,"manager",e.workDir,o,e.agentSessionId,e.modelId)}bindManagerAdapterEvents(e,a){a.on("agentEvent",t=>{if(t.state==="start"&&t.agentSessionId){const n=this.registry.getManager(e);n&&this.noteManagerAgentSession(e,t.agentSessionId,n.workDir,n.modelId)}t.state==="start"&&this.updateManagerStatus(e,"running"),(t.state==="final"||t.state==="error"||t.state==="aborted")&&this.updateManagerStatus(e,"idle")})}updateManagerStatus(e,a){const t=this.registry.getManager(e);t&&this.registry.upsertManager({...t,status:a})}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(a=>X(a,void 0,e,"manager")).join(`
18
+ ${a}`:a;await this.dispatchChatSend(e.sessionId,"manager",e.workDir,o,e.agentSessionId,e.modelId)}bindManagerAdapterEvents(e,a){a.on("agentEvent",n=>{if(n.state==="start"&&n.agentSessionId){const t=this.registry.getManager(e);t&&this.noteManagerAgentSession(e,n.agentSessionId,t.workDir,t.modelId)}n.state==="start"&&this.updateManagerStatus(e,"running"),(n.state==="final"||n.state==="error"||n.state==="aborted")&&this.updateManagerStatus(e,"idle")})}updateManagerStatus(e,a){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,status:a})}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(a=>ee(a,void 0,e,"manager")).join(`
19
19
 
20
- `).trim()}}function W(r){return Array.isArray(r)?r.map(e=>({name:String(e?.name||"").trim()})).filter(e=>e.name):[]}function $(r){return r==="wechat-channel"||r==="macos-flow"||r==="macos-probe"||r==="windows-visual-flow"||r==="wechat-rpa-lab"||r==="fixture-jsonl"?r:void 0}function oe(r,e){const a=r.map(t=>v(t,e)).filter(t=>t!=null);return a.length?a:void 0}function le(r,e,a,t){const n=e||"",s=new Set;return r.map((i,l)=>{const c=v(i,t),d=H({type:i.type,name:c?.name||i.name,path:c?.path,mimeType:c?.mimeType||i.mimeType,availability:i.availability,providerError:i.providerError||ue(i)},l),h=c?.path||"";if(h){const R=`${d}
21
- ${h}`;return s.has(R)||n.includes(h)?"":(s.add(R),`${a}: ${d}`)}const p=d;return s.has(p)?"":(s.add(p),`${a}: ${d}`)}).filter(i=>!n.includes(i)).join(`
22
- `)}function de(r){const a=(r.channelType==="wechat-rpa"?ce(r.sender.name):r.sender.name||r.sender.id)||(r.channelType==="wechat-rpa"?"\u5BF9\u65B9":r.sender.id)||"\u5BF9\u65B9",t=le(r.attachments,r.text,a,r.channelType),s=[r.text?K({senderName:a,senderId:r.sender.id,text:r.text}):t?"":`${a}:`,t].filter(Boolean).join(`
23
- `);return[O({conversationName:r.conversationName||r.conversationId,messages:[]}),s].filter(Boolean).join(`
24
- `)}function ce(r){const e=r?.trim()||"";return!e||/^(contact|self|system|unknown)$/i.test(e)||/^wechat-sender:/i.test(e)?"":e}function ue(r){return!r.localPath||r.availability&&r.availability!=="edge-local"||b(r.localPath)?"":"edge-local-unavailable"}function v(r,e){return r.localPath&&pe(r,e)&&b(r.localPath)?{path:r.localPath,name:r.name||f.basename(r.localPath)||"attachment",mimeType:r.mimeType||B(r)}:r.url&&ge(r)?{path:r.url,name:r.name||r.url.split("/").filter(Boolean).at(-1)||"attachment",mimeType:r.mimeType||B(r)}:r.thumbnailPath&&!_(r,e)&&b(r.thumbnailPath)?{path:r.thumbnailPath,name:r.name?`${r.name}-preview.png`:f.basename(r.thumbnailPath)||"preview.png",mimeType:"image/png"}:null}function he(r){return r?r.type!=="wechat-rpa"?r:{configured:r.configured,connected:r.connected,type:r.type,channelId:r.channelId,name:r.name,canReply:r.canReply,systemPrompt:r.systemPrompt,wechatRpaSource:r.wechatRpaSource,wechatRpaGroups:r.wechatRpaGroups,pollIntervalMs:r.pollIntervalMs,recentLimit:r.recentLimit,idleSeconds:r.idleSeconds,forceForeground:r.forceForeground,noRestore:r.noRestore,downloadAttachments:r.downloadAttachments,selfNickname:r.selfNickname,wechatRpaPrivacyConsentAccepted:r.wechatRpaPrivacyConsentAccepted,wechatRpaServerDecisionAvailable:r.wechatRpaServerDecisionAvailable,wechatRpaPreflightChecks:r.wechatRpaPreflightChecks,wechatRpaRuntimeState:r.wechatRpaRuntimeState,wechatRpaLastMessageAt:r.wechatRpaLastMessageAt,wechatRpaPendingReplyCount:r.wechatRpaPendingReplyCount,wechatRpaLastError:r.wechatRpaLastError}:null}function pe(r,e){return r.providerError||r.availability&&r.availability!=="edge-local"?!1:_(r,e)?r.materializationKind==="original-file"&&r.isOriginal===!0&&r.mimeKindMatches===!0&&!me(r.localPath):!0}function ge(r){return!r.providerError&&(!r.availability||r.availability==="server-url")}function _(r,e){if(e!=="wechat-rpa")return!1;const a=String(r.type||"").toLowerCase();return a==="file"||a==="video"||a==="video-file"}function me(r){const e=String(r||"").replace(/\\/g,"/"),a=f.basename(e).toLowerCase();return/(^|\/)\.uploads(\/|$)/.test(e)||/(^|-)preview([-.]|$)/i.test(a)}function b(r){try{return k.statSync(r).isFile()}catch{return!1}}function B(r){return r.type==="image"?"image/*":r.type==="video"?"video/*":r.type==="audio"?"audio/*":"application/octet-stream"}function I(r){const e=Number(r);return Number.isFinite(e)?e:void 0}export{Ne as ManagerRuntimeService,xe as getManagerRuntimeService,Te as setManagerRuntimeService};
20
+ `).trim()}}function $(r){return Array.isArray(r)?r.map(e=>({name:String(e?.name||"").trim()})).filter(e=>e.name):[]}function _(r){return r==="wechat-channel"||r==="macos-flow"||r==="macos-probe"||r==="windows-visual-flow"||r==="wechat-rpa-lab"||r==="fixture-jsonl"?r:void 0}function de(r,e){const a=r.map(n=>B(n,e)).filter(n=>n!=null);return a.length?a:void 0}function ue(r,e,a,n){const t=e||"",i=new Set;return r.map((s,l)=>{const c=B(s,n),d=G({type:s.type,name:c?.name||s.name,path:c?.path,mimeType:c?.mimeType||s.mimeType,availability:s.availability,providerError:s.providerError||ge(s)},l),h=c?.path||"";if(h){const R=`${d}
21
+ ${h}`;return i.has(R)||t.includes(h)?"":(i.add(R),`${a}: ${d}`)}const p=d;return i.has(p)?"":(i.add(p),`${a}: ${d}`)}).filter(s=>!t.includes(s)).join(`
22
+ `)}function he(r){const a=(r.channelType==="wechat-rpa"?pe(r.sender.name):r.sender.name||r.sender.id)||(r.channelType==="wechat-rpa"?"\u5BF9\u65B9":r.sender.id)||"\u5BF9\u65B9",n=ue(r.attachments,r.text,a,r.channelType),i=[r.text?j({senderName:a,senderId:r.sender.id,text:r.text}):n?"":`${a}:`,n].filter(Boolean).join(`
23
+ `);return[H({conversationName:r.conversationName||r.conversationId,messages:[]}),i].filter(Boolean).join(`
24
+ `)}function pe(r){const e=r?.trim()||"";return!e||/^(contact|self|system|unknown)$/i.test(e)||/^wechat-sender:/i.test(e)?"":e}function ge(r){return!r.localPath||r.availability&&r.availability!=="edge-local"||b(r.localPath)?"":"edge-local-unavailable"}function B(r,e){return r.localPath&&fe(r,e)&&b(r.localPath)?{path:r.localPath,name:r.name||y.basename(r.localPath)||"attachment",mimeType:r.mimeType||F(r)}:r.url&&ye(r)?{path:r.url,name:r.name||r.url.split("/").filter(Boolean).at(-1)||"attachment",mimeType:r.mimeType||F(r)}:r.thumbnailPath&&!q(r,e)&&b(r.thumbnailPath)?{path:r.thumbnailPath,name:r.name?`${r.name}-preview.png`:y.basename(r.thumbnailPath)||"preview.png",mimeType:"image/png"}:null}function me(r){return r?r.type!=="wechat-rpa"?r:{configured:r.configured,connected:r.connected,type:r.type,channelId:r.channelId,name:r.name,canReply:r.canReply,systemPrompt:r.systemPrompt,wechatRpaSource:r.wechatRpaSource,wechatRpaGroups:r.wechatRpaGroups,pollIntervalMs:r.pollIntervalMs,recentLimit:r.recentLimit,idleSeconds:r.idleSeconds,forceForeground:r.forceForeground,noRestore:r.noRestore,downloadAttachments:r.downloadAttachments,selfNickname:r.selfNickname,wechatRpaPrivacyConsentAccepted:r.wechatRpaPrivacyConsentAccepted,wechatRpaServerDecisionAvailable:r.wechatRpaServerDecisionAvailable,wechatRpaPreflightChecks:r.wechatRpaPreflightChecks,wechatRpaRuntimeState:r.wechatRpaRuntimeState,wechatRpaLastMessageAt:r.wechatRpaLastMessageAt,wechatRpaPendingReplyCount:r.wechatRpaPendingReplyCount,wechatRpaLastError:r.wechatRpaLastError}:null}function fe(r,e){return r.providerError||r.availability&&r.availability!=="edge-local"?!1:q(r,e)?r.materializationKind==="original-file"&&r.isOriginal===!0&&r.mimeKindMatches===!0&&!we(r.localPath):!0}function ye(r){return!r.providerError&&(!r.availability||r.availability==="server-url")}function q(r,e){if(e!=="wechat-rpa")return!1;const a=String(r.type||"").toLowerCase();return a==="file"||a==="video"||a==="video-file"}function we(r){const e=String(r||"").replace(/\\/g,"/"),a=y.basename(e).toLowerCase();return/(^|\/)\.uploads(\/|$)/.test(e)||/(^|-)preview([-.]|$)/i.test(a)}function b(r){try{return k.statSync(r).isFile()}catch{return!1}}function F(r){return r.type==="image"?"image/*":r.type==="video"?"video/*":r.type==="audio"?"audio/*":"application/octet-stream"}function m(r){const e=Number(r);return Number.isFinite(e)?e:void 0}export{ve as ManagerRuntimeService,Pe as getManagerRuntimeService,We as setManagerRuntimeService};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.2.97",
3
+ "version": "0.2.99",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {