shennian 0.2.108 → 0.2.110

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.
Files changed (56) hide show
  1. package/dist/publish-build-manifest.json +63 -58
  2. package/dist/src/agents/model-registry/discovery.js +2 -2
  3. package/dist/src/agents/pi-context.d.ts +1 -1
  4. package/dist/src/agents/pi-context.js +3 -3
  5. package/dist/src/channels/runtime.d.ts +2 -0
  6. package/dist/src/channels/runtime.js +1 -1
  7. package/dist/src/channels/secret-registry.d.ts +2 -0
  8. package/dist/src/channels/wechat-channel/automation-lane.d.ts +12 -0
  9. package/dist/src/channels/wechat-channel/automation-lane.js +2 -1
  10. package/dist/src/channels/wechat-channel/client.d.ts +25 -2
  11. package/dist/src/channels/wechat-channel/client.js +1 -1
  12. package/dist/src/channels/wechat-channel/helper-assets.d.ts +1 -1
  13. package/dist/src/channels/wechat-channel/helper-assets.js +1 -1
  14. package/dist/src/channels/wechat-channel/helper-client.d.ts +2 -0
  15. package/dist/src/channels/wechat-channel/helper-client.js +3 -3
  16. package/dist/src/channels/wechat-channel/helper-protocol.d.ts +1 -1
  17. package/dist/src/channels/wechat-channel/observer.d.ts +9 -1
  18. package/dist/src/channels/wechat-channel/observer.js +7 -6
  19. package/dist/src/channels/wechat-channel/outbound-sender.d.ts +8 -0
  20. package/dist/src/channels/wechat-channel/outbound-sender.js +1 -1
  21. package/dist/src/channels/wechat-channel/runner.js +1 -1
  22. package/dist/src/channels/wechat-channel/runtime.d.ts +1 -0
  23. package/dist/src/channels/wechat-channel/runtime.js +1 -1
  24. package/dist/src/channels/wechat-channel/scheduler.d.ts +1 -1
  25. package/dist/src/channels/wechat-channel/scheduler.js +1 -1
  26. package/dist/src/channels/wechat-rpa/product-channel.d.ts +1 -0
  27. package/dist/src/channels/wechat-rpa/product-channel.js +4 -4
  28. package/dist/src/channels/wechat-rpa.d.ts +2 -0
  29. package/dist/src/channels/wechat-rpa.js +2 -2
  30. package/dist/src/commands/helper-runtime-official-download.d.ts +80 -0
  31. package/dist/src/commands/helper-runtime-official-download.js +1 -0
  32. package/dist/src/commands/runtime.d.ts +24 -0
  33. package/dist/src/commands/runtime.js +1 -1
  34. package/dist/src/commands/wechat/command.d.ts +1 -0
  35. package/dist/src/commands/wechat/command.js +1 -1
  36. package/dist/src/commands/wechat/ipc.js +1 -1
  37. package/dist/src/commands/wechat/output.js +3 -3
  38. package/dist/src/commands/wechat.d.ts +1 -1
  39. package/dist/src/commands/wechat.js +1 -1
  40. package/dist/src/devtools/wechat-channel-action-smoke.d.ts +3 -1
  41. package/dist/src/devtools/wechat-channel-action-smoke.js +9 -9
  42. package/dist/src/index.js +2 -2
  43. package/dist/src/manager/runtime.js +10 -10
  44. package/dist/src/native-fusion/service.d.ts +0 -10
  45. package/dist/src/native-fusion/service.js +2 -2
  46. package/dist/src/session/handlers/chat.js +2 -2
  47. package/dist/src/session/handlers/session-refresh.js +1 -1
  48. package/dist/src/session/handlers/wechat-helper-runtime.d.ts +31 -0
  49. package/dist/src/session/handlers/wechat-helper-runtime.js +1 -0
  50. package/dist/src/session/manager.d.ts +4 -1
  51. package/dist/src/session/manager.js +1 -1
  52. package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
  53. package/node_modules/@shennian/wire/dist/methods.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/dist/src/agents/codex-control.d.ts +0 -35
  56. package/dist/src/agents/codex-control.js +0 -2
@@ -1 +1 @@
1
- import c from"node:fs";import s from"node:path";import E from"node:crypto";const V="0.1.9",S="SHENNIAN_WECHAT_CHANNEL_HELPER_DIR",g="SHENNIAN_HELPER_RUNTIME_DIR",C="helper_runtime_required",u=["en","v"].join("");function $(n={}){const r=n.platform??process.platform;if(r!=="darwin"&&r!=="win32")return{ok:!1,reasonCode:"unsupported_platform",message:"WeChat channel helper is only available on macOS and Windows"};const e=n.baseDir?[s.resolve(n.baseDir)]:A({platform:r,env:n[u]??R(),homedir:n.homedir,includeInstalledDesktop:n.includeInstalledDesktop});let a=null;for(const t of e){const i=_({platform:r,baseDir:t,verifyIntegrity:n.verifyIntegrity});if(i.ok||(n.baseDir||c.existsSync(t))&&(a??=i,n.baseDir))return i}return a??{ok:!1,reasonCode:C,message:x(r,e)}}function _(n){const{platform:r,baseDir:e}=n,a=s.join(e,"manifest.json"),t=F(a);if(!t)return{ok:!1,reasonCode:"manifest_missing",message:`WeChat channel helper manifest is missing: ${a}`};const i=t.platforms[r],o=i?s.join(e,i.executable):"";if(!i||!o||!c.existsSync(o))return{ok:!1,reasonCode:"helper_missing",message:`WeChat channel helper executable is missing: ${o||e}`};if(N({platform:r,baseDir:e,verifyIntegrity:n.verifyIntegrity})&&i.sha256&&E.createHash("sha256").update(c.readFileSync(o)).digest("hex")!==i.sha256)return{ok:!1,reasonCode:"integrity_mismatch",message:`WeChat channel helper integrity mismatch: ${o}`};const f=H(r,o);return f.ok?{ok:!0,helperPath:o,helperDir:e,version:t.helperVersion,manifest:t,warning:i.signed&&i.notarized?void 0:"helper_not_signed_or_notarized"}:{ok:!1,reasonCode:"helper_not_executable",message:f.message}}function H(n,r){if(n!=="darwin")return{ok:!0};try{const e=c.statSync(r);return(e.mode&73)!==0?{ok:!0}:(c.chmodSync(r,e.mode|73),{ok:!0})}catch(e){return{ok:!1,message:`WeChat channel helper is not executable and could not be repaired: ${r}: ${e instanceof Error?e.message:String(e)}`}}}function A(n){const{platform:r,env:e}=n,a=r==="win32"?"windows":"macos",t=[],i=l=>{if(!l)return;const p=s.resolve(l);t.includes(p)||t.push(p)},o=e[S]?.trim();o&&i(j(o,a));const f=e[g]?.trim();if(f)for(const l of P(f,a))i(l);if(b({platform:r,platformDir:a,env:e,homedir:n.homedir,push:i}),n.includeInstalledDesktop===!1)return t;if(r==="darwin"){const l=n.homedir||e.HOME;l&&i(s.join(l,"Applications","Shennian.app","Contents","Resources","wechat-channel",a)),i(s.join("/Applications","Shennian.app","Contents","Resources","wechat-channel",a))}else if(r==="win32"){const l=n.homedir||e.USERPROFILE,p=e.LOCALAPPDATA||(l?s.join(l,"AppData","Local"):""),m=e.ProgramFiles||e.PROGRAMFILES,h=e["ProgramFiles(x86)"]||e["PROGRAMFILES(X86)"];for(const d of[p?s.join(p,"Programs","Shennian"):"",p?s.join(p,"Programs","shennian"):"",m?s.join(m,"Shennian"):"",h?s.join(h,"Shennian"):""])d&&i(s.join(d,"resources","wechat-channel",a))}return t}function b(n){const{platform:r,platformDir:e,env:a,push:t}=n;if(r==="darwin"){const i=n.homedir||a.HOME,o=k({platform:r,env:a,homedir:n.homedir});o&&(t(s.join(o,"Shennian Helper.app","Contents","Resources","wechat-channel",e)),t(s.join(o,"wechat-channel",e))),i&&t(s.join(i,"Applications","Shennian Helper.app","Contents","Resources","wechat-channel",e)),t(s.join("/Applications","Shennian Helper.app","Contents","Resources","wechat-channel",e)),t(s.join("/Library","Application Support","Shennian","Helper","wechat-channel",e))}else if(r==="win32"){const i=n.homedir||a.USERPROFILE,o=a.LOCALAPPDATA||(i?s.join(i,"AppData","Local"):""),f=a.ProgramFiles||a.PROGRAMFILES,l=a["ProgramFiles(x86)"]||a["PROGRAMFILES(X86)"];o&&(t(s.join(o,"Programs","Shennian Helper","resources","wechat-channel",e)),t(s.join(o,"Shennian","Helper","wechat-channel",e))),f&&t(s.join(f,"Shennian Helper","resources","wechat-channel",e)),l&&t(s.join(l,"Shennian Helper","resources","wechat-channel",e))}}function j(n,r){return c.existsSync(s.join(n,"manifest.json"))?n:s.join(n,r)}function P(n,r){if(c.existsSync(s.join(n,"manifest.json")))return[n];const e=s.join(n,"Shennian Helper.app","Contents","Resources","wechat-channel",r),a=s.join(n,"wechat-channel",r),t=s.join(n,r);return[e,a,t]}function k(n){const r=n[u],e=r[g]?.trim();if(e)return s.resolve(e);const a=n.homedir||(n.platform==="win32"?r.USERPROFILE:r.HOME);if(n.platform==="darwin")return a?s.join(a,"Library","Application Support","Shennian","Helper"):null;if(n.platform==="win32"){const t=r.LOCALAPPDATA||(a?s.join(a,"AppData","Local"):"");return t?s.join(t,"Shennian","Helper"):null}return null}function q(n={}){return k({platform:n.platform??process.platform,env:n.env??R(),homedir:n.homedir})}function D(n){const r=s.resolve(n);return O([s.join(r,"helper-runtime-package.json"),s.join(s.dirname(r),"..","helper-runtime-package.json")])}function U(n){const r=n.platform??process.platform;if(r!=="darwin"&&r!=="win32")return{ok:!1,reasonCode:"unsupported_platform",message:"WeChat channel helper runtime package is only available on macOS and Windows"};const e=n.manifestPath?[s.resolve(n.manifestPath)]:n.helperDir?D(n.helperDir):[],a=e.find(t=>c.existsSync(t));if(!a)return{ok:!1,reasonCode:"helper_runtime_package_manifest_missing",message:`Helper runtime package manifest is missing. Checked: ${e.join(", ")||"(none)"}`,manifestPath:e[0]};try{const t=JSON.parse(w(a)),i=I(t,r);return i.ok?{ok:!0,manifestPath:a,manifest:t}:{ok:!1,reasonCode:"helper_runtime_package_manifest_invalid",message:`${i.message}: ${a}`,manifestPath:a}}catch(t){return{ok:!1,reasonCode:"helper_runtime_package_manifest_invalid",message:`Helper runtime package manifest is invalid JSON: ${t instanceof Error?t.message:String(t)}`,manifestPath:a}}}function I(n,r){if(!n||typeof n!="object"||Array.isArray(n))return{ok:!1,message:"manifest must be an object"};const e=n;return e.schemaVersion!==1?{ok:!1,message:"schemaVersion must be 1"}:e.packageKind!=="shennian-helper-runtime"?{ok:!1,message:"packageKind must be shennian-helper-runtime"}:e.platform!==r?{ok:!1,message:`platform must be ${r}`}:e.helperVersion?!Number.isInteger(e.protocolVersion)||Number(e.protocolVersion)<=0?{ok:!1,message:"protocolVersion must be a positive integer"}:L(e.minCliVersion)?!e.sha256||typeof e.sha256.runtimeManifest!="string"?{ok:!1,message:"sha256.runtimeManifest is required"}:y(e.sha256.runtimeManifest)?e.sha256.entrypoint!==null&&typeof e.sha256.entrypoint!="string"?{ok:!1,message:"sha256.entrypoint must be a string or null"}:typeof e.sha256.entrypoint=="string"&&!y(e.sha256.entrypoint)?{ok:!1,message:"sha256.entrypoint must be a sha256 digest or null"}:!e.installTarget?.kind||!e.installTarget.defaultPath?{ok:!1,message:"installTarget.kind and installTarget.defaultPath are required"}:!e.payload?.kind||!e.payload.runtimeManifest||!e.payload.entrypoint?{ok:!1,message:"payload.kind, payload.runtimeManifest, and payload.entrypoint are required"}:r==="darwin"&&e.installTarget.kind!=="app-bundle"?{ok:!1,message:"darwin installTarget.kind must be app-bundle"}:r==="darwin"&&e.payload.kind!=="macos-helper-app"?{ok:!1,message:"darwin payload.kind must be macos-helper-app"}:r==="win32"&&e.installTarget.kind!=="directory"?{ok:!1,message:"win32 installTarget.kind must be directory"}:r==="win32"&&e.payload.kind!=="windows-helper-runtime"?{ok:!1,message:"win32 payload.kind must be windows-helper-runtime"}:!e.signature||typeof e.signature.requiredForRelease!="boolean"||typeof e.signature.signed!="boolean"||typeof e.signature.notarized!="boolean"?{ok:!1,message:"signature.requiredForRelease, signature.signed, and signature.notarized are required"}:{ok:!0}:{ok:!1,message:"sha256.runtimeManifest must be a sha256 digest"}:{ok:!1,message:"minCliVersion must be a semver string"}:{ok:!1,message:"helperVersion is required"}}function L(n){return typeof n=="string"&&/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(n)}function y(n){return/^[a-f0-9]{64}$/i.test(n)}function N(n){return n.verifyIntegrity===!0?!0:n.verifyIntegrity===!1?!1:!v(n.platform,n.baseDir)}function v(n,r){const e=r.replace(/[\\/]+/g,"/");return n==="darwin"?/\/Shennian\.app\/Contents\/Resources\/wechat-channel\/macos$/i.test(e):n==="win32"?/\/resources\/wechat-channel\/windows$/i.test(e):!1}function x(n,r){const e=n==="win32"?"Windows":"macOS",a=r.length>0?` Checked helper directories: ${r.join(", ")}`:"";return`WeChat RPA requires Shennian Helper runtime on ${e}; install or open Shennian Desktop, or run shennian runtime install helper, then retry.${a}`}function R(){return globalThis.process?.[u]??{}}function F(n){try{const r=JSON.parse(w(n));return r.schemaVersion!==1||typeof r.helperVersion!="string"||!r.platforms?null:r}catch{return null}}function w(n){return c.readFileSync(n,"utf8").replace(/^\uFEFF/,"")}function O(n){const r=new Set,e=[];for(const a of n){const t=s.resolve(a);r.has(t)||(r.add(t),e.push(t))}return e}export{g as SHENNIAN_HELPER_RUNTIME_DIR_ENV,S as WECHAT_CHANNEL_HELPER_DIR_ENV,C as WECHAT_CHANNEL_HELPER_RUNTIME_REQUIRED_REASON,V as WECHAT_CHANNEL_HELPER_VERSION,q as getDefaultWeChatHelperRuntimeRoot,D as helperRuntimePackageManifestCandidates,U as readWeChatChannelHelperRuntimePackageManifest,$ as resolveWeChatChannelHelperAsset,I as validateWeChatChannelHelperRuntimePackageManifest};
1
+ import c from"node:fs";import s from"node:path";import E from"node:crypto";const V="0.1.10",S="SHENNIAN_WECHAT_CHANNEL_HELPER_DIR",g="SHENNIAN_HELPER_RUNTIME_DIR",C="helper_runtime_required",u=["en","v"].join("");function $(n={}){const r=n.platform??process.platform;if(r!=="darwin"&&r!=="win32")return{ok:!1,reasonCode:"unsupported_platform",message:"WeChat channel helper is only available on macOS and Windows"};const e=n.baseDir?[s.resolve(n.baseDir)]:A({platform:r,env:n[u]??R(),homedir:n.homedir,includeInstalledDesktop:n.includeInstalledDesktop});let a=null;for(const t of e){const i=_({platform:r,baseDir:t,verifyIntegrity:n.verifyIntegrity});if(i.ok||(n.baseDir||c.existsSync(t))&&(a??=i,n.baseDir))return i}return a??{ok:!1,reasonCode:C,message:x(r,e)}}function _(n){const{platform:r,baseDir:e}=n,a=s.join(e,"manifest.json"),t=F(a);if(!t)return{ok:!1,reasonCode:"manifest_missing",message:`WeChat channel helper manifest is missing: ${a}`};const i=t.platforms[r],o=i?s.join(e,i.executable):"";if(!i||!o||!c.existsSync(o))return{ok:!1,reasonCode:"helper_missing",message:`WeChat channel helper executable is missing: ${o||e}`};if(N({platform:r,baseDir:e,verifyIntegrity:n.verifyIntegrity})&&i.sha256&&E.createHash("sha256").update(c.readFileSync(o)).digest("hex")!==i.sha256)return{ok:!1,reasonCode:"integrity_mismatch",message:`WeChat channel helper integrity mismatch: ${o}`};const f=H(r,o);return f.ok?{ok:!0,helperPath:o,helperDir:e,version:t.helperVersion,manifest:t,warning:i.signed&&i.notarized?void 0:"helper_not_signed_or_notarized"}:{ok:!1,reasonCode:"helper_not_executable",message:f.message}}function H(n,r){if(n!=="darwin")return{ok:!0};try{const e=c.statSync(r);return(e.mode&73)!==0?{ok:!0}:(c.chmodSync(r,e.mode|73),{ok:!0})}catch(e){return{ok:!1,message:`WeChat channel helper is not executable and could not be repaired: ${r}: ${e instanceof Error?e.message:String(e)}`}}}function A(n){const{platform:r,env:e}=n,a=r==="win32"?"windows":"macos",t=[],i=l=>{if(!l)return;const p=s.resolve(l);t.includes(p)||t.push(p)},o=e[S]?.trim();o&&i(j(o,a));const f=e[g]?.trim();if(f)for(const l of P(f,a))i(l);if(b({platform:r,platformDir:a,env:e,homedir:n.homedir,push:i}),n.includeInstalledDesktop===!1)return t;if(r==="darwin"){const l=n.homedir||e.HOME;l&&i(s.join(l,"Applications","Shennian.app","Contents","Resources","wechat-channel",a)),i(s.join("/Applications","Shennian.app","Contents","Resources","wechat-channel",a))}else if(r==="win32"){const l=n.homedir||e.USERPROFILE,p=e.LOCALAPPDATA||(l?s.join(l,"AppData","Local"):""),m=e.ProgramFiles||e.PROGRAMFILES,h=e["ProgramFiles(x86)"]||e["PROGRAMFILES(X86)"];for(const d of[p?s.join(p,"Programs","Shennian"):"",p?s.join(p,"Programs","shennian"):"",m?s.join(m,"Shennian"):"",h?s.join(h,"Shennian"):""])d&&i(s.join(d,"resources","wechat-channel",a))}return t}function b(n){const{platform:r,platformDir:e,env:a,push:t}=n;if(r==="darwin"){const i=n.homedir||a.HOME,o=k({platform:r,env:a,homedir:n.homedir});o&&(t(s.join(o,"Shennian Helper.app","Contents","Resources","wechat-channel",e)),t(s.join(o,"wechat-channel",e))),i&&t(s.join(i,"Applications","Shennian Helper.app","Contents","Resources","wechat-channel",e)),t(s.join("/Applications","Shennian Helper.app","Contents","Resources","wechat-channel",e)),t(s.join("/Library","Application Support","Shennian","Helper","wechat-channel",e))}else if(r==="win32"){const i=n.homedir||a.USERPROFILE,o=a.LOCALAPPDATA||(i?s.join(i,"AppData","Local"):""),f=a.ProgramFiles||a.PROGRAMFILES,l=a["ProgramFiles(x86)"]||a["PROGRAMFILES(X86)"];o&&(t(s.join(o,"Programs","Shennian Helper","resources","wechat-channel",e)),t(s.join(o,"Shennian","Helper","wechat-channel",e))),f&&t(s.join(f,"Shennian Helper","resources","wechat-channel",e)),l&&t(s.join(l,"Shennian Helper","resources","wechat-channel",e))}}function j(n,r){return c.existsSync(s.join(n,"manifest.json"))?n:s.join(n,r)}function P(n,r){if(c.existsSync(s.join(n,"manifest.json")))return[n];const e=s.join(n,"Shennian Helper.app","Contents","Resources","wechat-channel",r),a=s.join(n,"wechat-channel",r),t=s.join(n,r);return[e,a,t]}function k(n){const r=n[u],e=r[g]?.trim();if(e)return s.resolve(e);const a=n.homedir||(n.platform==="win32"?r.USERPROFILE:r.HOME);if(n.platform==="darwin")return a?s.join(a,"Library","Application Support","Shennian","Helper"):null;if(n.platform==="win32"){const t=r.LOCALAPPDATA||(a?s.join(a,"AppData","Local"):"");return t?s.join(t,"Shennian","Helper"):null}return null}function q(n={}){return k({platform:n.platform??process.platform,env:n.env??R(),homedir:n.homedir})}function D(n){const r=s.resolve(n);return O([s.join(r,"helper-runtime-package.json"),s.join(s.dirname(r),"..","helper-runtime-package.json")])}function U(n){const r=n.platform??process.platform;if(r!=="darwin"&&r!=="win32")return{ok:!1,reasonCode:"unsupported_platform",message:"WeChat channel helper runtime package is only available on macOS and Windows"};const e=n.manifestPath?[s.resolve(n.manifestPath)]:n.helperDir?D(n.helperDir):[],a=e.find(t=>c.existsSync(t));if(!a)return{ok:!1,reasonCode:"helper_runtime_package_manifest_missing",message:`Helper runtime package manifest is missing. Checked: ${e.join(", ")||"(none)"}`,manifestPath:e[0]};try{const t=JSON.parse(w(a)),i=I(t,r);return i.ok?{ok:!0,manifestPath:a,manifest:t}:{ok:!1,reasonCode:"helper_runtime_package_manifest_invalid",message:`${i.message}: ${a}`,manifestPath:a}}catch(t){return{ok:!1,reasonCode:"helper_runtime_package_manifest_invalid",message:`Helper runtime package manifest is invalid JSON: ${t instanceof Error?t.message:String(t)}`,manifestPath:a}}}function I(n,r){if(!n||typeof n!="object"||Array.isArray(n))return{ok:!1,message:"manifest must be an object"};const e=n;return e.schemaVersion!==1?{ok:!1,message:"schemaVersion must be 1"}:e.packageKind!=="shennian-helper-runtime"?{ok:!1,message:"packageKind must be shennian-helper-runtime"}:e.platform!==r?{ok:!1,message:`platform must be ${r}`}:e.helperVersion?!Number.isInteger(e.protocolVersion)||Number(e.protocolVersion)<=0?{ok:!1,message:"protocolVersion must be a positive integer"}:L(e.minCliVersion)?!e.sha256||typeof e.sha256.runtimeManifest!="string"?{ok:!1,message:"sha256.runtimeManifest is required"}:y(e.sha256.runtimeManifest)?e.sha256.entrypoint!==null&&typeof e.sha256.entrypoint!="string"?{ok:!1,message:"sha256.entrypoint must be a string or null"}:typeof e.sha256.entrypoint=="string"&&!y(e.sha256.entrypoint)?{ok:!1,message:"sha256.entrypoint must be a sha256 digest or null"}:!e.installTarget?.kind||!e.installTarget.defaultPath?{ok:!1,message:"installTarget.kind and installTarget.defaultPath are required"}:!e.payload?.kind||!e.payload.runtimeManifest||!e.payload.entrypoint?{ok:!1,message:"payload.kind, payload.runtimeManifest, and payload.entrypoint are required"}:r==="darwin"&&e.installTarget.kind!=="app-bundle"?{ok:!1,message:"darwin installTarget.kind must be app-bundle"}:r==="darwin"&&e.payload.kind!=="macos-helper-app"?{ok:!1,message:"darwin payload.kind must be macos-helper-app"}:r==="win32"&&e.installTarget.kind!=="directory"?{ok:!1,message:"win32 installTarget.kind must be directory"}:r==="win32"&&e.payload.kind!=="windows-helper-runtime"?{ok:!1,message:"win32 payload.kind must be windows-helper-runtime"}:!e.signature||typeof e.signature.requiredForRelease!="boolean"||typeof e.signature.signed!="boolean"||typeof e.signature.notarized!="boolean"?{ok:!1,message:"signature.requiredForRelease, signature.signed, and signature.notarized are required"}:{ok:!0}:{ok:!1,message:"sha256.runtimeManifest must be a sha256 digest"}:{ok:!1,message:"minCliVersion must be a semver string"}:{ok:!1,message:"helperVersion is required"}}function L(n){return typeof n=="string"&&/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(n)}function y(n){return/^[a-f0-9]{64}$/i.test(n)}function N(n){return n.verifyIntegrity===!0?!0:n.verifyIntegrity===!1?!1:!v(n.platform,n.baseDir)}function v(n,r){const e=r.replace(/[\\/]+/g,"/");return n==="darwin"?/\/Shennian\.app\/Contents\/Resources\/wechat-channel\/macos$/i.test(e):n==="win32"?/\/resources\/wechat-channel\/windows$/i.test(e):!1}function x(n,r){const e=n==="win32"?"Windows":"macOS",a=r.length>0?` Checked helper directories: ${r.join(", ")}`:"";return`WeChat RPA requires Shennian Helper runtime on ${e}; open Shennian Desktop or use the \u4F7F\u7528\u5FAE\u4FE1 page to install Helper, then retry.${a}`}function R(){return globalThis.process?.[u]??{}}function F(n){try{const r=JSON.parse(w(n));return r.schemaVersion!==1||typeof r.helperVersion!="string"||!r.platforms?null:r}catch{return null}}function w(n){return c.readFileSync(n,"utf8").replace(/^\uFEFF/,"")}function O(n){const r=new Set,e=[];for(const a of n){const t=s.resolve(a);r.has(t)||(r.add(t),e.push(t))}return e}export{g as SHENNIAN_HELPER_RUNTIME_DIR_ENV,S as WECHAT_CHANNEL_HELPER_DIR_ENV,C as WECHAT_CHANNEL_HELPER_RUNTIME_REQUIRED_REASON,V as WECHAT_CHANNEL_HELPER_VERSION,q as getDefaultWeChatHelperRuntimeRoot,D as helperRuntimePackageManifestCandidates,U as readWeChatChannelHelperRuntimePackageManifest,$ as resolveWeChatChannelHelperAsset,I as validateWeChatChannelHelperRuntimePackageManifest};
@@ -63,8 +63,10 @@ export declare class WeChatChannelHelperClient {
63
63
  private formatHelperExitMessage;
64
64
  private rejectAllPending;
65
65
  private emitRequestTrace;
66
+ private stopAfterCommandTimeout;
66
67
  private connectDarwinHelperSocket;
67
68
  }
