From 4453a40daaaddbd46a4935c9966827cc419ea4fc Mon Sep 17 00:00:00 2001 From: xmanrui <841206367@qq.com> Date: Mon, 17 Aug 2026 15:39:32 +0800 Subject: [PATCH] release: prepare dsh-im 0.3.0 --- lib/index.js | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- src/channels/discord/discord-api.mjs | 2 +- src/channels/weixin/weixin-api.mjs | 2 +- test/channels/weixin/weixin-api.test.mjs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/index.js b/lib/index.js index 67427e5..2aefda0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -64,7 +64,7 @@ ${R}`),f.pop(),`{${H}}`}case"number":return isFinite(Q)?String(Q):a?a(Q):"null"; `).trim()}var jm=class{#A;#e;#t=null;#a=null;#n=new Map;#s="";#I=!1;#g=null;constructor({promptRpcId:a,afterSeq:o=-1}){this.#A=a,this.#e=o}get finished(){return this.#I}get answer(){return this.#s.trim()}get reason(){return this.#g}consume(a){let o=null,i=[...a].map(e=>e?.event??e).filter(Boolean).sort((e,r)=>(e.seq??-1)-(r.seq??-1));for(let e of i){let r=e.seq??-1;if(!(r<=this.#e)){if(this.#e=r,e.type==="turn/start"&&(this.#t=e.data?.turn??null),e.type==="user/message"&&e.data?.source?.rpcId===this.#A){this.#a=this.#t;continue}if(this.#a!==null){if(e.type==="turn/end"){if(e.data?.turn!==this.#a)continue;this.#I=!0,this.#g=e.data?.reason??null,this.#t=null;continue}if(e.data?.turn===this.#a){if(e.type==="assistant/chunk"&&e.data?.chunk?.type==="text-delta"){let A=e.data?.step??0,t=e.data.chunk.index??0,s=`${A}:${t}`;this.#n.set(s,(this.#n.get(s)??"")+e.data.chunk.text);let g=`${A}:`,c=[...this.#n.entries()].filter(([l])=>l.startsWith(g)).sort(([l],[C])=>Number(l.split(":")[1])-Number(C.split(":")[1])).map(([,l])=>l).join(` `).trim();c&&c!==this.#s&&(this.#s=c,o={type:"text",text:c});continue}if(e.type==="assistant/message"){let A=i$(e);A&&A!==this.#s&&(this.#s=A,o={type:"text",text:A});continue}e.type==="tool/call"?o={type:"tool",name:e.data?.name??"\u5DE5\u5177"}:e.type==="tool/result"&&(o={type:"status",text:"\u6B63\u5728\u6574\u7406\u7ED3\u679C\u2026"})}}}}return o}},Bh=class extends Error{constructor(a,o){super(`${a}: ${o?.message??"unknown Harness RPC error"}`),this.name="HarnessRpcError",this.method=a,this.code=o?.code??"internal",this.details=o?.details??{}}},uh=class{#A;#e;#t;#a;#n;#s;#I=null;constructor({baseUrl:a,workspace:o,agentPreset:i="standard",autostart:e=!1,dshBin:r="dsh",fetchImpl:A=fetch}){this.#A=new URL(a),this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A}async rpc(a,o={},i=3e4,e={}){let r=e.rpcId??`dingtalk-${uv()}`,A=AbortSignal.timeout(i),t=e.signal?AbortSignal.any([e.signal,A]):A,s=await this.#s(new URL(`/api/${a}`,this.#A),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({type:"client-request",rpcId:r,method:a,payload:o}),signal:t});if(!s.ok)throw new Error(`Harness transport ${a} failed: HTTP ${s.status}`);let g=await s.json();if(g?.type!=="server-response"||g?.rpcId!==r)throw new Error(`Harness returned an invalid response for ${a}`);if(!g.result?.ok)throw new Bh(a,g.result?.error);return g.result.value}async health(a={}){return await this.rpc("host.describe",{},5e3,a),!0}async ensureRunning(a={}){try{return await this.health(a)}catch(e){if(!this.#a)throw e}if(!this.#I||this.#I.exitCode!==null){let e=this.#A.port||(this.#A.protocol==="https:"?"443":"80");this.#I=r$(this.#n,["web","--host",this.#A.hostname,"--port",e],{cwd:this.#e,env:process.env,stdio:["ignore","inherit","inherit"]}),this.#I.on("error",r=>{console.error("[dsh-dingtalk] failed to start Harness:",r.message)})}let o=Date.now()+6e4,i;for(;Date.now()r.path===this.#e);return i?i.workspaceId:(await this.rpc("workspace.create",{path:this.#e},3e4,a)).workspace.workspaceId}async createSession(a={}){await this.ensureRunning(a);let o=await this.workspaceId(a);return(await this.rpc("session.create",{workspaceId:o,agentPreset:this.#t},3e4,a)).sessionId}async sessionExists(a,o={}){try{return await this.rpc("session.history",{sessionId:a,maxMessages:1},3e4,o),!0}catch(i){if(i instanceof Bh&&i.code==="session-not-found")return!1;throw i}}async ask(a,o,i={}){typeof i=="number"&&(i={timeoutMs:i});let e=i.timeoutMs??6e5,r=i.signal,A=typeof i.onUpdate=="function"?i.onUpdate:null;await this.ensureRunning({signal:r});let t=await this.rpc("session.history",{sessionId:a,maxMessages:1},3e4,{signal:r}),s=Math.max(-1,...(t.events??[]).map(({event:C})=>C.seq??-1)),g=`dingtalk-${uv()}`,c=new jm({promptRpcId:g,afterSeq:s});await this.rpc("session.prompt",{sessionId:a,mode:"queue",content:[{type:"text",text:o}],clientTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone},3e4,{rpcId:g,signal:r});let l=Date.now()+e;for(;Date.now()[e?.requestId,e]):Object.entries(n.pendingSenders&&typeof n.pendingSenders=="object"?n.pendingSenders:{});for(let[e,r]of i){let A=E$(r,e);if(!A)continue;let t=Object.values(o).find(s=>s.staffId===A.staffId);(!t||t.lastSeenAtnew Date().toISOString()}={}){if(!_t(a))throw new TypeError("state path is required");if(typeof o!="function"||typeof i!="function")throw new TypeError("idFactory and now must be functions");this.#A=a,this.#a=o,this.#n=i}async load(){try{this.#e=C$(JSON.parse(await s$(this.#A,"utf8")))}catch(a){if(a?.code!=="ENOENT")throw a;this.#e=structuredClone(Qh),await this.#s()}return this}sessionFor(a){return this.#e.sessions[a]??null}async setSession(a,o){let i=_t(a),e=_t(o);if(!i||!e)throw new TypeError("key and sessionId are required");this.#e.sessions[i]=e,await this.#s()}async clearSession(a){let o=_t(a);!o||!(o in this.#e.sessions)||(delete this.#e.sessions[o],await this.#s())}hasSeen(a){let o=_t(a);return!!(o&&this.#e.seenMessageIds.includes(o))}async markSeen(a){let o=_t(a);if(!o)throw new TypeError("messageId is required");this.hasSeen(o)||(this.#e.seenMessageIds.push(o),this.#e.seenMessageIds.length>1e3&&this.#e.seenMessageIds.splice(0,this.#e.seenMessageIds.length-1e3),await this.#s())}pendingSenders(){return Object.values(this.#e.pendingSenders).sort((a,o)=>a.requestedAt.localeCompare(o.requestedAt)).map(a=>structuredClone(a))}pendingSender(a){let o=_t(a),i=o?this.#e.pendingSenders[o]:null;return i?structuredClone(i):null}async recordPendingSender(a,o,i){let e=a&&typeof a=="object"?a:{staffId:a,displayName:o,lastSeenAt:i},r=_t(e.staffId);if(!r)throw new TypeError("staffId is required");let A=_t(e.lastSeenAt)??_t(e.requestedAt)??this.#n(),t=Object.values(this.#e.pendingSenders).find(g=>g.staffId===r),s={requestId:t?.requestId??`ding_sender_${this.#a()}`,staffId:r,displayName:fv(e.displayName??e.nick??o),requestedAt:t?.requestedAt??A,lastSeenAt:A};return this.#e.pendingSenders[s.requestId]=s,await this.#s(),structuredClone(s)}async removePendingSender(a){let o=_t(a);return!o||!this.#e.pendingSenders[o]?!1:(delete this.#e.pendingSenders[o],await this.#s(),!0)}async removePendingSenderByStaffId(a){let o=_t(a),i=o?Object.values(this.#e.pendingSenders).find(e=>e.staffId===o):null;return i?this.removePendingSender(i.requestId):!1}snapshot(){return structuredClone(this.#e)}async remove(){await this.#t;try{await c$(this.#A)}catch(a){if(a?.code!=="ENOENT")throw a}this.#e=structuredClone(Qh)}async#s(){let a=`${JSON.stringify(this.#e,null,2)} `,o=this.#t.then(async()=>{await n$(l$(this.#A),{recursive:!0,mode:448});let i=`${this.#A}.tmp`;await I$(i,a,{encoding:"utf8",mode:384}),await g$(i,this.#A)});this.#t=o.then(()=>{},()=>{}),await o}};var yv=Object.freeze([250,1e3,3e3,5e3,1e4,3e4]);function p$(n){if(!Array.isArray(n)||n.length===0)return[...yv];let a=n.filter(o=>Number.isFinite(o)&&o>=0);return a.length>0?a:[...yv]}var yh=class{#A;#e;#t;#a;#n;#s;#I;#g=null;#o=null;#i=0;#r=!1;#c=!1;#l;#E;constructor({controller:a,harness:o,logger:i=console,retryDelaysMs:e,healthyIntervalMs:r=15e3,setTimeoutImpl:A=setTimeout,clearTimeoutImpl:t=clearTimeout}){if(!a||typeof a.initialize!="function"||typeof a.status!="function")throw new TypeError("ConnectionSupervisor requires a controller");if(!o||typeof o.ensureRunning!="function")throw new TypeError("ConnectionSupervisor requires a Harness client");this.#A=a,this.#e=o,this.#t=i,this.#a=p$(e),this.#n=Number.isFinite(r)&&r>=0?r:15e3,this.#s=A,this.#I=t,this.#l=new Promise(s=>{this.#E=s})}get ready(){return this.#l}start(){return this.#c||this.#r?this:(this.#c=!0,this.#C(0),this)}async close(){this.#r||(this.#r=!0,this.#g!==null&&this.#I(this.#g),this.#g=null,await this.#o?.catch(()=>{}),this.#E?.(null),this.#E=null)}#C(a){this.#r||(this.#g=this.#s(()=>{this.#g=null,this.#p()},a),this.#g?.unref?.())}async#p(){if(this.#r||this.#o)return;let a=this.#h();this.#o=a;try{await a}finally{this.#o===a&&(this.#o=null)}}async#h(){try{if(await this.#e.ensureRunning(),this.#r)return;let a=await this.#A.initialize();if(this.#r)return;this.#E?.(a),this.#E=null;let{configured:o,connected:i}=a.totals;if(i65535)throw new Error("dsh-dingtalk requires an initialized DSH webServer port");return new URL(`http://127.0.0.1:${o}`)}function u$(n){let a=Ac(n.dshHome??process.env.DSH_HOME??mh(d$(),".dsh")),o=Ac(n.dataDir??mh(a,"integrations","dsh-dingtalk"));return{root:o,config:Ac(n.configPath??mh(o,"config.json")),bots:Ac(n.botsDir??mh(o,"bots"))}}async function Vm(n,a={},o={}){if(!n?.credentials)throw new TypeError("dsh-dingtalk requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-dingtalk requires ctx.webServer");let i=o.ConfigStore??Ih,e=o.DeviceAuth??Eh,r=o.StateStore??fh,A=o.HarnessClient??uh,t=o.Controller??kl,s=o.Runtime??Fl,g=o.createConnectionSupervisor??qm,c=typeof n.logger=="function"?n.logger("dsh-dingtalk"):n.logger??console,l=u$(a),C=await new i(l.config).load(),u=o.deviceAuth??new e({baseUrl:a.registrationBaseUrl}),Q=new Map,f=k=>Ac(l.bots,k,"state.json"),y=async k=>{let U=Q.get(k);return U||(U=await new r(f(k)).load(),Q.set(k,U)),U},m=new A({baseUrl:B$(n.webServer,a.harnessBaseUrl),workspace:Ac(a.workspace??process.cwd()),agentPreset:a.agentPreset??"standard",autostart:!1,dshBin:a.dshBin??"dsh"}),R=new t({deviceAuth:u,credentials:n.credentials,configStore:C,logger:c,createRuntime:async({botId:k,config:U,clientSecret:H})=>{let F=await y(k);return new s({config:U,clientSecret:H,harness:m,state:F,replyTimeoutMs:a.replyTimeoutMs??6e5,maxMessageChars:a.maxMessageChars??4e3,connectTimeoutMs:a.connectTimeoutMs??15e3,logger:{error:(...q)=>c.error?.(`[${k}]`,...q),warn:(...q)=>c.warn?.(`[${k}]`,...q),info:(...q)=>c.info?.(`[${k}]`,...q),debug:(...q)=>c.debug?.(`[${k}]`,...q)}})},deleteState:async({botId:k})=>{let U=Q.get(k);if(Q.delete(k),U&&typeof U.remove=="function"){await U.remove();return}try{await h$(f(k))}catch(H){if(H?.code!=="ENOENT")throw H}}}),N=g({controller:R,harness:m,logger:c,retryDelaysMs:a.retryDelaysMs,healthyIntervalMs:a.healthyIntervalMs}).start();return{controller:R,ready:N.ready,async close(){await N.close(),await R.close(),m.stopManagedProcess()}}}import f$ from"qrcode";var Q$=new Set(["loopback","trusted-host"]);function Ra(n){if(n===void 0)return"loopback";if(Q$.has(n))return n;throw new TypeError('dsh-im rpcAuthority must be "loopback" or "trusted-host"')}var Sv="/dingtalk",Vt=Object.freeze({status:"connection.status",beginProvisioning:"provision.begin",pollProvisioning:"provision.poll",cancelProvisioning:"provision.cancel",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete",approveSender:"bot.sender.approve",revokeSender:"bot.sender.revoke"}),Dv=Object.freeze(Object.values(Vt)),y$=new Set(["clientSecret","client_secret","deviceCode","device_code","secretRef","staffId","senderStaffId","verificationUrl","verificationUri","userCode"]);function Wm(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function Bn(n,a){return Wm(n)&&Object.keys(n).every(o=>a.includes(o))}function Ms(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n)}function mv(n,a){return typeof n=="string"&&n.trim().length>0&&n.length<=a}function m$(n,a){return Wm(a)?n===Vt.status?Bn(a,[])?null:"connection.status does not accept fields.":n===Vt.beginProvisioning?Bn(a,["locale"])&&(a.locale===void 0||a.locale==="zh-CN")?null:"provision.begin received unsupported fields.":[Vt.pollProvisioning,Vt.cancelProvisioning].includes(n)?Bn(a,["attemptId"])&&Ms(a.attemptId)?null:`${n} requires an attemptId.`:n===Vt.bindCredentials?Bn(a,["clientId","clientSecret"])&&mv(a.clientId,256)&&mv(a.clientSecret,1024)?null:"bot.bind-credentials requires Client ID and Client Secret.":n===Vt.reconnectBot?Bn(a,["botId"])&&Ms(a.botId)?null:"bot.reconnect requires a botId.":n===Vt.deleteBot?Bn(a,["botId","confirm"])&&Ms(a.botId)&&a.confirm===!0?null:"bot.delete requires a botId and confirm=true.":n===Vt.approveSender?Bn(a,["botId","requestId","confirm"])&&Ms(a.botId)&&Ms(a.requestId)&&a.confirm===!0?null:"bot.sender.approve requires botId, requestId, and confirm=true.":n===Vt.revokeSender?Bn(a,["botId","senderKey","confirm"])&&Ms(a.botId)&&Ms(a.senderKey)&&a.confirm===!0?null:"bot.sender.revoke requires botId, senderKey, and confirm=true.":"Unknown DingTalk endpoint.":"Payload must be an object."}function Sh(n){return{ok:!1,error:{code:"bad-request",message:n}}}function Dh(){return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}}function S$(){return{ok:!1,error:{code:"dingtalk-operation-failed",message:"\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}function ac(n){if(Array.isArray(n))return n.map(ac);if(!Wm(n))return n;let a={};for(let[o,i]of Object.entries(n))y$.has(o)||(a[o]=ac(i));return a}async function D$(n){return f$.toDataURL(n,{type:"image/png",errorCorrectionLevel:"M",margin:2,width:320})}async function zm(n,a){return!n||typeof n.verificationUrl!="string"?ac(n):ac({...n,qrCodeDataUrl:await a(n.verificationUrl)})}async function tc(n,a){let o=structuredClone(n);return o?.provisioning&&(o.provisioning=await zm(o.provisioning,a)),ac(o)}function w$(n){for(let a of["status","startProvisioning","registrationStatus","cancelProvisioning","bindCredentials","reconnectBot","deleteBot","approveSender","revokeSender"])if(typeof n?.[a]!="function")throw new TypeError(`A complete DingTalk controller is required (${a})`)}function wv(n,{encodeQr:a=D$}={}){w$(n);let o=new Map,i=e=>{let r=o.get(e);return r||(o.size>=16&&o.delete(o.keys().next().value),r=Promise.resolve().then(()=>a(e)),o.set(e,r)),r};return async(e,r,A)=>{if(A?.aborted)return Dh();if(!Dv.includes(e))return Sh("Unknown DingTalk endpoint.");let t=m$(e,r);if(t)return Sh(t);try{let s;if(e===Vt.status)s=await tc(await n.status(),i);else if(e===Vt.beginProvisioning){let g=await n.startProvisioning({signal:A});if(A?.aborted)return await n.cancelProvisioning(g.attemptId),Dh();s=await zm(g,i)}else if(e===Vt.pollProvisioning){let g=await n.registrationStatus(r.attemptId);if(!g)return Sh("The provisioning attempt no longer exists.");s=await zm(g,i)}else if(e===Vt.cancelProvisioning){if(s=await n.cancelProvisioning(r.attemptId),!s)return Sh("The provisioning attempt no longer exists.");s=ac(s)}else e===Vt.bindCredentials?s=await tc(await n.bindCredentials(r),i):e===Vt.reconnectBot?s=await tc(await n.reconnectBot(r.botId),i):e===Vt.deleteBot?s=await tc(await n.deleteBot(r.botId),i):e===Vt.approveSender?s=await tc(await n.approveSender(r.botId,r.requestId),i):s=await tc(await n.revokeSender(r.botId,r.senderKey),i);return A?.aborted?Dh():{ok:!0,value:s}}catch{return A?.aborted?Dh():S$()}}}function wh(n,a,o,i){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(Sv,wv(a,o),{authority:Ra(i)})}async function Ov(n,a={}){if(a?.controller)return wh(n,a.controller,a.rpcOptions,a.rpcAuthority);let o=await Vm(n,a,a.internals),i=wh(n,o.controller,a.rpcOptions,a.rpcAuthority);return n.effect(()=>async()=>{await o.close()},"dsh-dingtalk: close bot connections"),i}import{createHash as O$}from"node:crypto";import{mkdir as M$,readFile as b$,rename as _$,unlink as N$,writeFile as T$}from"node:fs/promises";import{dirname as R$}from"node:path";var Zm=Object.freeze({version:1,bots:Object.freeze([])});function Oo(n){return typeof n=="string"&&n.trim()?n.trim():null}function Mv(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Ll(n,{botPrefix:a,tokenRefPrefix:o}){let i=Oo(n);if(!i)throw new TypeError("platformId is required");let e=O$("sha256").update(i).digest("hex").slice(0,24);return{botId:`${a}_${e}`,tokenRef:`${o}_${e.toUpperCase()}`}}function Oh(n,a){let o=Oo(n)??"";return o.length<=10?o?`${o.slice(0,3)}\u2022\u2022\u2022`:a:`${o.slice(0,6)}\u2022\u2022\u2022\u2022${o.slice(-4)}`}var rc=class{#A;#e;#t;#a;#n;#s;#I=Zm;#g=Promise.resolve();constructor(a,{channel:o,botPrefix:i,tokenRefPrefix:e}){this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=new RegExp(`^${Mv(i)}_[a-f0-9]{24}$`),this.#s=new RegExp(`^${Mv(e)}_[A-F0-9]{24}$`)}async load(){try{let a=this.#i(JSON.parse(await b$(this.#A,"utf8")));if(!a)throw new Error(`dsh-im ${this.#e} config contains invalid bot data`);this.#I=a}catch(a){if(a?.code!=="ENOENT")throw a;this.#I=Zm}return this}list(){return structuredClone(this.#I.bots)}get(a){let o=this.#I.bots.find(i=>i.botId===a);return o?structuredClone(o):null}getByPlatformId(a){let o=this.#I.bots.find(i=>i.platformId===a);return o?structuredClone(o):null}async save(a){let o=this.#o(a);if(!o)throw new Error(`Refusing to persist incomplete ${this.#e} bot data`);return this.#r(i=>{let e=i.find(t=>t.platformId===o.platformId&&t.botId!==o.botId),r=i.find(t=>t.tokenRef===o.tokenRef&&t.botId!==o.botId);if(e||r)throw new Error(`Duplicate ${this.#e} bot identity`);let A=i.findIndex(t=>t.botId===o.botId);return A===-1?i.push(o):i[A]=o,structuredClone(o)})}async remove(a){if(!this.#n.test(a))throw new TypeError(`Invalid ${this.#e} bot id`);return this.#r(o=>{let i=o.findIndex(r=>r.botId===a);if(i===-1)return null;let[e]=o.splice(i,1);return structuredClone(e)})}async clear(){let a=this.#g.then(async()=>{try{await N$(this.#A)}catch(o){if(o?.code!=="ENOENT")throw o}this.#I=Zm});this.#g=a.then(()=>{},()=>{}),await a}#o(a){if(!a||typeof a!="object")return null;let o=Oo(a.platformId),i=Oo(a.botId),e=Oo(a.tokenRef),r=Oo(a.name);if(!o||!i||!e||!r||!this.#n.test(i)||!this.#s.test(e))return null;let A=Ll(o,{botPrefix:this.#t,tokenRefPrefix:this.#a});return A.botId!==i||A.tokenRef!==e?null:Object.freeze({botId:i,platformId:o,tokenRef:e,name:r,username:Oo(a.username),createdAt:Oo(a.createdAt)??new Date().toISOString(),connectedAt:Oo(a.connectedAt)})}#i(a){if(!a||a.version!==1||!Array.isArray(a.bots))return null;let o=a.bots.map(A=>this.#o(A));if(o.some(A=>A===null))return null;let i=new Set,e=new Set,r=new Set;for(let A of o){if(i.has(A.botId)||e.has(A.platformId)||r.has(A.tokenRef))return null;i.add(A.botId),e.add(A.platformId),r.add(A.tokenRef)}return Object.freeze({version:1,bots:Object.freeze(o)})}async#r(a){let o,i=this.#g.then(async()=>{let e=[...this.#I.bots];o=a(e);let r=Object.freeze({version:1,bots:Object.freeze(e)});await this.#c(r),this.#I=r});return this.#g=i.then(()=>{},()=>{}),await i,o}async#c(a){await M$(R$(this.#A),{recursive:!0,mode:448});let o=`${this.#A}.tmp`;await T$(o,`${JSON.stringify(a,null,2)} -`,{encoding:"utf8",mode:384}),await _$(o,this.#A)}};var bv=Object.freeze({botPrefix:"discord",tokenRefPrefix:"DSH_DISCORD_BOT_TOKEN"});function _v(n){return Ll(n,bv)}function Nv(n){return Oh(n,"Discord\u673A\u5668\u4EBA")}var Mh=class extends rc{constructor(a){super(a,{channel:"Discord",...bv})}};function Ul(n){return typeof n=="string"&&n.trim()?n.trim():null}function bh(n,a){return Object.freeze({code:n,message:a})}var ic=class{#A;#e;#t;#a;#n;#s;#I;#g;#o;#i=new Map;#r=new Map;#c=new Map;#l=0;#E=!1;constructor({descriptor:a,credentials:o,configStore:i,inspectToken:e,deriveIdentity:r,maskPlatformId:A,createRuntime:t,deleteState:s=async()=>{},logger:g=console}){if(!a?.key||!a?.label||!a?.connectionLabel)throw new TypeError("TokenBotController requires a channel descriptor");if(!o||typeof o.resolve!="function"||typeof o.set!="function"||typeof o.unset!="function")throw new TypeError(`${a.label} requires the DSH credential provider`);if(!i||typeof i.list!="function"||typeof i.save!="function"||typeof i.remove!="function")throw new TypeError(`${a.label} requires a config store`);if(typeof e!="function"||typeof r!="function"||typeof A!="function"||typeof t!="function")throw new TypeError(`${a.label} controller dependencies are incomplete`);this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t,this.#g=s,this.#o=g}async initialize(){if(this.#E)return this.status();for(let a of this.#t.list())await this.#u(a.botId,async()=>{if(this.#E||this.#i.get(a.botId)?.status?.ready)return;let o=await this.#h(a.tokenRef);if(!o){this.#r.set(a.botId,bh("missing-token",`${this.#A.label}\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u79FB\u9664\u540E\u91CD\u65B0\u63A5\u5165\u3002`));return}try{await this.#C(a,o),this.#r.delete(a.botId)}catch(i){this.#r.set(a.botId,bh("connection-failed",`${this.#A.label}\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002`)),this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${a.botId} failed to initialize:`,i)}finally{this.#B()}});return this.status()}async bindCredentials({token:a}={}){if(this.#E)throw new Error(`${this.#A.label} controller is closed`);let o=Ul(a);if(!o)throw new TypeError(`${this.#A.label} Bot Token is required`);let i=await this.#a(o),e=Ul(i?.platformId),r=Ul(i?.name);if(!e||!r)throw new Error(`${this.#A.label} returned an invalid bot identity`);let A=this.#n(e);return await this.#u(A.botId,async()=>{if(this.#E)throw new Error(`${this.#A.label} controller is closed`);let t=this.#t.getByPlatformId(e),s=await this.#e.resolve(A.tokenRef).catch(()=>{}),g={botId:A.botId,platformId:e,tokenRef:A.tokenRef,name:r,username:Ul(i.username),createdAt:t?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()};await this.#e.set(A.tokenRef,o);try{await this.#t.save(g)}catch(c){throw await this.#d(A.tokenRef,s),c}try{await this.#C(g,o),this.#r.delete(A.botId)}catch(c){this.#r.set(A.botId,bh("connection-failed",`${this.#A.label}\u673A\u5668\u4EBA\u5DF2\u63A5\u5165\uFF0C\u6D88\u606F\u8FDE\u63A5\u6682\u672A\u5C31\u7EEA\u3002`)),this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${A.botId} credential connection failed:`,c)}this.#B()}),this.status()}async reconnectBot(a){let o=this.#t.get(a);if(!o)throw new Error(`Unknown ${this.#A.label} bot`);return await this.#u(a,async()=>{let i=await this.#h(o.tokenRef);if(!i)throw new Error(`${this.#A.label} bot token is missing`);try{await this.#C(o,i),this.#r.delete(a)}catch(e){throw this.#r.set(a,bh("connection-failed",`${this.#A.label}\u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`)),e}finally{this.#B()}}),this.status()}async deleteBot(a){let o=this.#t.get(a);if(!o)throw new Error(`Unknown ${this.#A.label} bot`);return await this.#u(a,async()=>{let i=await this.#e.resolve(o.tokenRef).catch(()=>{});await this.#p(a);try{await this.#e.unset(o.tokenRef),await this.#t.remove(a)}catch(e){throw i?.value&&(await this.#e.set(o.tokenRef,i.value).catch(()=>{}),await this.#C(o,i.value).catch(()=>{})),new Error(`Unable to remove the ${this.#A.label} bot safely.`,{cause:e})}await this.#g({botId:a,config:o}).catch(e=>{this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${a} state cleanup failed:`,e)}),this.#r.delete(a),this.#B()}),this.status()}status(){let a=this.#t.list().map(i=>{let e=this.#i.get(i.botId)?.status??null,r=e?.ready===!0&&e.connectionState==="connected"&&e.harnessReachable===!0,A=r?"connected":e?.connectionState==="connecting"?"connecting":this.#r.has(i.botId)||e?.connectionState==="failed"?"error":"offline";return{botId:i.botId,state:A,connected:r,configured:!0,bot:{name:i.name,username:i.username,idMasked:this.#s(i.platformId)},health:{status:r?"healthy":A==="error"?"error":"offline",summary:r?`${this.#A.label}${this.#A.connectionLabel}\u8FD0\u884C\u6B63\u5E38`:A==="error"?`${this.#A.label}\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5`:`${this.#A.label}\u8FDE\u63A5\u5F53\u524D\u79BB\u7EBF`,lastCheckedAt:e?.lastCheckedAt??null,lastConnectedAt:e?.lastConnectedAt??null},stats:{messagesReceived:e?.messagesReceived??0,messagesReplied:e?.messagesReplied??0},error:structuredClone(this.#r.get(i.botId)??null)}}),o=a.filter(i=>i.connected).length;return{schemaVersion:1,revision:this.#l,state:a.length===0?"disconnected":o===a.length?"connected":o>0?"degraded":"offline",bots:a,totals:{configured:a.length,connected:o}}}async close(){this.#E||(this.#E=!0,await Promise.allSettled([...this.#c.values()]),await Promise.allSettled([...this.#i.keys()].map(a=>this.#p(a))))}async#C(a,o){if(this.#E)throw new Error(`${this.#A.label} controller is closed`);if(await this.#p(a.botId),this.#E)throw new Error(`${this.#A.label} controller is closed`);let i=await this.#I({botId:a.botId,config:a,token:o});if(!i||typeof i.start!="function"||typeof i.stop!="function")throw new TypeError(`createRuntime returned an invalid ${this.#A.label} runtime`);this.#i.set(a.botId,i);try{await i.start()}catch(e){throw await i.stop().catch(()=>{}),this.#i.delete(a.botId),e}}async#p(a){let o=this.#i.get(a);this.#i.delete(a),await o?.stop().catch(i=>{this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${a} failed to stop cleanly:`,i)})}async#h(a){let o=await this.#e.resolve(a).catch(()=>{});return Ul(o?.value)}async#d(a,o){o?.value?await this.#e.set(a,o.value).catch(()=>{}):await this.#e.unset(a).catch(()=>{})}#u(a,o){let r=(this.#c.get(a)??Promise.resolve()).catch(()=>{}).then(o).finally(()=>{this.#c.get(a)===r&&this.#c.delete(a)});return this.#c.set(a,r),r}#B(){this.#l+=1}};var k$="https://discord.com/api/v10/";function Hl(n){return typeof n=="string"&&n.trim()?n.trim():null}function v$(n,a){let o=AbortSignal.timeout(a);return n?AbortSignal.any([n,o]):o}function P$(n,a){return new Promise((o,i)=>{if(a?.aborted){i(a.reason??new DOMException("Aborted","AbortError"));return}let e=setTimeout(o,n);e?.unref?.(),a?.addEventListener("abort",()=>{clearTimeout(e),i(a.reason??new DOMException("Aborted","AbortError"))},{once:!0})})}function oc(n,a){let o=Hl(n);if(!o||!/^\d{5,30}$/.test(o))throw new TypeError(`Invalid Discord ${a}`);return o}function G$(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{20,}$/.test(n.trim())}var Kl=class{#A;#e;#t;constructor({token:a,fetchImpl:o=fetch,baseUrl:i=k$}){if(!G$(a))throw new TypeError("Discord Bot Token is invalid");if(typeof o!="function")throw new TypeError("DiscordApi requires fetch");this.#A=a.trim(),this.#e=o,this.#t=new URL(i)}getCurrentUser(a={}){return this.#a("users/@me",{...a,method:"GET"})}getGatewayBot(a={}){return this.#a("gateway/bot",{...a,method:"GET"})}createMessage({channelId:a,content:o,replyToMessageId:i,signal:e}){return this.#a(`channels/${oc(a,"channel id")}/messages`,{method:"POST",signal:e,body:{content:o,allowed_mentions:{parse:[],replied_user:!1},...i?{message_reference:{message_id:oc(i,"message id"),channel_id:oc(a,"channel id"),fail_if_not_exists:!1}}:{}}})}editMessage({channelId:a,messageId:o,content:i,signal:e}){return this.#a(`channels/${oc(a,"channel id")}/messages/${oc(o,"message id")}`,{method:"PATCH",signal:e,body:{content:i,allowed_mentions:{parse:[],replied_user:!1}}})}sendTyping({channelId:a,signal:o}){return this.#a(`channels/${oc(a,"channel id")}/typing`,{method:"POST",signal:o,expectBody:!1})}async#a(a,{method:o,body:i,signal:e,timeoutMs:r=15e3,expectBody:A=!0,retry:t=!0}){let s;try{s=await this.#e(new URL(a,this.#t),{method:o,headers:{authorization:`Bot ${this.#A}`,"content-type":"application/json","user-agent":"DeepSeek-Harness-dsh-im (https://github.com/xmanrui/dsh-im, 0.2.2)"},...i===void 0?{}:{body:JSON.stringify(i)},signal:v$(e,r),redirect:"error"})}catch(c){throw c?.name==="AbortError"||c?.name==="TimeoutError"?c:new Error(`Discord ${o} transport failed`)}let g=null;if(A||s.status===429||!s.ok)try{g=await s.json()}catch{if(A)throw new Error(`Discord ${o} returned invalid JSON`)}if(s.status===429&&t){let c=Math.min(1e4,Math.max(50,Number(g?.retry_after)*1e3||1e3));return await P$(c,e),this.#a(a,{method:o,body:i,signal:e,timeoutMs:r,expectBody:A,retry:!1})}if(!s.ok){let c=new Error(Hl(g?.message)??`Discord API failed with HTTP ${s.status}`);throw c.code=`discord-${s.status}`,c}return A?g:null}};async function Tv(n,a={}){let i=await new Kl({token:n,...a}).getCurrentUser();if(!i?.id||i?.bot!==!0)throw new Error("Discord token does not belong to a bot");return{platformId:String(i.id),name:Hl(i.global_name)??Hl(i.username)??"Discord\u673A\u5668\u4EBA",username:Hl(i.username)}}function _h(n){return typeof n=="string"?n.trim():""}function lr(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null}}var Ri=class{#A;#e;#t;#a;#n;#s;#I;#g=new Map;constructor({descriptor:a,bot:o,harness:i,state:e,status:r=lr(),logger:A=console,replyTimeoutMs:t=6e5}){if(!a?.key||!a?.label)throw new TypeError("A channel descriptor is required");if(!o||typeof o.sendText!="function")throw new TypeError("A bot client is required");if(!i||!e)throw new TypeError("Harness client and state store are required");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t}get status(){return structuredClone(this.#n)}accept(a){let o=_h(a?.conversationId),i=a?.kind==="group"?"group":"direct",e=`${i}:${o}`,A=(this.#g.get(e)??Promise.resolve()).catch(()=>{}).then(()=>this.#o({...a,kind:i,conversationId:o})).finally(()=>{this.#g.get(e)===A&&this.#g.delete(e)});return this.#g.set(e,A),A}async waitForIdle(){await Promise.allSettled([...this.#g.values()])}async#o(a){let o=_h(a.messageId),i=_h(a.senderId);if(!o||!i||!a.conversationId||a.senderIsBot===!0||this.#a.hasSeen(o))return;if(this.#n.messagesReceived+=1,this.#n.lastMessageAt=new Date().toISOString(),a.kind==="group"&&a.addressed!==!0){this.#n.messagesRejected+=1,this.#n.lastRejectedAt=new Date().toISOString();return}let e=a.replyTarget,r=_h(a.content);try{if(!r){await this.#e.sendText(e,"\u76EE\u524D\u4EC5\u652F\u6301\u6587\u5B57\u6D88\u606F\u3002"),await this.#a.markSeen(o);return}let A=r.toLowerCase();if(A==="/help"){await this.#e.sendText(e,[`${this.#A.label}\u673A\u5668\u4EBA\u5DF2\u8FDE\u63A5 DeepSeek Harness\u3002`,"","\u76F4\u63A5\u53D1\u9001\u6587\u5B57\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002","/new \u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD","/status \u68C0\u67E5\u8FDE\u63A5\u72B6\u6001","/help \u663E\u793A\u672C\u5E2E\u52A9"].join(` +`,{encoding:"utf8",mode:384}),await _$(o,this.#A)}};var bv=Object.freeze({botPrefix:"discord",tokenRefPrefix:"DSH_DISCORD_BOT_TOKEN"});function _v(n){return Ll(n,bv)}function Nv(n){return Oh(n,"Discord\u673A\u5668\u4EBA")}var Mh=class extends rc{constructor(a){super(a,{channel:"Discord",...bv})}};function Ul(n){return typeof n=="string"&&n.trim()?n.trim():null}function bh(n,a){return Object.freeze({code:n,message:a})}var ic=class{#A;#e;#t;#a;#n;#s;#I;#g;#o;#i=new Map;#r=new Map;#c=new Map;#l=0;#E=!1;constructor({descriptor:a,credentials:o,configStore:i,inspectToken:e,deriveIdentity:r,maskPlatformId:A,createRuntime:t,deleteState:s=async()=>{},logger:g=console}){if(!a?.key||!a?.label||!a?.connectionLabel)throw new TypeError("TokenBotController requires a channel descriptor");if(!o||typeof o.resolve!="function"||typeof o.set!="function"||typeof o.unset!="function")throw new TypeError(`${a.label} requires the DSH credential provider`);if(!i||typeof i.list!="function"||typeof i.save!="function"||typeof i.remove!="function")throw new TypeError(`${a.label} requires a config store`);if(typeof e!="function"||typeof r!="function"||typeof A!="function"||typeof t!="function")throw new TypeError(`${a.label} controller dependencies are incomplete`);this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t,this.#g=s,this.#o=g}async initialize(){if(this.#E)return this.status();for(let a of this.#t.list())await this.#u(a.botId,async()=>{if(this.#E||this.#i.get(a.botId)?.status?.ready)return;let o=await this.#h(a.tokenRef);if(!o){this.#r.set(a.botId,bh("missing-token",`${this.#A.label}\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u79FB\u9664\u540E\u91CD\u65B0\u63A5\u5165\u3002`));return}try{await this.#C(a,o),this.#r.delete(a.botId)}catch(i){this.#r.set(a.botId,bh("connection-failed",`${this.#A.label}\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002`)),this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${a.botId} failed to initialize:`,i)}finally{this.#B()}});return this.status()}async bindCredentials({token:a}={}){if(this.#E)throw new Error(`${this.#A.label} controller is closed`);let o=Ul(a);if(!o)throw new TypeError(`${this.#A.label} Bot Token is required`);let i=await this.#a(o),e=Ul(i?.platformId),r=Ul(i?.name);if(!e||!r)throw new Error(`${this.#A.label} returned an invalid bot identity`);let A=this.#n(e);return await this.#u(A.botId,async()=>{if(this.#E)throw new Error(`${this.#A.label} controller is closed`);let t=this.#t.getByPlatformId(e),s=await this.#e.resolve(A.tokenRef).catch(()=>{}),g={botId:A.botId,platformId:e,tokenRef:A.tokenRef,name:r,username:Ul(i.username),createdAt:t?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()};await this.#e.set(A.tokenRef,o);try{await this.#t.save(g)}catch(c){throw await this.#d(A.tokenRef,s),c}try{await this.#C(g,o),this.#r.delete(A.botId)}catch(c){this.#r.set(A.botId,bh("connection-failed",`${this.#A.label}\u673A\u5668\u4EBA\u5DF2\u63A5\u5165\uFF0C\u6D88\u606F\u8FDE\u63A5\u6682\u672A\u5C31\u7EEA\u3002`)),this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${A.botId} credential connection failed:`,c)}this.#B()}),this.status()}async reconnectBot(a){let o=this.#t.get(a);if(!o)throw new Error(`Unknown ${this.#A.label} bot`);return await this.#u(a,async()=>{let i=await this.#h(o.tokenRef);if(!i)throw new Error(`${this.#A.label} bot token is missing`);try{await this.#C(o,i),this.#r.delete(a)}catch(e){throw this.#r.set(a,bh("connection-failed",`${this.#A.label}\u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`)),e}finally{this.#B()}}),this.status()}async deleteBot(a){let o=this.#t.get(a);if(!o)throw new Error(`Unknown ${this.#A.label} bot`);return await this.#u(a,async()=>{let i=await this.#e.resolve(o.tokenRef).catch(()=>{});await this.#p(a);try{await this.#e.unset(o.tokenRef),await this.#t.remove(a)}catch(e){throw i?.value&&(await this.#e.set(o.tokenRef,i.value).catch(()=>{}),await this.#C(o,i.value).catch(()=>{})),new Error(`Unable to remove the ${this.#A.label} bot safely.`,{cause:e})}await this.#g({botId:a,config:o}).catch(e=>{this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${a} state cleanup failed:`,e)}),this.#r.delete(a),this.#B()}),this.status()}status(){let a=this.#t.list().map(i=>{let e=this.#i.get(i.botId)?.status??null,r=e?.ready===!0&&e.connectionState==="connected"&&e.harnessReachable===!0,A=r?"connected":e?.connectionState==="connecting"?"connecting":this.#r.has(i.botId)||e?.connectionState==="failed"?"error":"offline";return{botId:i.botId,state:A,connected:r,configured:!0,bot:{name:i.name,username:i.username,idMasked:this.#s(i.platformId)},health:{status:r?"healthy":A==="error"?"error":"offline",summary:r?`${this.#A.label}${this.#A.connectionLabel}\u8FD0\u884C\u6B63\u5E38`:A==="error"?`${this.#A.label}\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5`:`${this.#A.label}\u8FDE\u63A5\u5F53\u524D\u79BB\u7EBF`,lastCheckedAt:e?.lastCheckedAt??null,lastConnectedAt:e?.lastConnectedAt??null},stats:{messagesReceived:e?.messagesReceived??0,messagesReplied:e?.messagesReplied??0},error:structuredClone(this.#r.get(i.botId)??null)}}),o=a.filter(i=>i.connected).length;return{schemaVersion:1,revision:this.#l,state:a.length===0?"disconnected":o===a.length?"connected":o>0?"degraded":"offline",bots:a,totals:{configured:a.length,connected:o}}}async close(){this.#E||(this.#E=!0,await Promise.allSettled([...this.#c.values()]),await Promise.allSettled([...this.#i.keys()].map(a=>this.#p(a))))}async#C(a,o){if(this.#E)throw new Error(`${this.#A.label} controller is closed`);if(await this.#p(a.botId),this.#E)throw new Error(`${this.#A.label} controller is closed`);let i=await this.#I({botId:a.botId,config:a,token:o});if(!i||typeof i.start!="function"||typeof i.stop!="function")throw new TypeError(`createRuntime returned an invalid ${this.#A.label} runtime`);this.#i.set(a.botId,i);try{await i.start()}catch(e){throw await i.stop().catch(()=>{}),this.#i.delete(a.botId),e}}async#p(a){let o=this.#i.get(a);this.#i.delete(a),await o?.stop().catch(i=>{this.#o.warn?.(`[dsh-im:${this.#A.key}] bot ${a} failed to stop cleanly:`,i)})}async#h(a){let o=await this.#e.resolve(a).catch(()=>{});return Ul(o?.value)}async#d(a,o){o?.value?await this.#e.set(a,o.value).catch(()=>{}):await this.#e.unset(a).catch(()=>{})}#u(a,o){let r=(this.#c.get(a)??Promise.resolve()).catch(()=>{}).then(o).finally(()=>{this.#c.get(a)===r&&this.#c.delete(a)});return this.#c.set(a,r),r}#B(){this.#l+=1}};var k$="https://discord.com/api/v10/";function Hl(n){return typeof n=="string"&&n.trim()?n.trim():null}function v$(n,a){let o=AbortSignal.timeout(a);return n?AbortSignal.any([n,o]):o}function P$(n,a){return new Promise((o,i)=>{if(a?.aborted){i(a.reason??new DOMException("Aborted","AbortError"));return}let e=setTimeout(o,n);e?.unref?.(),a?.addEventListener("abort",()=>{clearTimeout(e),i(a.reason??new DOMException("Aborted","AbortError"))},{once:!0})})}function oc(n,a){let o=Hl(n);if(!o||!/^\d{5,30}$/.test(o))throw new TypeError(`Invalid Discord ${a}`);return o}function G$(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{20,}$/.test(n.trim())}var Kl=class{#A;#e;#t;constructor({token:a,fetchImpl:o=fetch,baseUrl:i=k$}){if(!G$(a))throw new TypeError("Discord Bot Token is invalid");if(typeof o!="function")throw new TypeError("DiscordApi requires fetch");this.#A=a.trim(),this.#e=o,this.#t=new URL(i)}getCurrentUser(a={}){return this.#a("users/@me",{...a,method:"GET"})}getGatewayBot(a={}){return this.#a("gateway/bot",{...a,method:"GET"})}createMessage({channelId:a,content:o,replyToMessageId:i,signal:e}){return this.#a(`channels/${oc(a,"channel id")}/messages`,{method:"POST",signal:e,body:{content:o,allowed_mentions:{parse:[],replied_user:!1},...i?{message_reference:{message_id:oc(i,"message id"),channel_id:oc(a,"channel id"),fail_if_not_exists:!1}}:{}}})}editMessage({channelId:a,messageId:o,content:i,signal:e}){return this.#a(`channels/${oc(a,"channel id")}/messages/${oc(o,"message id")}`,{method:"PATCH",signal:e,body:{content:i,allowed_mentions:{parse:[],replied_user:!1}}})}sendTyping({channelId:a,signal:o}){return this.#a(`channels/${oc(a,"channel id")}/typing`,{method:"POST",signal:o,expectBody:!1})}async#a(a,{method:o,body:i,signal:e,timeoutMs:r=15e3,expectBody:A=!0,retry:t=!0}){let s;try{s=await this.#e(new URL(a,this.#t),{method:o,headers:{authorization:`Bot ${this.#A}`,"content-type":"application/json","user-agent":"DeepSeek-Harness-dsh-im (https://github.com/xmanrui/dsh-im, 0.3.0)"},...i===void 0?{}:{body:JSON.stringify(i)},signal:v$(e,r),redirect:"error"})}catch(c){throw c?.name==="AbortError"||c?.name==="TimeoutError"?c:new Error(`Discord ${o} transport failed`)}let g=null;if(A||s.status===429||!s.ok)try{g=await s.json()}catch{if(A)throw new Error(`Discord ${o} returned invalid JSON`)}if(s.status===429&&t){let c=Math.min(1e4,Math.max(50,Number(g?.retry_after)*1e3||1e3));return await P$(c,e),this.#a(a,{method:o,body:i,signal:e,timeoutMs:r,expectBody:A,retry:!1})}if(!s.ok){let c=new Error(Hl(g?.message)??`Discord API failed with HTTP ${s.status}`);throw c.code=`discord-${s.status}`,c}return A?g:null}};async function Tv(n,a={}){let i=await new Kl({token:n,...a}).getCurrentUser();if(!i?.id||i?.bot!==!0)throw new Error("Discord token does not belong to a bot");return{platformId:String(i.id),name:Hl(i.global_name)??Hl(i.username)??"Discord\u673A\u5668\u4EBA",username:Hl(i.username)}}function _h(n){return typeof n=="string"?n.trim():""}function lr(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null}}var Ri=class{#A;#e;#t;#a;#n;#s;#I;#g=new Map;constructor({descriptor:a,bot:o,harness:i,state:e,status:r=lr(),logger:A=console,replyTimeoutMs:t=6e5}){if(!a?.key||!a?.label)throw new TypeError("A channel descriptor is required");if(!o||typeof o.sendText!="function")throw new TypeError("A bot client is required");if(!i||!e)throw new TypeError("Harness client and state store are required");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t}get status(){return structuredClone(this.#n)}accept(a){let o=_h(a?.conversationId),i=a?.kind==="group"?"group":"direct",e=`${i}:${o}`,A=(this.#g.get(e)??Promise.resolve()).catch(()=>{}).then(()=>this.#o({...a,kind:i,conversationId:o})).finally(()=>{this.#g.get(e)===A&&this.#g.delete(e)});return this.#g.set(e,A),A}async waitForIdle(){await Promise.allSettled([...this.#g.values()])}async#o(a){let o=_h(a.messageId),i=_h(a.senderId);if(!o||!i||!a.conversationId||a.senderIsBot===!0||this.#a.hasSeen(o))return;if(this.#n.messagesReceived+=1,this.#n.lastMessageAt=new Date().toISOString(),a.kind==="group"&&a.addressed!==!0){this.#n.messagesRejected+=1,this.#n.lastRejectedAt=new Date().toISOString();return}let e=a.replyTarget,r=_h(a.content);try{if(!r){await this.#e.sendText(e,"\u76EE\u524D\u4EC5\u652F\u6301\u6587\u5B57\u6D88\u606F\u3002"),await this.#a.markSeen(o);return}let A=r.toLowerCase();if(A==="/help"){await this.#e.sendText(e,[`${this.#A.label}\u673A\u5668\u4EBA\u5DF2\u8FDE\u63A5 DeepSeek Harness\u3002`,"","\u76F4\u63A5\u53D1\u9001\u6587\u5B57\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002","/new \u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD","/status \u68C0\u67E5\u8FDE\u63A5\u72B6\u6001","/help \u663E\u793A\u672C\u5E2E\u52A9"].join(` `)),await this.#a.markSeen(o);return}if(A==="/status"){await this.#t.ensureRunning(),await this.#e.sendText(e,`${this.#A.label}\u673A\u5668\u4EBA\u4E0E DeepSeek Harness \u8FDE\u63A5\u6B63\u5E38\u3002`),await this.#a.markSeen(o);return}let t=`${a.kind}:${a.conversationId}`;if(A==="/new"){await this.#a.clearSession(t),await this.#e.sendText(e,"\u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002\u8BF7\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002"),await this.#a.markSeen(o);return}let s=this.#a.sessionFor(t);(!s||!await this.#t.sessionExists(s))&&(s=await this.#t.createSession(),await this.#a.setSession(t,s)),await this.#e.sendTyping?.(e).catch(C=>{this.#s.warn?.(`[dsh-im:${this.#A.key}] typing indicator failed:`,C)});let g=null,c=!1;if(typeof this.#e.openStream=="function")try{g=await this.#e.openStream(e)}catch(C){this.#s.warn?.(`[dsh-im:${this.#A.key}] unable to start a streamed reply; using text:`,C)}let l=await this.#t.ask(s,r,{timeoutMs:this.#I,onUpdate:g?async C=>{let u=C.type==="text"?C.text:C.type==="tool"?`\u6B63\u5728\u4F7F\u7528${C.name}\u2026`:C.text;u&&await g.update(u)}:void 0});if(g)try{await g.finish(l),c=!0}catch(C){g.cancel?.(),this.#s.warn?.(`[dsh-im:${this.#A.key}] streamed reply finalization failed; using text:`,C)}c||await this.#e.sendText(e,l),await this.#a.markSeen(o),this.#n.messagesReplied+=1,this.#n.lastReplyAt=new Date().toISOString(),this.#n.lastError=null}catch(A){this.#n.lastError=A?.message??String(A),this.#s.error?.(`[dsh-im:${this.#A.key}] failed to process a message:`,A);try{await this.#e.sendText(e,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"),await this.#a.markSeen(o)}catch(t){this.#s.error?.(`[dsh-im:${this.#A.key}] failed to send the safe error reply:`,t)}}}};var Xm=Object.freeze({key:"discord",label:"Discord",connectionLabel:" Gateway \u957F\u8FDE\u63A5"}),Nh=class extends Ri{constructor(a){super({descriptor:Xm,...a})}};var Yl=class extends ic{constructor(a){super({...a,descriptor:Xm,inspectToken:a.inspectToken??Tv,deriveIdentity:_v,maskPlatformId:Nv})}};import{spawn as F$}from"node:child_process";import{randomUUID as Rv}from"node:crypto";var kv=n=>new Promise(a=>setTimeout(a,n));function L$(n){return(n?.data?.message?.content??[]).filter(a=>a.type==="text"&&typeof a.text=="string").map(a=>a.text).join(` `).trim()}var $m=class{#A;#e;#t=null;#a=null;#n=new Map;#s="";#I=!1;#g=null;constructor({promptRpcId:a,afterSeq:o=-1}){this.#A=a,this.#e=o}get finished(){return this.#I}get answer(){return this.#s.trim()}get reason(){return this.#g}consume(a){let o=null,i=[...a].map(e=>e?.event??e).filter(Boolean).sort((e,r)=>(e.seq??-1)-(r.seq??-1));for(let e of i){let r=e.seq??-1;if(!(r<=this.#e)){if(this.#e=r,e.type==="turn/start"&&(this.#t=e.data?.turn??null),e.type==="user/message"&&e.data?.source?.rpcId===this.#A){this.#a=this.#t;continue}if(this.#a!==null){if(e.type==="turn/end"){if(e.data?.turn!==this.#a)continue;this.#I=!0,this.#g=e.data?.reason??null,this.#t=null;continue}if(e.data?.turn===this.#a){if(e.type==="assistant/chunk"&&e.data?.chunk?.type==="text-delta"){let A=e.data?.step??0,t=e.data.chunk.index??0,s=`${A}:${t}`;this.#n.set(s,(this.#n.get(s)??"")+e.data.chunk.text);let g=`${A}:`,c=[...this.#n.entries()].filter(([l])=>l.startsWith(g)).sort(([l],[C])=>Number(l.split(":")[1])-Number(C.split(":")[1])).map(([,l])=>l).join(` `).trim();c&&c!==this.#s&&(this.#s=c,o={type:"text",text:c});continue}if(e.type==="assistant/message"){let A=L$(e);A&&A!==this.#s&&(this.#s=A,o={type:"text",text:A});continue}e.type==="tool/call"?o={type:"tool",name:e.data?.name??"\u5DE5\u5177"}:e.type==="tool/result"&&(o={type:"status",text:"\u6B63\u5728\u6574\u7406\u7ED3\u679C\u2026"})}}}}return o}},Th=class extends Error{constructor(a,o){super(`${a}: ${o?.message??"unknown Harness RPC error"}`),this.name="HarnessRpcError",this.method=a,this.code=o?.code??"internal",this.details=o?.details??{}}},ka=class{#A;#e;#t;#a;#n;#s=null;constructor({baseUrl:a,workspace:o,agentPreset:i="standard",autostart:e=!1,dshBin:r="dsh"}){this.#A=new URL(a),this.#e=o,this.#t=i,this.#a=e,this.#n=r}async rpc(a,o={},i=3e4,e={}){let r=e.rpcId??`weixin-${Rv()}`,A=await fetch(new URL(`/api/${a}`,this.#A),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({type:"client-request",rpcId:r,method:a,payload:o}),signal:AbortSignal.timeout(i)});if(!A.ok)throw new Error(`Harness transport ${a} failed: HTTP ${A.status}`);let t=await A.json();if(t?.type!=="server-response"||t?.rpcId!==r)throw new Error(`Harness returned an invalid response for ${a}`);if(!t.result?.ok)throw new Th(a,t.result?.error);return t.result.value}async health(){return await this.rpc("host.describe",{},5e3),!0}async ensureRunning(){try{return await this.health()}catch(i){if(!this.#a)throw i}if(!this.#s||this.#s.exitCode!==null){let i=this.#A.port||(this.#A.protocol==="https:"?"443":"80");this.#s=F$(this.#n,["web","--host",this.#A.hostname,"--port",i],{cwd:this.#e,env:process.env,stdio:["ignore","inherit","inherit"]}),this.#s.on("error",e=>{console.error("[dsh-weixin] failed to start Harness:",e.message)})}let a=Date.now()+6e4,o;for(;Date.now()e.path===this.#e);return o?o.workspaceId:(await this.rpc("workspace.create",{path:this.#e})).workspace.workspaceId}async createSession(){await this.ensureRunning();let a=await this.workspaceId();return(await this.rpc("session.create",{workspaceId:a,agentPreset:this.#t})).sessionId}async sessionExists(a){try{return await this.rpc("session.history",{sessionId:a,maxMessages:1}),!0}catch(o){if(o instanceof Th&&o.code==="session-not-found")return!1;throw o}}async ask(a,o,i={}){typeof i=="number"&&(i={timeoutMs:i});let e=i.timeoutMs??6e5,r=typeof i.onUpdate=="function"?i.onUpdate:null;await this.ensureRunning();let A=await this.rpc("session.history",{sessionId:a,maxMessages:1}),t=Math.max(-1,...(A.events??[]).map(({event:l})=>l.seq??-1)),s=`weixin-${Rv()}`,g=new $m({promptRpcId:s,afterSeq:t});await this.rpc("session.prompt",{sessionId:a,mode:"queue",content:[{type:"text",text:o}],clientTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone},3e4,{rpcId:s});let c=Date.now()+e;for(;Date.now()a;){let r=e.lastIndexOf(` @@ -168,7 +168,7 @@ ${r.join(` `,{encoding:"utf8",mode:384}),await sde(o,this.#A)}};var fu=class extends ka{};var Cde="https://work.weixin.qq.com/ai/qc/generate",pde="https://work.weixin.qq.com/ai/qc/query_result";function Ux(){return process.platform==="win32"?2:process.platform==="linux"?3:1}function eI(n){return typeof n=="string"&&n.trim()?n.trim():null}function hde(n){let a=eI(n);if(!a)return null;try{let o=new URL(a);return o.protocol==="https:"&&o.hostname==="work.weixin.qq.com"&&(!o.port||o.port==="443")?o.href:null}catch{return null}}function dde(n,a){return n?AbortSignal.any([n,AbortSignal.timeout(a)]):AbortSignal.timeout(a)}async function Hx(n,a,o){let i=await n(a,{method:"GET",redirect:"error",signal:dde(o,1e4),headers:{accept:"application/json"}});if(!i.ok)throw new Error(`Enterprise WeChat QR service returned HTTP ${i.status}`);return i.json()}var yu=class{#A;#e;#t;#a;constructor({fetch:a=globalThis.fetch,clock:o=()=>Date.now(),source:i="deepseek-harness",platform:e=Ux()}={}){if(typeof a!="function")throw new TypeError("A fetch implementation is required");this.#A=a,this.#e=o,this.#t=i,this.#a=[1,2,3].includes(e)?e:Ux()}async start({signal:a}={}){let o=new URL(Cde);o.searchParams.set("source",this.#t),o.searchParams.set("plat",String(this.#a));let i=await Hx(this.#A,o,a),e=eI(i?.data?.scode),r=hde(i?.data?.auth_url);if(!e||!r)throw new Error("Enterprise WeChat QR service returned invalid data");return{scode:e,verificationUrl:r,expiresAt:this.#e()+3e5,pollIntervalMs:3e3}}async poll({scode:a,signal:o}={}){let i=eI(a);if(!i)throw new TypeError("Enterprise WeChat QR poll code is required");let e=new URL(pde);e.searchParams.set("scode",i);let r=await Hx(this.#A,e,o),A=eI(r?.data?.status)?.toLowerCase();if(A==="success"){let t=eI(r?.data?.bot_info?.botid),s=eI(r?.data?.bot_info?.secret);if(!t||!s)throw new Error("Enterprise WeChat QR result omitted bot credentials");return{status:"success",remoteBotId:t,secret:s}}return["expired","timeout"].includes(A)?{status:"expired"}:["fail","failed","error"].includes(A)?{status:"failed"}:{status:"waiting"}}};import{mkdir as Bde,readFile as ude,rename as Qde,unlink as fde,writeFile as yde}from"node:fs/promises";import{dirname as mde}from"node:path";var mu=Object.freeze({version:1,sessions:{},seenMessageIds:[]});function Sde(n){if(!n||typeof n!="object")return structuredClone(mu);let a={};if(n.sessions&&typeof n.sessions=="object"&&!Array.isArray(n.sessions))for(let[o,i]of Object.entries(n.sessions))typeof o=="string"&&typeof i=="string"&&i&&(a[o]=i);return{version:1,sessions:a,seenMessageIds:Array.isArray(n.seenMessageIds)?n.seenMessageIds.filter(o=>typeof o=="string").slice(-1e3):[]}}var Su=class{#A;#e=structuredClone(mu);#t=Promise.resolve();constructor(a){this.#A=a}async load(){try{this.#e=Sde(JSON.parse(await ude(this.#A,"utf8")))}catch(a){if(a?.code!=="ENOENT")throw a;this.#e=structuredClone(mu),await this.#a()}return this}sessionFor(a){return this.#e.sessions[a]??null}async setSession(a,o){this.#e.sessions[a]=o,await this.#a()}async clearSession(a){delete this.#e.sessions[a],await this.#a()}hasSeen(a){return this.#e.seenMessageIds.includes(a)}async markSeen(a){this.hasSeen(a)||(this.#e.seenMessageIds.push(a),this.#e.seenMessageIds.length>1e3&&this.#e.seenMessageIds.splice(0,this.#e.seenMessageIds.length-1e3),await this.#a())}async remove(){try{await fde(this.#A)}catch(a){if(a?.code!=="ENOENT")throw a}this.#e=structuredClone(mu)}async#a(){let a=`${JSON.stringify(this.#e,null,2)} `,o=this.#t.then(async()=>{await Bde(mde(this.#A),{recursive:!0,mode:448});let i=`${this.#A}.tmp`;await yde(i,a,{encoding:"utf8",mode:384}),await Qde(i,this.#A)});this.#t=o.then(()=>{},()=>{}),await o}};import{randomUUID as Dde}from"node:crypto";var Kx=new Set(["pending","connecting"]),uC=new Set(["connected","failed","cancelled","expired"]);function Ig(n){return typeof n=="string"&&n.trim()?n.trim():null}function ar(n,a){return Object.freeze({code:n,message:a})}function lg(n){return n?{attemptId:n.id,status:n.state,pollIntervalMs:n.pollIntervalMs,qrRevision:n.qrRevision,...n.verificationUrl?{verificationUrl:n.verificationUrl}:{},...n.expiresAt?{expiresAt:n.expiresAt}:{},...n.botId?{botId:n.botId}:{},...n.error?{error:structuredClone(n.error)}:{}}:null}var QC=class{#A;#e;#t;#a;#n;#s;#I=new Map;#g=new Map;#o=new Map;#i=null;#r=new Map;#c=0;#l=!1;constructor({qrAuth:a,credentials:o,configStore:i,createRuntime:e,deleteState:r=async()=>{},logger:A=console}){if(!a||typeof a.start!="function"||typeof a.poll!="function")throw new TypeError("Enterprise WeChat QR auth is required");if(!o||typeof o.resolve!="function"||typeof o.set!="function"||typeof o.unset!="function")throw new TypeError("WecomController requires the DSH credential provider");if(!i||typeof i.list!="function"||typeof i.save!="function"||typeof i.remove!="function")throw new TypeError("WecomController requires a config store");if(typeof e!="function")throw new TypeError("createRuntime is required");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A}async initialize(){if(this.#l)return this.status();for(let a of this.#t.list())await this.#Q(a.botId,async()=>{let o=this.#I.get(a.botId)?.status;if(this.#l||o?.ready||o?.wecomConnectionState==="connecting")return;let i=await this.#u(a.secretRef);if(!i){this.#g.set(a.botId,ar("missing-secret","\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u79FB\u9664\u540E\u91CD\u65B0\u626B\u7801\u3002"));return}try{await this.#h(a,i),this.#g.delete(a.botId)}catch{this.#g.set(a.botId,ar("connection-failed","\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002")),this.#s.warn?.(`[dsh-im:wecom] bot ${a.botId} failed to initialize`)}finally{this.#f()}});return this.status()}async startProvisioning(){if(this.#l)throw new Error("Enterprise WeChat controller is closed");this.#i&&await this.cancelProvisioning(this.#i);let a={id:Dde(),state:"pending",createdAt:Date.now(),expiresAt:null,pollIntervalMs:3e3,qrRevision:1,verificationUrl:null,scode:null,botId:null,error:null,controller:new AbortController,polling:null,transition:null};this.#o.set(a.id,a),this.#i=a.id,this.#f();try{let o=await this.#A.start({signal:a.controller.signal});if(a.scode=Ig(o.scode),a.verificationUrl=Ig(o.verificationUrl),a.expiresAt=Number(o.expiresAt),a.pollIntervalMs=Math.min(1e4,Math.max(500,Number(o.pollIntervalMs)||3e3)),!a.scode||!a.verificationUrl||!Number.isFinite(a.expiresAt))throw new Error("Enterprise WeChat QR auth returned incomplete data");return this.#f(),lg(a)}catch(o){throw a.state=a.controller.signal.aborted?"cancelled":"failed",a.error=a.controller.signal.aborted?ar("cancelled","\u626B\u7801\u7ED1\u5B9A\u5DF2\u53D6\u6D88\u3002"):ar("qr-start-failed","\u65E0\u6CD5\u751F\u6210\u4F01\u4E1A\u5FAE\u4FE1\u4E8C\u7EF4\u7801\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"),this.#y(a),o}}async registrationStatus(a){let o=this.#o.get(a);if(!o||uC.has(o.state))return lg(o);if(o.state==="connecting")return await o.transition?.catch(()=>{}),lg(o);if(Date.now()>=o.expiresAt)return o.state="expired",o.error=ar("expired","\u4F01\u4E1A\u5FAE\u4FE1\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u3002"),o.controller.abort(),this.#y(o),lg(o);if(!o.polling){let i=this.#E(o).finally(()=>{o.polling===i&&(o.polling=null)});o.polling=i}return await o.polling.catch(()=>{}),lg(o)}async bindCredentials({botId:a,secret:o}={}){if(this.#l)throw new Error("Enterprise WeChat controller is closed");let i=Ig(a),e=Ig(o);if(!i||!e)throw new TypeError("Enterprise WeChat Bot ID and Secret are required");if(this.#i&&await this.cancelProvisioning(this.#i),this.#l)throw new Error("Enterprise WeChat controller is closed");let r=Qu(i);return await this.#Q(r.botId,async()=>{if(this.#l)throw new Error("Enterprise WeChat controller is closed");let A=this.#t.getByRemoteBotId(i),t=await this.#e.resolve(r.secretRef).catch(()=>{});if(this.#l)throw new Error("Enterprise WeChat controller is closed");let s={botId:r.botId,remoteBotId:i,secretRef:r.secretRef,createdAt:A?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()};await this.#e.set(r.secretRef,e);try{await this.#t.save(s)}catch(g){throw await this.#B(r.secretRef,t),g}try{await this.#h(s,e),this.#g.delete(r.botId)}catch{this.#g.set(r.botId,ar("connection-failed","\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u5DF2\u7ED1\u5B9A\uFF0C\u6D88\u606F\u8FDE\u63A5\u6682\u672A\u5C31\u7EEA\u3002")),this.#s.warn?.(`[dsh-im:wecom] bot ${r.botId} credential connection failed`)}this.#f()}),this.status()}async cancelProvisioning(a){let o=this.#o.get(a);return o?(uC.has(o.state)||(o.controller.abort(),await Promise.allSettled([o.polling,o.transition].filter(Boolean)),uC.has(o.state)||(o.state="cancelled"),o.error??=ar("cancelled","\u626B\u7801\u7ED1\u5B9A\u5DF2\u53D6\u6D88\u3002"),this.#y(o)),lg(o)):null}async reconnectBot(a){let o=this.#t.get(a);if(!o)throw new Error("Unknown Enterprise WeChat bot");return await this.#Q(a,async()=>{let i=await this.#u(o.secretRef);if(!i)throw new Error("Enterprise WeChat bot secret is missing");try{await this.#h(o,i),this.#g.delete(a)}catch(e){throw this.#g.set(a,ar("connection-failed","\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")),e}finally{this.#f()}}),this.status()}async deleteBot(a){let o=this.#t.get(a);if(!o)throw new Error("Unknown Enterprise WeChat bot");return await this.#Q(a,async()=>{let i=await this.#e.resolve(o.secretRef).catch(()=>{});await this.#d(a);try{await this.#e.unset(o.secretRef),await this.#t.remove(a)}catch(e){throw i?.value&&(await this.#e.set(o.secretRef,i.value).catch(()=>{}),await this.#h(o,i.value).catch(()=>{})),new Error("Unable to remove the Enterprise WeChat bot safely.",{cause:e})}await this.#n({botId:a,config:o}).catch(e=>{this.#s.warn?.(`[dsh-im:wecom] bot ${a} state cleanup failed:`,e)}),this.#g.delete(a),this.#f()}),this.status()}status(){let a=this.#t.list().map(e=>{let r=this.#I.get(e.botId)?.status??null,A=r?.ready===!0&&r.wecomConnectionState==="connected"&&r.harnessReachable===!0,t=A?"connected":r?.wecomConnectionState==="connecting"?"connecting":this.#g.has(e.botId)||r?.wecomConnectionState==="failed"?"error":"offline";return{botId:e.botId,state:t,connected:A,configured:!0,bot:{name:"\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA",appIdMasked:Fx(e.remoteBotId)},health:{status:A?"healthy":t==="error"?"error":"offline",summary:A?"\u4F01\u4E1A\u5FAE\u4FE1 WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38":t==="error"?"\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5":"\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5F53\u524D\u79BB\u7EBF",lastCheckedAt:r?.lastCheckedAt??null,lastConnectedAt:r?.lastConnectedAt??null},stats:{messagesReceived:r?.messagesReceived??0,messagesReplied:r?.messagesReplied??0},error:structuredClone(this.#g.get(e.botId)??null)}}),o=a.filter(e=>e.connected).length,i=this.#i?this.#o.get(this.#i):null;return{schemaVersion:1,revision:this.#c,state:i&&Kx.has(i.state)?"provisioning":a.length===0?"disconnected":o===a.length?"connected":o>0?"degraded":"offline",bots:a,totals:{configured:a.length,connected:o},...i&&Kx.has(i.state)?{provisioning:lg(i)}:{}}}async close(){this.#l||(this.#l=!0,this.#i&&await this.cancelProvisioning(this.#i),await Promise.allSettled([...this.#r.values()]),await Promise.allSettled([...this.#I.keys()].map(a=>this.#d(a))))}async#E(a){try{let o=await this.#A.poll({scode:a.scode,signal:a.controller.signal});if(a.controller.signal.aborted||uC.has(a.state)||o.status==="waiting")return;if(o.status==="expired"){a.state="expired",a.error=ar("expired","\u4F01\u4E1A\u5FAE\u4FE1\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u3002"),this.#y(a);return}if(o.status!=="success"){a.state="failed",a.error=ar("qr-connect-failed","\u4F01\u4E1A\u5FAE\u4FE1\u626B\u7801\u6CA1\u6709\u5B8C\u6210\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801\u3002"),this.#y(a);return}a.state="connecting",a.verificationUrl=null,a.expiresAt=null,a.scode=null,this.#f();let i=this.#C(a,o);a.transition=i,await i}catch{if(a.controller.signal.aborted)return;a.state="failed",a.error=ar("qr-connect-failed","\u4F01\u4E1A\u5FAE\u4FE1\u626B\u7801\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801\u3002"),this.#s.warn?.("[dsh-im:wecom] QR polling failed"),this.#y(a)}}async#C(a,o){try{let i=Ig(o.remoteBotId),e=Ig(o.secret);if(!i||!e)throw new Error("Enterprise WeChat authorization returned incomplete credentials");a.botId=await this.#p(a,{remoteBotId:i,secret:e}),a.state="connected",a.error=null}catch{a.controller.signal.aborted?(a.state="cancelled",a.error=ar("cancelled","\u626B\u7801\u7ED1\u5B9A\u5DF2\u53D6\u6D88\u3002")):(a.state="failed",a.error=ar("activation-failed","\u4F01\u4E1A\u5FAE\u4FE1\u5DF2\u6388\u6743\uFF0C\u4F46\u65E0\u6CD5\u5B89\u5168\u4FDD\u5B58\u63A5\u5165\u914D\u7F6E\u3002"),this.#s.error?.("[dsh-im:wecom] provisioning failed"))}finally{this.#y(a)}}async#p(a,{remoteBotId:o,secret:i}){let e=Qu(o),r=this.#t.getByRemoteBotId(o),A=await this.#e.resolve(e.secretRef).catch(()=>{}),t={botId:e.botId,remoteBotId:o,secretRef:e.secretRef,createdAt:r?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()};return this.#Q(e.botId,async()=>{await this.#e.set(e.secretRef,i);try{if(a.controller.signal.aborted)throw new DOMException("Cancelled","AbortError");await this.#t.save(t)}catch(s){throw await this.#B(e.secretRef,A),s}try{if(a.controller.signal.aborted)throw new DOMException("Cancelled","AbortError");await this.#h(t,i),this.#g.delete(e.botId)}catch(s){if(a.controller.signal.aborted)throw await this.#d(e.botId),r?await this.#t.save(r).catch(()=>{}):await this.#t.remove(e.botId).catch(()=>{}),await this.#B(e.secretRef,A),s;this.#g.set(e.botId,ar("connection-failed","\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u5DF2\u7ED1\u5B9A\uFF0C\u6D88\u606F\u8FDE\u63A5\u6682\u672A\u5C31\u7EEA\u3002")),this.#s.warn?.(`[dsh-im:wecom] bot ${e.botId} activation connection failed`)}return this.#f(),e.botId})}async#h(a,o){if(this.#l)throw new Error("Enterprise WeChat controller is closed");if(await this.#d(a.botId),this.#l)throw new Error("Enterprise WeChat controller is closed");let i=await this.#a({botId:a.botId,config:a,secret:o});if(!i||typeof i.start!="function"||typeof i.stop!="function")throw new TypeError("createRuntime returned an invalid Enterprise WeChat runtime");this.#I.set(a.botId,i);try{await i.start()}catch(e){throw await i.stop().catch(()=>{}),this.#I.delete(a.botId),e}}async#d(a){let o=this.#I.get(a);this.#I.delete(a),await o?.stop().catch(i=>{this.#s.warn?.(`[dsh-im:wecom] bot ${a} failed to stop cleanly:`,i)})}async#u(a){let o=await this.#e.resolve(a).catch(()=>{});return Ig(o?.value)}async#B(a,o){o?.value?await this.#e.set(a,o.value).catch(()=>{}):await this.#e.unset(a).catch(()=>{})}#Q(a,o){let r=(this.#r.get(a)??Promise.resolve()).catch(()=>{}).then(o).finally(()=>{this.#r.get(a)===r&&this.#r.delete(a)});return this.#r.set(a,r),r}#y(a){a.scode=null,a.verificationUrl=null,a.expiresAt=null,this.#i===a.id&&(this.#i=null),this.#f();let o=[...this.#o.values()].filter(i=>uC.has(i.state));for(;o.length>16;)this.#o.delete(o.shift().id)}#f(){this.#c+=1}};import{WSAuthFailureError as Nde,WSClient as Tde,WSReconnectExhaustedError as Rde}from"@wecom/aibot-node-sdk";import{generateReqId as wde}from"@wecom/aibot-node-sdk";var Ode=["\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u5DF2\u8FDE\u63A5 DeepSeek Harness\u3002","","\u76F4\u63A5\u53D1\u9001\u6587\u5B57\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002","/new \u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD","/status \u68C0\u67E5\u8FDE\u63A5\u72B6\u6001","/help \u663E\u793A\u672C\u5E2E\u52A9"].join(` `),Mde=18e3;function F_(n){return n?.body&&typeof n.body=="object"?n.body:{}}function Yx(n){let a=F_(n);return a.chattype==="group"?`group:${a.chatid}`:`direct:${a.from?.userid}`}function bde(n){let a=F_(n);return a.msgtype==="text"?typeof a.text?.content=="string"?a.text.content.trim():"":a.msgtype==="voice"?typeof a.voice?.content=="string"?a.voice.content.trim():"":a.msgtype==="mixed"&&Array.isArray(a.mixed?.msg_item)?a.mixed.msg_item.filter(o=>o?.msgtype==="text"&&typeof o.text?.content=="string").map(o=>o.text.content).join(` -`).trim():""}function Du(n,a=Mde){let o=String(n??"").trim();if(!o)return[];let i=[],e="",r=0;for(let A of o){let t=Buffer.byteLength(A);e&&r+t>a?(i.push(e),e=A,r=t):(e+=A,r+=t)}return e&&i.push(e),i}function _de(n){return n?.type==="text"?n.text:n?.type==="tool"?`\u6B63\u5728\u4F7F\u7528${n.name}\u2026`:n?.text}function L_(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null}}var wu=class{#A;#e;#t;#a;#n;#s;#I;#g=new Map;constructor({client:a,harness:o,state:i,status:e=L_(),logger:r=console,replyTimeoutMs:A=6e5,generateStreamId:t=wde}){if(!a||typeof a.replyStream!="function"||typeof a.sendMessage!="function")throw new TypeError("Enterprise WeChat client is required");if(!o||!i)throw new TypeError("Harness client and state store are required");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t}get status(){return structuredClone(this.#a)}accept(a){let o=Yx(a),e=(this.#g.get(o)??Promise.resolve()).catch(()=>{}).then(()=>this.#r(a)).finally(()=>{this.#g.get(o)===e&&this.#g.delete(o)});return this.#g.set(o,e),e}async waitForIdle(){await Promise.allSettled([...this.#g.values()])}async#o(a,o){for(let i of Du(o))await this.#A.sendMessage(a,{msgtype:"markdown",markdown:{content:i}})}async#i(a,o,i){let e=Du(i);if(e.length!==0)try{await this.#A.replyStream(a,this.#I("stream"),e[0],!0);for(let r of e.slice(1))await this.#A.sendMessage(o,{msgtype:"markdown",markdown:{content:r}})}catch{await this.#o(o,i)}}async#r(a){let o=F_(a),i=typeof o.msgid=="string"?o.msgid:"",e=typeof o.from?.userid=="string"?o.from.userid:"",r=o.chattype==="group"?o.chatid:e;if(!i||!e||!r||!["single","group"].includes(o.chattype)||this.#t.hasSeen(i))return;this.#a.messagesReceived+=1,this.#a.lastMessageAt=new Date().toISOString();let A=bde(a),t=null,s=!1;try{if(!A){await this.#i(a,r,"\u76EE\u524D\u652F\u6301\u6587\u5B57\u3001\u8BED\u97F3\u8F6C\u5199\u548C\u56FE\u6587\u6DF7\u6392\u4E2D\u7684\u6587\u5B57\u6D88\u606F\u3002"),await this.#t.markSeen(i);return}let g=A.toLowerCase();if(g==="/help"){await this.#i(a,r,Ode),await this.#t.markSeen(i);return}if(g==="/status"){await this.#e.ensureRunning(),await this.#i(a,r,"\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u4E0E DeepSeek Harness \u8FDE\u63A5\u6B63\u5E38\u3002"),await this.#t.markSeen(i);return}let c=Yx(a);if(g==="/new"){await this.#t.clearSession(c),await this.#i(a,r,"\u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002\u8BF7\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002"),await this.#t.markSeen(i);return}let l=this.#t.sessionFor(c);(!l||!await this.#e.sessionExists(l))&&(l=await this.#e.createSession(),await this.#t.setSession(c,l)),t=this.#I("stream");try{await this.#A.replyStream(a,t,"\u6B63\u5728\u601D\u8003\u4E2D\u2026",!1),s=!0}catch(f){this.#n.warn?.("[dsh-im:wecom] unable to start a stream; using an active reply:",f)}let C=await this.#e.ask(l,A,{timeoutMs:this.#s,onUpdate:s&&typeof this.#A.replyStreamNonBlocking=="function"?async f=>{let y=Du(_de(f))[0];y&&await this.#A.replyStreamNonBlocking(a,t,y,!1)}:void 0}),u=Du(C||"\u4EFB\u52A1\u5DF2\u5B8C\u6210\uFF0C\u4F46\u6CA1\u6709\u751F\u6210\u53EF\u663E\u793A\u7684\u6587\u672C\u3002"),Q=!1;if(s&&u.length>0)try{await this.#A.replyStream(a,t,u[0],!0);for(let f of u.slice(1))await this.#A.sendMessage(r,{msgtype:"markdown",markdown:{content:f}});Q=!0}catch(f){this.#n.warn?.("[dsh-im:wecom] stream finalization failed; using an active reply:",f)}Q||await this.#o(r,C),await this.#t.markSeen(i),this.#a.messagesReplied+=1,this.#a.lastReplyAt=new Date().toISOString(),this.#a.lastError=null}catch(g){this.#a.lastError=g?.message??String(g),this.#n.error?.("[dsh-im:wecom] failed to process an inbound message");try{s&&t?await this.#A.replyStream(a,t,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",!0):await this.#i(a,r,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"),await this.#t.markSeen(i)}catch{this.#n.error?.("[dsh-im:wecom] failed to send the safe error reply")}}}};function kde(){let n=new Error("Enterprise WeChat WebSocket authentication timed out");return n.code="connect-timeout",n}function vde(){return{startedAt:null,ready:!1,wecomConnectionState:"idle",harnessReachable:!1,lastCheckedAt:null,lastConnectedAt:null,lastError:null,...L_()}}var fC=class{#A;#e;#t;#a;#n;#s;#I;#g;#o;#i=vde();#r=null;#c=null;#l=null;#E=null;constructor({config:a,secret:o,harness:i,state:e,logger:r=console,replyTimeoutMs:A=6e5,connectTimeoutMs:t=2e4,maxReconnectAttempts:s=10,createClient:g=c=>new Tde(c)}){if(!a||!o||!i||!e)throw new TypeError("WecomRuntime requires config, secret, Harness, and state");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t,this.#g=s,this.#o=g}get status(){return structuredClone(this.#i)}async start(){if(this.#i.ready&&this.#r)return this.status;if(this.#l)return this.#l;let a=new AbortController;return this.#E=a,this.#l=this.#C(a.signal).finally(()=>{this.#E===a&&(this.#E=null),this.#l=null}),this.#l}async#C(a){await this.#p(),a.throwIfAborted(),this.#i.startedAt=new Date().toISOString(),this.#i.wecomConnectionState="connecting",this.#i.lastError=null,await this.#t.ensureRunning(),this.#i.harnessReachable=!0;let o={debug(){},info(){},warn(){},error(){}},i=this.#o({botId:this.#A.remoteBotId,secret:this.#e,logger:o,maxReconnectAttempts:this.#g});if(!i||typeof i.connect!="function"||typeof i.disconnect!="function")throw new TypeError("Enterprise WeChat client factory returned an invalid client");this.#r=i,this.#c=new wu({client:i,harness:this.#t,state:this.#a,status:this.#i,logger:this.#n,replyTimeoutMs:this.#s});let e,r,A=!1,t=new Promise((Q,f)=>{e=Q,r=f}),s=()=>{if(this.#r!==i||a.aborted)return;A=!0;let Q=Date.now();this.#i.ready=!0,this.#i.wecomConnectionState="connected",this.#i.lastCheckedAt=Q,this.#i.lastConnectedAt=Q,this.#i.lastError=null,e()},g=()=>{this.#r===i&&(this.#i.ready=!1,this.#i.wecomConnectionState="connecting",this.#i.lastCheckedAt=Date.now())},c=()=>{this.#r===i&&(this.#i.ready=!1,this.#i.wecomConnectionState="connecting",this.#i.lastCheckedAt=Date.now())},l=Q=>{if(this.#r!==i)return;let f=Q instanceof Nde||Q instanceof Rde;!A&&f&&r(Q),f&&(this.#i.ready=!1,this.#i.wecomConnectionState="failed"),this.#i.lastError=f?Q.name:"connection-error",this.#n.warn?.(`[dsh-im:wecom] bot ${this.#A.botId} connection error`)},C=Q=>this.#c?.accept(Q);i.on("authenticated",s),i.on("disconnected",g),i.on("reconnecting",c),i.on("error",l),i.on("message",C);let u;try{return i.connect(),await Promise.race([t,new Promise((Q,f)=>{a.addEventListener("abort",()=>f(a.reason),{once:!0})}),new Promise((Q,f)=>{u=setTimeout(()=>f(kde()),this.#I)})]),this.status}catch(Q){throw a.aborted?(await this.#p(),Q):(this.#i.ready=!1,this.#i.wecomConnectionState="failed",this.#i.lastError=Q?.message??String(Q),await this.#p(),Q)}finally{clearTimeout(u)}}async stop(){let a=this.#l;return this.#E?.abort(new DOMException("Enterprise WeChat runtime stopped","AbortError")),await this.#p(),await a?.catch(()=>{}),this.status}async#p(){let a=this.#r,o=this.#c;this.#r=null,this.#c=null;try{a?.disconnect(),a?.removeAllListeners?.()}catch{this.#n.warn?.(`[dsh-im:wecom] bot ${this.#A.botId} failed to stop cleanly`)}await o?.waitForIdle(),this.#i.ready=!1,this.#i.wecomConnectionState="idle"}};var xx=Object.freeze([250,1e3,3e3,5e3,1e4,3e4]);function Pde(n){if(!Array.isArray(n)||n.length===0)return[...xx];let a=n.filter(o=>Number.isFinite(o)&&o>=0);return a.length>0?a:[...xx]}var Ou=class{#A;#e;#t;#a;#n;#s;#I;#g=null;#o=null;#i=0;#r=!1;#c=!1;#l;#E;constructor({controller:a,harness:o,logger:i=console,retryDelaysMs:e,healthyIntervalMs:r=15e3,setTimeoutImpl:A=setTimeout,clearTimeoutImpl:t=clearTimeout}){if(!a||typeof a.initialize!="function"||typeof a.status!="function")throw new TypeError("ConnectionSupervisor requires a controller");if(!o||typeof o.ensureRunning!="function")throw new TypeError("ConnectionSupervisor requires a Harness client");this.#A=a,this.#e=o,this.#t=i,this.#a=Pde(e),this.#n=Number.isFinite(r)&&r>=0?r:15e3,this.#s=A,this.#I=t,this.#l=new Promise(s=>{this.#E=s})}get ready(){return this.#l}start(){return this.#c||this.#r?this:(this.#c=!0,this.#C(0),this)}async close(){this.#r||(this.#r=!0,this.#g!==null&&this.#I(this.#g),this.#g=null,await this.#o?.catch(()=>{}),this.#E?.(null),this.#E=null)}#C(a){this.#r||(this.#g=this.#s(()=>{this.#g=null,this.#p()},a),this.#g?.unref?.())}async#p(){if(this.#r||this.#o)return;let a=this.#h();this.#o=a;try{await a}finally{this.#o===a&&(this.#o=null)}}async#h(){try{if(await this.#e.ensureRunning(),this.#r)return;let a=await this.#A.initialize();if(this.#r)return;this.#E?.(a),this.#E=null;let{configured:o,connected:i}=a.totals;if(i65535)throw new Error("dsh-im Enterprise WeChat requires an initialized DSH webServer port");return new URL(`http://127.0.0.1:${o}`)}function Ude(n){let a=AI(n.dshHome??process.env.DSH_HOME??Mu(Fde(),".dsh")),o=AI(n.dataDir??Mu(a,"integrations","dsh-wecom"));return{config:AI(n.configPath??Mu(o,"config.json")),bots:AI(n.botsDir??Mu(o,"bots"))}}async function H_(n,a={},o={}){if(!n?.credentials)throw new TypeError("dsh-im Enterprise WeChat requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-im Enterprise WeChat requires ctx.webServer");let i=o.ConfigStore??uu,e=o.StateStore??Su,r=o.HarnessClient??fu,A=o.Controller??QC,t=o.Runtime??fC,s=o.QrAuth??yu,g=o.createConnectionSupervisor??U_,c=typeof n.logger=="function"?n.logger("dsh-im:wecom"):n.logger??console,l=Ude(a),C=await new i(l.config).load(),u=o.qrAuth??new s({source:a.qrSource??"deepseek-harness",platform:a.qrPlatform}),Q=new Map,f=k=>AI(l.bots,k,"state.json"),y=async k=>{let U=Q.get(k);return U||(U=await new e(f(k)).load(),Q.set(k,U)),U},m=new r({baseUrl:Lde(n.webServer,a.harnessBaseUrl),workspace:AI(a.workspace??process.cwd()),agentPreset:a.agentPreset??"standard",autostart:!1,dshBin:a.dshBin??"dsh"}),R=new A({qrAuth:u,credentials:n.credentials,configStore:C,logger:c,createRuntime:async({botId:k,config:U,secret:H})=>new t({config:U,secret:H,harness:m,state:await y(k),replyTimeoutMs:a.replyTimeoutMs??6e5,connectTimeoutMs:a.connectTimeoutMs??2e4,maxReconnectAttempts:a.maxReconnectAttempts??10,logger:{error:(...F)=>c.error?.(`[${k}]`,...F),warn:(...F)=>c.warn?.(`[${k}]`,...F),info:(...F)=>c.info?.(`[${k}]`,...F),debug:(...F)=>c.debug?.(`[${k}]`,...F)}}),deleteState:async({botId:k})=>{let U=Q.get(k);if(Q.delete(k),U&&typeof U.remove=="function")return U.remove();try{await Gde(f(k))}catch(H){if(H?.code!=="ENOENT")throw H}}}),N=g({controller:R,harness:m,logger:c,retryDelaysMs:a.retryDelaysMs,healthyIntervalMs:a.healthyIntervalMs}).start();return{controller:R,ready:N.ready,async close(){await N.close(),await R.close(),m.stopManagedProcess()}}}import Hde from"qrcode";var jx="/wecom",Ha=Object.freeze({status:"connection.status",beginProvisioning:"provision.begin",pollProvisioning:"provision.poll",cancelProvisioning:"provision.cancel",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete"}),qx=Object.freeze(Object.values(Ha)),Kde=new Set(["secret","secretRef","scode","remoteBotId","verificationUrl","bot_info","botid"]);function x_(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function tI(n,a){return x_(n)&&Object.keys(n).every(o=>a.includes(o))}function K_(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n)}function Jx(n,a){return typeof n=="string"&&n.trim().length>0&&n.length<=a}function Yde(n,a){return x_(a)?n===Ha.status?tI(a,[])?null:"connection.status does not accept fields.":n===Ha.beginProvisioning?tI(a,["locale"])&&(a.locale===void 0||a.locale==="zh-CN")?null:"provision.begin received unsupported fields.":[Ha.pollProvisioning,Ha.cancelProvisioning].includes(n)?tI(a,["attemptId"])&&K_(a.attemptId)?null:`${n} requires an attemptId.`:n===Ha.bindCredentials?tI(a,["botId","secret"])&&Jx(a.botId,512)&&Jx(a.secret,1024)?null:"bot.bind-credentials requires Bot ID and Secret.":n===Ha.reconnectBot?tI(a,["botId"])&&K_(a.botId)?null:"bot.reconnect requires a botId.":n===Ha.deleteBot?tI(a,["botId","confirm"])&&K_(a.botId)&&a.confirm===!0?null:"bot.delete requires a botId and confirm=true.":"Unknown Enterprise WeChat endpoint.":"Payload must be an object."}function aI(n){if(Array.isArray(n))return n.map(aI);if(!x_(n))return n;let a={};for(let[o,i]of Object.entries(n))Kde.has(o)||(a[o]=aI(i));return a}async function xde(n){return Hde.toDataURL(n,{type:"image/png",errorCorrectionLevel:"M",margin:2,width:320})}async function Y_(n,a){return!n||typeof n.verificationUrl!="string"?aI(n):aI({...n,qrCodeDataUrl:await a(n.verificationUrl)})}async function bu(n,a){let o=structuredClone(n);return o?.provisioning&&(o.provisioning=await Y_(o.provisioning,a)),aI(o)}function Vx(n,{encodeQr:a=xde}={}){for(let e of["status","startProvisioning","registrationStatus","cancelProvisioning","bindCredentials","reconnectBot","deleteBot"])if(typeof n?.[e]!="function")throw new TypeError(`A complete Enterprise WeChat controller is required (${e})`);let o=new Map,i=e=>{let r=o.get(e);return r||(o.size>=16&&o.delete(o.keys().next().value),r=Promise.resolve().then(()=>a(e)),o.set(e,r)),r};return async(e,r,A)=>{if(A?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};if(!qx.includes(e))return{ok:!1,error:{code:"bad-request",message:"Unknown Enterprise WeChat endpoint."}};let t=Yde(e,r);if(t)return{ok:!1,error:{code:"bad-request",message:t}};try{let s;if(e===Ha.status)s=await bu(await n.status(),i);else if(e===Ha.beginProvisioning)s=await Y_(await n.startProvisioning(),i);else if(e===Ha.pollProvisioning){let g=await n.registrationStatus(r.attemptId);if(!g)return{ok:!1,error:{code:"bad-request",message:"The provisioning attempt no longer exists."}};s=await Y_(g,i)}else e===Ha.cancelProvisioning?s=aI(await n.cancelProvisioning(r.attemptId)):e===Ha.bindCredentials?s=await bu(await n.bindCredentials(r),i):e===Ha.reconnectBot?s=await bu(await n.reconnectBot(r.botId),i):s=await bu(await n.deleteBot(r.botId),i);return A?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!0,value:s}}catch{return A?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!1,error:{code:"wecom-operation-failed",message:"\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}}}function _u(n,a,o,i){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(jx,Vx(a,o),{authority:Ra(i)})}async function zx(n,a={}){if(a?.controller)return _u(n,a.controller,a.rpcOptions,a.rpcAuthority);let o=await H_(n,a,a.internals),i=_u(n,o.controller,a.rpcOptions,a.rpcAuthority);return n.effect(()=>async()=>o.close(),"dsh-im: close Enterprise WeChat bot connections"),i}import{unlink as SBe}from"node:fs/promises";import{homedir as DBe}from"node:os";import{join as Lu,resolve as nI}from"node:path";import{createHash as tBe}from"node:crypto";import{mkdir as aBe,readFile as rBe,rename as iBe,unlink as oBe,writeFile as nBe}from"node:fs/promises";import{dirname as sBe}from"node:path";import{randomBytes as Jde,randomUUID as jde}from"node:crypto";var Tu="https://ilinkai.weixin.qq.com/",qde="2.4.6",Vde="3",zde="bot",Wde=2<<16|1024|6,Zde=15e3,Wx=35e3,Xde=new Set(["wait","scaned","confirmed","expired","scaned_but_redirect","need_verifycode","verify_code_blocked","binded_redirect"]),ct=class extends Error{constructor(a,o,i={}){super(o,i),this.name="WeixinApiError",this.code=a,this.status=i.status}};function Ei(n){return typeof n=="string"&&n.trim()?n.trim():null}function J_(n){let a=n.toLowerCase().replace(/\.$/,"");return a==="weixin.qq.com"||a.endsWith(".weixin.qq.com")}function iI(n){let a;try{a=new URL(n)}catch{throw new ct("invalid-base-url","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u8FDE\u63A5\u5730\u5740\u3002")}if(a.protocol!=="https:"||!J_(a.hostname)||a.port!==""&&a.port!=="443")throw new ct("untrusted-base-url","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u53D7\u4FE1\u4EFB\u7684\u8FDE\u63A5\u5730\u5740\u3002");return a.username="",a.password="",a.search="",a.hash="",a.pathname.endsWith("/")||(a.pathname+="/"),a.toString()}function $de(n){let a=Ei(n);if(!a)throw new ct("invalid-qr","\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u5730\u5740\u3002");let o;try{o=new URL(a)}catch{throw new ct("invalid-qr","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u626B\u7801\u5730\u5740\u3002")}if(o.protocol!=="https:"||!J_(o.hostname))throw new ct("untrusted-qr","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u53D7\u4FE1\u4EFB\u7684\u626B\u7801\u5730\u5740\u3002");return o.toString()}function Xx(){return{"iLink-App-Id":zde,"iLink-App-ClientVersion":String(Wde)}}function eBe(n){let a={...Xx(),"content-type":"application/json",AuthorizationType:"ilink_bot_token","X-WECHAT-UIN":Buffer.from(String(Jde(4).readUInt32BE(0)),"utf8").toString("base64")};return Ei(n)&&(a.Authorization=`Bearer ${n.trim()}`),a}function Nu(){return{channel_version:qde,bot_agent:"DeepSeekHarness/0.2.2"}}function Zx(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}async function rI(n,{method:a,baseUrl:o,endpoint:i,body:e,token:r,timeoutMs:A=Zde,signal:t,authenticated:s=!0}){let g=iI(o),c=new URL(i,g);if(!J_(c.hostname))throw new ct("untrusted-endpoint","\u62D2\u7EDD\u8BBF\u95EE\u4E0D\u53D7\u4FE1\u4EFB\u7684\u5FAE\u4FE1\u670D\u52A1\u5730\u5740\u3002");let l=new AbortController,C=!1,u=()=>l.abort(t?.reason);if(t?.aborted)throw Zx(t);t?.addEventListener("abort",u,{once:!0});let Q=A>0?setTimeout(()=>{C=!0,l.abort()},A):null;try{let f=await n(c,{method:a,headers:s?eBe(r):Xx(),...e===void 0?{}:{body:JSON.stringify(e)},signal:l.signal});if(!f.ok)throw new ct("http-error",`\u5FAE\u4FE1\u670D\u52A1\u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${f.status}\uFF09\u3002`,{status:f.status});try{return await f.json()}catch(y){throw new ct("invalid-response","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\u3002",{cause:y})}}catch(f){throw t?.aborted?Zx(t):C?new ct("timeout","\u5FAE\u4FE1\u670D\u52A1\u8BF7\u6C42\u8D85\u65F6\u3002",{cause:f}):f instanceof ct?f:new ct("network-error","\u6682\u65F6\u65E0\u6CD5\u8BBF\u95EE\u5FAE\u4FE1\u670D\u52A1\u3002",{cause:f})}finally{Q&&clearTimeout(Q),t?.removeEventListener("abort",u)}}function ABe(n){if(!n||typeof n!="object"||!Xde.has(n.status))throw new ct("invalid-login-status","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u626B\u7801\u72B6\u6001\u3002");return n}function $x({fetchImpl:n=fetch}={}){if(typeof n!="function")throw new TypeError("fetchImpl must be a function");return Object.freeze({async beginLogin({localTokens:a=[],botType:o=Vde,signal:i}={}){let e=[...new Set(a.map(Ei).filter(Boolean))].slice(-10),r=await rI(n,{method:"POST",baseUrl:Tu,endpoint:`ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(o)}`,body:{local_token_list:e},timeoutMs:1e4,signal:i}),A=Ei(r?.qrcode);if(!A)throw new ct("invalid-qr","\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u4E8C\u7EF4\u7801\u4EE4\u724C\u3002");return{qrcode:A,qrcodeUrl:$de(r.qrcode_img_content)}},async pollLogin({qrcode:a,baseUrl:o=Tu,verifyCode:i,signal:e}){let r=Ei(a);if(!r)throw new TypeError("qrcode is required");let A=`ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(r)}`;Ei(i)&&(A+=`&verify_code=${encodeURIComponent(i.trim())}`);let t=await rI(n,{method:"GET",baseUrl:o,endpoint:A,timeoutMs:Wx,signal:e,authenticated:!1});return ABe(t)},async getUpdates({baseUrl:a,token:o,getUpdatesBuf:i="",timeoutMs:e,signal:r}){try{return await rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/getupdates",body:{get_updates_buf:i,base_info:Nu()},token:o,timeoutMs:e??Wx,signal:r})}catch(A){if(A instanceof ct&&A.code==="timeout")return{ret:0,msgs:[],get_updates_buf:i};throw A}},async sendText({baseUrl:a,token:o,toUserId:i,text:e,contextToken:r,runId:A,signal:t}){let s=Ei(i),g=Ei(e);if(!s||!g)throw new TypeError("toUserId and text are required");let c=await rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/sendmessage",token:o,signal:t,body:{msg:{from_user_id:"",to_user_id:s,client_id:`dsh-weixin-${jde()}`,message_type:2,message_state:2,item_list:[{type:1,text_item:{text:g}}],...Ei(r)?{context_token:r.trim()}:{},...Ei(A)?{run_id:A.trim()}:{}},base_info:Nu()}});if(c?.ret!==void 0&&c.ret!==0)throw new ct("send-rejected","\u5FAE\u4FE1\u670D\u52A1\u62D2\u7EDD\u4E86\u56DE\u590D\u6D88\u606F\u3002");return!0},async notifyStart({baseUrl:a,token:o,signal:i}){let e=await rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/msg/notifystart",token:o,signal:i,timeoutMs:1e4,body:{base_info:Nu()}});if(e?.ret!==void 0&&e.ret!==0)throw new ct("start-rejected","\u5FAE\u4FE1\u8D26\u53F7\u8FDE\u63A5\u542F\u52A8\u5931\u8D25\u3002");return e},async notifyStop({baseUrl:a,token:o,signal:i}){return rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/msg/notifystop",token:o,signal:i,timeoutMs:1e4,body:{base_info:Nu()}})}})}function e1(n){for(let a of n?.item_list??[]){if(a?.type===1&&typeof a.text_item?.text=="string"){let o=a.text_item.text.trim();if(o)return o}if(a?.type===3&&typeof a.voice_item?.text=="string"){let o=a.voice_item.text.trim();if(o)return o}}return null}function A1(n){return n?.message_id!==void 0&&n.message_id!==null?String(n.message_id):Ei(n?.client_id)}function t1(n,a=4e3){if(n.length<=a)return[n];let o=[],i=n;for(;i.length>a;){let e=i.lastIndexOf(` +`).trim():""}function Du(n,a=Mde){let o=String(n??"").trim();if(!o)return[];let i=[],e="",r=0;for(let A of o){let t=Buffer.byteLength(A);e&&r+t>a?(i.push(e),e=A,r=t):(e+=A,r+=t)}return e&&i.push(e),i}function _de(n){return n?.type==="text"?n.text:n?.type==="tool"?`\u6B63\u5728\u4F7F\u7528${n.name}\u2026`:n?.text}function L_(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null}}var wu=class{#A;#e;#t;#a;#n;#s;#I;#g=new Map;constructor({client:a,harness:o,state:i,status:e=L_(),logger:r=console,replyTimeoutMs:A=6e5,generateStreamId:t=wde}){if(!a||typeof a.replyStream!="function"||typeof a.sendMessage!="function")throw new TypeError("Enterprise WeChat client is required");if(!o||!i)throw new TypeError("Harness client and state store are required");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t}get status(){return structuredClone(this.#a)}accept(a){let o=Yx(a),e=(this.#g.get(o)??Promise.resolve()).catch(()=>{}).then(()=>this.#r(a)).finally(()=>{this.#g.get(o)===e&&this.#g.delete(o)});return this.#g.set(o,e),e}async waitForIdle(){await Promise.allSettled([...this.#g.values()])}async#o(a,o){for(let i of Du(o))await this.#A.sendMessage(a,{msgtype:"markdown",markdown:{content:i}})}async#i(a,o,i){let e=Du(i);if(e.length!==0)try{await this.#A.replyStream(a,this.#I("stream"),e[0],!0);for(let r of e.slice(1))await this.#A.sendMessage(o,{msgtype:"markdown",markdown:{content:r}})}catch{await this.#o(o,i)}}async#r(a){let o=F_(a),i=typeof o.msgid=="string"?o.msgid:"",e=typeof o.from?.userid=="string"?o.from.userid:"",r=o.chattype==="group"?o.chatid:e;if(!i||!e||!r||!["single","group"].includes(o.chattype)||this.#t.hasSeen(i))return;this.#a.messagesReceived+=1,this.#a.lastMessageAt=new Date().toISOString();let A=bde(a),t=null,s=!1;try{if(!A){await this.#i(a,r,"\u76EE\u524D\u652F\u6301\u6587\u5B57\u3001\u8BED\u97F3\u8F6C\u5199\u548C\u56FE\u6587\u6DF7\u6392\u4E2D\u7684\u6587\u5B57\u6D88\u606F\u3002"),await this.#t.markSeen(i);return}let g=A.toLowerCase();if(g==="/help"){await this.#i(a,r,Ode),await this.#t.markSeen(i);return}if(g==="/status"){await this.#e.ensureRunning(),await this.#i(a,r,"\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u4E0E DeepSeek Harness \u8FDE\u63A5\u6B63\u5E38\u3002"),await this.#t.markSeen(i);return}let c=Yx(a);if(g==="/new"){await this.#t.clearSession(c),await this.#i(a,r,"\u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002\u8BF7\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002"),await this.#t.markSeen(i);return}let l=this.#t.sessionFor(c);(!l||!await this.#e.sessionExists(l))&&(l=await this.#e.createSession(),await this.#t.setSession(c,l)),t=this.#I("stream");try{await this.#A.replyStream(a,t,"\u6B63\u5728\u601D\u8003\u4E2D\u2026",!1),s=!0}catch(f){this.#n.warn?.("[dsh-im:wecom] unable to start a stream; using an active reply:",f)}let C=await this.#e.ask(l,A,{timeoutMs:this.#s,onUpdate:s&&typeof this.#A.replyStreamNonBlocking=="function"?async f=>{let y=Du(_de(f))[0];y&&await this.#A.replyStreamNonBlocking(a,t,y,!1)}:void 0}),u=Du(C||"\u4EFB\u52A1\u5DF2\u5B8C\u6210\uFF0C\u4F46\u6CA1\u6709\u751F\u6210\u53EF\u663E\u793A\u7684\u6587\u672C\u3002"),Q=!1;if(s&&u.length>0)try{await this.#A.replyStream(a,t,u[0],!0);for(let f of u.slice(1))await this.#A.sendMessage(r,{msgtype:"markdown",markdown:{content:f}});Q=!0}catch(f){this.#n.warn?.("[dsh-im:wecom] stream finalization failed; using an active reply:",f)}Q||await this.#o(r,C),await this.#t.markSeen(i),this.#a.messagesReplied+=1,this.#a.lastReplyAt=new Date().toISOString(),this.#a.lastError=null}catch(g){this.#a.lastError=g?.message??String(g),this.#n.error?.("[dsh-im:wecom] failed to process an inbound message");try{s&&t?await this.#A.replyStream(a,t,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",!0):await this.#i(a,r,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"),await this.#t.markSeen(i)}catch{this.#n.error?.("[dsh-im:wecom] failed to send the safe error reply")}}}};function kde(){let n=new Error("Enterprise WeChat WebSocket authentication timed out");return n.code="connect-timeout",n}function vde(){return{startedAt:null,ready:!1,wecomConnectionState:"idle",harnessReachable:!1,lastCheckedAt:null,lastConnectedAt:null,lastError:null,...L_()}}var fC=class{#A;#e;#t;#a;#n;#s;#I;#g;#o;#i=vde();#r=null;#c=null;#l=null;#E=null;constructor({config:a,secret:o,harness:i,state:e,logger:r=console,replyTimeoutMs:A=6e5,connectTimeoutMs:t=2e4,maxReconnectAttempts:s=10,createClient:g=c=>new Tde(c)}){if(!a||!o||!i||!e)throw new TypeError("WecomRuntime requires config, secret, Harness, and state");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A,this.#I=t,this.#g=s,this.#o=g}get status(){return structuredClone(this.#i)}async start(){if(this.#i.ready&&this.#r)return this.status;if(this.#l)return this.#l;let a=new AbortController;return this.#E=a,this.#l=this.#C(a.signal).finally(()=>{this.#E===a&&(this.#E=null),this.#l=null}),this.#l}async#C(a){await this.#p(),a.throwIfAborted(),this.#i.startedAt=new Date().toISOString(),this.#i.wecomConnectionState="connecting",this.#i.lastError=null,await this.#t.ensureRunning(),this.#i.harnessReachable=!0;let o={debug(){},info(){},warn(){},error(){}},i=this.#o({botId:this.#A.remoteBotId,secret:this.#e,logger:o,maxReconnectAttempts:this.#g});if(!i||typeof i.connect!="function"||typeof i.disconnect!="function")throw new TypeError("Enterprise WeChat client factory returned an invalid client");this.#r=i,this.#c=new wu({client:i,harness:this.#t,state:this.#a,status:this.#i,logger:this.#n,replyTimeoutMs:this.#s});let e,r,A=!1,t=new Promise((Q,f)=>{e=Q,r=f}),s=()=>{if(this.#r!==i||a.aborted)return;A=!0;let Q=Date.now();this.#i.ready=!0,this.#i.wecomConnectionState="connected",this.#i.lastCheckedAt=Q,this.#i.lastConnectedAt=Q,this.#i.lastError=null,e()},g=()=>{this.#r===i&&(this.#i.ready=!1,this.#i.wecomConnectionState="connecting",this.#i.lastCheckedAt=Date.now())},c=()=>{this.#r===i&&(this.#i.ready=!1,this.#i.wecomConnectionState="connecting",this.#i.lastCheckedAt=Date.now())},l=Q=>{if(this.#r!==i)return;let f=Q instanceof Nde||Q instanceof Rde;!A&&f&&r(Q),f&&(this.#i.ready=!1,this.#i.wecomConnectionState="failed"),this.#i.lastError=f?Q.name:"connection-error",this.#n.warn?.(`[dsh-im:wecom] bot ${this.#A.botId} connection error`)},C=Q=>this.#c?.accept(Q);i.on("authenticated",s),i.on("disconnected",g),i.on("reconnecting",c),i.on("error",l),i.on("message",C);let u;try{return i.connect(),await Promise.race([t,new Promise((Q,f)=>{a.addEventListener("abort",()=>f(a.reason),{once:!0})}),new Promise((Q,f)=>{u=setTimeout(()=>f(kde()),this.#I)})]),this.status}catch(Q){throw a.aborted?(await this.#p(),Q):(this.#i.ready=!1,this.#i.wecomConnectionState="failed",this.#i.lastError=Q?.message??String(Q),await this.#p(),Q)}finally{clearTimeout(u)}}async stop(){let a=this.#l;return this.#E?.abort(new DOMException("Enterprise WeChat runtime stopped","AbortError")),await this.#p(),await a?.catch(()=>{}),this.status}async#p(){let a=this.#r,o=this.#c;this.#r=null,this.#c=null;try{a?.disconnect(),a?.removeAllListeners?.()}catch{this.#n.warn?.(`[dsh-im:wecom] bot ${this.#A.botId} failed to stop cleanly`)}await o?.waitForIdle(),this.#i.ready=!1,this.#i.wecomConnectionState="idle"}};var xx=Object.freeze([250,1e3,3e3,5e3,1e4,3e4]);function Pde(n){if(!Array.isArray(n)||n.length===0)return[...xx];let a=n.filter(o=>Number.isFinite(o)&&o>=0);return a.length>0?a:[...xx]}var Ou=class{#A;#e;#t;#a;#n;#s;#I;#g=null;#o=null;#i=0;#r=!1;#c=!1;#l;#E;constructor({controller:a,harness:o,logger:i=console,retryDelaysMs:e,healthyIntervalMs:r=15e3,setTimeoutImpl:A=setTimeout,clearTimeoutImpl:t=clearTimeout}){if(!a||typeof a.initialize!="function"||typeof a.status!="function")throw new TypeError("ConnectionSupervisor requires a controller");if(!o||typeof o.ensureRunning!="function")throw new TypeError("ConnectionSupervisor requires a Harness client");this.#A=a,this.#e=o,this.#t=i,this.#a=Pde(e),this.#n=Number.isFinite(r)&&r>=0?r:15e3,this.#s=A,this.#I=t,this.#l=new Promise(s=>{this.#E=s})}get ready(){return this.#l}start(){return this.#c||this.#r?this:(this.#c=!0,this.#C(0),this)}async close(){this.#r||(this.#r=!0,this.#g!==null&&this.#I(this.#g),this.#g=null,await this.#o?.catch(()=>{}),this.#E?.(null),this.#E=null)}#C(a){this.#r||(this.#g=this.#s(()=>{this.#g=null,this.#p()},a),this.#g?.unref?.())}async#p(){if(this.#r||this.#o)return;let a=this.#h();this.#o=a;try{await a}finally{this.#o===a&&(this.#o=null)}}async#h(){try{if(await this.#e.ensureRunning(),this.#r)return;let a=await this.#A.initialize();if(this.#r)return;this.#E?.(a),this.#E=null;let{configured:o,connected:i}=a.totals;if(i65535)throw new Error("dsh-im Enterprise WeChat requires an initialized DSH webServer port");return new URL(`http://127.0.0.1:${o}`)}function Ude(n){let a=AI(n.dshHome??process.env.DSH_HOME??Mu(Fde(),".dsh")),o=AI(n.dataDir??Mu(a,"integrations","dsh-wecom"));return{config:AI(n.configPath??Mu(o,"config.json")),bots:AI(n.botsDir??Mu(o,"bots"))}}async function H_(n,a={},o={}){if(!n?.credentials)throw new TypeError("dsh-im Enterprise WeChat requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-im Enterprise WeChat requires ctx.webServer");let i=o.ConfigStore??uu,e=o.StateStore??Su,r=o.HarnessClient??fu,A=o.Controller??QC,t=o.Runtime??fC,s=o.QrAuth??yu,g=o.createConnectionSupervisor??U_,c=typeof n.logger=="function"?n.logger("dsh-im:wecom"):n.logger??console,l=Ude(a),C=await new i(l.config).load(),u=o.qrAuth??new s({source:a.qrSource??"deepseek-harness",platform:a.qrPlatform}),Q=new Map,f=k=>AI(l.bots,k,"state.json"),y=async k=>{let U=Q.get(k);return U||(U=await new e(f(k)).load(),Q.set(k,U)),U},m=new r({baseUrl:Lde(n.webServer,a.harnessBaseUrl),workspace:AI(a.workspace??process.cwd()),agentPreset:a.agentPreset??"standard",autostart:!1,dshBin:a.dshBin??"dsh"}),R=new A({qrAuth:u,credentials:n.credentials,configStore:C,logger:c,createRuntime:async({botId:k,config:U,secret:H})=>new t({config:U,secret:H,harness:m,state:await y(k),replyTimeoutMs:a.replyTimeoutMs??6e5,connectTimeoutMs:a.connectTimeoutMs??2e4,maxReconnectAttempts:a.maxReconnectAttempts??10,logger:{error:(...F)=>c.error?.(`[${k}]`,...F),warn:(...F)=>c.warn?.(`[${k}]`,...F),info:(...F)=>c.info?.(`[${k}]`,...F),debug:(...F)=>c.debug?.(`[${k}]`,...F)}}),deleteState:async({botId:k})=>{let U=Q.get(k);if(Q.delete(k),U&&typeof U.remove=="function")return U.remove();try{await Gde(f(k))}catch(H){if(H?.code!=="ENOENT")throw H}}}),N=g({controller:R,harness:m,logger:c,retryDelaysMs:a.retryDelaysMs,healthyIntervalMs:a.healthyIntervalMs}).start();return{controller:R,ready:N.ready,async close(){await N.close(),await R.close(),m.stopManagedProcess()}}}import Hde from"qrcode";var jx="/wecom",Ha=Object.freeze({status:"connection.status",beginProvisioning:"provision.begin",pollProvisioning:"provision.poll",cancelProvisioning:"provision.cancel",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete"}),qx=Object.freeze(Object.values(Ha)),Kde=new Set(["secret","secretRef","scode","remoteBotId","verificationUrl","bot_info","botid"]);function x_(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function tI(n,a){return x_(n)&&Object.keys(n).every(o=>a.includes(o))}function K_(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n)}function Jx(n,a){return typeof n=="string"&&n.trim().length>0&&n.length<=a}function Yde(n,a){return x_(a)?n===Ha.status?tI(a,[])?null:"connection.status does not accept fields.":n===Ha.beginProvisioning?tI(a,["locale"])&&(a.locale===void 0||a.locale==="zh-CN")?null:"provision.begin received unsupported fields.":[Ha.pollProvisioning,Ha.cancelProvisioning].includes(n)?tI(a,["attemptId"])&&K_(a.attemptId)?null:`${n} requires an attemptId.`:n===Ha.bindCredentials?tI(a,["botId","secret"])&&Jx(a.botId,512)&&Jx(a.secret,1024)?null:"bot.bind-credentials requires Bot ID and Secret.":n===Ha.reconnectBot?tI(a,["botId"])&&K_(a.botId)?null:"bot.reconnect requires a botId.":n===Ha.deleteBot?tI(a,["botId","confirm"])&&K_(a.botId)&&a.confirm===!0?null:"bot.delete requires a botId and confirm=true.":"Unknown Enterprise WeChat endpoint.":"Payload must be an object."}function aI(n){if(Array.isArray(n))return n.map(aI);if(!x_(n))return n;let a={};for(let[o,i]of Object.entries(n))Kde.has(o)||(a[o]=aI(i));return a}async function xde(n){return Hde.toDataURL(n,{type:"image/png",errorCorrectionLevel:"M",margin:2,width:320})}async function Y_(n,a){return!n||typeof n.verificationUrl!="string"?aI(n):aI({...n,qrCodeDataUrl:await a(n.verificationUrl)})}async function bu(n,a){let o=structuredClone(n);return o?.provisioning&&(o.provisioning=await Y_(o.provisioning,a)),aI(o)}function Vx(n,{encodeQr:a=xde}={}){for(let e of["status","startProvisioning","registrationStatus","cancelProvisioning","bindCredentials","reconnectBot","deleteBot"])if(typeof n?.[e]!="function")throw new TypeError(`A complete Enterprise WeChat controller is required (${e})`);let o=new Map,i=e=>{let r=o.get(e);return r||(o.size>=16&&o.delete(o.keys().next().value),r=Promise.resolve().then(()=>a(e)),o.set(e,r)),r};return async(e,r,A)=>{if(A?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};if(!qx.includes(e))return{ok:!1,error:{code:"bad-request",message:"Unknown Enterprise WeChat endpoint."}};let t=Yde(e,r);if(t)return{ok:!1,error:{code:"bad-request",message:t}};try{let s;if(e===Ha.status)s=await bu(await n.status(),i);else if(e===Ha.beginProvisioning)s=await Y_(await n.startProvisioning(),i);else if(e===Ha.pollProvisioning){let g=await n.registrationStatus(r.attemptId);if(!g)return{ok:!1,error:{code:"bad-request",message:"The provisioning attempt no longer exists."}};s=await Y_(g,i)}else e===Ha.cancelProvisioning?s=aI(await n.cancelProvisioning(r.attemptId)):e===Ha.bindCredentials?s=await bu(await n.bindCredentials(r),i):e===Ha.reconnectBot?s=await bu(await n.reconnectBot(r.botId),i):s=await bu(await n.deleteBot(r.botId),i);return A?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!0,value:s}}catch{return A?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!1,error:{code:"wecom-operation-failed",message:"\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}}}function _u(n,a,o,i){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(jx,Vx(a,o),{authority:Ra(i)})}async function zx(n,a={}){if(a?.controller)return _u(n,a.controller,a.rpcOptions,a.rpcAuthority);let o=await H_(n,a,a.internals),i=_u(n,o.controller,a.rpcOptions,a.rpcAuthority);return n.effect(()=>async()=>o.close(),"dsh-im: close Enterprise WeChat bot connections"),i}import{unlink as SBe}from"node:fs/promises";import{homedir as DBe}from"node:os";import{join as Lu,resolve as nI}from"node:path";import{createHash as tBe}from"node:crypto";import{mkdir as aBe,readFile as rBe,rename as iBe,unlink as oBe,writeFile as nBe}from"node:fs/promises";import{dirname as sBe}from"node:path";import{randomBytes as Jde,randomUUID as jde}from"node:crypto";var Tu="https://ilinkai.weixin.qq.com/",qde="2.4.6",Vde="3",zde="bot",Wde=2<<16|1024|6,Zde=15e3,Wx=35e3,Xde=new Set(["wait","scaned","confirmed","expired","scaned_but_redirect","need_verifycode","verify_code_blocked","binded_redirect"]),ct=class extends Error{constructor(a,o,i={}){super(o,i),this.name="WeixinApiError",this.code=a,this.status=i.status}};function Ei(n){return typeof n=="string"&&n.trim()?n.trim():null}function J_(n){let a=n.toLowerCase().replace(/\.$/,"");return a==="weixin.qq.com"||a.endsWith(".weixin.qq.com")}function iI(n){let a;try{a=new URL(n)}catch{throw new ct("invalid-base-url","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u8FDE\u63A5\u5730\u5740\u3002")}if(a.protocol!=="https:"||!J_(a.hostname)||a.port!==""&&a.port!=="443")throw new ct("untrusted-base-url","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u53D7\u4FE1\u4EFB\u7684\u8FDE\u63A5\u5730\u5740\u3002");return a.username="",a.password="",a.search="",a.hash="",a.pathname.endsWith("/")||(a.pathname+="/"),a.toString()}function $de(n){let a=Ei(n);if(!a)throw new ct("invalid-qr","\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u5730\u5740\u3002");let o;try{o=new URL(a)}catch{throw new ct("invalid-qr","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u626B\u7801\u5730\u5740\u3002")}if(o.protocol!=="https:"||!J_(o.hostname))throw new ct("untrusted-qr","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u53D7\u4FE1\u4EFB\u7684\u626B\u7801\u5730\u5740\u3002");return o.toString()}function Xx(){return{"iLink-App-Id":zde,"iLink-App-ClientVersion":String(Wde)}}function eBe(n){let a={...Xx(),"content-type":"application/json",AuthorizationType:"ilink_bot_token","X-WECHAT-UIN":Buffer.from(String(Jde(4).readUInt32BE(0)),"utf8").toString("base64")};return Ei(n)&&(a.Authorization=`Bearer ${n.trim()}`),a}function Nu(){return{channel_version:qde,bot_agent:"DeepSeekHarness/0.3.0"}}function Zx(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}async function rI(n,{method:a,baseUrl:o,endpoint:i,body:e,token:r,timeoutMs:A=Zde,signal:t,authenticated:s=!0}){let g=iI(o),c=new URL(i,g);if(!J_(c.hostname))throw new ct("untrusted-endpoint","\u62D2\u7EDD\u8BBF\u95EE\u4E0D\u53D7\u4FE1\u4EFB\u7684\u5FAE\u4FE1\u670D\u52A1\u5730\u5740\u3002");let l=new AbortController,C=!1,u=()=>l.abort(t?.reason);if(t?.aborted)throw Zx(t);t?.addEventListener("abort",u,{once:!0});let Q=A>0?setTimeout(()=>{C=!0,l.abort()},A):null;try{let f=await n(c,{method:a,headers:s?eBe(r):Xx(),...e===void 0?{}:{body:JSON.stringify(e)},signal:l.signal});if(!f.ok)throw new ct("http-error",`\u5FAE\u4FE1\u670D\u52A1\u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${f.status}\uFF09\u3002`,{status:f.status});try{return await f.json()}catch(y){throw new ct("invalid-response","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\u3002",{cause:y})}}catch(f){throw t?.aborted?Zx(t):C?new ct("timeout","\u5FAE\u4FE1\u670D\u52A1\u8BF7\u6C42\u8D85\u65F6\u3002",{cause:f}):f instanceof ct?f:new ct("network-error","\u6682\u65F6\u65E0\u6CD5\u8BBF\u95EE\u5FAE\u4FE1\u670D\u52A1\u3002",{cause:f})}finally{Q&&clearTimeout(Q),t?.removeEventListener("abort",u)}}function ABe(n){if(!n||typeof n!="object"||!Xde.has(n.status))throw new ct("invalid-login-status","\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u626B\u7801\u72B6\u6001\u3002");return n}function $x({fetchImpl:n=fetch}={}){if(typeof n!="function")throw new TypeError("fetchImpl must be a function");return Object.freeze({async beginLogin({localTokens:a=[],botType:o=Vde,signal:i}={}){let e=[...new Set(a.map(Ei).filter(Boolean))].slice(-10),r=await rI(n,{method:"POST",baseUrl:Tu,endpoint:`ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(o)}`,body:{local_token_list:e},timeoutMs:1e4,signal:i}),A=Ei(r?.qrcode);if(!A)throw new ct("invalid-qr","\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u4E8C\u7EF4\u7801\u4EE4\u724C\u3002");return{qrcode:A,qrcodeUrl:$de(r.qrcode_img_content)}},async pollLogin({qrcode:a,baseUrl:o=Tu,verifyCode:i,signal:e}){let r=Ei(a);if(!r)throw new TypeError("qrcode is required");let A=`ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(r)}`;Ei(i)&&(A+=`&verify_code=${encodeURIComponent(i.trim())}`);let t=await rI(n,{method:"GET",baseUrl:o,endpoint:A,timeoutMs:Wx,signal:e,authenticated:!1});return ABe(t)},async getUpdates({baseUrl:a,token:o,getUpdatesBuf:i="",timeoutMs:e,signal:r}){try{return await rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/getupdates",body:{get_updates_buf:i,base_info:Nu()},token:o,timeoutMs:e??Wx,signal:r})}catch(A){if(A instanceof ct&&A.code==="timeout")return{ret:0,msgs:[],get_updates_buf:i};throw A}},async sendText({baseUrl:a,token:o,toUserId:i,text:e,contextToken:r,runId:A,signal:t}){let s=Ei(i),g=Ei(e);if(!s||!g)throw new TypeError("toUserId and text are required");let c=await rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/sendmessage",token:o,signal:t,body:{msg:{from_user_id:"",to_user_id:s,client_id:`dsh-weixin-${jde()}`,message_type:2,message_state:2,item_list:[{type:1,text_item:{text:g}}],...Ei(r)?{context_token:r.trim()}:{},...Ei(A)?{run_id:A.trim()}:{}},base_info:Nu()}});if(c?.ret!==void 0&&c.ret!==0)throw new ct("send-rejected","\u5FAE\u4FE1\u670D\u52A1\u62D2\u7EDD\u4E86\u56DE\u590D\u6D88\u606F\u3002");return!0},async notifyStart({baseUrl:a,token:o,signal:i}){let e=await rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/msg/notifystart",token:o,signal:i,timeoutMs:1e4,body:{base_info:Nu()}});if(e?.ret!==void 0&&e.ret!==0)throw new ct("start-rejected","\u5FAE\u4FE1\u8D26\u53F7\u8FDE\u63A5\u542F\u52A8\u5931\u8D25\u3002");return e},async notifyStop({baseUrl:a,token:o,signal:i}){return rI(n,{method:"POST",baseUrl:a,endpoint:"ilink/bot/msg/notifystop",token:o,signal:i,timeoutMs:1e4,body:{base_info:Nu()}})}})}function e1(n){for(let a of n?.item_list??[]){if(a?.type===1&&typeof a.text_item?.text=="string"){let o=a.text_item.text.trim();if(o)return o}if(a?.type===3&&typeof a.voice_item?.text=="string"){let o=a.voice_item.text.trim();if(o)return o}}return null}function A1(n){return n?.message_id!==void 0&&n.message_id!==null?String(n.message_id):Ei(n?.client_id)}function t1(n,a=4e3){if(n.length<=a)return[n];let o=[],i=n;for(;i.length>a;){let e=i.lastIndexOf(` `,a);er===null))return null;let o=new Set,i=new Set,e=new Set;for(let r of a){if(o.has(r.botId)||i.has(r.accountId)||e.has(r.tokenRef))return null;o.add(r.botId),i.add(r.accountId),e.add(r.tokenRef)}return Object.freeze({version:1,accounts:Object.freeze(a)})}var Ru=class{#A;#e=j_;#t=Promise.resolve();constructor(a){this.#A=a}async load(){try{let a=cBe(JSON.parse(await rBe(this.#A,"utf8")));if(!a)throw new Error("dsh-weixin config contains invalid account data");this.#e=a}catch(a){if(a?.code!=="ENOENT")throw a;this.#e=j_}return this}list(){return structuredClone(this.#e.accounts)}get(a){let o=this.#e.accounts.find(i=>i.botId===a);return o?structuredClone(o):null}getByAccountId(a){let o=this.#e.accounts.find(i=>i.accountId===a);return o?structuredClone(o):null}async save(a){let o=i1(a);if(!o)throw new Error("Refusing to persist incomplete dsh-weixin account data");return this.#a(i=>{let e=i.find(t=>t.accountId===o.accountId&&t.botId!==o.botId),r=i.find(t=>t.tokenRef===o.tokenRef&&t.botId!==o.botId);if(e||r)throw new Error("Duplicate Weixin account identity");let A=i.findIndex(t=>t.botId===o.botId);return A===-1?i.push(o):i[A]=o,structuredClone(o)})}async remove(a){if(!a1(a))throw new TypeError("Invalid Weixin bot id");return this.#a(o=>{let i=o.findIndex(r=>r.botId===a);if(i===-1)return null;let[e]=o.splice(i,1);return structuredClone(e)})}async clear(){let a=this.#t.then(async()=>{try{await oBe(this.#A)}catch(o){if(o?.code!=="ENOENT")throw o}this.#e=j_});this.#t=a.then(()=>{},()=>{}),await a}async#a(a){let o,i=this.#t.then(async()=>{let e=[...this.#e.accounts];o=a(e);let r=Object.freeze({version:1,accounts:Object.freeze(e)});await this.#n(r),this.#e=r});return this.#t=i.then(()=>{},()=>{}),await i,o}async#n(a){await aBe(sBe(this.#A),{recursive:!0,mode:448});let o=`${this.#A}.tmp`;await nBe(o,`${JSON.stringify(a,null,2)} `,{encoding:"utf8",mode:384}),await iBe(o,this.#A)}};import{mkdir as IBe,readFile as lBe,rename as EBe,unlink as CBe,writeFile as pBe}from"node:fs/promises";import{dirname as hBe}from"node:path";var ku=Object.freeze({version:1,sessions:{},seenMessageIds:[],getUpdatesBuf:""});function dBe(n){if(!n||typeof n!="object")return structuredClone(ku);let a={};if(n.sessions&&typeof n.sessions=="object"&&!Array.isArray(n.sessions))for(let[o,i]of Object.entries(n.sessions))typeof o=="string"&&typeof i=="string"&&i&&(a[o]=i);return{version:1,sessions:a,seenMessageIds:Array.isArray(n.seenMessageIds)?n.seenMessageIds.filter(o=>typeof o=="string").slice(-1e3):[],getUpdatesBuf:typeof n.getUpdatesBuf=="string"?n.getUpdatesBuf:""}}var vu=class{#A;#e=structuredClone(ku);#t=Promise.resolve();constructor(a){this.#A=a}async load(){try{this.#e=dBe(JSON.parse(await lBe(this.#A,"utf8")))}catch(a){if(a?.code!=="ENOENT")throw a;this.#e=structuredClone(ku),await this.#a()}return this}sessionFor(a){return this.#e.sessions[a]??null}async setSession(a,o){this.#e.sessions[a]=o,await this.#a()}async clearSession(a){delete this.#e.sessions[a],await this.#a()}hasSeen(a){return this.#e.seenMessageIds.includes(a)}async markSeen(a){this.hasSeen(a)||(this.#e.seenMessageIds.push(a),this.#e.seenMessageIds.length>1e3&&this.#e.seenMessageIds.splice(0,this.#e.seenMessageIds.length-1e3),await this.#a())}getUpdatesBuf(){return this.#e.getUpdatesBuf}async setGetUpdatesBuf(a){typeof a!="string"||a===this.#e.getUpdatesBuf||(this.#e.getUpdatesBuf=a,await this.#a())}snapshot(){return structuredClone(this.#e)}async remove(){try{await CBe(this.#A)}catch(a){if(a?.code!=="ENOENT")throw a}this.#e=structuredClone(ku)}async#a(){let a=`${JSON.stringify(this.#e,null,2)} `,o=this.#t.then(async()=>{await IBe(hBe(this.#A),{recursive:!0,mode:448});let i=`${this.#A}.tmp`;await pBe(i,a,{encoding:"utf8",mode:384}),await EBe(i,this.#A)});this.#t=o.then(()=>{},()=>{}),await o}};import{randomUUID as BBe}from"node:crypto";var o1=new Set(["starting","pending","scanned","needs_verification","connecting"]),Pu=new Set(["connected","expired","failed","cancelled"]),n1=5*6e4;function oI(n){return typeof n=="string"&&n.trim()?n.trim():null}function uBe(){return new DOMException("Provisioning was cancelled","AbortError")}function s1(n,a){let o=oI(n);return o?iI(o.includes("://")?o:`https://${o}`):iI(a)}function yC(n){return n?{attemptId:n.id,status:n.state,...n.verificationUrl?{verificationUrl:n.verificationUrl}:{},...n.expiresAt?{expiresAt:n.expiresAt}:{},pollIntervalMs:1e3,...n.state==="needs_verification"?{verificationRequired:!0}:{},...n.botId?{botId:n.botId}:{},...n.alreadyConnected?{alreadyConnected:!0}:{},...n.error?{error:structuredClone(n.error)}:{}}:null}function Br(n,a){return Object.freeze({code:n,message:a})}var mC=class{#A;#e;#t;#a;#n;#s;#I=new Map;#g=new Map;#o=new Map;#i=null;#r=new Map;#c=0;#l=!1;constructor({api:a,credentials:o,configStore:i,createRuntime:e,deleteState:r=async()=>{},logger:A=console}){if(!a||typeof a.beginLogin!="function"||typeof a.pollLogin!="function")throw new TypeError("WeixinController requires a Weixin API client");if(!o||typeof o.resolve!="function"||typeof o.set!="function"||typeof o.unset!="function")throw new TypeError("WeixinController requires the DSH credential provider");if(!i||typeof i.list!="function"||typeof i.save!="function"||typeof i.remove!="function")throw new TypeError("WeixinController requires a config store");if(typeof e!="function")throw new TypeError("createRuntime is required");this.#A=a,this.#e=o,this.#t=i,this.#a=e,this.#n=r,this.#s=A}async initialize(){if(this.#l)return this.status();for(let a of this.#t.list())this.#I.get(a.botId)?.status?.ready!==!0&&await this.#Q(a.botId,async()=>{let i=this.#t.get(a.botId);if(!(!i||this.#l))try{let e=await this.#d(i.tokenRef);if(!e){this.#g.set(i.botId,Br("missing-token","\u767B\u5F55\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u79FB\u9664\u8D26\u53F7\u540E\u91CD\u65B0\u626B\u7801\u3002"));return}await this.#p(i,e),this.#g.delete(i.botId)}catch(e){this.#g.set(i.botId,Br("connection-failed","\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002")),this.#s.warn?.(`[dsh-weixin] account ${i.botId} failed to initialize:`,e)}finally{this.#f()}});return this.status()}async startProvisioning(){if(this.#l)throw new Error("dsh-weixin controller is closed");this.#i&&await this.cancelProvisioning(this.#i);let a={id:BBe(),state:"starting",createdAt:Date.now(),expiresAt:Date.now()+n1,controller:new AbortController,pendingVerifyCode:null,verifyResolve:null,currentBaseUrl:Tu,error:null,botId:null,task:null};this.#o.set(a.id,a),this.#i=a.id,this.#f();try{let o=(await Promise.all(this.#t.list().slice(-10).map(async e=>this.#d(e.tokenRef)))).filter(Boolean),i=await this.#A.beginLogin({localTokens:o,signal:a.controller.signal});return this.#B(a),a.qrcode=i.qrcode,a.verificationUrl=i.qrcodeUrl,a.state="pending",a.expiresAt=Date.now()+n1,this.#f(),a.task=this.#E(a),yC(a)}catch(o){throw a.controller.signal.aborted?(a.state="cancelled",a.error=Br("cancelled","\u626B\u7801\u7ED1\u5B9A\u5DF2\u53D6\u6D88\u3002")):(a.state="failed",a.error=Br(o instanceof ct?o.code:"qr-start-failed",o instanceof ct?o.message:"\u65E0\u6CD5\u751F\u6210\u5FAE\u4FE1\u4E8C\u7EF4\u7801\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")),this.#i===a.id&&(this.#i=null),this.#f(),o}}registrationStatus(a){return yC(this.#o.get(a))}async submitVerification(a,o){let i=this.#o.get(a);if(!i||i.state!=="needs_verification")throw new Error("The provisioning attempt is not waiting for a verification code");let e=oI(o);if(!e||!/^\d{4,8}$/.test(e))throw new TypeError("Verification code must contain 4 to 8 digits");return i.pendingVerifyCode=e,i.state="scanned",i.verifyResolve?.(),i.verifyResolve=null,this.#f(),yC(i)}async cancelProvisioning(a){let o=this.#o.get(a);return o?(Pu.has(o.state)||(o.controller.abort(),o.verifyResolve?.(),o.verifyResolve=null,await o.task?.catch(()=>{}),Pu.has(o.state)||(o.state="cancelled"),o.error??=Br("cancelled","\u626B\u7801\u7ED1\u5B9A\u5DF2\u53D6\u6D88\u3002")),this.#i===o.id&&(this.#i=null),this.#f(),yC(o)):null}async reconnectBot(a){let o=this.#t.get(a);if(!o)throw new Error("Unknown Weixin account");return await this.#Q(a,async()=>{let i=await this.#d(o.tokenRef);if(!i)throw new Error("The Weixin token is missing");try{await this.#p(o,i),this.#g.delete(a)}catch(e){throw this.#g.set(a,Br("connection-failed","\u5FAE\u4FE1\u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")),e}finally{this.#f()}}),this.status()}async deleteBot(a){let o=this.#t.get(a);if(!o)throw new Error("Unknown Weixin account");return await this.#Q(a,async()=>{let i=await this.#e.resolve(o.tokenRef).catch(()=>{});await this.#h(a);try{await this.#e.unset(o.tokenRef),await this.#t.remove(a)}catch(e){throw i?.value&&(await this.#e.set(o.tokenRef,i.value).catch(()=>{}),await this.#p(o,i.value).catch(()=>{})),new Error("Unable to remove the Weixin account safely.",{cause:e})}try{await this.#n({botId:a,config:o})}catch(e){this.#s.warn?.(`[dsh-weixin] account ${a} state cleanup failed:`,e)}this.#g.delete(a),this.#f()}),this.status()}status(){let a=this.#t.list().map(e=>{let r=this.#I.get(e.botId)?.status??null,A=r?.ready===!0&&r.weixinConnectionState==="connected"&&r.harnessReachable===!0,t=A?"connected":r?.weixinConnectionState==="connecting"?"connecting":this.#g.has(e.botId)||r?.weixinConnectionState==="failed"?"error":"offline",s=this.#g.get(e.botId)??(t==="error"?Br("connection-failed","\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002"):null);return{botId:e.botId,state:t,connected:A,configured:!0,bot:{name:"\u5FAE\u4FE1\u673A\u5668\u4EBA",accountIdMasked:r1(e.accountId)},health:{status:A?"healthy":t==="error"?"error":"offline",summary:A?"\u5FAE\u4FE1\u6D88\u606F\u957F\u8F6E\u8BE2\u8FD0\u884C\u6B63\u5E38":t==="error"?"\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5":"\u5FAE\u4FE1\u8FDE\u63A5\u5F53\u524D\u79BB\u7EBF",lastCheckedAt:r?.lastCheckedAt??null},stats:{messagesReceived:r?.messagesReceived??0,messagesReplied:r?.messagesReplied??0},error:s?structuredClone(s):null}}),o=a.filter(e=>e.connected).length,i=this.#i?this.#o.get(this.#i):null;return{schemaVersion:1,revision:this.#c,state:i&&o1.has(i.state)?"provisioning":a.length===0?"disconnected":o===a.length?"connected":o>0?"degraded":"offline",bots:a,totals:{configured:a.length,connected:o},...i&&o1.has(i.state)?{provisioning:yC(i)}:{}}}async close(){this.#l||(this.#l=!0,this.#i&&await this.cancelProvisioning(this.#i),await Promise.allSettled([...this.#I.keys()].map(a=>this.#h(a))))}async#E(a){try{for(;!a.controller.signal.aborted&&Date.now(){a.verifyResolve=i,a.controller.signal.aborted&&i()}),a.verifyResolve=null,this.#B(a));let o=await this.#A.pollLogin({qrcode:a.qrcode,baseUrl:a.currentBaseUrl,verifyCode:a.pendingVerifyCode,signal:a.controller.signal});if(this.#B(a),o.status==="wait")a.state="pending";else if(o.status==="scaned")a.pendingVerifyCode=null,a.state="scanned";else if(o.status==="need_verifycode")a.pendingVerifyCode=null,a.state="needs_verification";else if(o.status==="verify_code_blocked"){a.state="failed",a.error=Br("verification-blocked","\u914D\u5BF9\u7801\u591A\u6B21\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801\u3002");break}else if(o.status==="expired"){a.state="expired",a.error=Br("expired","\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u3002");break}else if(o.status==="scaned_but_redirect")a.currentBaseUrl=s1(o.redirect_host,a.currentBaseUrl),a.state="scanned";else if(o.status==="binded_redirect"){let i=this.#t.list().find(e=>this.#I.get(e.botId)?.status?.ready===!0)??this.#t.list()[0];i?(a.state="connected",a.botId=i.botId,a.alreadyConnected=!0):(a.state="failed",a.error=Br("already-bound","\u8BE5\u5FAE\u4FE1\u8D26\u53F7\u5DF2\u7ED1\u5B9A\uFF0C\u4F46\u672C\u673A\u6CA1\u6709\u53EF\u6062\u590D\u7684\u51ED\u636E\u3002"));break}else if(o.status==="confirmed"){let i=oI(o.bot_token),e=oI(o.ilink_bot_id),r=oI(o.ilink_user_id);if(!i||!e||!r)throw new ct("incomplete-login","\u5FAE\u4FE1\u6388\u6743\u6210\u529F\uFF0C\u4F46\u8FD4\u56DE\u7684\u8D26\u53F7\u51ED\u636E\u4E0D\u5B8C\u6574\u3002");a.state="connecting",this.#f();let A=s1(o.baseurl,a.currentBaseUrl);a.botId=await this.#C(a,{token:i,accountId:e,ownerUserId:r,baseUrl:A}),a.state="connected",a.error=null;break}this.#f()}!a.controller.signal.aborted&&Date.now()>=a.expiresAt&&!Pu.has(a.state)&&(a.state="expired",a.error=Br("expired","\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u3002"))}catch(o){a.controller.signal.aborted||o?.name==="AbortError"?(a.state="cancelled",a.error=Br("cancelled","\u626B\u7801\u7ED1\u5B9A\u5DF2\u53D6\u6D88\u3002")):(a.state="failed",a.error=Br(o instanceof ct?o.code:"activation-failed",o instanceof ct?o.message:"\u5FAE\u4FE1\u5DF2\u6388\u6743\uFF0C\u4F46\u65E0\u6CD5\u4FDD\u5B58\u51ED\u636E\u6216\u542F\u52A8\u6D88\u606F\u8FDE\u63A5\u3002"),this.#s.error?.("[dsh-weixin] provisioning failed:",o))}finally{a.pendingVerifyCode=null,a.verifyResolve?.(),a.verifyResolve=null,this.#i===a.id&&(this.#i=null),this.#f(),this.#y()}}async#C(a,{token:o,accountId:i,ownerUserId:e,baseUrl:r}){let A=q_(i),t=this.#t.getByAccountId(i),s={botId:A.botId,accountId:i,tokenRef:A.tokenRef,ownerUserId:e,baseUrl:r,createdAt:t?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()},g=await this.#e.resolve(A.tokenRef).catch(()=>{});return this.#Q(A.botId,async()=>{await this.#e.set(A.tokenRef,o);try{return this.#B(a),await this.#t.save(s),this.#B(a),await this.#p(s,o),this.#B(a),this.#g.delete(A.botId),this.#f(),A.botId}catch(c){throw await this.#h(A.botId),t?await this.#t.save(t).catch(()=>{}):this.#t.get(A.botId)&&await this.#t.remove(A.botId).catch(()=>{}),await this.#u(A.tokenRef,g),t&&g?.value&&await this.#p(t,g.value).catch(()=>{}),c}})}async#p(a,o){await this.#h(a.botId);let i=await this.#a({botId:a.botId,config:a,token:o});if(!i||typeof i.start!="function"||typeof i.stop!="function")throw new TypeError("createRuntime returned an invalid Weixin runtime");try{await i.start(),this.#I.set(a.botId,i)}catch(e){throw await i.stop().catch(()=>{}),e}}async#h(a){let o=this.#I.get(a);this.#I.delete(a),await o?.stop().catch(i=>{this.#s.warn?.(`[dsh-weixin] account ${a} failed to stop cleanly:`,i)})}async#d(a){let o=await this.#e.resolve(a).catch(()=>{});return oI(o?.value)}async#u(a,o){try{o?.value?await this.#e.set(a,o.value):await this.#e.unset(a)}catch(i){this.#s.error?.(`[dsh-weixin] failed to restore credential ${a}:`,i)}}#B(a){if(a.controller.signal.aborted||this.#i!==a.id)throw uBe()}#Q(a,o){let r=(this.#r.get(a)??Promise.resolve()).catch(()=>{}).then(o).finally(()=>{this.#r.get(a)===r&&this.#r.delete(a)});return this.#r.set(a,r),r}#y(){for(let[a,o]of this.#o)a!==this.#i&&Pu.has(o.state)&&this.#o.size>16&&this.#o.delete(a)}#f(){this.#c+=1}};var QBe=["\u5FAE\u4FE1\u5DF2\u8FDE\u63A5 DeepSeek Harness\u3002","","\u76F4\u63A5\u53D1\u9001\u6587\u5B57\u6216\u5E26\u6587\u5B57\u8BC6\u522B\u7ED3\u679C\u7684\u8BED\u97F3\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002","/new \u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD","/status \u68C0\u67E5\u8FDE\u63A5\u72B6\u6001","/help \u663E\u793A\u672C\u5E2E\u52A9"].join(` diff --git a/package-lock.json b/package-lock.json index 8750a28..ee810df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@xmanrui/dsh-im", - "version": "0.2.2", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@xmanrui/dsh-im", - "version": "0.2.2", + "version": "0.3.0", "license": "MIT", "dependencies": { "@tencent-connect/qqbot-connector": "1.2.0", diff --git a/package.json b/package.json index fc25b85..e1bd154 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@xmanrui/dsh-im", - "version": "0.2.2", + "version": "0.3.0", "description": "通过扫码、App Manifest或机器人凭据把IM机器人接入DeepSeek Harness(支持飞书、微信、钉钉、企业微信、QQ、Slack、Telegram、Discord和WhatsApp)。", "license": "MIT", "type": "module", diff --git a/src/channels/discord/discord-api.mjs b/src/channels/discord/discord-api.mjs index ed55034..3292822 100644 --- a/src/channels/discord/discord-api.mjs +++ b/src/channels/discord/discord-api.mjs @@ -108,7 +108,7 @@ export class DiscordApi { headers: { authorization: `Bot ${this.#token}`, 'content-type': 'application/json', - 'user-agent': 'DeepSeek-Harness-dsh-im (https://github.com/xmanrui/dsh-im, 0.2.2)', + 'user-agent': 'DeepSeek-Harness-dsh-im (https://github.com/xmanrui/dsh-im, 0.3.0)', }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), signal: requestSignal(signal, timeoutMs), diff --git a/src/channels/weixin/weixin-api.mjs b/src/channels/weixin/weixin-api.mjs index aeb6fd9..eaa3030 100644 --- a/src/channels/weixin/weixin-api.mjs +++ b/src/channels/weixin/weixin-api.mjs @@ -92,7 +92,7 @@ function authenticatedHeaders(token) { function baseInfo() { return { channel_version: WEIXIN_PROTOCOL_VERSION, - bot_agent: 'DeepSeekHarness/0.2.2', + bot_agent: 'DeepSeekHarness/0.3.0', }; } diff --git a/test/channels/weixin/weixin-api.test.mjs b/test/channels/weixin/weixin-api.test.mjs index 1f731fe..0adb870 100644 --- a/test/channels/weixin/weixin-api.test.mjs +++ b/test/channels/weixin/weixin-api.test.mjs @@ -93,7 +93,7 @@ test('sendText emits the iLink message envelope without reflecting the token in assert.equal(body.msg.context_token, 'message-context'); assert.equal(body.msg.item_list[0].text_item.text, 'Harness reply'); assert.equal(body.base_info.channel_version, '2.4.6'); - assert.equal(body.base_info.bot_agent, 'DeepSeekHarness/0.2.2'); + assert.equal(body.base_info.bot_agent, 'DeepSeekHarness/0.3.0'); assert.doesNotMatch(calls[0].init.body, /host-only-token/); });