69
+ export declare function stopWindowsWeChatChannelHelperProcesses(): Promise<void>;
68
70
  type LegacyRawHelperLaunchSpec = {
69
71
  transport: 'legacy-stdio';
70
72
  command: string;
@@ -1,3 +1,3 @@
1
- import{spawn as w}from"node:child_process";import{randomUUID as _}from"node:crypto";import f from"node:fs";import W from"node:net";import b from"node:os";import d from"node:path";import{createInterface as m}from"node:readline";import{decideWeChatChannelActivityGate as T,normalizeWeChatChannelActivitySnapshot as v}from"./human-coordination.js";import{createWeChatChannelHelperHello as y,extractWeChatChannelHelperWarmupSnapshot as P,timeoutForWeChatChannelHelperCommand as R,validateWeChatChannelHelperReady as g}from"./helper-protocol.js";const M=["en","v"].join("");class se{options;child=null;socket=null;lines=null;readyState=null;warmupState=null;stderrTail="";startPromise=null;requestQueueTail=Promise.resolve();pending=new Map;constructor(e){this.options=e}async start(){return this.hasTransport()&&this.readyState?this.readyState:this.startPromise?this.startPromise:(this.hasTransport()&&await this.stop(),this.startPromise=this.startFresh().catch(async e=>{throw await this.stop().catch(()=>{}),e}).finally(()=>{this.startPromise=null}),this.startPromise)}async startFresh(){const e=F(this.options.helperPath,this.options.args??[]);return e.transport==="macos-socket"?this.startDarwinAppSocketFresh(e):this.startStdioFresh(e)}async startStdioFresh(e){const t=w(e.command,e.args,{cwd:this.options.cwd,stdio:["pipe","pipe","pipe"],windowsHide:!0});this.child=t,this.stderrTail="",this.lines=m({input:t.stdout}),this.lines.on("line",i=>this.handleLine(i)),t.stderr.on("data",i=>{this.captureStderr(i)}),t.stdin.on("error",i=>{this.rejectAllPending(i instanceof Error?i:new Error(String(i)))}),t.once("error",i=>{this.child===t&&(this.child=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(i instanceof Error?i:new Error(String(i)))}),t.once("exit",(i,n)=>{this.child===t&&(this.child=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(new Error(this.formatHelperExitMessage(i,n)))});const s=new Promise((i,n)=>{const a=setTimeout(()=>n(new Error("WeChat channel helper handshake timed out")),1e4),l=u=>{clearTimeout(a),this.lines?.off("line",c),t.off("exit",o),n(new Error(`WeChat channel helper failed to start: ${u.message}`))},o=(u,h)=>{clearTimeout(a),t.off("error",l),this.lines?.off("line",c),n(new Error(this.formatHelperExitMessage(u,h)))},c=u=>{let h;try{h=JSON.parse(u)}catch{clearTimeout(a),t.off("error",l),this.lines?.off("line",c),n(new Error("WeChat channel helper sent invalid handshake JSON"));return}if(!C(h))return;clearTimeout(a),t.off("error",l),t.off("exit",o),this.lines?.off("line",c);const p=g(h,this.options.expectedHelperVersion,this.options.requiredCapabilities);p.ok?(this.readyState=h,this.captureWarmupSnapshot(h),i(h)):n(new Error(`${p.errorCode}: ${p.errorSummary}`))};t.once("error",l),t.once("exit",o),this.lines?.on("line",c)});try{t.stdin.write(`${JSON.stringify(y(this.options.expectedHelperVersion,this.options.requiredCapabilities))}
2
- `)}catch(i){throw await this.stop().catch(()=>{}),i}return s}async startDarwinAppSocketFresh(e){const t=await this.connectDarwinHelperSocket(e);this.socket=t,this.stderrTail="",this.lines=m({input:t}),this.lines.on("line",i=>this.handleLine(i)),t.on("error",i=>{this.socket===t&&(this.socket=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(i instanceof Error?i:new Error(String(i)))}),t.once("close",()=>{this.socket===t&&(this.socket=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(new Error("WeChat channel helper socket closed"))});const s=new Promise((i,n)=>{const a=setTimeout(()=>n(new Error("WeChat channel helper socket handshake timed out")),1e4),l=u=>{clearTimeout(a),this.lines?.off("line",c),t.off("close",o),n(new Error(`WeChat channel helper socket failed: ${u.message}`))},o=()=>{clearTimeout(a),t.off("error",l),this.lines?.off("line",c),n(new Error("WeChat channel helper socket closed before handshake"))},c=u=>{let h;try{h=JSON.parse(u)}catch{clearTimeout(a),t.off("error",l),t.off("close",o),this.lines?.off("line",c),n(new Error("WeChat channel helper sent invalid socket handshake JSON"));return}if(!C(h))return;clearTimeout(a),t.off("error",l),t.off("close",o),this.lines?.off("line",c);const p=g(h,this.options.expectedHelperVersion,this.options.requiredCapabilities);p.ok?(this.readyState=h,this.captureWarmupSnapshot(h),i(h)):n(new Error(`${p.errorCode}: ${p.errorSummary}`))};t.once("error",l),t.once("close",o),this.lines?.on("line",c)});try{this.writeFrame(y(this.options.expectedHelperVersion,this.options.requiredCapabilities))}catch(i){throw await this.stop().catch(()=>{}),i}return s}async request(e,t,s){const i=this.requestQueueTail.catch(()=>{}).then(()=>this.sendRequest(e,t,s));return this.requestQueueTail=i.then(()=>{},()=>{}),i}async sendRequest(e,t,s){await this.guardUnsafeWindowsCommand(e,s);try{return await this.sendRawRequest(e,t,s)}finally{await this.cleanupWindowsOverlaysAfterCommand(e,s).catch(()=>{})}}async sendRawRequest(e,t,s){if((!this.hasTransport()||!this.readyState)&&await this.start(),!this.hasTransport())throw new Error("WeChat channel helper is not started");const i=_(),n=R(e),a=Date.now();this.emitRequestTrace({phase:"request",at:new Date(a).toISOString(),id:i,command:e,traceId:s,params:t,timeoutMs:n});const l=new Promise((o,c)=>{const u=setTimeout(()=>{this.pending.delete(i),c(new Error(`helper_command_timeout: ${e}`))},n);this.pending.set(i,{resolve:o,reject:c,timer:u})});try{this.writeFrame({id:i,command:e,params:t,traceId:s})}catch(o){const c=this.pending.get(i);throw c&&clearTimeout(c.timer),this.pending.delete(i),this.emitRequestTrace({phase:"error",at:new Date().toISOString(),id:i,command:e,traceId:s,durationMs:Date.now()-a,errorSummary:o instanceof Error?o.message:String(o)}),o}try{const o=await l;return this.emitRequestTrace({phase:"response",at:new Date().toISOString(),id:i,command:e,traceId:s,durationMs:Date.now()-a,ok:o.ok,errorCode:o.errorCode,errorSummary:o.errorSummary,latencyMs:o.latencyMs,result:o.result}),this.captureWarmupSnapshot(o),this.captureWarmupSnapshot(o.result),o}catch(o){throw this.emitRequestTrace({phase:"error",at:new Date().toISOString(),id:i,command:e,traceId:s,durationMs:Date.now()-a,errorSummary:o instanceof Error?o.message:String(o)}),o}}async guardUnsafeWindowsCommand(e,t){if(!this.options.guardUnsafeWindowsCommands||!j(e))return;const s=await this.sendRawRequest("permissions.check",{},t);if(!s.ok)throw new Error(`${s.errorCode??"permissions_check_failed"}: ${s.errorSummary??e}`);const i=s.result??{},n=await this.requestFirstMissingMacPermissionPrompt(i,t);if(n==="screen-recording")throw new Error("permission_screen_recording_missing");if(n==="accessibility")throw new Error("permission_accessibility_missing");if(n==="input-monitoring")throw new Error("permission_input_monitoring_missing");if(i.automation===!1)throw new Error("permission_automation_missing");if(i.wechatRunning===!1)throw new Error("wechat_not_running");if(A(i))throw new Error("wechat_login_required");if($(i))throw new Error("windows_visible_desktop_unavailable");if(i.dpiMappingAvailable===!1||i.displayTopologySupported===!1)throw new Error("dpi_mapping_failed");if(i.wechatWindowAvailable===!1)throw new Error("wechat_window_unavailable");if(i.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(!this.options.skipUserActivityGuard&&B(e)){const a=await this.sendRawRequest("activity.snapshot",{},t);if(!a.ok)throw new Error(`${a.errorCode??"user_activity_unknown"}: ${a.errorSummary??e}`);const l=T({snapshot:v(a.result),stage:"dangerous_action"});if(!l.ok)throw new Error(`user_active:${l.reasonCode}`)}await this.cleanupWindowsOverlays("before",e,t)}async requestFirstMissingMacPermissionPrompt(e,t){const s=V(e);if(!s||process.platform!=="darwin")return s;const i=G(s);try{await this.sendRawRequest(i,{},t)}catch{}return s}async cleanupWindowsOverlaysAfterCommand(e,t){!this.options.guardUnsafeWindowsCommands||!z(e)||await this.cleanupWindowsOverlays("after",e,t)}async cleanupWindowsOverlays(e,t,s){if(this.options.cleanupWindowsOverlays===!1)return;if(!this.readyState?.capabilities.includes("overlayCleanup"))throw new Error("helper_capability_missing: overlayCleanup");const i=await this.sendRawRequest("windows.cleanupOverlays",{stage:e,command:t,includeGeneratedMediaPreviews:!0,includeToolingTerminals:!1,waitMs:e==="after"?220:120},s);if(!i.ok)throw new Error(`${i.errorCode??"overlay_cleanup_failed"}: ${i.errorSummary??t}`)}async healthCheck(e){return this.request("health.check",{},e)}getReadyState(){return this.readyState?{...this.readyState,capabilities:[...this.readyState.capabilities]}:null}getWarmupState(){return this.warmupState?{warmState:this.warmupState.warmState,metrics:this.warmupState.metrics?{...this.warmupState.metrics}:void 0}:null}async stop(){const e=this.child,t=this.socket;this.child=null,this.socket=null,this.readyState=null,this.lines?.close(),this.lines=null,this.rejectAllPending(new Error("WeChat channel helper stopped")),t&&!t.destroyed&&t.destroy(),!(!e||e.killed)&&e.kill("SIGTERM")}hasTransport(){return!!this.child||!!this.socket}writeFrame(e){const t=`${JSON.stringify(e)}
3
- `;if(this.socket){this.socket.write(t);return}if(this.child){this.child.stdin.write(t);return}throw new Error("WeChat channel helper is not started")}handleLine(e){let t;try{t=JSON.parse(e)}catch{return}if(!J(t))return;const s=this.pending.get(t.id);s&&(clearTimeout(s.timer),this.pending.delete(t.id),s.resolve(t))}captureWarmupSnapshot(e){const t=P(e);t&&(this.warmupState=t)}captureStderr(e){const t=Buffer.isBuffer(e)?e.toString("utf8"):String(e??"");t&&(this.stderrTail=(this.stderrTail+t).slice(-2e3))}formatHelperExitMessage(e,t){const s=[e===null?null:`code=${e}`,t?`signal=${t}`:null,this.stderrTail.trim()?`stderr=${this.stderrTail.trim()}`:null].filter(Boolean);return s.length?`WeChat channel helper process exited (${s.join(", ")})`:"WeChat channel helper process exited"}rejectAllPending(e){for(const[t,s]of this.pending)clearTimeout(s.timer),s.reject(e),this.pending.delete(t)}emitRequestTrace(e){try{this.options.requestLogger?.(e)}catch{}}async connectDarwinHelperSocket(e){try{return await S(e.runtimeFile)}catch{f.rmSync(e.runtimeFile,{force:!0})}await E(e,{},this.options.openHelperAppForTest);const t=await k(e.runtimeFile,this.options.macosRuntimeInitialReadyTimeoutMs??5e3);if(t.ok)return t.socket;f.rmSync(e.runtimeFile,{force:!0}),await E(e,{forceNewInstance:!0},this.options.openHelperAppForTest);const s=await k(e.runtimeFile,this.options.macosRuntimeRelaunchReadyTimeoutMs??1e4);if(s.ok)return s.socket;throw new Error(`WeChat channel Helper.app socket did not become ready: ${s.error.message}`)}}function A(r){return r.wechatWindowAvailable!==!1?!1:![...r.captureCandidates??[],...r.restoreCandidates??[],...r.hiddenRestoreCandidates??[]].some(H)}function $(r){return r.windowsVisibleDesktopAvailable===!1||r.rdpVisibleDesktopAvailable===!1||r.desktopSessionVisible===!1||r.screenLocked===!0||r.rdpDisconnected===!0}function q(r){const e=String(r.appName||"").toLowerCase();return e==="wechat"||e==="weixin"}function H(r){return!(!q(r)||r.visible===!1||r.minimized===!0)}function F(r,e,t=process.platform){if(t==="darwin"){const s=x(r);if(s&&e.length===0){const i=D();return{transport:"macos-socket",command:"/usr/bin/open",args:["-g",s,"--args","--socket-runtime",i],appPath:s,runtimeDir:i,runtimeFile:d.join(i,"runtime.json")}}}return{transport:"legacy-stdio",command:r,args:e}}function x(r){const e=d.resolve(r),t=`${d.sep}Contents${d.sep}MacOS${d.sep}`,s=e.lastIndexOf(t);if(s<0)return null;const i=e.slice(0,s);return i.endsWith(".app")?i:null}function D(){const r=O().SHENNIAN_HELPER_RUNTIME_DIR?.trim();return r?d.resolve(r):d.join(b.homedir(),"Library","Application Support","Shennian","Helper")}function O(){return globalThis.process?.[M]??{}}function N(r){let e;try{e=JSON.parse(f.readFileSync(r,"utf8"))}catch(i){throw new Error(`runtime_file_unreadable: ${i instanceof Error?i.message:String(i)}`)}if(!e||typeof e!="object")throw new Error("runtime_file_invalid");const t=e.socketPath;if(typeof t!="string"||!t.trim())throw new Error("runtime_socket_missing");const s=e.pid;return{socketPath:t,...typeof s=="number"&&Number.isInteger(s)&&s>0?{pid:s}:{}}}async function S(r){const{socketPath:e,pid:t}=N(r);if(t&&!L(t))throw new Error(`runtime_process_stale: ${t}`);return new Promise((s,i)=>{const n=W.createConnection(e),a=setTimeout(()=>{n.destroy(),i(new Error(`runtime_socket_connect_timeout: ${e}`))},1e3);n.once("connect",()=>{clearTimeout(a),n.off("error",l),s(n)});const l=o=>{clearTimeout(a),n.destroy(),i(o)};n.once("error",l)})}async function k(r,e){const t=Date.now()+e;let s=null;for(;Date.now()<t;)try{return{ok:!0,socket:await S(r)}}catch(i){s=i instanceof Error?i:new Error(String(i));const n=t-Date.now();n>0&&await I(Math.min(150,n))}return{ok:!1,error:s??new Error("runtime file missing")}}async function E(r,e={},t=U){f.mkdirSync(r.runtimeDir,{recursive:!0,mode:448});const s=e.forceNewInstance?["-n",...r.args]:r.args;try{await t(r.command,s)}catch(i){if(!(i instanceof Error?i.message:String(i)).includes("-1712"))throw i;await t(r.command,["-n",...r.args])}}function L(r){try{return process.kill(r,0),!0}catch{return!1}}async function U(r,e){await new Promise((t,s)=>{const i=w(r,e,{stdio:["ignore","ignore","pipe"],windowsHide:!0});let n="";i.stderr.on("data",a=>{n=(n+String(a)).slice(-2e3)}),i.once("error",s),i.once("exit",(a,l)=>{a===0?t():s(new Error(`open Helper.app failed (${l?`signal=${l}`:`code=${a}`}${n.trim()?`, stderr=${n.trim()}`:""})`))})})}function I(r){return new Promise(e=>setTimeout(e,r))}function V(r){return r.screenRecording===!1?"screen-recording":r.accessibility===!1?"accessibility":r.inputMonitoring===!1?"input-monitoring":null}function G(r){return r==="screen-recording"?"permissions.requestScreenRecording":r==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring"}function C(r){if(!r||typeof r!="object")return!1;const e=r;return e.type==="ready"&&typeof e.helperVersion=="string"&&typeof e.protocolVersion=="number"&&Array.isArray(e.capabilities)&&typeof e.pid=="number"}function J(r){if(!r||typeof r!="object")return!1;const e=r;return typeof e.id=="string"&&typeof e.ok=="boolean"&&typeof e.latencyMs=="number"}function j(r){return r==="windows.focus"||r==="windows.capture"||r==="screen.capture"||r==="ocr.recognize"||r==="image.cropHash"||r==="wechat.searchConversation"||r==="wechat.focusMessageInput"||r.startsWith("mouse.")||r.startsWith("keyboard.")||r.startsWith("clipboard.")||r==="menu.pickItem"||r==="savePanel.saveToPath"}function z(r){return r.startsWith("mouse.")||r.startsWith("keyboard.")||r.startsWith("clipboard.")||r==="menu.pickItem"||r==="savePanel.saveToPath"}function B(r){return r==="windows.focus"||r==="wechat.searchConversation"||r==="wechat.focusMessageInput"||r.startsWith("mouse.")||r.startsWith("keyboard.")||r.startsWith("clipboard.set")||r==="clipboard.restore"||r==="menu.pickItem"||r==="savePanel.saveToPath"}export{se as WeChatChannelHelperClient,F as helperLaunchSpec};
1
+ import{spawn as w}from"node:child_process";import{randomUUID as R}from"node:crypto";import f from"node:fs";import v from"node:net";import M from"node:os";import d from"node:path";import{createInterface as g}from"node:readline";import{decideWeChatChannelActivityGate as x,normalizeWeChatChannelActivitySnapshot as A}from"./human-coordination.js";import{createWeChatChannelHelperHello as S,extractWeChatChannelHelperWarmupSnapshot as H,timeoutForWeChatChannelHelperCommand as $,validateWeChatChannelHelperReady as k}from"./helper-protocol.js";const q=["en","v"].join(""),F="shennian-wechat-channel-helper.exe",m=1500;class ue{options;child=null;socket=null;lines=null;readyState=null;warmupState=null;stderrTail="";startPromise=null;requestQueueTail=Promise.resolve();pending=new Map;constructor(e){this.options=e}async start(){return this.hasTransport()&&this.readyState?this.readyState:this.startPromise?this.startPromise:(this.hasTransport()&&await this.stop(),this.startPromise=this.startFresh().catch(async e=>{throw await this.stop().catch(()=>{}),e}).finally(()=>{this.startPromise=null}),this.startPromise)}async startFresh(){const e=U(this.options.helperPath,this.options.args??[]);return e.transport==="macos-socket"?this.startDarwinAppSocketFresh(e):this.startStdioFresh(e)}async startStdioFresh(e){const r=w(e.command,e.args,{cwd:this.options.cwd,stdio:["pipe","pipe","pipe"],windowsHide:!0});this.child=r,this.stderrTail="",this.lines=g({input:r.stdout}),this.lines.on("line",i=>this.handleLine(i)),r.stderr.on("data",i=>{this.captureStderr(i)}),r.stdin.on("error",i=>{this.rejectAllPending(i instanceof Error?i:new Error(String(i)))}),r.once("error",i=>{this.child===r&&(this.child=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(i instanceof Error?i:new Error(String(i)))}),r.once("exit",(i,n)=>{this.child===r&&(this.child=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(new Error(this.formatHelperExitMessage(i,n)))});const s=new Promise((i,n)=>{const a=setTimeout(()=>n(new Error("WeChat channel helper handshake timed out")),1e4),l=u=>{clearTimeout(a),this.lines?.off("line",c),r.off("exit",o),n(new Error(`WeChat channel helper failed to start: ${u.message}`))},o=(u,h)=>{clearTimeout(a),r.off("error",l),this.lines?.off("line",c),n(new Error(this.formatHelperExitMessage(u,h)))},c=u=>{let h;try{h=JSON.parse(u)}catch{clearTimeout(a),r.off("error",l),this.lines?.off("line",c),n(new Error("WeChat channel helper sent invalid handshake JSON"));return}if(!P(h))return;clearTimeout(a),r.off("error",l),r.off("exit",o),this.lines?.off("line",c);const p=k(h,this.options.expectedHelperVersion,this.options.requiredCapabilities);p.ok?(this.readyState=h,this.captureWarmupSnapshot(h),i(h)):n(new Error(`${p.errorCode}: ${p.errorSummary}`))};r.once("error",l),r.once("exit",o),this.lines?.on("line",c)});try{r.stdin.write(`${JSON.stringify(S(this.options.expectedHelperVersion,this.options.requiredCapabilities))}
2
+ `)}catch(i){throw await this.stop().catch(()=>{}),i}return s}async startDarwinAppSocketFresh(e){const r=await this.connectDarwinHelperSocket(e);this.socket=r,this.stderrTail="",this.lines=g({input:r}),this.lines.on("line",i=>this.handleLine(i)),r.on("error",i=>{this.socket===r&&(this.socket=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(i instanceof Error?i:new Error(String(i)))}),r.once("close",()=>{this.socket===r&&(this.socket=null,this.readyState=null,this.lines?.close(),this.lines=null),this.rejectAllPending(new Error("WeChat channel helper socket closed"))});const s=new Promise((i,n)=>{const a=setTimeout(()=>n(new Error("WeChat channel helper socket handshake timed out")),1e4),l=u=>{clearTimeout(a),this.lines?.off("line",c),r.off("close",o),n(new Error(`WeChat channel helper socket failed: ${u.message}`))},o=()=>{clearTimeout(a),r.off("error",l),this.lines?.off("line",c),n(new Error("WeChat channel helper socket closed before handshake"))},c=u=>{let h;try{h=JSON.parse(u)}catch{clearTimeout(a),r.off("error",l),r.off("close",o),this.lines?.off("line",c),n(new Error("WeChat channel helper sent invalid socket handshake JSON"));return}if(!P(h))return;clearTimeout(a),r.off("error",l),r.off("close",o),this.lines?.off("line",c);const p=k(h,this.options.expectedHelperVersion,this.options.requiredCapabilities);p.ok?(this.readyState=h,this.captureWarmupSnapshot(h),i(h)):n(new Error(`${p.errorCode}: ${p.errorSummary}`))};r.once("error",l),r.once("close",o),this.lines?.on("line",c)});try{this.writeFrame(S(this.options.expectedHelperVersion,this.options.requiredCapabilities))}catch(i){throw await this.stop().catch(()=>{}),i}return s}async request(e,r,s){const i=this.requestQueueTail.catch(()=>{}).then(()=>this.sendRequest(e,r,s));return this.requestQueueTail=i.then(()=>{},()=>{}),i}async sendRequest(e,r,s){await this.guardUnsafeWindowsCommand(e,s);try{return await this.sendRawRequest(e,r,s)}finally{await this.cleanupWindowsOverlaysAfterCommand(e,s).catch(()=>{})}}async sendRawRequest(e,r,s){if((!this.hasTransport()||!this.readyState)&&await this.start(),!this.hasTransport())throw new Error("WeChat channel helper is not started");const i=R(),n=$(e),a=Date.now();this.emitRequestTrace({phase:"request",at:new Date(a).toISOString(),id:i,command:e,traceId:s,params:r,timeoutMs:n});const l=new Promise((o,c)=>{const u=setTimeout(()=>{this.pending.get(i)&&(this.pending.delete(i),this.stopAfterCommandTimeout(e).finally(()=>{c(new Error(`helper_command_timeout: ${e}`))}))},n);this.pending.set(i,{resolve:o,reject:c,timer:u})});try{this.writeFrame({id:i,command:e,params:r,traceId:s})}catch(o){const c=this.pending.get(i);throw c&&clearTimeout(c.timer),this.pending.delete(i),this.emitRequestTrace({phase:"error",at:new Date().toISOString(),id:i,command:e,traceId:s,durationMs:Date.now()-a,errorSummary:o instanceof Error?o.message:String(o)}),o}try{const o=await l;return this.emitRequestTrace({phase:"response",at:new Date().toISOString(),id:i,command:e,traceId:s,durationMs:Date.now()-a,ok:o.ok,errorCode:o.errorCode,errorSummary:o.errorSummary,latencyMs:o.latencyMs,result:o.result}),this.captureWarmupSnapshot(o),this.captureWarmupSnapshot(o.result),o}catch(o){throw this.emitRequestTrace({phase:"error",at:new Date().toISOString(),id:i,command:e,traceId:s,durationMs:Date.now()-a,errorSummary:o instanceof Error?o.message:String(o)}),o}}async guardUnsafeWindowsCommand(e,r){if(!this.options.guardUnsafeWindowsCommands||!Z(e))return;const s=await this.sendRawRequest("permissions.check",{},r);if(!s.ok)throw new Error(`${s.errorCode??"permissions_check_failed"}: ${s.errorSummary??e}`);const i=s.result??{},n=await this.requestFirstMissingMacPermissionPrompt(i,r);if(n==="screen-recording")throw new Error("permission_screen_recording_missing");if(n==="accessibility")throw new Error("permission_accessibility_missing");if(n==="input-monitoring")throw new Error("permission_input_monitoring_missing");if(i.automation===!1)throw new Error("permission_automation_missing");if(i.wechatRunning===!1)throw new Error("wechat_not_running");if(O(i))throw new Error("wechat_login_required");if(N(i))throw new Error("windows_visible_desktop_unavailable");if(i.dpiMappingAvailable===!1||i.displayTopologySupported===!1)throw new Error("dpi_mapping_failed");if(i.wechatWindowAvailable===!1)throw new Error("wechat_window_unavailable");if(i.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(!this.options.skipUserActivityGuard&&te(e)){const a=await this.sendRawRequest("activity.snapshot",{},r);if(!a.ok)throw new Error(`${a.errorCode??"user_activity_unknown"}: ${a.errorSummary??e}`);const l=x({snapshot:A(a.result),stage:"dangerous_action"});if(!l.ok)throw new Error(`user_active:${l.reasonCode}`)}await this.cleanupWindowsOverlays("before",e,r)}async requestFirstMissingMacPermissionPrompt(e,r){const s=K(e);if(!s||process.platform!=="darwin")return s;const i=Y(s);try{await this.sendRawRequest(i,{},r)}catch{}return s}async cleanupWindowsOverlaysAfterCommand(e,r){!this.options.guardUnsafeWindowsCommands||!ee(e)||await this.cleanupWindowsOverlays("after",e,r)}async cleanupWindowsOverlays(e,r,s){if(this.options.cleanupWindowsOverlays===!1)return;if(!this.readyState?.capabilities.includes("overlayCleanup"))throw new Error("helper_capability_missing: overlayCleanup");const i=await this.sendRawRequest("windows.cleanupOverlays",{stage:e,command:r,includeGeneratedMediaPreviews:!0,includeToolingTerminals:!1,waitMs:e==="after"?220:120},s);if(!i.ok)throw new Error(`${i.errorCode??"overlay_cleanup_failed"}: ${i.errorSummary??r}`)}async healthCheck(e){return this.request("health.check",{},e)}getReadyState(){return this.readyState?{...this.readyState,capabilities:[...this.readyState.capabilities]}:null}getWarmupState(){return this.warmupState?{warmState:this.warmupState.warmState,metrics:this.warmupState.metrics?{...this.warmupState.metrics}:void 0}:null}async stop(){const e=this.child,r=this.socket;this.child=null,this.socket=null,this.readyState=null,this.lines?.close(),this.lines=null,this.rejectAllPending(new Error("WeChat channel helper stopped")),r&&!r.destroyed&&r.destroy(),e&&await J(e)}hasTransport(){return!!this.child||!!this.socket}writeFrame(e){const r=`${JSON.stringify(e)}
3
+ `;if(this.socket){this.socket.write(r);return}if(this.child){this.child.stdin.write(r);return}throw new Error("WeChat channel helper is not started")}handleLine(e){let r;try{r=JSON.parse(e)}catch{return}if(!X(r))return;const s=this.pending.get(r.id);s&&(clearTimeout(s.timer),this.pending.delete(r.id),s.resolve(r))}captureWarmupSnapshot(e){const r=H(e);r&&(this.warmupState=r)}captureStderr(e){const r=Buffer.isBuffer(e)?e.toString("utf8"):String(e??"");r&&(this.stderrTail=(this.stderrTail+r).slice(-2e3))}formatHelperExitMessage(e,r){const s=[e===null?null:`code=${e}`,r?`signal=${r}`:null,this.stderrTail.trim()?`stderr=${this.stderrTail.trim()}`:null].filter(Boolean);return s.length?`WeChat channel helper process exited (${s.join(", ")})`:"WeChat channel helper process exited"}rejectAllPending(e){for(const[r,s]of this.pending)clearTimeout(s.timer),s.reject(e),this.pending.delete(r)}emitRequestTrace(e){try{this.options.requestLogger?.(e)}catch{}}async stopAfterCommandTimeout(e){await this.stop().catch(()=>{}),process.platform==="win32"&&await D().catch(()=>{}),this.emitRequestTrace({phase:"error",at:new Date().toISOString(),id:`timeout-cleanup:${e}`,command:e,errorSummary:"helper process stopped after command timeout"})}async connectDarwinHelperSocket(e){try{return await _(e.runtimeFile)}catch{f.rmSync(e.runtimeFile,{force:!0})}await W(e,{},this.options.openHelperAppForTest);const r=await T(e.runtimeFile,this.options.macosRuntimeInitialReadyTimeoutMs??5e3);if(r.ok)return r.socket;f.rmSync(e.runtimeFile,{force:!0}),await W(e,{forceNewInstance:!0},this.options.openHelperAppForTest);const s=await T(e.runtimeFile,this.options.macosRuntimeRelaunchReadyTimeoutMs??1e4);if(s.ok)return s.socket;throw new Error(`WeChat channel Helper.app socket did not become ready: ${s.error.message}`)}}async function D(){process.platform==="win32"&&await C(["taskkill","/IM",F,"/T","/F"],[0,128])}function O(t){return t.wechatWindowAvailable!==!1?!1:![...t.captureCandidates??[],...t.restoreCandidates??[],...t.hiddenRestoreCandidates??[]].some(L)}function N(t){return t.windowsVisibleDesktopAvailable===!1||t.rdpVisibleDesktopAvailable===!1||t.desktopSessionVisible===!1||t.screenLocked===!0||t.rdpDisconnected===!0}function I(t){const e=String(t.appName||"").toLowerCase();return e==="wechat"||e==="weixin"}function L(t){return!(!I(t)||t.visible===!1||t.minimized===!0)}function U(t,e,r=process.platform){if(r==="darwin"){const s=G(t);if(s&&e.length===0){const i=V();return{transport:"macos-socket",command:"/usr/bin/open",args:["-g",s,"--args","--socket-runtime",i],appPath:s,runtimeDir:i,runtimeFile:d.join(i,"runtime.json")}}}return{transport:"legacy-stdio",command:t,args:e}}function G(t){const e=d.resolve(t),r=`${d.sep}Contents${d.sep}MacOS${d.sep}`,s=e.lastIndexOf(r);if(s<0)return null;const i=e.slice(0,s);return i.endsWith(".app")?i:null}function V(){const t=j().SHENNIAN_HELPER_RUNTIME_DIR?.trim();return t?d.resolve(t):d.join(M.homedir(),"Library","Application Support","Shennian","Helper")}async function J(t){if(E(t))return;if(process.platform==="win32"&&t.pid){t.kill("SIGTERM"),await C(["taskkill","/PID",String(t.pid),"/T","/F"],[0,128]).catch(()=>{}),await y(t,m);return}t.kill("SIGTERM"),!await y(t,m)&&t.pid&&b(t.pid)&&(t.kill("SIGKILL"),await y(t,m))}function E(t){return t.exitCode!==null||t.signalCode!==null}function y(t,e){return E(t)?Promise.resolve(!0):new Promise(r=>{const s=setTimeout(()=>{t.off("exit",i),r(!1)},e),i=()=>{clearTimeout(s),r(!0)};t.once("exit",i)})}function C(t,e){return new Promise((r,s)=>{const[i,...n]=t,a=w(i,n,{stdio:"ignore",windowsHide:!0});a.once("error",s),a.once("exit",l=>{l!==null&&e.includes(l)?r():s(new Error(`${i} exited ${l}`))})})}function j(){return globalThis.process?.[q]??{}}function z(t){let e;try{e=JSON.parse(f.readFileSync(t,"utf8"))}catch(i){throw new Error(`runtime_file_unreadable: ${i instanceof Error?i.message:String(i)}`)}if(!e||typeof e!="object")throw new Error("runtime_file_invalid");const r=e.socketPath;if(typeof r!="string"||!r.trim())throw new Error("runtime_socket_missing");const s=e.pid;return{socketPath:r,...typeof s=="number"&&Number.isInteger(s)&&s>0?{pid:s}:{}}}async function _(t){const{socketPath:e,pid:r}=z(t);if(r&&!b(r))throw new Error(`runtime_process_stale: ${r}`);return new Promise((s,i)=>{const n=v.createConnection(e),a=setTimeout(()=>{n.destroy(),i(new Error(`runtime_socket_connect_timeout: ${e}`))},1e3);n.once("connect",()=>{clearTimeout(a),n.off("error",l),s(n)});const l=o=>{clearTimeout(a),n.destroy(),i(o)};n.once("error",l)})}async function T(t,e){const r=Date.now()+e;let s=null;for(;Date.now()<r;)try{return{ok:!0,socket:await _(t)}}catch(i){s=i instanceof Error?i:new Error(String(i));const n=r-Date.now();n>0&&await Q(Math.min(150,n))}return{ok:!1,error:s??new Error("runtime file missing")}}async function W(t,e={},r=B){f.mkdirSync(t.runtimeDir,{recursive:!0,mode:448});const s=e.forceNewInstance?["-n",...t.args]:t.args;try{await r(t.command,s)}catch(i){if(!(i instanceof Error?i.message:String(i)).includes("-1712"))throw i;await r(t.command,["-n",...t.args])}}function b(t){try{return process.kill(t,0),!0}catch{return!1}}async function B(t,e){await new Promise((r,s)=>{const i=w(t,e,{stdio:["ignore","ignore","pipe"],windowsHide:!0});let n="";i.stderr.on("data",a=>{n=(n+String(a)).slice(-2e3)}),i.once("error",s),i.once("exit",(a,l)=>{a===0?r():s(new Error(`open Helper.app failed (${l?`signal=${l}`:`code=${a}`}${n.trim()?`, stderr=${n.trim()}`:""})`))})})}function Q(t){return new Promise(e=>setTimeout(e,t))}function K(t){return t.screenRecording===!1?"screen-recording":t.accessibility===!1?"accessibility":t.inputMonitoring===!1?"input-monitoring":null}function Y(t){return t==="screen-recording"?"permissions.requestScreenRecording":t==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring"}function P(t){if(!t||typeof t!="object")return!1;const e=t;return e.type==="ready"&&typeof e.helperVersion=="string"&&typeof e.protocolVersion=="number"&&Array.isArray(e.capabilities)&&typeof e.pid=="number"}function X(t){if(!t||typeof t!="object")return!1;const e=t;return typeof e.id=="string"&&typeof e.ok=="boolean"&&typeof e.latencyMs=="number"}function Z(t){return t==="windows.focus"||t==="windows.capture"||t==="screen.capture"||t==="ocr.recognize"||t==="image.cropHash"||t==="wechat.searchConversation"||t==="wechat.focusMessageInput"||t==="wechat.pasteAndSubmit"||t==="keyboard.primeTextPaste"||t.startsWith("mouse.")||t.startsWith("keyboard.")||t.startsWith("clipboard.")||t==="menu.pickItem"||t==="savePanel.saveToPath"}function ee(t){return t.startsWith("mouse.")||t.startsWith("keyboard.")||t.startsWith("clipboard.")||t==="menu.pickItem"||t==="savePanel.saveToPath"}function te(t){return t==="windows.focus"||t==="wechat.searchConversation"||t==="wechat.focusMessageInput"||t==="wechat.pasteAndSubmit"||t==="keyboard.primeTextPaste"||t.startsWith("mouse.")||t.startsWith("keyboard.")||t.startsWith("clipboard.set")||t==="clipboard.restore"||t==="menu.pickItem"||t==="savePanel.saveToPath"}export{ue as WeChatChannelHelperClient,U as helperLaunchSpec,D as stopWindowsWeChatChannelHelperProcesses};
@@ -90,7 +90,7 @@ export type WeChatChannelHumanActivitySnapshot = {
90
90
  capturesMousePath?: boolean;
91
91
  };
92
92
  };
93
- export type WeChatChannelHelperCommandName = 'health.check' | 'processes.list' | 'permissions.check' | 'permissions.requestScreenRecording' | 'permissions.requestAccessibility' | 'permissions.requestInputMonitoring' | 'activity.snapshot' | 'automation.lease.acquire' | 'automation.lease.release' | 'automation.lease.status' | 'automation.lease.simulateInterruption' | 'windows.ensureReady' | 'windows.list' | 'windows.enumerateRaw' | 'windows.focus' | 'windows.capture' | 'windows.captureAndOcr' | 'windows.cleanupOverlays' | 'windows.recoverWeChat' | 'screen.capture' | 'ocr.recognize' | 'mouse.click' | 'mouse.rightClick' | 'mouse.scroll' | 'keyboard.type' | 'keyboard.shortcut' | 'clipboard.snapshot' | 'clipboard.restore' | 'clipboard.setText' | 'clipboard.setFiles' | 'clipboard.setImage' | 'clipboard.readFileUrls' | 'clipboard.readAttachment' | 'menu.pickItem' | 'savePanel.saveToPath' | 'image.cropHash' | 'wechat.searchConversation' | 'wechat.focusMessageInput';
93
+ export type WeChatChannelHelperCommandName = 'health.check' | 'processes.list' | 'permissions.check' | 'permissions.requestScreenRecording' | 'permissions.requestAccessibility' | 'permissions.requestInputMonitoring' | 'activity.snapshot' | 'automation.lease.acquire' | 'automation.lease.release' | 'automation.lease.status' | 'automation.lease.simulateInterruption' | 'windows.ensureReady' | 'windows.list' | 'windows.enumerateRaw' | 'windows.focus' | 'windows.capture' | 'windows.captureAndOcr' | 'windows.cleanupOverlays' | 'windows.recoverWeChat' | 'screen.capture' | 'ocr.recognize' | 'mouse.click' | 'mouse.rightClick' | 'mouse.scroll' | 'keyboard.type' | 'keyboard.shortcut' | 'keyboard.primeTextPaste' | 'clipboard.snapshot' | 'clipboard.restore' | 'clipboard.setText' | 'clipboard.setFiles' | 'clipboard.setImage' | 'clipboard.readFileUrls' | 'clipboard.readAttachment' | 'menu.pickItem' | 'savePanel.saveToPath' | 'image.cropHash' | 'wechat.searchConversation' | 'wechat.focusMessageInput' | 'wechat.pasteAndSubmit';
94
94
  export type WeChatChannelHelperCommand = {
95
95
  id: string;
96
96
  command: WeChatChannelHelperCommandName;
@@ -126,6 +126,12 @@ export declare function selectWeChatWindowForBinding(options: HelperBackedObserv
126
126
  foregroundMode?: WeChatChannelForegroundMode;
127
127
  forceVision?: boolean;
128
128
  }): Promise<WeChatChannelWindowInfo>;
129
+ export declare function detectWeChatMessageInputPointByServerVision(input: HelperBackedObserveOptions & {
130
+ window: WeChatChannelWindowInfo;
131
+ }): Promise<WeChatChannelScreenPoint>;
132
+ export declare function detectWeChatSearchInputPointByServerVision(input: HelperBackedObserveOptions & {
133
+ window: WeChatChannelWindowInfo;
134
+ }): Promise<WeChatChannelScreenPoint>;
129
135
  export declare function ensureHelperPreflight(helper: WeChatChannelHelperTransport, traceId?: string): Promise<void>;
130
136
  export declare function ensureHelperPermissionPreflight(helper: WeChatChannelHelperTransport, traceId?: string): Promise<void>;
131
137
  export declare function ensureWeChatWindowReady(helper: WeChatChannelHelperTransport, traceId?: string, options?: {
@@ -149,6 +155,9 @@ export declare function openConversationBySearch(input: {
149
155
  helper: WeChatChannelHelperTransport;
150
156
  window: WeChatChannelWindowInfo;
151
157
  binding: WeChatChannelBindingConfig;
158
+ runtime?: WeChatChannelRuntime;
159
+ api?: WeChatChannelObserveApi;
160
+ workDir?: string;
152
161
  traceId?: string;
153
162
  searchDelayMs?: number;
154
163
  settleToBottom?: boolean;
@@ -156,7 +165,6 @@ export declare function openConversationBySearch(input: {
156
165
  opened: boolean;
157
166
  reason: string;
158
167
  }>;
159
- export declare function fallbackWeChatMessageInputPointForWindow(window: WeChatChannelWindowInfo): WeChatChannelScreenPoint | null;
160
168
  export declare function captureWeChatWindow(helper: WeChatChannelHelperTransport, windowId: string, traceId?: string, bounds?: WeChatChannelWindowInfo['bounds']): Promise<WeChatChannelScreenshotWithData>;
161
169
  export declare function captureAndRecognizeWeChatWindow(helper: WeChatChannelHelperTransport, windowId: string, traceId?: string, bounds?: WeChatChannelWindowInfo['bounds']): Promise<WeChatChannelWindowObservation>;
162
170
  export declare function recognizeWeChatScreenshot(helper: WeChatChannelHelperTransport, screenshot: WeChatChannelScreenshotWithData, traceId?: string): Promise<WeChatChannelOcrResult>;
@@ -1,6 +1,7 @@
1
- import{defaultWeChatChannelAttachmentDir as _e,resolveVisibleWeChatChannelMedia as Me}from"./media-resolver.js";import{updateWeChatChannelBindingLedger as Se}from"./ledger.js";import{defaultWeChatChannelVectorStorePath as Ne,loadWeChatChannelVectorStore as Te,saveWeChatChannelVectorStore as Be,upsertWeChatChannelVectorReferences as Ee}from"./vector-store.js";import{normalizeWeChatChannelAttachmentAvailability as H,normalizeWeChatChannelMessageKind as We}from"./core/schema.js";import{waitForWeChatChannelPacing as U,weChatChannelPacingDelayMs as Re}from"./pacing.js";import{matchWeChatConversationFingerprints as Fe}from"./fingerprint.js";import{normalizeWeChatAnchorText as x,weChatTextSimilarity as Y}from"./anchor.js";import{decideWeChatChannelActivityGate as Ae,normalizeWeChatChannelActivitySnapshot as Oe}from"./human-coordination.js";const Le=3,Pe=5,De="wechat_login_required",Ke=5500;class S extends Error{reasonCode;stage;action;constructor(t){super(`user_active:${t.reasonCode}:${t.stage}:${t.action}`),this.name="WeChatChannelUserActivityAbort",this.reasonCode=t.reasonCode,this.stage=t.stage,this.action=t.action}}async function sn(e){return await je(e.helper,e.activityGuard,e.traceId).withLease("observe","observe-binding",async n=>$e({...e,helper:n}))}async function $e(e){const t=e.foregroundMode??"required";let n=await ze(e,{foregroundMode:t});if(t!=="background"&&(n=await ue(e.helper,n,e.traceId)),t==="background"){const{capture:a,ocr:s}=await I({helper:e.helper,window:n,traceId:e.traceId}),c=T({capture:a,ocr:s,window:n});if(c)throw new Error(c);if(!A(s,a,e.binding.conversationDisplayName))throw new Error("conversation_not_visible_background");if(V({capture:a,ocr:s,binding:e.binding}))throw new Error("wechat_window_obstructed_background");return e.onObservationEvidence?.({window:n,capture:a,ocr:s}),Z(e)?Q({...e,window:n,capture:a,ocr:s}):L({...e,window:n,capture:a,ocr:s})}const r=await D({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId});if(!r.opened){const a=await X({...e,fallback:n,requireTargetConversation:!1,force:!0});if(a.windowId!==n.windowId){n=await ue(e.helper,a,e.traceId);const s=await D({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId});if(!s.opened)throw new Error(s.reason||r.reason||"conversation_not_opened")}else throw new Error(r.reason||"conversation_not_opened")}let{capture:i,ocr:o}=await I({helper:e.helper,window:n,traceId:e.traceId});if(V({capture:i,ocr:o,binding:e.binding})){n=await It(e.helper,e.traceId);const a=await D({helper:e.helper,window:n,binding:e.binding,traceId:e.traceId});if(!a.opened)throw new Error(a.reason||"wechat_window_obstructed");if({capture:i,ocr:o}=await I({helper:e.helper,window:n,traceId:e.traceId}),V({capture:i,ocr:o,binding:e.binding}))throw new Error("wechat_window_obstructed")}return e.onObservationEvidence?.({window:n,capture:i,ocr:o}),Z(e)?Q({...e,window:n,capture:i,ocr:o}):L({...e,window:n,capture:i,ocr:o})}async function ze(e,t={}){const n=t.foregroundMode??e.foregroundMode??"required",r=await Ct(e.helper,e.traceId,{foreground:n});return n==="background"?r:X({...e,fallback:r,requireTargetConversation:!1,force:t.forceVision})}async function X(e){if(!e.api.classifyWindow)throw new Error("wechat_window_classifier_unavailable");const t=await e.helper.request("windows.list",{},e.traceId);b(t,"windows.list");const n=(t.result?.windows??[]).filter(z).filter(a=>a.visible!==!1&&a.minimized!==!0&&!!a.windowId),r=qe(n.length?n:[e.fallback],e.fallback);if(!r.length)throw new Error("wechat_window_not_found");const i=[];for(const a of r)try{const s=await K(e.helper,a.windowId,e.traceId,a.bounds),c=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:s.mimeType,dataBase64:s.dataBase64,width:s.width,height:s.height,windowId:a.windowId},traceId:e.traceId});i.push({window:a,classification:c,score:Ve(c,e.requireTargetConversation===!0)})}catch{i.push({window:a,classification:null,score:-1})}const o=i.filter(a=>a.score>0).sort((a,s)=>s.score-a.score)[0];if(!o)throw new Error("wechat_chat_main_window_not_found");return o.window}function qe(e,t){const n=[],r=i=>{i?.windowId&&(n.some(o=>o.windowId===i.windowId)||n.push(i))};r(e.find(i=>i.windowId===t.windowId));for(const i of e)r(i);return n}function Ve(e,t){if(!e||e.windowKind!=="chat_main")return 0;const n=Number(e.confidence??0);return t&&e.isTargetConversation!==!0?0:100+(e.isTargetConversation?50:0)+Math.round(Math.max(0,Math.min(1,n))*100)}function je(e,t,n){if(!t)return{helper:e,withLease:async(s,c,l)=>await l(e)};let r=null;const i=s=>{t.onEvent?.({...s,at:new Date().toISOString()})},o=async(s,c,l={})=>{if(r){const u=await e.request("automation.lease.status",{},n),d=u.result??{},f=u.ok&&d.interrupted?J(d.interruptReason):u.ok?void 0:u.errorCode||"user_activity_unknown";if(i({phase:"lease-status",stage:s,action:c,ok:u.ok===!0&&!d.interrupted,...f?{reasonCode:f}:{}}),!u.ok)throw new S({reasonCode:u.errorCode||"user_activity_unknown",stage:s,action:c});if(d.active===!1||d.leaseId!==r||!d.interrupted)return;throw new S({reasonCode:J(d.interruptReason),stage:s,action:c})}const w=Date.now()+He(t.preflightIdleSettleTimeoutMs);for(;;){const u=await e.request("activity.snapshot",{},n);if(!u.ok)throw i({phase:"snapshot",stage:s,action:c,ok:!1,reasonCode:u.errorCode||"user_activity_unknown"}),new S({reasonCode:u.errorCode||"user_activity_unknown",stage:s,action:c});const d=Ae({snapshot:Oe(u.result),stage:s,policy:t.policy});if(i({phase:"snapshot",stage:s,action:c,ok:d.ok,...d.ok?{}:{reasonCode:d.reasonCode,waitMs:d.waitMs}}),d.ok)return;const f=new S({reasonCode:d.reasonCode,stage:s,action:c});if(!l.settle)throw f;const G=w-Date.now();if(G<=0)throw f;await q(Math.max(50,Math.min(d.waitMs,G)))}},a={request:async(s,c,l)=>{const w=Ge(s);w&&await o(w.stage,`${s}:before`);const u=await e.request(s,c,l);return w&&u.ok&&await o(w.stage,`${s}:after`),u}};return{helper:a,async withLease(s,c,l){if(await yt(e,n),await o(s,`${c}:preflight`,{settle:!0}),t.useAutomationLease===!1)return await l(a);const w=await e.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`observe:${c}`,ttlMs:12e4},n);if(r=typeof w.result?.leaseId=="string"?w.result.leaseId:null,i({phase:"lease-acquire",stage:s,action:c,ok:w.ok===!0,...w.ok?{}:{reasonCode:w.errorCode||"user_activity_unknown"}}),!w.ok)throw r=null,new S({reasonCode:w.errorCode||"user_activity_unknown",stage:s,action:c});try{const u=await l(a);return await o(s,`${c}:complete`),u}finally{const u=r;if(r=null,u){const d=await e.request("automation.lease.release",{leaseId:u},n).catch(f=>({ok:!1,errorCode:"automation_lease_release_failed",errorSummary:f instanceof Error?f.message:String(f)}));i({phase:"lease-release",stage:s,action:c,ok:d.ok===!0,...d.ok?{}:{reasonCode:d.errorCode||"automation_lease_release_failed"}})}}}}}function Ge(e){return e==="windows.ensureReady"||e==="windows.focus"||e==="wechat.searchConversation"?{stage:"open_conversation"}:e==="keyboard.shortcut"||e==="mouse.click"||e==="mouse.rightClick"||e==="mouse.scroll"||e==="clipboard.snapshot"||e==="clipboard.readAttachment"||e==="menu.pickItem"?{stage:"dangerous_action"}:null}function J(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function He(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:Ke}function Z(e){return e.observePipeline==="edge-structure"?!0:e.observePipeline==="server-observe"?!1:!!e.api.structureWindow}async function L(e){const t=await fe(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 re({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 pe(r,ve({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}))}async function Q(e){if(!e.api.structureWindow)throw new Error("wechat_structure_window_unavailable");const t=await fe(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(Ue(c))return L(e);throw c}const r=rt(n.structuredMessages??n.observedMessages??[]),i=await Ye({...e,messages:r,screenshot:t}),o=await re({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=pe(o,ve({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}));return e.localLedger?Se({ledger:e.localLedger,bindingId:e.binding.bindingId,observedMessages:a,baselineOnly:e.baselineOnly,vectorReferences:i.vectorReferences}).newMessages:a}function Ue(e){return e instanceof Error&&/\bedge_runtime_disabled\b/.test(e.message)}async function Ye(e){const t=Xe(e.messages);if(!t.length)return{messages:e.messages,vectorReferences:[]};const n=e.api.embedVisual?await Ze({...e,seedBlocks:t}):t.filter(a=>h(a.vectorBase64)||h(a.signature));if(!n.length)return{messages:e.messages,vectorReferences:[]};const r=e.vectorStorePath??Ne(e.workDir||process.cwd(),e.runtime.runtimeId),i=Te(r,e.runtime.runtimeId),o=Ee({store:i,bindingId:e.binding.bindingId,blocks:n});return o.length?(Be(r,i),{messages:tt(e.messages,o),vectorReferences:o}):{messages:e.messages,vectorReferences:[]}}function Xe(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 Je(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 et(t.visualBlocks??t.embeddedBlocks??[],e.seedBlocks)}async function Ze(e){try{return await Je(e)}catch(t){if(Qe(t))throw t;return[]}}function Qe(e){return!e||typeof e!="object"?!1:e.reasonCode==="insufficient_credits"?!0:e instanceof Error&&/\binsufficient_credits\b/.test(e.message)}function et(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 tt(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:nt(r,i)}:r})}function nt(e,t){const r=(e.visualBlocks??[]).map((o,a)=>{const s=h(o.blockId)||`${e.stableMessageKey}:visual-${a}`,c=t.find(l=>l.blockId===s);return c?ee(c,o):te(o)}),i=new Set(r.map(o=>o.blockId));for(const o of t)i.has(o.blockId)||r.push(ee(o));return r}function ee(e,t){return{...t?te(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 te(e){const{vectorBase64:t,...n}=e;return n}function rt(e){return e.map((t,n)=>it(t,n)).filter(t=>t!=null)}function it(e,t){if(!m(e))return null;const n=We(e.kind),r=st(e.senderRole),i=g(e.normalizedText),o=g(e.anchorText)??i??g(e.textExcerpt),a=h(e.stableMessageKey)||ot({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}:{},...C(e,"anchorMetadata")?{anchorMetadata:e.anchorMetadata}:{},...C(e,"neighborContext")?{neighborContext:e.neighborContext}:{},...g(e.textExcerpt)!==null?{textExcerpt:g(e.textExcerpt)}:{},...C(e,"bbox")?{bbox:e.bbox}:{},...C(e,"mediaMetadata")?{mediaMetadata:at(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 ot(e){const t=m(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 at(e){if(!m(e))return e;const t={...e};return C(t,"availability")&&(t.availability=H(t.availability)),m(t.attachment)&&(t.attachment=ne(t.attachment)),Array.isArray(t.attachments)&&(t.attachments=t.attachments.map(n=>m(n)?ne(n):n)),t}function ne(e){const t={...e};return C(t,"availability")&&(t.availability=H(t.availability)),t}function st(e){return e==="self"||e==="contact"||e==="system"||e==="unknown"?e:"unknown"}async function re(e){if(e.binding.downloadMedia===!1)return e.messages;const t=e.messages.map((o,a)=>ft(o,e.screenshot,e.window,ht(e.messages,a))).filter((o,a)=>ct(e.messages,a,e.mediaAnchorText)).filter(o=>o!=null);if(!t.length)return e.messages;const n=e.attachmentsDir??_e(e.workDir||process.cwd(),e.runtime.runtimeId,e.binding.bindingId),r=await Me({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 M({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:bt(o.mediaMetadata,a.attachment,a.reasonCode,a.attemptReasonCodes,a.resolveTrace)}:o})}function ct(e,t,n){const r=oe(n);if(!r)return!0;const i=dt(r),o=e.map((a,s)=>oe(wt(a)).includes(r)?s:-1).filter(a=>a>=0);if(!o.length)return t===lt(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(ie))return!0;return!1}function dt(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 lt(e,t=null){for(let n=e.length-1;n>=0;n-=1)if(ie(e[n]))return ut(e[n],t)?n:-1;return-1}function ie(e){if(!e)return!1;const t=String(e.kind||"").toLowerCase(),n=m(e.mediaMetadata)?e.mediaMetadata:{},r=m(n.attachment)?n.attachment:{};return ae(t,n,r)}function ut(e,t){if(!e||!t)return!0;const n=String(e.kind||"").toLowerCase(),r=m(e.mediaMetadata)?e.mediaMetadata:{},i=m(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 wt(e){if(!e)return"";const t=e;return[e.normalizedText,e.anchorText,e.textExcerpt,t.text].map(n=>String(n||"")).join(`
2
- `)}function oe(e){return String(e||"").normalize("NFKC").replace(/[o]/giu,"0").replace(/[^\p{L}\p{N}]/gu,"").toLowerCase()}function ht(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 ft(e,t,n,r){const i=String(e.kind||"").toLowerCase(),o=m(e.mediaMetadata)?e.mediaMetadata:{},a=m(o.attachment)?o.attachment:{},s=h(a.availability)||h(o.availability),c=h(a.localPath)||h(o.localPath);if(s==="edge-local"&&c||!ae(i,o,a))return null;const l=W(e.bbox)??W(o.bbox)??W(o.downloadActionBbox),w=W(o.downloadActionBbox),u=se(l,t,n),d=gt(l,t,n),f=se(w,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:k(a.size)??k(o.size),mediaStatus:mt(o,a),observedAt:e.observedAt??null,contextText:r??e.normalizedText??e.anchorText??e.textExcerpt??null,...u?{bbox:u}:{},...d?{screenshotBbox:d}:{},...f?{downloadActionBbox:f}:{}}}function bt(e,t,n,r,i){const o=m(e)?{...e}:{};return{...o,availability:m(t)?t.availability:o.availability,mediaStatus:m(t)&&t.availability==="edge-local"?"downloaded":o.mediaStatus,attachment:t,edgeResolveReasonCode:n,...r?.length?{edgeResolveAttempts:r}:{},...i?{edgeResolveTrace:i}:{}}}function mt(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 ae(e,t,n){const r=`${e} ${h(t.messageType)} ${h(n.type)} ${h(n.kind)}`.toLowerCase();return/image|photo|video|file|document/.test(r)}function W(e){if(!m(e))return null;const t=k(e.x),n=k(e.y),r=k(e.width),i=k(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 se(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 gt(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 m(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function C(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 k(e){const t=Number(e);return Number.isFinite(t)?t:null}async function cn(e,t){await de(e,t)}async function yt(e,t){await ce(e,t)}async function ce(e,t){const n=await e.request("permissions.check",{},t);b(n,"permissions.check");const r=n.result??{},i=await xt(e,r,t);if(i==="screen-recording")throw new Error("permission_screen_recording_missing");if(i==="accessibility")throw new Error("permission_accessibility_missing");if(i==="input-monitoring")throw new Error("permission_input_monitoring_missing");if(r.automation===!1)throw new Error("permission_automation_missing");return r}async function de(e,t,n={}){const r=await ce(e,t);if(r.wechatRunning===!1)throw new Error("wechat_not_running");if(kt(r))throw new Error("windows_visible_desktop_unavailable");if(r.dpiMappingAvailable===!1||r.displayTopologySupported===!1)throw new Error("dpi_mapping_failed");if(r.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(r.wechatWindowAvailable===!1&&String(r.platform??"").toLowerCase()!=="win32"&&n.allowUnavailableWindow!==!0)throw new Error("wechat_window_unavailable");return r}async function xt(e,t,n){const r=vt(t);if(!r||process.platform!=="darwin")return r;const i=pt(r);try{await e.request(i,{},n)}catch{}return r}function vt(e){return e.screenRecording===!1?"screen-recording":e.accessibility===!1?"accessibility":e.inputMonitoring===!1?"input-monitoring":null}function pt(e){return e==="screen-recording"?"permissions.requestScreenRecording":e==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring"}async function Ct(e,t,n={}){const i=(n.foreground??"required")!=="background",o=await de(e,t,{allowUnavailableWindow:i});if(String(o.platform??"").toLowerCase()==="win32"){const c=await e.request("windows.ensureReady",{activate:i,allowRecovery:!1,allowLaunch:!1},t);b(c,"windows.ensureReady");const l=c.result;if(!l?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return l}const a=await e.request("windows.ensureReady",{restore:i,focus:i},t);b(a,"windows.ensureReady");const s=a.result;if(!s?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return s}function kt(e){return e.windowsVisibleDesktopAvailable===!1||e.rdpVisibleDesktopAvailable===!1||e.desktopSessionVisible===!1||e.screenLocked===!0||e.rdpDisconnected===!0}function le(e){const t=e.filter(z),n=t.filter(i=>i.visible!==!1&&i.minimized!==!0);return(n.length?n:t)[0]??null}async function dn(e,t){let n=await e.request("windows.list",{},t);b(n,"windows.list");let r=n.result?.windows??[],i=le(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return b(o,"windows.focus"),await we(e,i,t)}async function ue(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 b(r,"windows.focus"),t}async function It(e,t){const n=await e.request("windows.list",{},t);b(n,"windows.list");const r=n.result?.windows??[],i=le(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return b(o,"windows.focus"),await we(e,i,t)}async function we(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(z);return i.find(o=>o.windowId===t.windowId)??i[0]??t}async function P(e){const{capture:t,ocr:n}=e.observation??await I(e),r=T({capture:t,ocr:n,window:e.window});if(r)return{opened:!1,reason:r};const i=Fe({visibleItems:Ft(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=Xt(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 b(a,"mouse.click"),{opened:!0,reason:i.reason}}async function D(e){let t={opened:!1,reason:"conversation_not_opened"};for(let r=0;r<Le;r+=1){if(t=await _t(e),t.opened||t.reason!=="conversation_title_not_confirmed")return t;await _(e,"open-retry",`retry:${r}`)}const n=await he(e);return n.opened?{opened:!0,reason:`${n.reason}:final-visible-recovery`}:t}async function _t(e){const t=await I(e),n=T({capture:t.capture,ocr:t.ocr,window:e.window});if(n)return{opened:!1,reason:n};let r=!1;if(A(t.ocr,t.capture,e.binding.conversationDisplayName))return e.settleToBottom===!0&&await N({helper:e.helper,window:e.window,traceId:e.traceId,observation:t}),{opened:!0,reason:"current-conversation-title-confirmed"};if(!r){const u=await P({...e,observation:t});if(u.opened){if(await _(e,"open-click-settle","visible-initial"),(await M(e)).ok)return{opened:!0,reason:u.reason};const f=await he(e);if(f.opened)return f}}const i=Et(e,t),o=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??R(e,"search-input-settle","search-input"),...i?{searchPoint:i}:{}},e.traceId);b(o,"wechat.searchConversation");const a=await Mt(e);if(a.opened){await _(e,"open-click-settle","search-result-click");const u=await M(e);return u.ok?(e.settleToBottom===!0&&await N({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:a.reason}):{opened:!1,reason:u.reason}}let s=a.observation;const c=y(e.binding.conversationDisplayName)&&a.reason==="search_result_not_visible";if(!y(e.binding.conversationDisplayName)){await Rt(e.helper,e.traceId),await _(e,"open-click-settle","search-return");const u=await M(e);if(u.ok)return e.settleToBottom===!0&&await N({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:u.reason};const d=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??R(e,"search-input-settle","search-input-retry-after-return"),...i?{searchPoint:i}:{}},e.traceId);b(d,"wechat.searchConversation"),s=void 0}const l=await P({...e,...s?{observation:s}:{},allowOcrTitleRows:!c});if(!l.opened)return l;await _(e,"open-click-settle","visible-final");const w=await M(e);return w.ok?(e.settleToBottom===!0&&await N({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:l.reason}):{opened:!1,reason:w.reason}}async function he(e){const t=await P(e);if(!t.opened)return t;await _(e,"open-click-settle","visible-retry");const n=await M(e);return n.ok?(e.settleToBottom===!0&&await N({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:`${t.reason}:retry-visible-title-confirmed`}):{opened:!1,reason:n.reason}}function ln(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 Mt(e){let t;const n=e.searchDelayMs===0?0:R(e,"search-result-probe","search-result-probe"),r=y(e.binding.conversationDisplayName)?Pe:1;for(let i=0;i<r;i+=1){i>0&&n>0&&await q(n);const o=await St(e);t=o;const{capture:a,ocr:s}=o,c=T({capture:a,ocr:s,window:e.window});if(c)return{opened:!1,reason:c,observation:o};const l=Lt(s,a,e.binding.conversationDisplayName);if(!l){if(Pt(s)||Dt(s,e.binding.conversationDisplayName))break;continue}const w=B(l.bbox,a,Nt(a,e.window));if(!w)return{opened:!1,reason:"search_result_bbox_missing",observation:o};const u=await e.helper.request("mouse.click",{x:w.x,y:w.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return b(u,"mouse.click"),{opened:!0,reason:l.reason,observation:o}}return{opened:!1,reason:"search_result_not_visible",observation:t}}async function St(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 be(e.helper,n,e.traceId);return{capture:n,ocr:r}}t.errorCode&&t.errorCode!=="helper_unknown_command"&&t.errorCode!=="helper_command_unsupported"&&b(t,"screen.capture")}return I(e)}function Nt(e,t){return e.bounds?{...t,bounds:e.bounds}:t}async function I(e){let{capture:t,ocr:n}=await $(e.helper,e.window.windowId,e.traceId,e.window.bounds);return await Tt({helper:e.helper,window:e.window,capture:t,ocr:n,traceId:e.traceId})&&(await U("preview-dismiss-settle",`${e.traceId||""}:${e.window.windowId}:preview-dismiss`),{capture:t,ocr:n}=await $(e.helper,e.window.windowId,e.traceId,e.window.bounds)),{capture:t,ocr:n}}async function Tt(e){const t=Bt(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 Bt(e,t,n){const r=e.blocks??[],i=r.find(c=>{const l=String(c.text||""),w=c.bbox;if(!w)return!1;const u=Number(w.x),d=Number(w.y);return Number.isFinite(u)&&Number.isFinite(d)&&d>t.height*.06&&d<t.height*.22&&u>t.width*.3&&/查看原视频|查看原图|原视频|原图|视频|图片|图像/.test(l)});if(!i)return null;const o=i.bbox,a=Number(o?.y);if(!Number.isFinite(a))return null;const s=r.filter(c=>{const l=String(c.text||"").trim(),w=c.bbox;if(!w||l!=="\xD7")return!1;const u=Number(w.x),d=Number(w.y);return Number.isFinite(u)&&Number.isFinite(d)&&u>t.width*.55&&u<t.width*.9&&Math.abs(d-a)<t.height*.08}).sort((c,l)=>Number(l.bbox?.x??0)-Number(c.bbox?.x??0))[0];return B(s?.bbox,t,n)}function Et(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),l=Number(s.y);return Number.isFinite(c)&&Number.isFinite(l)&&c<n.width*.22&&l<n.height*.12});return B(i?.bbox,n,e.window)}async function K(e,t,n,r){const i=await e.request("windows.capture",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);b(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 fe(e){return e.capture.dataBase64?e.capture:K(e.helper,e.window.windowId,e.traceId,e.window.bounds)}async function $(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"&&b(i,"windows.captureAndOcr");const o=await K(e,t,n,r),a=await be(e,o,n);return{capture:o,ocr:a}}async function be(e,t,n){const r=await e.request("ocr.recognize",{mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height},n);return b(r,"ocr.recognize"),r.result??{}}function b(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}function z(e){const t=String(e.appName||"").toLowerCase();return t==="wechat"||t==="weixin"}function q(e){return new Promise(t=>setTimeout(t,e))}function R(e,t,n){return e.searchDelayMs===0?0:Re(t,Wt(e,n))}async function _(e,t,n){const r=R(e,t,n);r>0&&await q(r)}function Wt(e,t){return`${e.traceId||""}:${e.binding.conversationDisplayName}:${t}`}async function Rt(e,t){const n=await e.request("keyboard.shortcut",{key:"return",modifiers:[]},t);b(n,"keyboard.shortcut")}async function N(e){if(!e.window.bounds)return;const t=e.observation,n=Jt(t?.ocr,t?.capture,e.window);if(n){const r=await e.helper.request("mouse.click",{x:n.x,y:n.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);b(r,"mouse.click"),await U("jump-latest-settle",`${e.traceId||""}:${e.window.windowId}:jump-latest`)}}async function M(e){const{capture:t,ocr:n}=await $(e.helper,e.window.windowId,e.traceId,e.window.bounds),r=T({capture:t,ocr:n,window:e.window});return r?{ok:!1,reason:r}:A(n,t,e.binding.conversationDisplayName)?{ok:!0,reason:"target-conversation-title-confirmed"}:{ok:!1,reason:"conversation_title_not_confirmed"}}function T(e){const n=(e.ocr.blocks??[]).map(r=>$t(r.text)).filter(Boolean).join("");return/(扫码登录|仅传输文件|重新登录|为了安全|安全验证|登录微信|微信登录|该账号已登录|帐号已登录|账号已登录|当前账号已登录|当前帐号已登录|已登录|进入微信|進入微信)/u.test(n)?De:null}function Ft(e,t,n=!0){const r=n?At(e.blocks??[],t):[];return r.length?r:e.visibleConversationFingerprints??[]}function At(e,t){const n=e.map(i=>me(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=>!ge(i.text)),r=new Set;return n.filter(i=>!Ot(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=E(i.title);return!o||r.has(o)?!1:(r.add(o),!0)})}function me(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 Ot(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 ge(e){const t=v(e);return/^(搜索|微信|通讯录|收藏|设置|文件传输助手|search)$/iu.test(t)||F(t)||Kt(t)||/^包含[::]?/u.test(t)||/搜索网络结果/u.test(t)}function Lt(e,t,n){const r=(e.blocks??[]).map(s=>me(s)).filter(s=>!!s),i=r.filter(s=>F(v(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(d=>v(d.text)===s);if(c<0)continue;const l=i[c],w=i[c+1]?.y??Number.POSITIVE_INFINITY,u=r.filter(d=>d.y>l.y&&d.y<w).filter(d=>d.x<t.width*.7).filter(d=>d.text.length>=2).filter(d=>!F(v(d.text))).filter(d=>!xe(d,r)).filter(d=>j(d.text,n)).sort((d,f)=>d.y-f.y||d.x-f.x)[0];if(u)return{bbox:ye(u,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=>!ge(s.text)).filter(s=>!xe(s,r)).filter(s=>j(s.text,n)).sort((s,c)=>s.y-c.y||s.x-c.x)[0];return y(n)?null:a?{bbox:ye(a,t),reason:"search-result-title"}:null}function ye(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 F(e){return/^(群聊|联系人|聊天记录|公众号|小程序|GroupChats|Contacts|ChatHistory|OfficialAccounts|MiniPrograms)$/u.test(e)}function Pt(e){return(e.blocks??[]).some(t=>F(v(t.text)))}function Dt(e,t){return(e.visibleConversationFingerprints??[]).some(n=>j(n.title,t))}function v(e){return String(e||"").normalize("NFKC").replace(/[^\p{L}\p{N}_-]/gu,"").trim()}function xe(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 Kt(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 $t(e){return String(e||"").normalize("NFKC").replace(/\s+/g,"").trim()}function A(e,t,n){const r=y(n)?E(n):O(n);return r?(e.blocks??[]).some(i=>{const o=y(n)?E(i.text):O(i.text);if(!o||!Ce(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 l=s>t.width*.32&&s<t.width*.78&&c<t.height*.16,w=s<t.width*.18&&c<t.height*.12;return l||w}):!1}function V(e){if(A(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 l=Array.isArray(c.source)?c.source.some(w=>c.pattern.test(w)):c.pattern.test(c.source);return s+(l?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
- `);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)&&zt(e.capture,e.ocr)?!0:((e.ocr.visibleConversationFingerprints??[]).some(s=>{const c=y(e.binding.conversationDisplayName)?E(s.title):O(s.title),l=y(e.binding.conversationDisplayName)?E(e.binding.conversationDisplayName):O(e.binding.conversationDisplayName);return!!(c&&l&&Ce(c,l))}),!1)}function zt(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 ve(e){const t=e.anchors.map(o=>({...o,normalized:x(o.expectedEchoAnchor)})).filter(o=>o.normalized);if(!t.length)return[];const n=[],r=new Set,i=qt(e.ocr,e.screenshot).sort((o,a)=>x(a.text).length-x(o.text).length);for(const o of i){const a=x(o.text);if(!a)continue;const s=t.find(l=>Vt(l.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 qt(e,t){const n=(e.blocks??[]).filter(i=>Yt(i,t)&&x(i.text)).sort((i,o)=>p(i.bbox,"y")-p(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(!jt(o[o.length-1],s,t))break;o.push(s),r.push({text:Gt(o.map(c=>String(c.text||"").trim())),bbox:Ut(o.map(c=>c.bbox))})}}return r}function Vt(e,t){if(!e||!t)return!1;if(Y(e,t)>=.88)return!0;const n=e.replace(/\s+/g,""),r=t.replace(/\s+/g,"");return r.length>=8&&n.includes(r)}function jt(e,t,n){const r=p(e.bbox,"x"),i=p(e.bbox,"y"),o=p(e.bbox,"height"),a=p(t.bbox,"x"),s=p(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 Gt(e){return e.reduce((t,n)=>t?n?`${t}${Ht(t,n)?" ":""}${n}`:t:n,"")}function Ht(e,t){return/[A-Za-z0-9]$/u.test(e)&&/^[A-Za-z0-9]/u.test(t)}function Ut(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 p(e,t){const n=Number(e?.[t]);return Number.isFinite(n)?n:Number.NaN}function pe(e,t){if(!t.length)return e;const n=[...e];for(const r of t){const i=x(r.anchorText||r.normalizedText||r.textExcerpt);n.some(a=>{if(a.senderRole!=="self")return!1;const s=x(a.anchorText||a.normalizedText||a.textExcerpt);return s&&i&&Y(s,i)>=.9})||n.push(r)}return n}function Yt(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 Xt(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,l=t.width&&n.bounds?.width?t.width/n.bounds.width:1,w=t.height&&n.bounds?.height?t.height/n.bounds.height:l,u={x:i+Math.min(a*.35,110*l),y:o+Math.min(s-8*w,Math.max(18*w,s/2))};if(c==="screen"||!n.bounds)return u;const d=Math.max(0,(t.width-n.bounds.width*l)/2),f=Math.max(0,(t.height-n.bounds.height*w)/2);return{x:n.bounds.x+(u.x-d)/l,y:n.bounds.y+(u.y-f)/w}}function 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,l={x:i+a/2,y:o+s/2};if(c==="screen"||!n.bounds)return l;const w=t.width&&n.bounds.width?t.width/n.bounds.width:1,u=t.height&&n.bounds.height?t.height/n.bounds.height:w,d=Math.max(0,(t.width-n.bounds.width*w)/2),f=Math.max(0,(t.height-n.bounds.height*u)/2);return{x:n.bounds.x+(l.x-d)/w,y:n.bounds.y+(l.y-f)/u}}function Jt(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 Ce(e,t){return y(t)?Ie(e,t):e===t||e.includes(t)||t.includes(e)}function j(e,t){if(y(t))return Ie(e,t);const n=ke(v(e)),r=ke(v(t));return!n||!r?!1:n===r?!0:n.replace(/\d+$/u,"")===r}function ke(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 E(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 Ie(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{S as WeChatChannelUserActivityAbort,$ as captureAndRecognizeWeChatWindow,K as captureWeChatWindow,yt as ensureHelperPermissionPreflight,cn as ensureHelperPreflight,Ct as ensureWeChatWindowReady,ln as fallbackWeChatMessageInputPointForWindow,It as focusExistingWeChatWindow,ue as focusKnownWeChatWindow,dn as focusWeChatWindow,sn as observeWeChatChannelBindingViaHelper,D as openConversationBySearch,P as openConversationInVisibleList,be as recognizeWeChatScreenshot,ze as selectWeChatWindowForBinding};
1
+ import W from"node:fs";import U from"node:path";import{WeChatChannelApiError as Re}from"./client.js";import{defaultWeChatChannelAttachmentDir as Fe,resolveVisibleWeChatChannelMedia as Ae}from"./media-resolver.js";import{updateWeChatChannelBindingLedger as Oe}from"./ledger.js";import{defaultWeChatChannelVectorStorePath as Le,loadWeChatChannelVectorStore as De,saveWeChatChannelVectorStore as Ke,upsertWeChatChannelVectorReferences as $e}from"./vector-store.js";import{normalizeWeChatChannelAttachmentAvailability as X,normalizeWeChatChannelMessageKind as ze}from"./core/schema.js";import{waitForWeChatChannelPacing as J,weChatChannelPacingDelayMs as Ve}from"./pacing.js";import{matchWeChatConversationFingerprints as qe}from"./fingerprint.js";import{normalizeWeChatAnchorText as v,weChatTextSimilarity as Z}from"./anchor.js";import{decideWeChatChannelActivityGate as je,normalizeWeChatChannelActivitySnapshot as Ge}from"./human-coordination.js";const He=3,Ye=5,Ue="wechat_login_required",Xe=5500;class N extends Error{reasonCode;stage;action;constructor(t){super(`user_active:${t.reasonCode}:${t.stage}:${t.action}`),this.name="WeChatChannelUserActivityAbort",this.reasonCode=t.reasonCode,this.stage=t.stage,this.action=t.action}}async function Tn(e){return await ct(e.helper,e.activityGuard,e.traceId).withLease("observe","observe-binding",async n=>Je({...e,helper:n}))}async function Je(e){const t=e.foregroundMode??"required";let n=await Ze(e,{foregroundMode:t});if(t!=="background"&&(n=await ve(e.helper,n,e.traceId)),t==="background"){const{capture:s,ocr:a}=await p({helper:e.helper,window:n,traceId:e.traceId}),c=B({capture:s,ocr:a,window:n});if(c)throw new Error(c);if(!O(a,s,e.binding.conversationDisplayName))throw new Error("conversation_not_visible_background");if(G({capture:s,ocr:a,binding:e.binding}))throw new Error("wechat_window_obstructed_background");return e.onObservationEvidence?.({window:n,capture:s,ocr:a}),se(e)?ce({...e,window:n,capture:s,ocr:a}):K({...e,window:n,capture:s,ocr:a})}const r=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!r.opened){const s=await oe({...e,fallback:n,requireTargetConversation:!1,force:!0});if(s.windowId!==n.windowId){n=await ve(e.helper,s,e.traceId);const a=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!a.opened)throw new Error(a.reason||r.reason||"conversation_not_opened")}else throw new Error(r.reason||"conversation_not_opened")}let{capture:i,ocr:o}=await p({helper:e.helper,window:n,traceId:e.traceId});if(G({capture:i,ocr:o,binding:e.binding})){n=await $t(e.helper,e.traceId);const s=await z({helper:e.helper,window:n,binding:e.binding,runtime:e.runtime,api:e.api,workDir:e.workDir,traceId:e.traceId});if(!s.opened)throw new Error(s.reason||"wechat_window_obstructed");if({capture:i,ocr:o}=await p({helper:e.helper,window:n,traceId:e.traceId}),G({capture:i,ocr:o,binding:e.binding}))throw new Error("wechat_window_obstructed")}return e.onObservationEvidence?.({window:n,capture:i,ocr:o}),se(e)?ce({...e,window:n,capture:i,ocr:o}):K({...e,window:n,capture:i,ocr:o})}async function Ze(e,t={}){const n=t.foregroundMode??e.foregroundMode??"required",r=await Dt(e.helper,e.traceId,{foreground:n});return n==="background"?r:oe({...e,fallback:r,requireTargetConversation:!1,force:t.forceVision})}const k=new Map;async function Bn(e){const t=await Q(e,"messageInputPoint");if(!t.messageInputPoint)throw new Error("wechat_message_input_not_found:vision_rect_missing");return t.messageInputPoint}async function Qe(e){const t=await Q(e,"searchInputPoint");if(!t.searchInputPoint)throw new Error("wechat_search_input_not_found:vision_rect_missing");return t.searchInputPoint}async function Q(e,t){const n=t==="searchInputPoint"?"wechat_search_input":"wechat_message_input";if(!e.api.classifyWindow)throw new Error(`${n}_detector_unavailable`);const r=e.window.windowId,i=tt(e.window),o=`${e.runtime.runtimeId}:${e.binding.bindingId}:${r||"unknown"}`,s=`${e.runtime.runtimeId}:window:${r||"unknown"}:${i}`,a=k.get(o)??k.get(s)??te(e,o)??te(e,s);if(a&&a.windowId===r&&a.boundsKey===i&&(!t||a[t]))return k.set(o,a),k.set(s,a),a;const c=e.screenshot??await F(e.helper,r,e.traceId,e.window.bounds),u=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:c.mimeType,dataBase64:c.dataBase64,width:c.width,height:c.height,windowId:r},traceId:e.traceId});if(u.windowKind!=="chat_main")throw new Error(`${n}_not_found:${u.windowKind||"unknown_window"}`);const w=ie(u.layout?.messageInputRect,c,e.window),l=ie(u.layout?.searchInputRect,c,e.window),d={windowId:r||"",boundsKey:i,messageInputPoint:w,searchInputPoint:l,updatedAt:new Date().toISOString()};return k.set(o,d),k.set(s,d),ne(e,o,d),ne(e,s,d),d}function ee(e){const t=e.workDir;return t?U.join(t,"wechat-channel",e.runtime.runtimeId,"vision-layout-point-cache.json"):null}function te(e,t){const n=ee(e);if(!n)return null;try{const r=JSON.parse(W.readFileSync(n,"utf8"));return et(r[t])}catch{return null}}function ne(e,t,n){const r=ee(e);if(r)try{let i={};try{i=JSON.parse(W.readFileSync(r,"utf8"))}catch{i={}}i[t]=n,W.mkdirSync(U.dirname(r),{recursive:!0}),W.writeFileSync(r,`${JSON.stringify(i,null,2)}
2
+ `,"utf8")}catch{}}function et(e){if(!e||typeof e!="object")return null;const t=e,n=typeof t.windowId=="string"?t.windowId:"",r=typeof t.boundsKey=="string"?t.boundsKey:"";if(!r)return null;const i=re(t.messageInputPoint??t.point),o=re(t.searchInputPoint);return{windowId:n,boundsKey:r,messageInputPoint:i,searchInputPoint:o,...typeof t.updatedAt=="string"?{updatedAt:t.updatedAt}:{}}}function re(e){if(!e||typeof e!="object")return null;const t=e,n=Number(t.x),r=Number(t.y);return!Number.isFinite(n)||!Number.isFinite(r)?null:{x:Math.round(n),y:Math.round(r),coordinateSpace:"screen"}}function tt(e){const t=e.bounds;return[Math.round(Number(t?.x??0)),Math.round(Number(t?.y??0)),Math.round(Number(t?.width??0)),Math.round(Number(t?.height??0))].join(",")}function ie(e,t,n){const r=Number(e?.x),i=Number(e?.y),o=Number(e?.width),s=Number(e?.height);if(![r,i,o,s].every(Number.isFinite)||o<=0||s<=0)return null;const a=e?.coordinateSpace==="screen"?{x:r,y:i,width:o,height:s,coordinateSpace:"screen"}:{x:r/999*t.width,y:i/999*t.height,width:o/999*t.width,height:s/999*t.height,coordinateSpace:"screenshotPixel"},c=nt(a,t,n);return c?{x:Math.round(c.x),y:Math.round(c.y),coordinateSpace:"screen"}:null}function nt(e,t,n){const r=rt({x:e.x+e.width*.54,y:e.y+e.height*.55,coordinateSpace:e.coordinateSpace},t,n);return r?{x:r.x,y:r.y,coordinateSpace:"screen"}:null}function rt(e,t,n){if(![e.x,e.y].every(Number.isFinite))return null;if(e.coordinateSpace==="screen"||!n.bounds)return{x:e.x,y:e.y};const r=t.width&&n.bounds.width?t.width/n.bounds.width:1,i=t.height&&n.bounds.height?t.height/n.bounds.height:r,o=Math.max(0,(t.width-n.bounds.width*r)/2),s=Math.max(0,(t.height-n.bounds.height*i)/2);return{x:n.bounds.x+(e.x-o)/r,y:n.bounds.y+(e.y-s)/i}}async function oe(e){if(!e.api.classifyWindow)throw new Error("wechat_window_classifier_unavailable");const t=await e.helper.request("windows.list",{},e.traceId);m(t,"windows.list");const n=(t.result?.windows??[]).filter(q).filter(s=>s.visible!==!1&&s.minimized!==!0&&!!s.windowId),r=at(n.length?n:[e.fallback],e.fallback);if(!r.length)throw new Error("wechat_window_not_found");const i=[];for(const s of r)try{const a=await F(e.helper,s.windowId,e.traceId,s.bounds),c=await e.api.classifyWindow(e.runtime,e.binding,{screenshot:{mimeType:a.mimeType,dataBase64:a.dataBase64,width:a.width,height:a.height,windowId:s.windowId},traceId:e.traceId});i.push({window:s,classification:c,score:st(c,e.requireTargetConversation===!0)})}catch(a){if(it(a))throw a;i.push({window:s,classification:null,errorSummary:a instanceof Error?a.message:String(a||"window classification failed"),score:-1})}const o=i.filter(s=>s.score>0).sort((s,a)=>a.score-s.score)[0];if(!o){const s=i.map(a=>({windowId:a.window.windowId,appName:a.window.appName,title:a.window.title,score:a.score,errorSummary:a.errorSummary,classification:a.classification?{windowKind:a.classification.windowKind,reasonCode:a.classification.reasonCode,confidence:a.classification.confidence,conversationTitle:a.classification.conversationTitle,isTargetConversation:a.classification.isTargetConversation}:null}));throw new Error(`wechat_chat_main_window_not_found: ${JSON.stringify(s)}`)}return o.window}function it(e){const t=ot(e);return t==="insufficient_credits"||t==="entitlement_required"||t==="manual_review_required"||t==="wechat_channel_network_failed"||t==="wechat_channel_invalid_response"}function ot(e){if(e instanceof Re||e&&typeof e=="object"&&typeof e.reasonCode=="string")return e.reasonCode.trim().toLowerCase();const t=e instanceof Error?e.message:String(e||"");return/classify-window (?:network )?failed:\s*([a-z][a-z0-9_]*)/i.exec(t)?.[1]?.trim().toLowerCase()||""}function at(e,t){const n=[],r=i=>{i?.windowId&&(n.some(o=>o.windowId===i.windowId)||n.push(i))};r(e.find(i=>i.windowId===t.windowId));for(const i of e)r(i);return n}function st(e,t){if(!e||e.windowKind!=="chat_main")return 0;const n=Number(e.confidence??0);return t&&e.isTargetConversation!==!0?0:100+(e.isTargetConversation?50:0)+Math.round(Math.max(0,Math.min(1,n))*100)}function ct(e,t,n){if(!t)return{helper:e,withLease:async(a,c,u)=>await u(e)};let r=null;const i=a=>{t.onEvent?.({...a,at:new Date().toISOString()})},o=async(a,c,u={})=>{if(r){const l=await e.request("automation.lease.status",{},n),d=l.result??{},f=l.ok&&d.interrupted?ae(d.interruptReason):l.ok?void 0:l.errorCode||"user_activity_unknown";if(i({phase:"lease-status",stage:a,action:c,ok:l.ok===!0&&!d.interrupted,...f?{reasonCode:f}:{}}),!l.ok)throw new N({reasonCode:l.errorCode||"user_activity_unknown",stage:a,action:c});if(d.active===!1||d.leaseId!==r||!d.interrupted)return;throw new N({reasonCode:ae(d.interruptReason),stage:a,action:c})}const w=Date.now()+lt(t.preflightIdleSettleTimeoutMs);for(;;){const l=await e.request("activity.snapshot",{},n);if(!l.ok)throw i({phase:"snapshot",stage:a,action:c,ok:!1,reasonCode:l.errorCode||"user_activity_unknown"}),new N({reasonCode:l.errorCode||"user_activity_unknown",stage:a,action:c});const d=je({snapshot:Ge(l.result),stage:a,policy:t.policy});if(i({phase:"snapshot",stage:a,action:c,ok:d.ok,...d.ok?{}:{reasonCode:d.reasonCode,waitMs:d.waitMs}}),d.ok)return;const f=new N({reasonCode:d.reasonCode,stage:a,action:c});if(!u.settle)throw f;const Y=w-Date.now();if(Y<=0)throw f;await j(Math.max(50,Math.min(d.waitMs,Y)))}},s={request:async(a,c,u)=>{const w=dt(a);w&&await o(w.stage,`${a}:before`);const l=await e.request(a,c,u);return w&&l.ok&&await o(w.stage,`${a}:after`),l}};return{helper:s,async withLease(a,c,u){if(await Ft(e,n),await o(a,`${c}:preflight`,{settle:!0}),t.useAutomationLease===!1)return await u(s);const w=await e.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`observe:${c}`,ttlMs:12e4},n);if(r=typeof w.result?.leaseId=="string"?w.result.leaseId:null,i({phase:"lease-acquire",stage:a,action:c,ok:w.ok===!0,...w.ok?{}:{reasonCode:w.errorCode||"user_activity_unknown"}}),!w.ok)throw r=null,new N({reasonCode:w.errorCode||"user_activity_unknown",stage:a,action:c});try{const l=await u(s);return await o(a,`${c}:complete`),l}finally{const l=r;if(r=null,l){const d=await e.request("automation.lease.release",{leaseId:l},n).catch(f=>({ok:!1,errorCode:"automation_lease_release_failed",errorSummary:f instanceof Error?f.message:String(f)}));i({phase:"lease-release",stage:a,action:c,ok:d.ok===!0,...d.ok?{}:{reasonCode:d.errorCode||"automation_lease_release_failed"}})}}}}}function dt(e){return e==="windows.ensureReady"||e==="windows.focus"||e==="wechat.searchConversation"?{stage:"open_conversation"}:e==="keyboard.shortcut"||e==="mouse.click"||e==="mouse.rightClick"||e==="mouse.scroll"||e==="clipboard.snapshot"||e==="clipboard.readAttachment"||e==="menu.pickItem"?{stage:"dangerous_action"}:null}function ae(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function lt(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:Xe}function se(e){return e.observePipeline==="edge-structure"?!0:e.observePipeline==="server-observe"?!1:!!e.api.structureWindow}async function K(e){const t=await _e(e),n=await e.api.observe(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height}],edgeOcrBlocks:e.ocr.blocks??[],visibleConversationFingerprints:e.ocr.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId}),r=await we({helper:e.helper,runtime:e.runtime,binding:e.binding,messages:n.observedMessages??[],workDir:e.workDir,attachmentsDir:e.attachmentsDir,window:e.window,screenshot:t,windowId:e.window.windowId,traceId:e.traceId,mediaAnchorText:e.mediaAnchorText});return Be(r,Te({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}))}async function ce(e){if(!e.api.structureWindow)throw new Error("wechat_structure_window_unavailable");const t=await _e(e);let n;try{n=await e.api.structureWindow(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height}],edgeOcrBlocks:e.ocr.blocks??[],visibleConversationFingerprints:e.ocr.visibleConversationFingerprints??[],localLedgerTailAnchors:e.localLedgerTailAnchors??[],traceId:e.traceId})}catch(c){if(ut(c))return K(e);throw c}const r=vt(n.structuredMessages??n.observedMessages??[]),i=await wt({...e,messages:r,screenshot:t}),o=await we({helper:e.helper,runtime:e.runtime,binding:e.binding,messages:i.messages,workDir:e.workDir,attachmentsDir:e.attachmentsDir,window:e.window,screenshot:t,windowId:e.window.windowId,traceId:e.traceId,mediaAnchorText:e.mediaAnchorText}),s=Be(o,Te({ocr:e.ocr,screenshot:t,binding:e.binding,anchors:e.localOutboundEchoAnchors??[]}));return e.localLedger?Oe({ledger:e.localLedger,bindingId:e.binding.bindingId,observedMessages:s,baselineOnly:e.baselineOnly,vectorReferences:i.vectorReferences}).newMessages:s}function ut(e){return e instanceof Error&&/\bedge_runtime_disabled\b/.test(e.message)}async function wt(e){const t=ht(e.messages);if(!t.length)return{messages:e.messages,vectorReferences:[]};const n=e.api.embedVisual?await mt({...e,seedBlocks:t}):t.filter(s=>h(s.vectorBase64)||h(s.signature));if(!n.length)return{messages:e.messages,vectorReferences:[]};const r=e.vectorStorePath??Le(e.workDir||process.cwd(),e.runtime.runtimeId),i=De(r,e.runtime.runtimeId),o=$e({store:i,bindingId:e.binding.bindingId,blocks:n});return o.length?(Ke(r,i),{messages:yt(e.messages,o),vectorReferences:o}):{messages:e.messages,vectorReferences:[]}}function ht(e){const t=[];for(const n of e)for(const[r,i]of(n.visualBlocks??[]).entries()){const o=h(i.blockId)||`${n.stableMessageKey}:visual-${r}`,s=h(i.blockKind)||n.kind||"visual";t.push({...i,stableMessageKey:n.stableMessageKey,blockId:o,blockKind:s,...i.bbox!==void 0?{bbox:i.bbox}:n.bbox!==void 0?{bbox:n.bbox}:{}})}return t}async function ft(e){if(!e.api.embedVisual)return[];const t=await e.api.embedVisual(e.runtime,e.binding,{screenshots:[{captureIndex:0,mimeType:e.screenshot.mimeType,dataBase64:e.screenshot.dataBase64,width:e.screenshot.width,height:e.screenshot.height}],visualBlocks:e.seedBlocks,traceId:e.traceId});return gt(t.visualBlocks??t.embeddedBlocks??[],e.seedBlocks)}async function mt(e){try{return await ft(e)}catch(t){if(bt(t))throw t;return[]}}function bt(e){return!e||typeof e!="object"?!1:e.reasonCode==="insufficient_credits"?!0:e instanceof Error&&/\binsufficient_credits\b/.test(e.message)}function gt(e,t){return e.map((n,r)=>{const i=t[r];return{...n,stableMessageKey:h(n.stableMessageKey)||h(i?.stableMessageKey),blockId:h(n.blockId)||h(i?.blockId),blockKind:h(n.blockKind)||h(i?.blockKind)||"visual",...n.bbox!==void 0?{bbox:n.bbox}:i?.bbox!==void 0?{bbox:i.bbox}:{}}}).filter(n=>h(n.stableMessageKey)&&h(n.blockId))}function yt(e,t){const n=new Map;for(const r of t){const i=n.get(r.stableMessageKey)??[];i.push(r),n.set(r.stableMessageKey,i)}return e.map(r=>{const i=n.get(r.stableMessageKey);return i?.length?{...r,visualBlocks:xt(r,i)}:r})}function xt(e,t){const r=(e.visualBlocks??[]).map((o,s)=>{const a=h(o.blockId)||`${e.stableMessageKey}:visual-${s}`,c=t.find(u=>u.blockId===a);return c?de(c,o):le(o)}),i=new Set(r.map(o=>o.blockId));for(const o of t)i.has(o.blockId)||r.push(de(o));return r}function de(e,t){return{...t?le(t):{},stableMessageKey:e.stableMessageKey,blockId:e.blockId,blockKind:e.blockKind,vectorStoreKey:e.vectorStoreKey,model:e.model,...e.modelVersion!==void 0?{modelVersion:e.modelVersion}:{},dims:e.dims,...e.signature?{signature:e.signature}:{},...e.bbox!==void 0?{bbox:e.bbox}:{}}}function le(e){const{vectorBase64:t,...n}=e;return n}function vt(e){return e.map((t,n)=>pt(t,n)).filter(t=>t!=null)}function pt(e,t){if(!b(e))return null;const n=ze(e.kind),r=It(e.senderRole),i=g(e.normalizedText),o=g(e.anchorText)??i??g(e.textExcerpt),s=h(e.stableMessageKey)||Ct({message:e,index:t,senderRole:r,kind:n,anchorText:o});return{stableMessageKey:s,senderRole:r,...g(e.senderName)!==null?{senderName:g(e.senderName)}:{},kind:n,...i!==null?{normalizedText:i}:{},...o!==null?{anchorText:o}:{},...S(e,"anchorMetadata")?{anchorMetadata:e.anchorMetadata}:{},...S(e,"neighborContext")?{neighborContext:e.neighborContext}:{},...g(e.textExcerpt)!==null?{textExcerpt:g(e.textExcerpt)}:{},...S(e,"bbox")?{bbox:e.bbox}:{},...S(e,"mediaMetadata")?{mediaMetadata:_t(e.mediaMetadata)}:{},...typeof e.isBaseline=="boolean"?{isBaseline:e.isBaseline}:{},...g(e.deliveryStatus)!==null?{deliveryStatus:g(e.deliveryStatus)??void 0}:{},...g(e.observedAt)!==null?{observedAt:g(e.observedAt)??void 0}:{},...Array.isArray(e.visualBlocks)?{visualBlocks:e.visualBlocks}:{},...o?{}:{anchorText:s}}}function Ct(e){const t=b(e.message.bbox)?JSON.stringify(e.message.bbox):"";return`structured-window:${[e.index,e.senderRole,e.kind,e.anchorText||h(e.message.textExcerpt)||"",t].join(":").slice(0,180)}`}function _t(e){if(!b(e))return e;const t={...e};return S(t,"availability")&&(t.availability=X(t.availability)),b(t.attachment)&&(t.attachment=ue(t.attachment)),Array.isArray(t.attachments)&&(t.attachments=t.attachments.map(n=>b(n)?ue(n):n)),t}function ue(e){const t={...e};return S(t,"availability")&&(t.availability=X(t.availability)),t}function It(e){return e==="self"||e==="contact"||e==="system"||e==="unknown"?e:"unknown"}async function we(e){if(e.binding.downloadMedia===!1)return e.messages;const t=e.messages.map((o,s)=>Et(o,e.screenshot,e.window,Bt(e.messages,s))).filter((o,s)=>kt(e.messages,s,e.mediaAnchorText)).filter(o=>o!=null);if(!t.length)return e.messages;const n=e.attachmentsDir??Fe(e.workDir||process.cwd(),e.runtime.runtimeId,e.binding.bindingId),r=await Ae({helper:e.helper,candidates:t,attachmentsDir:n,screenshot:e.screenshot,windowId:e.windowId,window:e.window,traceId:e.traceId,platform:e.runtime.policy.platform,stabilityCheck:async()=>{const o=await _({helper:e.helper,window:e.window,binding:e.binding,traceId:e.traceId});return o.ok?{ok:!0}:{ok:!1,reasonCode:o.reason}}});if(!r.length)return e.messages;const i=new Map(r.map(o=>[o.messageKey,o]));return e.messages.map(o=>{const s=i.get(o.stableMessageKey);return s?{...o,mediaMetadata:Pt(o.mediaMetadata,s.attachment,s.reasonCode,s.attemptReasonCodes,s.resolveTrace)}:o})}function kt(e,t,n){const r=fe(n);if(!r)return!0;const i=St(r),o=e.map((s,a)=>fe(Tt(s)).includes(r)?a:-1).filter(s=>s>=0);if(!o.length)return t===Mt(e,i);for(const s of o)if(t>=s&&t<=s+8||t===s-1&&!e.slice(s+1,Math.min(e.length,s+9)).some(he))return!0;return!1}function St(e){return e.includes("video")||e.includes("vide0")?"video":e.includes("image")||e.includes("photo")||e.includes("ph0t0")||e.includes("picture")?"image":e.includes("file")||e.includes("document")?"file":null}function Mt(e,t=null){for(let n=e.length-1;n>=0;n-=1)if(he(e[n]))return Nt(e[n],t)?n:-1;return-1}function he(e){if(!e)return!1;const t=String(e.kind||"").toLowerCase(),n=b(e.mediaMetadata)?e.mediaMetadata:{},r=b(n.attachment)?n.attachment:{};return me(t,n,r)}function Nt(e,t){if(!e||!t)return!0;const n=String(e.kind||"").toLowerCase(),r=b(e.mediaMetadata)?e.mediaMetadata:{},i=b(r.attachment)?r.attachment:{},o=String(i.type||"").toLowerCase(),s=String(i.mimeType||"").toLowerCase(),a=String(i.name||i.localPath||e.anchorText||e.textExcerpt||"").toLowerCase();return t==="video"?n.includes("video")||o==="video"||s.startsWith("video/")||/\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(a):t==="image"?/image|photo|picture/.test(n)||o==="image"||s.startsWith("image/")||/\.(png|jpe?g|gif|webp|heic|tiff?|bmp)$/i.test(a):/file|document/.test(n)||o==="file"||!/image|photo|picture|video/.test(n)&&o!=="image"&&o!=="video"&&!s.startsWith("image/")&&!s.startsWith("video/")}function Tt(e){if(!e)return"";const t=e;return[e.normalizedText,e.anchorText,e.textExcerpt,t.text].map(n=>String(n||"")).join(`
3
+ `)}function fe(e){return String(e||"").normalize("NFKC").replace(/[o]/giu,"0").replace(/[^\p{L}\p{N}]/gu,"").toLowerCase()}function Bt(e,t){return[e[t-1],e[t],e[t+1]].map(r=>r&&(r.normalizedText||r.anchorText||r.textExcerpt)||"").map(r=>String(r||"").trim()).filter(Boolean).join(`
4
+ `)||null}function Et(e,t,n,r){const i=String(e.kind||"").toLowerCase(),o=b(e.mediaMetadata)?e.mediaMetadata:{},s=b(o.attachment)?o.attachment:{},a=h(s.availability)||h(o.availability),c=h(s.localPath)||h(o.localPath);if(a==="edge-local"&&c||!me(i,o,s))return null;const u=R(e.bbox)??R(o.bbox)??R(o.downloadActionBbox),w=R(o.downloadActionBbox),l=be(u,t,n),d=Rt(u,t,n),f=be(w,t,n);return{messageKey:e.stableMessageKey,kind:h(s.type)||h(s.kind)||h(o.messageType)||i,fileName:h(s.name)||h(s.fileName)||h(o.fileName)||null,mimeType:h(s.mimeType)||h(o.mimeType)||null,size:M(s.size)??M(o.size),mediaStatus:Wt(o,s),observedAt:e.observedAt??null,contextText:r??e.normalizedText??e.anchorText??e.textExcerpt??null,...l?{bbox:l}:{},...d?{screenshotBbox:d}:{},...f?{downloadActionBbox:f}:{}}}function Pt(e,t,n,r,i){const o=b(e)?{...e}:{};return{...o,availability:b(t)?t.availability:o.availability,mediaStatus:b(t)&&t.availability==="edge-local"?"downloaded":o.mediaStatus,attachment:t,edgeResolveReasonCode:n,...r?.length?{edgeResolveAttempts:r}:{},...i?{edgeResolveTrace:i}:{}}}function Wt(e,t){const n=h(e.mediaStatus);if(n==="not_downloaded")return"not_downloaded";if(n==="downloaded"||n==="available")return"available";const r=h(t.availability)||h(e.availability);return r==="pending-download"?"not_downloaded":r==="metadata-only"?"metadata_only":n||null}function me(e,t,n){const r=`${e} ${h(t.messageType)} ${h(n.type)} ${h(n.kind)}`.toLowerCase();return/image|photo|video|file|document/.test(r)}function R(e){if(!b(e))return null;const t=M(e.x),n=M(e.y),r=M(e.width),i=M(e.height);return t==null||n==null||r==null||i==null?null:{x:t,y:n,width:r,height:i,...typeof e.coordinateSpace=="string"?{coordinateSpace:e.coordinateSpace}:{}}}function be(e,t,n){if(!e)return null;if(e.coordinateSpace==="screen")return e;const r=L(e,t,n);if(!r)return e;const i=n.bounds;if(!i?.width||!i?.height)return{...e,x:r.x-e.width/2,y:r.y-e.height/2,coordinateSpace:"screen"};const o=i.width/t.width,s=i.height/t.height,a=r.x,c=r.y;return{x:a-e.width*o/2,y:c-e.height*s/2,width:e.width*o,height:e.height*s,coordinateSpace:"screen"}}function Rt(e,t,n){if(!e)return null;if(e.coordinateSpace!=="screen")return{...e,coordinateSpace:"screenshotPixel"};const r=n.bounds;if(!r?.width||!r?.height)return null;const i=t.width/r.width,o=t.height/r.height;return{x:(e.x-r.x)*i,y:(e.y-r.y)*o,width:e.width*i,height:e.height*o,coordinateSpace:"screenshotPixel"}}function b(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function S(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function h(e){return typeof e=="string"?e.trim():""}function g(e){return h(e)||null}function M(e){const t=Number(e);return Number.isFinite(t)?t:null}async function En(e,t){await ye(e,t)}async function Ft(e,t){await ge(e,t)}async function ge(e,t){const n=await e.request("permissions.check",{},t);m(n,"permissions.check");const r=n.result??{},i=await At(e,r,t);if(i==="screen-recording")throw new Error("permission_screen_recording_missing");if(i==="accessibility")throw new Error("permission_accessibility_missing");if(i==="input-monitoring")throw new Error("permission_input_monitoring_missing");if(r.automation===!1)throw new Error("permission_automation_missing");return r}async function ye(e,t,n={}){const r=await ge(e,t);if(r.wechatRunning===!1)throw new Error("wechat_not_running");if(Kt(r))throw new Error("windows_visible_desktop_unavailable");if(r.dpiMappingAvailable===!1||r.displayTopologySupported===!1)throw new Error("dpi_mapping_failed");if(r.wechatMainWindowResponsive===!1)throw new Error("wechat_window_unresponsive");if(r.wechatWindowAvailable===!1&&String(r.platform??"").toLowerCase()!=="win32"&&n.allowUnavailableWindow!==!0)throw new Error("wechat_window_unavailable");return r}async function At(e,t,n){const r=Ot(t);if(!r||process.platform!=="darwin")return r;const i=Lt(r);try{await e.request(i,{},n)}catch{}return r}function Ot(e){return e.screenRecording===!1?"screen-recording":e.accessibility===!1?"accessibility":e.inputMonitoring===!1?"input-monitoring":null}function Lt(e){return e==="screen-recording"?"permissions.requestScreenRecording":e==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring"}async function Dt(e,t,n={}){const i=(n.foreground??"required")!=="background",o=await ye(e,t,{allowUnavailableWindow:i});if(String(o.platform??"").toLowerCase()==="win32"){const c=await e.request("windows.ensureReady",{activate:i,allowRecovery:!1,allowLaunch:!1},t);m(c,"windows.ensureReady");const u=c.result;if(!u?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return u}const s=await e.request("windows.ensureReady",{restore:i,focus:i},t);m(s,"windows.ensureReady");const a=s.result;if(!a?.windowId)throw new Error("helper_invalid_response: windows.ensureReady missing WeChat window data");return a}function Kt(e){return e.windowsVisibleDesktopAvailable===!1||e.rdpVisibleDesktopAvailable===!1||e.desktopSessionVisible===!1||e.screenLocked===!0||e.rdpDisconnected===!0}function xe(e){const t=e.filter(q),n=t.filter(i=>i.visible!==!1&&i.minimized!==!0);return(n.length?n:t)[0]??null}async function Pn(e,t){let n=await e.request("windows.list",{},t);m(n,"windows.list");let r=n.result?.windows??[],i=xe(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return m(o,"windows.focus"),await pe(e,i,t)}async function ve(e,t,n){if(!t.windowId)throw new Error("wechat_window_not_found");const r=await e.request("windows.focus",{windowId:t.windowId},n);return m(r,"windows.focus"),t}async function $t(e,t){const n=await e.request("windows.list",{},t);m(n,"windows.list");const r=n.result?.windows??[],i=xe(r);if(!i)throw new Error("wechat_window_not_found");const o=await e.request("windows.focus",{windowId:i.windowId},t);return m(o,"windows.focus"),await pe(e,i,t)}async function pe(e,t,n){let r;try{r=await e.request("windows.list",{},n)}catch{return t}if(!r.ok)return t;const i=(r.result?.windows??[]).filter(q);return i.find(o=>o.windowId===t.windowId)??i[0]??t}async function $(e){const{capture:t,ocr:n}=e.observation??await p(e),r=B({capture:t,ocr:n,window:e.window});if(r)return{opened:!1,reason:r};const i=qe({visibleItems:Zt(n,t,e.allowOcrTitleRows!==!1),targets:[{bindingId:e.binding.bindingId,conversationDisplayName:e.binding.conversationDisplayName}]})[0];if(!i)return{opened:!1,reason:"conversation_not_visible"};const o=bn(i.item.bbox,t,e.window);if(!o)return{opened:!1,reason:"conversation_bbox_missing"};const s=await e.helper.request("mouse.click",{x:o.x,y:o.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return m(s,"mouse.click"),{opened:!0,reason:i.reason}}async function z(e){let t={opened:!1,reason:"conversation_not_opened"};for(let r=0;r<He;r+=1){if(t=await zt(e),t.opened||t.reason!=="conversation_title_not_confirmed")return t;await C(e,"open-retry",`retry:${r}`)}const n=await Ce(e);return n.opened?{opened:!0,reason:`${n.reason}:final-visible-recovery`}:t}async function zt(e){const t=await p(e),n=B({capture:t.capture,ocr:t.ocr,window:e.window});if(n)return{opened:!1,reason:n};let r=!1;if(O(t.ocr,t.capture,e.binding.conversationDisplayName)){e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId,observation:t});const l=await Vt(e,t);return l.ok?{opened:!0,reason:"current-conversation-title-confirmed"}:{opened:!1,reason:l.reason}}if(!r){const l=await $({...e,observation:t});if(l.opened){if(await C(e,"open-click-settle","visible-initial"),(await _(e)).ok)return{opened:!0,reason:l.reason};const f=await Ce(e);if(f.opened)return f}}const i=await Ut(e,t.capture);if(!i.ok)return{opened:!1,reason:i.reason};const o=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??A(e,"search-input-settle","search-input"),searchPoint:i.point},e.traceId);m(o,"wechat.searchConversation");const s=await qt(e);if(s.opened){await C(e,"open-click-settle","search-result-click");const l=await _(e);return l.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:s.reason}):{opened:!1,reason:l.reason}}let a=s.observation;const c=y(e.binding.conversationDisplayName)&&s.reason==="search_result_not_visible";if(!y(e.binding.conversationDisplayName)){await Jt(e.helper,e.traceId),await C(e,"open-click-settle","search-return");const l=await _(e);if(l.ok)return e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:l.reason};const d=await e.helper.request("wechat.searchConversation",{conversationName:e.binding.conversationDisplayName,windowId:e.window.windowId,waitMs:e.searchDelayMs??A(e,"search-input-settle","search-input-retry-after-return"),searchPoint:i.point},e.traceId);m(d,"wechat.searchConversation"),a=void 0}const u=await $({...e,...a?{observation:a}:{},allowOcrTitleRows:!c});if(!u.opened)return u;await C(e,"open-click-settle","visible-final");const w=await _(e);return w.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:u.reason}):{opened:!1,reason:w.reason}}async function Vt(e,t){const n=t??await p(e);if(!rn(n.ocr))return{ok:!0};const r=await e.helper.request("keyboard.shortcut",{key:"escape",modifiers:[]},e.traceId);m(r,"keyboard.shortcut"),await C(e,"open-click-settle","escape-after-title-confirmed");const i=await _(e);return i.ok?{ok:!0}:{ok:!1,reason:`search_overlay_dismiss_failed:${i.reason}`}}async function Ce(e){const t=await $(e);if(!t.opened)return t;await C(e,"open-click-settle","visible-retry");const n=await _(e);return n.ok?(e.settleToBottom===!0&&await T({helper:e.helper,window:e.window,traceId:e.traceId}),{opened:!0,reason:`${t.reason}:retry-visible-title-confirmed`}):{opened:!1,reason:n.reason}}async function qt(e){let t;const n=e.searchDelayMs===0?0:A(e,"search-result-probe","search-result-probe"),r=y(e.binding.conversationDisplayName)?Ye:1;for(let i=0;i<r;i+=1){i>0&&n>0&&await j(n);const o=await jt(e);t=o;const{capture:s,ocr:a}=o,c=B({capture:s,ocr:a,window:e.window});if(c)return{opened:!1,reason:c,observation:o};const u=tn(a,s,e.binding.conversationDisplayName);if(!u){if(nn(a)||on(a,e.binding.conversationDisplayName))break;continue}const w=L(u.bbox,s,Gt(s,e.window));if(!w)return{opened:!1,reason:"search_result_bbox_missing",observation:o};const l=await e.helper.request("mouse.click",{x:w.x,y:w.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);return m(l,"mouse.click"),{opened:!0,reason:u.reason,observation:o}}return{opened:!1,reason:"search_result_not_visible",observation:t}}async function jt(e){if(e.window.bounds&&y(e.binding.conversationDisplayName)){const t=await e.helper.request("screen.capture",{bounds:e.window.bounds},e.traceId);if(t.ok&&t.result?.dataBase64&&t.result.width&&t.result.height){const n={...t.result,windowId:e.window.windowId,bounds:t.result.bounds??e.window.bounds},r=await Ie(e.helper,n,e.traceId);return{capture:n,ocr:r}}t.errorCode&&t.errorCode!=="helper_unknown_command"&&t.errorCode!=="helper_command_unsupported"&&m(t,"screen.capture")}return p(e)}function Gt(e,t){return e.bounds?{...t,bounds:e.bounds}:t}async function p(e){let{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds);return await Ht({helper:e.helper,window:e.window,capture:t,ocr:n,traceId:e.traceId})&&(await J("preview-dismiss-settle",`${e.traceId||""}:${e.window.windowId}:preview-dismiss`),{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds)),{capture:t,ocr:n}}async function Ht(e){const t=Yt(e.ocr,e.capture,e.window);if(!t)return!1;for(const n of[async()=>e.helper.request("keyboard.shortcut",{key:"escape",modifiers:[]},e.traceId),async()=>e.helper.request("mouse.click",{x:t.x,y:t.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId)])if((await n()).ok)return!0;return!1}function Yt(e,t,n){const r=e.blocks??[],i=r.find(c=>{const u=String(c.text||""),w=c.bbox;if(!w)return!1;const l=Number(w.x),d=Number(w.y);return Number.isFinite(l)&&Number.isFinite(d)&&d>t.height*.06&&d<t.height*.22&&l>t.width*.3&&/查看原视频|查看原图|原视频|原图|视频|图片|图像/.test(u)});if(!i)return null;const o=i.bbox,s=Number(o?.y);if(!Number.isFinite(s))return null;const a=r.filter(c=>{const u=String(c.text||"").trim(),w=c.bbox;if(!w||u!=="\xD7")return!1;const l=Number(w.x),d=Number(w.y);return Number.isFinite(l)&&Number.isFinite(d)&&l>t.width*.55&&l<t.width*.9&&Math.abs(d-s)<t.height*.08}).sort((c,u)=>Number(u.bbox?.x??0)-Number(c.bbox?.x??0))[0];return L(a?.bbox,t,n)}async function Ut(e,t){if(!e.runtime||!e.api?.classifyWindow)return{ok:!1,reason:"wechat_search_input_detector_unavailable"};try{return{ok:!0,point:await Qe({runtime:e.runtime,binding:e.binding,helper:e.helper,api:e.api,workDir:e.workDir,traceId:e.traceId,window:e.window,...t.dataBase64?{screenshot:t}:{}})}}catch(n){return{ok:!1,reason:n instanceof Error?n.message:"wechat_search_input_not_found"}}}async function F(e,t,n,r){const i=await e.request("windows.capture",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);m(i,"windows.capture");const o=i.result;if(!o?.dataBase64||!o.mimeType||!o.width||!o.height)throw new Error("helper_invalid_response: windows.capture missing screenshot data");return o}async function _e(e){return e.capture.dataBase64?e.capture:F(e.helper,e.window.windowId,e.traceId,e.window.bounds)}async function V(e,t,n,r){const i=await e.request("windows.captureAndOcr",{windowId:t,scope:"full-window",...r?{bounds:r}:{}},n);if(i.ok&&i.result?.capture&&i.result?.ocr)return{capture:i.result.capture,ocr:i.result.ocr};!i.ok&&i.errorCode&&i.errorCode!=="helper_unknown_command"&&i.errorCode!=="helper_command_unsupported"&&m(i,"windows.captureAndOcr");const o=await F(e,t,n,r),s=await Ie(e,o,n);return{capture:o,ocr:s}}async function Ie(e,t,n){const r=await e.request("ocr.recognize",{mimeType:t.mimeType,dataBase64:t.dataBase64,width:t.width,height:t.height},n);return m(r,"ocr.recognize"),r.result??{}}function m(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}function q(e){const t=String(e.appName||"").toLowerCase();return t==="wechat"||t==="weixin"||t==="\u5FAE\u4FE1"}function j(e){return new Promise(t=>setTimeout(t,e))}function A(e,t,n){return e.searchDelayMs===0?0:Ve(t,Xt(e,n))}async function C(e,t,n){const r=A(e,t,n);r>0&&await j(r)}function Xt(e,t){return`${e.traceId||""}:${e.binding.conversationDisplayName}:${t}`}async function Jt(e,t){const n=await e.request("keyboard.shortcut",{key:"return",modifiers:[]},t);m(n,"keyboard.shortcut")}async function T(e){if(!e.window.bounds)return;const t=e.observation,n=gn(t?.ocr,t?.capture,e.window);if(n){const r=await e.helper.request("mouse.click",{x:n.x,y:n.y,coordinateSpace:"screen",windowId:e.window.windowId},e.traceId);m(r,"mouse.click"),await J("jump-latest-settle",`${e.traceId||""}:${e.window.windowId}:jump-latest`)}}async function _(e){const{capture:t,ocr:n}=await V(e.helper,e.window.windowId,e.traceId,e.window.bounds),r=B({capture:t,ocr:n,window:e.window});return r?{ok:!1,reason:r}:O(n,t,e.binding.conversationDisplayName)?{ok:!0,reason:"target-conversation-title-confirmed"}:{ok:!1,reason:"conversation_title_not_confirmed"}}function B(e){const n=(e.ocr.blocks??[]).map(r=>sn(r.text)).filter(Boolean).join("");return/(扫码登录|仅传输文件|重新登录|为了安全|安全验证|登录微信|微信登录|该账号已登录|帐号已登录|账号已登录|当前账号已登录|当前帐号已登录|已登录|进入微信|進入微信)/u.test(n)?Ue:null}function Zt(e,t,n=!0){const r=n?Qt(e.blocks??[],t):[];return r.length?r:e.visibleConversationFingerprints??[]}function Qt(e,t){const n=e.map(i=>ke(i)).filter(i=>!!i).filter(i=>i.text.length>=2).filter(i=>i.x>t.width*.08&&i.x<t.width*.38).filter(i=>i.y>t.height*.06&&i.y<t.height*.96).filter(i=>!Se(i.text)),r=new Set;return n.filter(i=>!en(i,n,t)).sort((i,o)=>i.y-o.y||i.x-o.x).map(i=>{const o=i.text.trim();return{title:o,bbox:{x:Math.max(0,i.x-24),y:Math.max(0,i.y-Math.max(24,i.height)),width:Math.max(120,t.width*.3),height:Math.max(48,i.height+40),coordinateSpace:"screenshotPixel"},fingerprint:o.toLowerCase()}}).filter(i=>{const o=P(i.title);return!o||r.has(o)?!1:(r.add(o),!0)})}function ke(e){const t=e.bbox,n=String(e.text||"").normalize("NFKC").trim(),r=Number(t?.x),i=Number(t?.y),o=Number(t?.width),s=Number(t?.height);return!n||![r,i,o,s].every(Number.isFinite)?null:{text:n,x:r,y:i,width:o,height:s}}function en(e,t,n){const r=Math.max(36,Math.min(64,n.height*.058));return t.some(i=>i!==e&&i.y<e.y&&e.y-i.y<=r&&Math.abs(i.x-e.x)<=16&&i.height>=e.height*.85)}function Se(e){const t=x(e);return/^(搜索|微信|通讯录|收藏|设置|文件传输助手|search)$/iu.test(t)||E(t)||an(t)||/^包含[::]?/u.test(t)||/搜索网络结果/u.test(t)}function tn(e,t,n){const r=(e.blocks??[]).map(a=>ke(a)).filter(a=>!!a),i=r.filter(a=>E(x(a.text))).sort((a,c)=>a.y-c.y||a.x-c.x),o=["\u7FA4\u804A","GroupChats","\u8054\u7CFB\u4EBA","Contacts"];for(const a of o){const c=i.findIndex(d=>x(d.text)===a);if(c<0)continue;const u=i[c],w=i[c+1]?.y??Number.POSITIVE_INFINITY,l=r.filter(d=>d.y>u.y&&d.y<w).filter(d=>d.x<t.width*.7).filter(d=>d.text.length>=2).filter(d=>!E(x(d.text))).filter(d=>!Ne(d,r)).filter(d=>H(d.text,n)).sort((d,f)=>d.y-f.y||d.x-f.x)[0];if(l)return{bbox:Me(l,t),reason:"search-result-title"}}const s=r.filter(a=>a.y>t.height*.12&&a.y<t.height*.82).filter(a=>a.x>t.width*.08&&a.x<t.width*.45).filter(a=>a.text.length>=2).filter(a=>!Se(a.text)).filter(a=>!Ne(a,r)).filter(a=>H(a.text,n)).sort((a,c)=>a.y-c.y||a.x-c.x)[0];return y(n)?null:s?{bbox:Me(s,t),reason:"search-result-title"}:null}function Me(e,t){return{x:Math.max(0,e.x-24),y:Math.max(0,e.y-12),width:Math.max(e.width+t.width*.18,160),height:Math.max(e.height+28,44),coordinateSpace:"screenshotPixel"}}function E(e){return/^(群聊|联系人|聊天记录|公众号|小程序|GroupChats|Contacts|ChatHistory|OfficialAccounts|MiniPrograms)$/u.test(e)}function nn(e){return(e.blocks??[]).some(t=>E(x(t.text)))}function rn(e){return(e.blocks??[]).some(t=>{const n=x(t.text);return E(n)||n==="\u641C\u7D22\u7F51\u7EDC\u7ED3\u679C"})}function on(e,t){return(e.visibleConversationFingerprints??[]).some(n=>H(n.title,t))}function x(e){return String(e||"").normalize("NFKC").replace(/[^\p{L}\p{N}_-]/gu,"").trim()}function Ne(e,t){return/^包含[::]?/u.test(e.text.trim())?!0:t.some(n=>n!==e&&Math.abs(n.y-e.y)<=Math.max(18,e.height)&&n.x<e.x&&/^包含[::]?/u.test(n.text.trim()))}function an(e){const t=String(e||"").trim();return!!(/^(星期[一二三四五六日天]|周[一二三四五六日天])\s*\d{1,2}:\d{2}$/u.test(t)||/^\d{1,2}:\d{2}(?::\d{2})?$/u.test(t)||/^\d{4}[-/.年]\d{1,2}(?:[-/.月]\d{1,2}日?)?$/u.test(t)||/^\d{1,2}[-/.月]\d{1,2}日?$/u.test(t))}function sn(e){return String(e||"").normalize("NFKC").replace(/\s+/g,"").trim()}function O(e,t,n){const r=y(n)?P(n):D(n);return r?(e.blocks??[]).some(i=>{const o=y(n)?P(i.text):D(i.text);if(!o||!Ee(o,r))return!1;const s=i.bbox;if(!s)return!1;const a=Number(s.x),c=Number(s.y);if(!Number.isFinite(a)||!Number.isFinite(c))return!1;const u=a>t.width*.32&&a<t.width*.78&&c<t.height*.16,w=a<t.width*.18&&c<t.height*.12;return u||w}):!1}function G(e){if(O(e.ocr,e.capture,e.binding.conversationDisplayName))return!1;const t=(e.ocr.blocks??[]).map(a=>String(a.text||"").normalize("NFKC").replace(/\s+/g," ").trim()).filter(Boolean),n=t.join(`
5
+ `),i=[{pattern:/UTF-?8/iu,source:n},{pattern:/Unix\s*\(LF\)/iu,source:n},{pattern:/纯文本/u,source:n},{pattern:/\d+\s*个字符/u,source:n},{pattern:/\bH1\b/u,source:n},{pattern:/^查看$/u,source:t}].reduce((a,c)=>{const u=Array.isArray(c.source)?c.source.some(w=>c.pattern.test(w)):c.pattern.test(c.source);return a+(u?1:0)},0);if(i>=2)return!0;const o=(e.ocr.blocks??[]).filter(a=>Number(a.bbox?.y)<e.capture.height*.14).map(a=>String(a.text||"")).join(`
6
+ `);return/\.(txt|md|rtf|docx?|pdf)\b/i.test(o)&&i>=1||/\.(png|jpe?g|gif|webp|bmp|heic|mp4|mov|m4v|avi|mkv|webm)\b/i.test(o)&&cn(e.capture,e.ocr)?!0:((e.ocr.visibleConversationFingerprints??[]).some(a=>{const c=y(e.binding.conversationDisplayName)?P(a.title):D(a.title),u=y(e.binding.conversationDisplayName)?P(e.binding.conversationDisplayName):D(e.binding.conversationDisplayName);return!!(c&&u&&Ee(c,u))}),!1)}function cn(e,t){const n=(t.blocks??[]).map(o=>String(o.text||"").normalize("NFKC").trim()).filter(Boolean),r=n.join(`
7
+ `);if(/\b\d+\s*x\s*\d+\b/i.test(r)&&/\b\d+(\.\d+)?\s*(B|KB|MB|GB)\b/i.test(r)||/\b100%\b/.test(r)&&n.length<=20)return!0;const i=n.filter(o=>!/^(□|×|\+|…|\.\.\.|100%|\d+|发送)$/u.test(o));return e.width>600&&e.height>500&&i.length<=6}function Te(e){const t=e.anchors.map(o=>({...o,normalized:v(o.expectedEchoAnchor)})).filter(o=>o.normalized);if(!t.length)return[];const n=[],r=new Set,i=dn(e.ocr,e.screenshot).sort((o,s)=>v(s.text).length-v(o.text).length);for(const o of i){const s=v(o.text);if(!s)continue;const a=t.find(u=>ln(u.normalized,s));if(!a)continue;const c=`local-outbound-echo:${e.binding.bindingId}:${a.idempotencyKey||a.replyId||a.normalized}`;r.has(c)||(r.add(c),n.push({stableMessageKey:c,senderRole:"self",kind:"text",normalizedText:s,anchorText:s,textExcerpt:o.text.trim(),bbox:o.bbox??null,observedAt:new Date().toISOString(),deliveryStatus:"suppressed"}))}return n}function dn(e,t){const n=(e.blocks??[]).filter(i=>mn(i,t)&&v(i.text)).sort((i,o)=>I(i.bbox,"y")-I(o.bbox,"y")),r=n.map(i=>({text:String(i.text||"").trim(),bbox:i.bbox}));for(let i=0;i<n.length;i+=1){const o=[n[i]];for(let s=i+1;s<n.length&&o.length<5;s+=1){const a=n[s];if(!un(o[o.length-1],a,t))break;o.push(a),r.push({text:wn(o.map(c=>String(c.text||"").trim())),bbox:fn(o.map(c=>c.bbox))})}}return r}function ln(e,t){if(!e||!t)return!1;if(Z(e,t)>=.88)return!0;const n=e.replace(/\s+/g,""),r=t.replace(/\s+/g,"");return r.length>=8&&n.includes(r)}function un(e,t,n){const r=I(e.bbox,"x"),i=I(e.bbox,"y"),o=I(e.bbox,"height"),s=I(t.bbox,"x"),a=I(t.bbox,"y");if(![r,i,o,s,a].every(Number.isFinite)||r<n.width*.5||s<n.width*.5)return!1;const c=a-(i+o);return c>=-8&&c<=Math.max(64,n.height*.04)&&Math.abs(s-r)<=120}function wn(e){return e.reduce((t,n)=>t?n?`${t}${hn(t,n)?" ":""}${n}`:t:n,"")}function hn(e,t){return/[A-Za-z0-9]$/u.test(e)&&/^[A-Za-z0-9]/u.test(t)}function fn(e){const t=e.filter(c=>!!c);if(!t.length)return;const n=t.map(c=>Number(c.x)).filter(Number.isFinite),r=t.map(c=>Number(c.y)).filter(Number.isFinite),i=t.map(c=>Number(c.x)+Number(c.width)).filter(Number.isFinite),o=t.map(c=>Number(c.y)+Number(c.height)).filter(Number.isFinite);if(!n.length||!r.length||!i.length||!o.length)return t[0];const s=Math.min(...n),a=Math.min(...r);return{x:s,y:a,width:Math.max(...i)-s,height:Math.max(...o)-a,coordinateSpace:t.find(c=>c.coordinateSpace)?.coordinateSpace}}function I(e,t){const n=Number(e?.[t]);return Number.isFinite(n)?n:Number.NaN}function Be(e,t){if(!t.length)return e;const n=[...e];for(const r of t){const i=v(r.anchorText||r.normalizedText||r.textExcerpt);n.some(s=>{if(s.senderRole!=="self")return!1;const a=v(s.anchorText||s.normalizedText||s.textExcerpt);return a&&i&&Z(a,i)>=.9})||n.push(r)}return n}function mn(e,t){const n=e.bbox;if(!n)return!1;const r=Number(n.x),i=Number(n.y);return!Number.isFinite(r)||!Number.isFinite(i)?!1:r>t.width*.34&&r<t.width*.96&&i>t.height*.12&&i<t.height*.86}function bn(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),s=Number(r.width),a=Number(r.height);if(![i,o,s,a].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,u=t.width&&n.bounds?.width?t.width/n.bounds.width:1,w=t.height&&n.bounds?.height?t.height/n.bounds.height:u,l={x:i+Math.min(s*.35,110*u),y:o+Math.min(a-8*w,Math.max(18*w,a/2))};if(c==="screen"||!n.bounds)return l;const d=Math.max(0,(t.width-n.bounds.width*u)/2),f=Math.max(0,(t.height-n.bounds.height*w)/2);return{x:n.bounds.x+(l.x-d)/u,y:n.bounds.y+(l.y-f)/w}}function L(e,t,n){if(!e||typeof e!="object")return null;const r=e,i=Number(r.x),o=Number(r.y),s=Number(r.width),a=Number(r.height);if(![i,o,s,a].every(Number.isFinite))return null;const c=typeof r.coordinateSpace=="string"?r.coordinateSpace:void 0,u={x:i+s/2,y:o+a/2};if(c==="screen"||!n.bounds)return u;const w=t.width&&n.bounds.width?t.width/n.bounds.width:1,l=t.height&&n.bounds.height?t.height/n.bounds.height:w,d=Math.max(0,(t.width-n.bounds.width*w)/2),f=Math.max(0,(t.height-n.bounds.height*l)/2);return{x:n.bounds.x+(u.x-d)/w,y:n.bounds.y+(u.y-f)/l}}function gn(e,t,n){if(!e?.blocks?.length||!t)return null;const r=e.blocks.find(i=>{const o=String(i.text||"").trim(),s=i.bbox;if(!s||!o)return!1;const a=Number(s.x),c=Number(s.y);return!Number.isFinite(a)||!Number.isFinite(c)||!/跳转到最新消息|回到最新消息|jump\s+to\s+latest/i.test(o)?!1:a>t.width*.55&&c>t.height*.45&&c<t.height*.92});return L(r?.bbox,t,n)}function Ee(e,t){return y(t)?We(e,t):e===t||e.includes(t)||t.includes(e)}function H(e,t){if(y(t))return We(e,t);const n=Pe(x(e)),r=Pe(x(t));return!n||!r?!1:n===r?!0:n.replace(/\d+$/u,"")===r}function Pe(e){return e.toLowerCase().replace(/[l1]/g,"i")}function D(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").replace(/[l1]/gi,"i").toLowerCase().trim()}function P(e){return String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim()}function y(e){const t=String(e||"").trim();return/^[A-Z0-9_-]{1,6}$/.test(t)&&/[A-Z]/.test(t)}function We(e,t){const n=String(e||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim(),r=String(t||"").normalize("NFKC").replace(/[((]\d+[))]/g,"").replace(/\s+/g,"").trim();return!!(n&&r&&(n===r||n.replace(/\d+$/u,"")===r))}export{N as WeChatChannelUserActivityAbort,V as captureAndRecognizeWeChatWindow,F as captureWeChatWindow,Bn as detectWeChatMessageInputPointByServerVision,Qe as detectWeChatSearchInputPointByServerVision,Ft as ensureHelperPermissionPreflight,En as ensureHelperPreflight,Dt as ensureWeChatWindowReady,$t as focusExistingWeChatWindow,ve as focusKnownWeChatWindow,Pn as focusWeChatWindow,Tn as observeWeChatChannelBindingViaHelper,z as openConversationBySearch,$ as openConversationInVisibleList,Ie as recognizeWeChatScreenshot,Ze as selectWeChatWindowForBinding};
@@ -20,6 +20,8 @@ export declare function sendQueuedWeChatOutboundRecords(input: {
20
20
  export declare class WeChatChannelOutboundSender {
21
21
  private options;
22
22
  private activeAutomationLeaseId;
23
+ private focus?;
24
+ private windowsTextClipboardPrimed;
23
25
  constructor(options: {
24
26
  helper: WeChatChannelHelperTransport;
25
27
  openConversation: (conversationName: string) => Promise<{
@@ -33,6 +35,10 @@ export declare class WeChatChannelOutboundSender {
33
35
  takeoverCheck?: boolean;
34
36
  platform?: NodeJS.Platform | string;
35
37
  postPasteSettleMs?: number;
38
+ onAfterPaste?: (input: {
39
+ record: WeChatChannelOutboundRecord;
40
+ kind: 'text' | 'attachment';
41
+ }) => Promise<void> | void;
36
42
  });
37
43
  canStart(_record: WeChatChannelOutboundRecord, now?: Date): Promise<{
38
44
  ok: true;
@@ -44,10 +50,12 @@ export declare class WeChatChannelOutboundSender {
44
50
  send(record: WeChatChannelOutboundRecord): Promise<void>;
45
51
  private sendWithLease;
46
52
  private sendTextIfPresent;
53
+ private primeWindowsTextPasteIfNeeded;
47
54
  private sendAttachmentsIfPresent;
48
55
  private withAutomationLease;
49
56
  private releaseAutomationLease;
50
57
  private waitAfterPaste;
58
+ private focusMessageInputWithRetry;
51
59
  private ensureStageIdle;
52
60
  private activitySnapshot;
53
61
  private automationLeaseDecision;
@@ -1 +1 @@
1
- import g from"node:fs";import A from"node:path";import{waitForWeChatChannelPacing as h}from"./pacing.js";import{guardWeChatOutboundRevision as v,markWeChatOutboundFailed as C,markWeChatOutboundManualReview as k,markWeChatOutboundCommitStage as r,markWeChatOutboundSending as S,markWeChatOutboundSentUnconfirmed as x,markWeChatOutboundUserActiveTimeout as d,markWeChatOutboundWaitingUserIdle as w,shouldFailWeChatOutboundForUserActiveTimeout as l}from"./outbound-ledger.js";import{decideWeChatChannelActivityGate as y,nextWeChatChannelActivityRetryAt as I,normalizeWeChatChannelActivitySnapshot as R}from"./human-coordination.js";const W=600*1e3,_=520;async function j(e){const t={sentRecords:[],staleRecords:[],failedRecords:[],waitingRecords:[],manualReviewRecords:[]},s=e.now??new Date,i=e.maxUserActivityWaitMs??W,n=e.ledger.records.filter(a=>a.bindingId===e.bindingId&&a.sendStatus==="queued");for(const a of n){if(l({record:a,now:s,maxWaitMs:i})){d(a,s),t.failedRecords.push(a);continue}if(!v({record:a,currentLastInboundRevision:e.currentLastInboundRevision,now:s}).ok){t.staleRecords.push(a);continue}try{const o=await e.sender.canStart(a,s);if(o.ok===!1){w({record:a,reasonCode:o.reasonCode,nextAttemptAt:o.nextAttemptAt,now:s}),l({record:a,now:s,maxWaitMs:i})?(d(a,s),t.failedRecords.push(a)):t.waitingRecords.push(a);continue}S(a),await e.sender.send(a),x(a,s),t.sentRecords.push(a)}catch(o){if(o instanceof f){if(D(o)){k(a,"user_takeover_before_return","User activity was detected after paste and before Return; manual WeChat inspection is required",o.stage),t.manualReviewRecords.push(a);continue}w({record:a,reasonCode:o.reasonCode,nextAttemptAt:o.nextAttemptAt,now:s}),l({record:a,now:s,maxWaitMs:i})?(d(a,s),t.failedRecords.push(a)):t.waitingRecords.push(a);continue}C(a,U(o),o instanceof Error?o.message:String(o)),t.failedRecords.push(a)}}return t}class H{options;activeAutomationLeaseId=null;constructor(t){this.options=t}async canStart(t,s=new Date){const i=await this.activitySnapshot();await P(this.options.helper,i,this.options.platform,this.options.traceId);const n=y({snapshot:i,stage:"send_start",policy:this.options.activityGatePolicy});return n.ok===!1?{ok:!1,reasonCode:n.reasonCode,nextAttemptAt:I(s,n.waitMs)}:{ok:!0}}async send(t){await this.withAutomationLease(t,()=>this.sendWithLease(t))}async sendWithLease(t){await this.ensureStageIdle(t,"open_conversation"),r(t,"open_conversation");const s=await this.options.openConversation(t.conversationName);if(!s.opened)throw new Error(s.reason||"conversation_not_opened");r(t,"focus_input"),await T(this.options.helper,this.options.traceId,{windowId:s.windowId??void 0,inputPoint:s.inputPoint??void 0}),await this.ensureStageIdle(t,"focus_input"),await this.ensureStageIdle(t,"clipboard_snapshot"),r(t,"clipboard_snapshot");const i=await this.options.helper.request("clipboard.snapshot",{},this.options.traceId);c(i,"clipboard.snapshot");let n=!1;try{await this.sendTextIfPresent(t,()=>{n=!0}),await this.sendAttachmentsIfPresent(t,()=>{n=!0})}finally{const a=i.result&&typeof i.result=="object"?i.result:{},p=await this.options.helper.request("clipboard.restore",a,this.options.traceId);n||c(p,"clipboard.restore")}}async sendTextIfPresent(t,s){if(!t.text)return;await this.ensureStageIdle(t,"clipboard_set"),r(t,"clipboard_set"),await u(this.options.helper,"a",m(this.options.platform),this.options.traceId),await u(this.options.helper,"backspace",[],this.options.traceId);const i=await this.options.helper.request("clipboard.setText",{text:t.text},this.options.traceId);c(i,"clipboard.setText"),await this.ensureStageIdle(t,"paste"),r(t,"paste"),await u(this.options.helper,"v",m(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.ensureStageIdle(t,"before_return"),r(t,"before_return"),await u(this.options.helper,"return",[],this.options.traceId),s(),r(t,"after_return")}async sendAttachmentsIfPresent(t,s){for(const i of t.attachmentLocalRefs??[]){q(i),await this.ensureStageIdle(t,"clipboard_set"),r(t,"clipboard_set");const n=L(i),a=n==="image"&&b(this.options.platform)?await this.options.helper.request("clipboard.setImage",{filePath:i},this.options.traceId):await this.options.helper.request("clipboard.setFiles",{filePaths:[i]},this.options.traceId);c(a,n==="image"&&b(this.options.platform)?"clipboard.setImage":"clipboard.setFiles"),await this.ensureStageIdle(t,"paste"),r(t,"paste"),await u(this.options.helper,"v",m(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.ensureStageIdle(t,"before_return"),r(t,"before_return"),await u(this.options.helper,"return",[],this.options.traceId),s(),r(t,"after_return")}}async withAutomationLease(t,s){const i=await this.options.helper.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`send:${t.bindingId}`,ttlMs:6e4},this.options.traceId);c(i,"automation.lease.acquire");const n=typeof i.result?.leaseId=="string"?i.result.leaseId:"";try{this.activeAutomationLeaseId=n||null,await s()}finally{this.activeAutomationLeaseId=null,n&&await this.releaseAutomationLease(n)}}async releaseAutomationLease(t){try{await this.options.helper.request("automation.lease.release",{leaseId:t},this.options.traceId)}catch{}}async waitAfterPaste(t){await h("send-post-paste",`${this.options.traceId||""}:${t.replyId}:post-paste`,this.options.postPasteSettleMs??void 0)}async ensureStageIdle(t,s){if(this.options.takeoverCheck===!1)return;if(this.activeAutomationLeaseId){const a=await this.automationLeaseDecision();if(a.ok===!1)throw new f({reasonCode:a.reasonCode,nextAttemptAt:a.nextAttemptAt,stage:s,replyId:t.replyId});return}const i=await this.activitySnapshot(),n=y({snapshot:i,stage:M(s),policy:this.options.activityGatePolicy});if(!n.ok)throw new f({reasonCode:n.reasonCode,nextAttemptAt:I(new Date,n.waitMs),stage:s,replyId:t.replyId})}async activitySnapshot(){const t=await this.options.helper.request("activity.snapshot",{},this.options.traceId);return c(t,"activity.snapshot"),R(t.result)}async automationLeaseDecision(){if(!this.activeAutomationLeaseId)return{ok:!0};const t=await this.options.helper.request("automation.lease.status",{},this.options.traceId);c(t,"automation.lease.status");const s=t.result??{};return s.active===!1||s.leaseId!==this.activeAutomationLeaseId||!s.interrupted?{ok:!0}:{ok:!1,reasonCode:E(s.interruptReason),nextAttemptAt:new Date(Date.now()+1e3)}}}class f extends Error{reasonCode;nextAttemptAt;stage;replyId;constructor(t){super(`user_takeover_aborted:${t.reasonCode}:${t.stage}`),this.name="WeChatChannelUserTakeoverAbort",this.reasonCode=t.reasonCode,this.nextAttemptAt=t.nextAttemptAt,this.stage=t.stage,this.replyId=t.replyId}}function M(e){return e==="open_conversation"?"open_conversation":e==="queued"?"send_start":"dangerous_action"}async function T(e,t,s){const i={waitMs:_,...s?.windowId?{windowId:s.windowId}:{},...s?.inputPoint?{inputPoint:s.inputPoint}:{}};if((await e.request("wechat.focusMessageInput",i,t)).ok){await h("send-focus-stabilize",`${t||""}:focus-stabilize`);const p=await e.request("wechat.focusMessageInput",i,t);c(p,"wechat.focusMessageInput");return}await h("send-focus-retry",`${t||""}:focus-retry`);const a=await e.request("wechat.focusMessageInput",{...i,waitMs:Math.max(_,700)},t);c(a,"wechat.focusMessageInput")}async function u(e,t,s,i){const n=await e.request("keyboard.shortcut",{key:t,modifiers:s},i);c(n,"keyboard.shortcut")}function q(e){if(!g.statSync(e).isFile())throw new Error(`wechat_channel_attachment_not_file:${e}`)}function L(e){const t=A.extname(e).toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".heic",".tiff",".bmp"].includes(t)?"image":[".mp4",".mov",".m4v",".avi",".mkv",".webm"].includes(t)?"video":"file"}function b(e){return(e??process.platform)==="win32"}function m(e){return(e??process.platform)==="win32"?["control"]:["command"]}async function P(e,t,s,i){if((s??process.platform)!=="darwin")return;const n=t?.permissions;if(!n)return;const a=n.accessibilityTrusted===!1?"accessibility":n.iohidListenGranted===!1?"input-monitoring":null;if(a)throw await O(e,a==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring",i),new Error(`permission_missing:mac_input:${a}`)}async function O(e,t,s){try{await e.request(t,{},s)}catch{}}function U(e){const t=e instanceof Error?e.message:String(e);return/conversation_not|conversation.*visible|conversation.*open/i.test(t)?"conversation_not_opened":/permission|accessibility|screen|automation/i.test(t)?"permission_missing":/clipboard/i.test(t)?"clipboard_failed":/attachment|not_file|ENOENT|no such file/i.test(t)?"attachment_unavailable":"send_failed"}function E(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function D(e){return e.stage==="before_return"}function c(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}export{H as WeChatChannelOutboundSender,f as WeChatChannelUserTakeoverAbort,j as sendQueuedWeChatOutboundRecords};
1
+ import g from"node:fs";import A from"node:path";import{waitForWeChatChannelPacing as d}from"./pacing.js";import{guardWeChatOutboundRevision as v,markWeChatOutboundFailed as C,markWeChatOutboundManualReview as x,markWeChatOutboundCommitStage as o,markWeChatOutboundSending as P,markWeChatOutboundSentUnconfirmed as S,markWeChatOutboundUserActiveTimeout as h,markWeChatOutboundWaitingUserIdle as _,shouldFailWeChatOutboundForUserActiveTimeout as l}from"./outbound-ledger.js";import{decideWeChatChannelActivityGate as I,nextWeChatChannelActivityRetryAt as b,normalizeWeChatChannelActivitySnapshot as k}from"./human-coordination.js";const W=600*1e3,f=520;async function Y(e){const t={sentRecords:[],staleRecords:[],failedRecords:[],waitingRecords:[],manualReviewRecords:[]},s=e.now??new Date,a=e.maxUserActivityWaitMs??W,n=e.ledger.records.filter(i=>i.bindingId===e.bindingId&&i.sendStatus==="queued");for(const i of n){if(l({record:i,now:s,maxWaitMs:a})){h(i,s),t.failedRecords.push(i);continue}if(!v({record:i,currentLastInboundRevision:e.currentLastInboundRevision,now:s}).ok){t.staleRecords.push(i);continue}try{const r=await e.sender.canStart(i,s);if(r.ok===!1){_({record:i,reasonCode:r.reasonCode,nextAttemptAt:r.nextAttemptAt,now:s}),l({record:i,now:s,maxWaitMs:a})?(h(i,s),t.failedRecords.push(i)):t.waitingRecords.push(i);continue}P(i),await e.sender.send(i),S(i,s),t.sentRecords.push(i)}catch(r){if(r instanceof m){if(H(r)){x(i,"user_takeover_before_return","User activity was detected after paste and before Return; manual WeChat inspection is required",r.stage),t.manualReviewRecords.push(i);continue}_({record:i,reasonCode:r.reasonCode,nextAttemptAt:r.nextAttemptAt,now:s}),l({record:i,now:s,maxWaitMs:a})?(h(i,s),t.failedRecords.push(i)):t.waitingRecords.push(i);continue}C(i,z(r),r instanceof Error?r.message:String(r)),t.failedRecords.push(i)}}return t}class J{options;activeAutomationLeaseId=null;focus;windowsTextClipboardPrimed=!1;constructor(t){this.options=t}async canStart(t,s=new Date){const a=await this.activitySnapshot();await $(this.options.helper,a,this.options.platform,this.options.traceId);const n=I({snapshot:a,stage:"send_start",policy:this.options.activityGatePolicy});return n.ok===!1?{ok:!1,reasonCode:n.reasonCode,nextAttemptAt:b(s,n.waitMs)}:{ok:!0}}async send(t){await this.withAutomationLease(t,()=>this.sendWithLease(t))}async sendWithLease(t){await this.ensureStageIdle(t,"open_conversation"),o(t,"open_conversation");const s=await this.options.openConversation(t.conversationName);if(!s.opened)throw new Error(s.reason||"conversation_not_opened");if(D(this.options.platform)&&!s.inputPoint)throw new Error("wechat_message_input_point_required: Windows send requires a vision-detected message input point");o(t,"focus_input"),this.focus={windowId:s.windowId??void 0,inputPoint:s.inputPoint??void 0},await this.focusMessageInputWithRetry(t),await this.ensureStageIdle(t,"clipboard_snapshot"),o(t,"clipboard_snapshot");const a=await this.options.helper.request("clipboard.snapshot",{},this.options.traceId);u(a,"clipboard.snapshot");let n=!1;try{await this.sendTextIfPresent(t,()=>{n=!0}),await this.sendAttachmentsIfPresent(t,()=>{n=!0})}finally{const i=a.result&&typeof a.result=="object"?a.result:{},c=await this.options.helper.request("clipboard.restore",i,this.options.traceId);n||u(c,"clipboard.restore")}}async sendTextIfPresent(t,s){if(!t.text)return;if(F(this.options.platform)){await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set"),await this.ensureStageIdle(t,"paste"),o(t,"paste");const n=await this.options.helper.request("wechat.pasteAndSubmit",{text:t.text,waitMs:f,pasteWaitMs:this.options.postPasteSettleMs??900,...this.focus?.windowId?{windowId:this.focus.windowId}:{},...this.focus?.inputPoint?{inputPoint:this.focus.inputPoint}:{}},this.options.traceId);u(n,"wechat.pasteAndSubmit"),s(),o(t,"after_return");return}await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set"),O(this.options.platform)||(await p(this.options.helper,"a",w(this.options.platform),this.options.traceId),await p(this.options.helper,"backspace",[],this.options.traceId));const a=await this.options.helper.request("clipboard.setText",{text:t.text},this.options.traceId);u(a,"clipboard.setText"),U(this.options.platform)&&await this.focusMessageInputWithRetry(t,"clipboard_set"),await this.ensureStageIdle(t,"paste"),o(t,"paste"),await this.primeWindowsTextPasteIfNeeded(t),await p(this.options.helper,"v",w(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.options.onAfterPaste?.({record:t,kind:"text"}),await this.ensureStageIdle(t,"before_return"),o(t,"before_return"),await p(this.options.helper,"return",[],this.options.traceId),s(),o(t,"after_return")}async primeWindowsTextPasteIfNeeded(t){if(!E(this.options.platform)||this.windowsTextClipboardPrimed)return;const s=await this.options.helper.request("keyboard.primeTextPaste",{},this.options.traceId);u(s,"keyboard.primeTextPaste"),this.windowsTextClipboardPrimed=!0,await this.ensureStageIdle(t,"paste")}async sendAttachmentsIfPresent(t,s){for(const a of t.attachmentLocalRefs??[]){M(a),await this.ensureStageIdle(t,"clipboard_set"),o(t,"clipboard_set");const n=q(a),i=n==="image"&&y(this.options.platform)?await this.options.helper.request("clipboard.setImage",{filePath:a},this.options.traceId):await this.options.helper.request("clipboard.setFiles",{filePaths:[a]},this.options.traceId);u(i,n==="image"&&y(this.options.platform)?"clipboard.setImage":"clipboard.setFiles"),await this.ensureStageIdle(t,"paste"),o(t,"paste"),await p(this.options.helper,"v",w(this.options.platform),this.options.traceId),await this.waitAfterPaste(t),await this.options.onAfterPaste?.({record:t,kind:"attachment"}),await this.ensureStageIdle(t,"before_return"),o(t,"before_return"),await p(this.options.helper,"return",[],this.options.traceId),s(),o(t,"after_return")}}async withAutomationLease(t,s){const a=await this.options.helper.request("automation.lease.acquire",{owner:"wechat-channel",purpose:`send:${t.bindingId}`,ttlMs:6e4},this.options.traceId);u(a,"automation.lease.acquire");const n=typeof a.result?.leaseId=="string"?a.result.leaseId:"";try{this.activeAutomationLeaseId=n||null,await s()}finally{this.activeAutomationLeaseId=null,n&&await this.releaseAutomationLease(n)}}async releaseAutomationLease(t){try{await this.options.helper.request("automation.lease.release",{leaseId:t},this.options.traceId)}catch{}}async waitAfterPaste(t){const s=(this.options.platform??process.platform)==="win32"?1e3:void 0;await d("send-post-paste",`${this.options.traceId||""}:${t.replyId}:post-paste`,this.options.postPasteSettleMs??s)}async focusMessageInputWithRetry(t,s="focus_input"){await T(this.options.helper,this.options.traceId,L(this.focus)),await this.ensureStageIdle(t,s)}async ensureStageIdle(t,s){if(this.options.takeoverCheck===!1)return;if(this.activeAutomationLeaseId){const i=await this.automationLeaseDecision();if(i.ok===!1)throw new m({reasonCode:i.reasonCode,nextAttemptAt:i.nextAttemptAt,stage:s,replyId:t.replyId});return}const a=await this.activitySnapshot(),n=I({snapshot:a,stage:R(s),policy:this.options.activityGatePolicy});if(!n.ok)throw new m({reasonCode:n.reasonCode,nextAttemptAt:b(new Date,n.waitMs),stage:s,replyId:t.replyId})}async activitySnapshot(){const t=await this.options.helper.request("activity.snapshot",{},this.options.traceId);return u(t,"activity.snapshot"),k(t.result)}async automationLeaseDecision(){if(!this.activeAutomationLeaseId)return{ok:!0};const t=await this.options.helper.request("automation.lease.status",{},this.options.traceId);u(t,"automation.lease.status");const s=t.result??{};return s.active===!1||s.leaseId!==this.activeAutomationLeaseId||!s.interrupted?{ok:!0}:{ok:!1,reasonCode:G(s.interruptReason),nextAttemptAt:new Date(Date.now()+1e3)}}}class m extends Error{reasonCode;nextAttemptAt;stage;replyId;constructor(t){super(`user_takeover_aborted:${t.reasonCode}:${t.stage}`),this.name="WeChatChannelUserTakeoverAbort",this.reasonCode=t.reasonCode,this.nextAttemptAt=t.nextAttemptAt,this.stage=t.stage,this.replyId=t.replyId}}function R(e){return e==="open_conversation"?"open_conversation":e==="queued"?"send_start":"dangerous_action"}async function T(e,t,s){const a={waitMs:f,...s?.windowId?{windowId:s.windowId}:{},...s?.inputPoint?{inputPoint:s.inputPoint}:{}};if((await e.request("wechat.focusMessageInput",a,t)).ok){await d("send-focus-stabilize",`${t||""}:focus-stabilize`);const c=await e.request("wechat.focusMessageInput",a,t);u(c,"wechat.focusMessageInput");return}await d("send-focus-retry",`${t||""}:focus-retry`);const i=await e.request("wechat.focusMessageInput",{...a,waitMs:Math.max(f,700)},t);u(i,"wechat.focusMessageInput")}async function p(e,t,s,a){const n=await e.request("keyboard.shortcut",{key:t,modifiers:s},a);u(n,"keyboard.shortcut")}function M(e){if(!g.statSync(e).isFile())throw new Error(`wechat_channel_attachment_not_file:${e}`)}function q(e){const t=A.extname(e).toLowerCase();return[".png",".jpg",".jpeg",".gif",".webp",".heic",".tiff",".bmp"].includes(t)?"image":[".mp4",".mov",".m4v",".avi",".mkv",".webm"].includes(t)?"video":"file"}function y(e){return(e??process.platform)==="win32"}function w(e){return(e??process.platform)==="win32"?["control"]:["command"]}function L(e){if(e)return{...e.windowId?{windowId:e.windowId}:{},...e.inputPoint?{inputPoint:e.inputPoint}:{}}}function O(e){return(e??process.platform)==="win32"}function U(e){return(e??process.platform)==="win32"}function E(e){return(e??process.platform)==="win32"}function F(e){return!1}function D(e){return(e??process.platform)==="win32"}async function $(e,t,s,a){if((s??process.platform)!=="darwin")return;const n=t?.permissions;if(!n)return;const i=n.accessibilityTrusted===!1?"accessibility":n.iohidListenGranted===!1?"input-monitoring":null;if(i)throw await N(e,i==="accessibility"?"permissions.requestAccessibility":"permissions.requestInputMonitoring",a),new Error(`permission_missing:mac_input:${i}`)}async function N(e,t,s){try{await e.request(t,{},s)}catch{}}function z(e){const t=e instanceof Error?e.message:String(e);return/conversation_not|conversation.*visible|conversation.*open/i.test(t)?"conversation_not_opened":/wechat_message_input_point_required|wechat_message_input_not_found/i.test(t)?"wechat_message_input_not_found":/permission|accessibility|screen|automation/i.test(t)?"permission_missing":/clipboard/i.test(t)?"clipboard_failed":/attachment|not_file|ENOENT|no such file/i.test(t)?"attachment_unavailable":"send_failed"}function G(e){return e==="recent_mouse_activity"||e==="recent_mouse_click"||e==="recent_scroll_activity"||e==="recent_keyboard_activity"||e==="frontmost_app_changed"?e:"user_activity_unknown"}function H(e){return e.stage==="before_return"}function u(e,t){if(!e.ok)throw new Error(`${e.errorCode||"helper_command_failed"}: ${e.errorSummary||t}`)}export{J as WeChatChannelOutboundSender,m as WeChatChannelUserTakeoverAbort,Y as sendQueuedWeChatOutboundRecords};
@@ -1 +1 @@
1
- import d from"node:path";import u from"node:fs";import{createWeChatChannelApiClient as p}from"./client.js";import{WeChatChannelHelperClient as m}from"./helper-client.js";import{resolveWeChatChannelHelperAsset as k,WECHAT_CHANNEL_HELPER_VERSION as W}from"./helper-assets.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as h}from"./helper-protocol.js";import{captureWeChatWindow as S,fallbackWeChatMessageInputPointForWindow as I,focusKnownWeChatWindow as f,observeWeChatChannelBindingViaHelper as P,openConversationBySearch as O,recognizeWeChatScreenshot as A,selectWeChatWindowForBinding as g}from"./observer.js";import{WeChatChannelScheduler as F}from"./scheduler.js";import{loadWeChatChannelLedger as D}from"./ledger.js";import{buildWeChatConversationFingerprint as M,matchWeChatConversationFingerprints as T}from"./fingerprint.js";import{WeChatChannelOutboundSender as x}from"./outbound-sender.js";import{decideWeChatChannelActivityGate as L,nextWeChatChannelActivityRetryAt as _,normalizeWeChatChannelActivitySnapshot as q}from"./human-coordination.js";class H{options;scheduler;helper;helperStarted=!1;constructor(e){this.options=e;const n=e.api??p();this.helper=e.helper??E(e),this.scheduler=new F({runtime:e.runtime,workDir:e.workDir,api:n,ledgerPath:e.ledgerPath,outboundLedgerPath:e.outboundLedgerPath,onInboundMessages:e.onInboundMessages,activityGate:{canObserve:async(i,a)=>{if(e.runtime.foregroundPolicy==="work")return{ok:!0};const o=await this.helper.request("activity.snapshot",{});if(!o.ok)return{ok:!1,reasonCode:"user_activity_unknown",nextAttemptAt:new Date(a.getTime()+5e3)};const t=L({snapshot:q(o.result),stage:"observe"});return t.ok?{ok:!0}:{ok:!1,reasonCode:t.reasonCode,nextAttemptAt:_(a,t.waitMs)}}},shouldSkipObserve:(i,a)=>this.shouldSkipObserveForUnchangedFingerprint(i,a.foregroundMode),outboundSender:new x({helper:this.helper,platform:e.runtime.policy.platform,activityGatePolicy:e.runtime.foregroundPolicy==="work"?{mouseMovedThresholdMs:0,mouseClickThresholdMs:0,scrollWheelThresholdMs:0,keyDownThresholdMs:0}:void 0,takeoverCheck:e.runtime.foregroundPolicy!=="work",openConversation:async i=>{const a={bindingId:`outbound:${i}`,sessionId:"outbound",conversationDisplayName:i,enabled:!0,allowReply:!0,downloadMedia:!0},o=await g({runtime:e.runtime,binding:a,helper:this.helper,api:n,workDir:e.workDir}),t=await f(this.helper,o);return{...await O({helper:this.helper,window:t,settleToBottom:!1,binding:a}),windowId:t.windowId,inputPoint:I(t)}}}),observeBinding:(i,a)=>P({runtime:e.runtime,binding:i,helper:this.helper,api:n,workDir:e.workDir,localLedgerTailAnchors:R(e.ledgerPath??U(e.workDir,e.runtime.runtimeId),e.runtime.runtimeId,i.bindingId),localOutboundEchoAnchors:a?.localOutboundEchoAnchors,foregroundMode:a?.foregroundMode,onObservationEvidence:({ocr:o})=>{N({statePath:C(e.workDir,e.runtime.runtimeId),runtimeId:e.runtime.runtimeId,binding:i,ocr:o})}})})}async start(){await this.ensureHelperStarted(),await this.scheduler.start()}async tick(e){return await this.ensureHelperStarted(),this.scheduler.tick(e)}async stop(){this.scheduler.stop(),this.helperStarted&&this.helper.stop&&await this.helper.stop(),this.helperStarted=!1}async ensureHelperStarted(){this.helperStarted||(this.helper.start&&await this.helper.start(),this.helperStarted=!0)}async shouldSkipObserveForUnchangedFingerprint(e,n="required"){if(this.options.runtime.policy.platform!=="darwin"&&this.options.runtime.policy.platform!=="win32")return{skip:!1};const i=C(this.options.workDir,this.options.runtime.runtimeId),a=c(i,this.options.runtime.runtimeId).bindings[e.bindingId];if(!a?.fingerprint)return{skip:!1};try{const o=this.options.api??p(),t=await g({runtime:this.options.runtime,binding:e,helper:this.helper,api:o,workDir:this.options.workDir},{foregroundMode:n}),s=n==="background"?t:await f(this.helper,t),v=await S(this.helper,s.windowId,void 0,s.bounds),y=await A(this.helper,v),l=b({binding:e,ocr:y,prior:a});return!l?.fingerprint||l.fingerprint!==a.fingerprint?{skip:!1}:{skip:!0,reasonCode:"conversation_fingerprint_unchanged",fingerprint:l.fingerprint}}catch{return{skip:!1}}}}function ne(r){return new H(r)}function R(r,e,n,i=3){return(D(r,e).bindings[n]?.recent??[]).slice(-i).map(t=>({stableMessageKey:t.stableMessageKey,senderRole:t.senderRole,kind:t.kind,anchorText:t.anchorText??t.normalizedText??t.textExcerpt??null,anchorMetadata:t.anchorMetadata??null}))}function E(r){if(r.helperClientOptions)return new m({...r.helperClientOptions,requiredCapabilities:r.helperClientOptions.requiredCapabilities??w(r.runtime),guardUnsafeWindowsCommands:r.helperClientOptions.guardUnsafeWindowsCommands??r.runtime.policy.platform==="win32",skipUserActivityGuard:r.helperClientOptions.skipUserActivityGuard??r.runtime.foregroundPolicy==="work",cleanupWindowsOverlays:r.helperClientOptions.cleanupWindowsOverlays??r.runtime.policy.platform==="win32",requestLogger:r.helperClientOptions.requestLogger??r.helperRequestLogger});const e=k();if(!e.ok)throw new Error(`${e.reasonCode}: ${e.message}`);return new m({helperPath:e.helperPath,expectedHelperVersion:e.version||W,requiredCapabilities:w(r.runtime),guardUnsafeWindowsCommands:r.runtime.policy.platform==="win32",skipUserActivityGuard:r.runtime.foregroundPolicy==="work",cleanupWindowsOverlays:r.runtime.policy.platform==="win32",requestLogger:r.helperRequestLogger})}function w(r){if(r.policy.platform==="win32")return r.bindings.some(e=>e.enabled!==!1&&e.allowReply!==!1)?h("send"):r.bindings.some(e=>e.enabled!==!1&&e.downloadMedia!==!1)?h("download"):h("observe")}function U(r,e){return d.join(r,"wechat-channel",`${e}.ledger.json`)}function C(r,e){return d.join(r,"wechat-channel",`${G(e)}.conversation-fingerprints.json`)}function c(r,e){try{const n=JSON.parse(u.readFileSync(r,"utf8"));if(n?.version===1&&n.runtimeId===e&&n.bindings&&typeof n.bindings=="object")return n}catch{}return{version:1,runtimeId:e,bindings:{}}}function B(r,e){u.mkdirSync(d.dirname(r),{recursive:!0}),u.writeFileSync(r,JSON.stringify(e,null,2))}function N(r){const e=b({binding:r.binding,ocr:r.ocr,prior:c(r.statePath,r.runtimeId).bindings[r.binding.bindingId]});if(!e?.fingerprint)return;const n=c(r.statePath,r.runtimeId);n.bindings[r.binding.bindingId]={bindingId:r.binding.bindingId,fingerprint:e.fingerprint,title:e.item.title??null,preview:e.item.preview??null,timeText:e.item.timeText??null,unreadText:e.item.unreadText??null,observedAt:new Date().toISOString()},B(r.statePath,n)}function b(r){const e=r.ocr.visibleConversationFingerprints??[],n=T({visibleItems:e,targets:[{bindingId:r.binding.bindingId,conversationDisplayName:r.binding.conversationDisplayName,lastConversationFingerprint:r.prior?.fingerprint,lastPreview:r.prior?.preview??void 0}]})[0];if(!n)return null;const i=n.item.fingerprint||M(n.item);return i?{item:n.item,fingerprint:i}:null}function G(r){return String(r||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"wechat-channel-runtime"}export{H as WeChatChannelProductRunner,R as buildLocalLedgerTailAnchors,ne as createWeChatChannelProductRunner};
1
+ import u from"node:path";import h from"node:fs";import{createWeChatChannelApiClient as m}from"./client.js";import{WeChatChannelHelperClient as f}from"./helper-client.js";import{resolveWeChatChannelHelperAsset as k,WECHAT_CHANNEL_HELPER_VERSION as W}from"./helper-assets.js";import{requiredWindowsWeChatChannelHelperCapabilitiesForProfile as c}from"./helper-protocol.js";import{captureWeChatWindow as S,detectWeChatMessageInputPointByServerVision as I,focusKnownWeChatWindow as g,observeWeChatChannelBindingViaHelper as P,openConversationBySearch as O,recognizeWeChatScreenshot as A,selectWeChatWindowForBinding as w}from"./observer.js";import{WeChatChannelScheduler as D}from"./scheduler.js";import{loadWeChatChannelLedger as F}from"./ledger.js";import{buildWeChatConversationFingerprint as M,matchWeChatConversationFingerprints as T}from"./fingerprint.js";import{WeChatChannelOutboundSender as x}from"./outbound-sender.js";import{decideWeChatChannelActivityGate as L,nextWeChatChannelActivityRetryAt as _,normalizeWeChatChannelActivitySnapshot as q}from"./human-coordination.js";class H{options;scheduler;helper;helperStarted=!1;constructor(e){this.options=e;const n=e.api??m();this.helper=e.helper??E(e),this.scheduler=new D({runtime:e.runtime,workDir:e.workDir,api:n,ledgerPath:e.ledgerPath,outboundLedgerPath:e.outboundLedgerPath,onInboundMessages:e.onInboundMessages,activityGate:{canObserve:async(i,a)=>{if(e.runtime.foregroundPolicy==="work")return{ok:!0};const o=await this.helper.request("activity.snapshot",{});if(!o.ok)return{ok:!1,reasonCode:"user_activity_unknown",nextAttemptAt:new Date(a.getTime()+5e3)};const t=L({snapshot:q(o.result),stage:"observe"});return t.ok?{ok:!0}:{ok:!1,reasonCode:t.reasonCode,nextAttemptAt:_(a,t.waitMs)}}},shouldSkipObserve:(i,a)=>this.shouldSkipObserveForUnchangedFingerprint(i,a.foregroundMode),outboundSender:new x({helper:this.helper,platform:e.runtime.policy.platform,activityGatePolicy:e.runtime.foregroundPolicy==="work"?{mouseMovedThresholdMs:0,mouseClickThresholdMs:0,scrollWheelThresholdMs:0,keyDownThresholdMs:0}:void 0,takeoverCheck:e.runtime.foregroundPolicy!=="work",openConversation:async i=>{const a={bindingId:`outbound:${i}`,sessionId:"outbound",conversationDisplayName:i,enabled:!0,allowReply:!0,downloadMedia:!0},o=await w({runtime:e.runtime,binding:a,helper:this.helper,api:n,workDir:e.workDir}),t=await g(this.helper,o),s=await O({helper:this.helper,window:t,settleToBottom:!1,binding:a,runtime:e.runtime,api:n,workDir:e.workDir});if(!s.opened)return{...s,windowId:t.windowId,inputPoint:null};const l=await I({runtime:e.runtime,binding:a,helper:this.helper,api:n,workDir:e.workDir,window:t});return{...s,windowId:t.windowId,inputPoint:l}}}),observeBinding:(i,a)=>P({runtime:e.runtime,binding:i,helper:this.helper,api:n,workDir:e.workDir,localLedgerTailAnchors:R(e.ledgerPath??B(e.workDir,e.runtime.runtimeId),e.runtime.runtimeId,i.bindingId),localOutboundEchoAnchors:a?.localOutboundEchoAnchors,foregroundMode:a?.foregroundMode,onObservationEvidence:({ocr:o})=>{N({statePath:b(e.workDir,e.runtime.runtimeId),runtimeId:e.runtime.runtimeId,binding:i,ocr:o})}})})}async start(){await this.ensureHelperStarted(),await this.scheduler.start()}async tick(e){return await this.ensureHelperStarted(),this.scheduler.tick(e)}async stop(){await this.scheduler.stop(),this.helperStarted&&this.helper.stop&&await this.helper.stop(),this.helperStarted=!1}async ensureHelperStarted(){this.helperStarted||(this.helper.start&&await this.helper.start(),this.helperStarted=!0)}async shouldSkipObserveForUnchangedFingerprint(e,n="required"){if(this.options.runtime.policy.platform!=="darwin"&&this.options.runtime.policy.platform!=="win32")return{skip:!1};const i=b(this.options.workDir,this.options.runtime.runtimeId),a=p(i,this.options.runtime.runtimeId).bindings[e.bindingId];if(!a?.fingerprint)return{skip:!1};try{const o=this.options.api??m(),t=await w({runtime:this.options.runtime,binding:e,helper:this.helper,api:o,workDir:this.options.workDir},{foregroundMode:n}),s=n==="background"?t:await g(this.helper,t),l=await S(this.helper,s.windowId,void 0,s.bounds),y=await A(this.helper,l),d=v({binding:e,ocr:y,prior:a});return!d?.fingerprint||d.fingerprint!==a.fingerprint?{skip:!1}:{skip:!0,reasonCode:"conversation_fingerprint_unchanged",fingerprint:d.fingerprint}}catch{return{skip:!1}}}}function ne(r){return new H(r)}function R(r,e,n,i=3){return(F(r,e).bindings[n]?.recent??[]).slice(-i).map(t=>({stableMessageKey:t.stableMessageKey,senderRole:t.senderRole,kind:t.kind,anchorText:t.anchorText??t.normalizedText??t.textExcerpt??null,anchorMetadata:t.anchorMetadata??null}))}function E(r){if(r.helperClientOptions)return new f({...r.helperClientOptions,requiredCapabilities:r.helperClientOptions.requiredCapabilities??C(r.runtime),guardUnsafeWindowsCommands:r.helperClientOptions.guardUnsafeWindowsCommands??r.runtime.policy.platform==="win32",skipUserActivityGuard:r.helperClientOptions.skipUserActivityGuard??r.runtime.foregroundPolicy==="work",cleanupWindowsOverlays:r.helperClientOptions.cleanupWindowsOverlays??r.runtime.policy.platform==="win32",requestLogger:r.helperClientOptions.requestLogger??r.helperRequestLogger});const e=k();if(!e.ok)throw new Error(`${e.reasonCode}: ${e.message}`);return new f({helperPath:e.helperPath,expectedHelperVersion:e.version||W,requiredCapabilities:C(r.runtime),guardUnsafeWindowsCommands:r.runtime.policy.platform==="win32",skipUserActivityGuard:r.runtime.foregroundPolicy==="work",cleanupWindowsOverlays:r.runtime.policy.platform==="win32",requestLogger:r.helperRequestLogger})}function C(r){if(r.policy.platform==="win32")return r.bindings.some(e=>e.enabled!==!1&&e.allowReply!==!1)?c("send"):r.bindings.some(e=>e.enabled!==!1&&e.downloadMedia!==!1)?c("download"):c("observe")}function B(r,e){return u.join(r,"wechat-channel",`${e}.ledger.json`)}function b(r,e){return u.join(r,"wechat-channel",`${G(e)}.conversation-fingerprints.json`)}function p(r,e){try{const n=JSON.parse(h.readFileSync(r,"utf8"));if(n?.version===1&&n.runtimeId===e&&n.bindings&&typeof n.bindings=="object")return n}catch{}return{version:1,runtimeId:e,bindings:{}}}function U(r,e){h.mkdirSync(u.dirname(r),{recursive:!0}),h.writeFileSync(r,JSON.stringify(e,null,2))}function N(r){const e=v({binding:r.binding,ocr:r.ocr,prior:p(r.statePath,r.runtimeId).bindings[r.binding.bindingId]});if(!e?.fingerprint)return;const n=p(r.statePath,r.runtimeId);n.bindings[r.binding.bindingId]={bindingId:r.binding.bindingId,fingerprint:e.fingerprint,title:e.item.title??null,preview:e.item.preview??null,timeText:e.item.timeText??null,unreadText:e.item.unreadText??null,observedAt:new Date().toISOString()},U(r.statePath,n)}function v(r){const e=r.ocr.visibleConversationFingerprints??[],n=T({visibleItems:e,targets:[{bindingId:r.binding.bindingId,conversationDisplayName:r.binding.conversationDisplayName,lastConversationFingerprint:r.prior?.fingerprint,lastPreview:r.prior?.preview??void 0}]})[0];if(!n)return null;const i=n.item.fingerprint||M(n.item);return i?{item:n.item,fingerprint:i}:null}function G(r){return String(r||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||"wechat-channel-runtime"}export{H as WeChatChannelProductRunner,R as buildLocalLedgerTailAnchors,ne as createWeChatChannelProductRunner};