diff --git a/lib/index.js b/lib/index.js index 14cdba0..65fa2d9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -244,7 +244,7 @@ Generate a new one`,"\u4E8C\u7EF4\u7801\u56FE\u7247\u6B63\u5728\u751F\u6210\u202 `),a=[],A="",t=!1,s=[],g=E=>{if(E.length<=i){if(!A){A=E;return}let f=`${A} ${E}`;f.length>i?(a.push(A),A=E):A=f;return}A&&(a.push(A),A="");let B=E;for(;B.length>i;)a.push(B.slice(0,i)),B=B.slice(i);A=B},c=()=>{if(s.length===0)return;let E=s.join(` `);s=[],g(E)},I=E=>{let B=E;for(;B.length>i;)A&&(a.push(A),A=""),a.push(B.slice(0,i)),B=B.slice(i);g(B)};for(let E of e){if(NMe.test(E)){c(),!t&&A&&(a.push(A),A=""),t=!t,I(E);continue}if(t){I(E);continue}if(TMe.test(E)){s.push(E);continue}c(),I(E)}return c(),A&&a.push(A),a}function kMe(){let n=Date.now()%1e8,r=Math.floor(Math.random()*65536);return(n^r)%65536}async function V8(n,r,o,{logger:i}={}){let e=RMe(o),a=[];for(let A of e){if(typeof n?.send=="function")try{a.push(await n.send({target:r,msgType:2,markdown:{content:A},extra:{msg_seq:kMe()}}));continue}catch(t){i?.warn?.("[dsh-im:qq] markdown delivery failed; retrying as plain text:",t)}a.push(await n.sendText(r,A))}return a}var xy="\u8FD9\u4E2A\u95EE\u9898\u5DF2\u5728\u5176\u4ED6\u5BA2\u6237\u7AEF\u5904\u7406\uFF0C\u65E0\u9700\u518D\u6B21\u56DE\u7B54\u3002",W8=12e4,vMe=Object.freeze([".myqcloud.com",".qpic.cn",".qq.com",".qq.com.cn",".tencentcos.com",".ugcimg.cn"]),PMe=/\.(?:gif|jpe?g|png|webp)$/i,GMe=["QQ \u673A\u5668\u4EBA\u5DF2\u8FDE\u63A5 DeepSeek Harness\u3002","","\u76F4\u63A5\u53D1\u9001\u6587\u5B57\u3001\u56FE\u7247\u6216\u6587\u4EF6\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002","/new \u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD","/compact \u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u7684\u8F83\u65E9\u4E0A\u4E0B\u6587","/workspace \u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84 \u5207\u6362\u5DE5\u4F5C\u533A","/workspacelist \u5217\u51FA\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84","/sessionlist [\u5DE5\u4F5C\u533A\u5E8F\u53F7\u6216\u7EDD\u5BF9\u8DEF\u5F84] \u5217\u51FA\u4F1A\u8BDD ID \u548C\u6807\u9898","/session Session ID \u6216\u5F53\u524D\u5DE5\u4F5C\u533A\u5E8F\u53F7 \u5C06\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u5230\u6307\u5B9A\u4F1A\u8BDD","/models \u6309\u5E8F\u53F7\u5217\u51FA\u6240\u6709\u53EF\u7528\u6A21\u578B","/model [\u5E8F\u53F7\u6216\u5B8C\u6574\u6A21\u578BID] \u67E5\u770B\u6216\u5207\u6362\u5F53\u524D\u4F1A\u8BDD\u6A21\u578B","\u793A\u4F8B\uFF1A\u5148\u53D1 /models\uFF0C\u518D\u53D1 /model 2","/presetlist \u6309\u5E8F\u53F7\u5217\u51FA\u53EF\u7528 Agent Preset","/preset [\u5E8F\u53F7\u6216\u5B8C\u6574ID] \u67E5\u770B\u6216\u8BBE\u7F6E\u5F53\u524D\u673A\u5668\u4EBA Agent Preset","\u7EAF\u6570\u5B57 ID\uFF1A/preset id:","/preset --default \u8DDF\u968F Host \u9ED8\u8BA4","/stop \u505C\u6B62\u5F53\u524D\u4EFB\u52A1","/steer \u8865\u5145\u6307\u4EE4 \u7EA0\u504F\u5F53\u524D\u4EFB\u52A1","/status \u68C0\u67E5\u8FDE\u63A5\u72B6\u6001","/help \u663E\u793A\u672C\u5E2E\u52A9"].join(` -`);function FMe(n){return`${n.kind}:${n.kind==="group"?n.groupOpenid:n.senderId}`}function gC(n){return typeof n?.content=="string"?n.content.trim():""}function $8(n){let r=Ma(n?.content_type??n?.contentType);return r?r.split(";",1)[0].trim().toLowerCase():null}function Ck(n){return $8(n)?.startsWith("image/")===!0||PMe.test(Ma(n?.filename)??"")}function Yy(n){return Array.isArray(n?.attachments)&&n.attachments.some(Ck)}function sC(n){return Array.isArray(n?.attachments)&&n.attachments.some(r=>!Ck(r))}async function LMe(n,{fetchImpl:r,signal:o}){let i=n.startsWith("//")?`https:${n}`:n,e=await r(new URL(i),{method:"GET",signal:o,redirect:"follow"});if(!e?.ok)throw await e?.body?.cancel?.().catch?.(()=>{}),new Error(`QQ file download failed with HTTP ${e?.status??"unknown"}`);return Buffer.from(await e.arrayBuffer())}function Z8(n,{fetchImpl:r=fetch}={}){if(typeof r!="function")throw new TypeError("fetchImpl must be a function");let o=[],i=[];for(let e of n?.attachments??[]){let a=Ma(e?.url),A=Ma(e?.filename)??void 0,t=$8(e),s=Number(e?.size);if(Ck(e)){o.push({...A?{name:A}:{},...t?.startsWith("image/")?{mediaType:t}:{},...Number.isFinite(s)&&s>=0?{size:s}:{},load:({signal:g,maxBytes:c})=>{if(!a)throw new Error("QQ image attachment has no download URL");return Ki(a,{fetchImpl:r,signal:g,maxBytes:c,allowedHosts:vMe})}});continue}i.push({name:A??(i.length===0?"file":`file-${i.length+1}`),...t?.includes("/")?{mediaType:t}:{},...Number.isFinite(s)&&s>=0?{size:s}:{},load:({signal:g}={})=>{if(!a)throw new Error("QQ file attachment has no download URL");return LMe(a,{fetchImpl:r,signal:g})}})}return{content:gC(n),images:o,files:i}}function Ma(n){return typeof n=="string"&&n.trim()?n.trim():null}function UMe(n,r){let o=String(n??"\u7ED3\u679C\u6587\u4EF6").replace(/[\r\n]+/g," ").trim()||"\u7ED3\u679C\u6587\u4EF6";if(r?.name==="UploadDailyLimitExceededError")return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46 QQ \u4ECA\u65E5\u6587\u4EF6\u4E0A\u4F20\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`;switch(r?.code){case"artifact-delivery-uncertain":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u7684\u53D1\u9001\u7ED3\u679C\u672A\u80FD\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u804A\u5929\u5185\u662F\u5426\u5DF2\u6536\u5230\uFF0C\u4E0D\u8981\u7ACB\u5373\u91CD\u8BD5\u3002`;case"artifact-permission-required":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u5F53\u524D QQ \u673A\u5668\u4EBA\u6CA1\u6709\u6587\u4EF6\u6D88\u606F\u6743\u9650\u3002`;case"artifact-too-large":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u8D85\u8FC7\u5F53\u524D QQ \u673A\u5668\u4EBA\u53EF\u53D1\u9001\u7684\u6587\u4EF6\u5927\u5C0F\uFF0C\u672A\u53D1\u9001\u3002`;case"artifact-empty":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u4E3A\u7A7A\uFF0CQQ \u4E0D\u5141\u8BB8\u53D1\u9001\u7A7A\u6587\u4EF6\u3002`;case"artifact-changed":case"artifact-invalid":case"artifact-unavailable":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u6216\u51C6\u5907\u53D1\u9001\uFF0C\u8BF7\u786E\u8BA4\u6587\u4EF6\u4ECD\u53EF\u8BBF\u95EE\u540E\u91CD\u8BD5\u3002`;case"artifact-rate-limited":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u6682\u65F6\u88AB QQ \u9650\u6D41\uFF0C\u672A\u80FD\u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`;case"artifact-provider-rejected":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46 QQ \u62D2\u7EDD\u4E86\u8BE5\u6587\u4EF6\u6216\u6587\u4EF6\u6D88\u606F\u3002`;default:return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u6682\u65F6\u672A\u80FD\u901A\u8FC7 QQ \u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`}}function HMe(n,r){return typeof n=="string"&&n.trim()?n:r.length>0?"\u7ED3\u679C\u6587\u4EF6\u5DF2\u751F\u6210\u3002":n}function X8(n,{dispatched:r=!1}={}){if(n?.code?.startsWith?.("artifact-")||n?.name==="UploadDailyLimitExceededError")return n;let o=Number(n?.httpStatus),i=new Error("QQ file delivery failed",{cause:n});return o===401||o===403?i.code="artifact-permission-required":o===413?i.code="artifact-too-large":o===429?i.code="artifact-rate-limited":o===400||o===404?i.code="artifact-provider-rejected":i.code=r?"artifact-delivery-uncertain":"artifact-provider-failed",i}function ez(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}function KMe(n,r){return r?(r.throwIfAborted(),new Promise((o,i)=>{let e=!1,a=(t,s)=>{e||(e=!0,r.removeEventListener("abort",A),t(s))},A=()=>a(i,ez(r));r.addEventListener("abort",A,{once:!0}),Promise.resolve(n).then(t=>a(o,t),t=>a(i,t)),r.aborted&&A()})):n}function xMe(n,r){return r.questions[r.index]&&Ma(n?.senderId)===r.actor&&(n.kind!=="group"||n.rawEventType==="GROUP_AT_MESSAGE_CREATE")&&!Yy(n)&&!sC(n)&&Ma(gC(n))}function uk(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,artifactsSent:0,artifactSendErrors:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null}}var jy=class{#e;#A;#t;#r;#s;#i;#I;#o;#l;#a;#n=new Map;#g=new Map;#c=new Map;#p=new Set;#h=new Set;#d=new Set;#E;constructor({bot:r,ownerUserOpenid:o,harness:i,state:e,status:a=uk(),logger:A=console,replyTimeoutMs:t=6e5,signal:s,fetchImpl:g=fetch,fileUploadTimeoutMs:c=W8}){if(!r||typeof r.sendText!="function")throw new TypeError("QQ bot client is required");if(!o)throw new TypeError("QQ scanner identity is required");if(!i||!e)throw new TypeError("Harness client and state store are required");if(typeof g!="function")throw new TypeError("fetchImpl must be a function");if(!Number.isInteger(c)||c<1)throw new TypeError("fileUploadTimeoutMs must be a positive integer");this.#e=r,this.#A=o,this.#t=i,this.#r=e,this.#s=a,this.#i=A,this.#I=t,this.#o=s,this.#l=g,this.#a=Math.min(c,W8),this.#E=new Wa({label:"qq",logger:A})}get status(){return structuredClone(this.#s)}accept(r){if(this.#o?.aborted)return Promise.resolve();let o=Ma(r?.messageId),i=Ma(r?.senderId);if(!o||!i||r?.senderIsBot===!0||!["c2c","group"].includes(r?.kind)||this.#r.hasSeen(o)||this.#p.has(o))return Promise.resolve();let e=FMe(r);this.#p.add(o),r.kind==="c2c"&&(this.#A==="*"||i===this.#A)&&r.replyTarget?.scope==="c2c"&&Ma(r.replyTarget.targetId)===i&&Hi(this.#r,r.replyTarget);let a=this.#g.get(e),A=gC(r),t=sC(r)?null:Bi(A)?Ji:fi(A)?zi:Qi(A)?Vi:null,s=this.#A==="*"||i===this.#A,g=r.kind!=="group"||r.rawEventType==="GROUP_AT_MESSAGE_CREATE";if(t&&s&&g){let I;return I=this.#u(r,o,e,A,t).catch(E=>{if(!(E?.code==="turn-stopped"||this.#o?.aborted))return this.#s.lastError=E?.message??String(E),this.#i.error?.("[dsh-im:qq] failed to process a command:",E),this.#e.sendText(r.replyTarget,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002").catch(()=>{})}).finally(()=>{this.#p.delete(o),this.#d.delete(I)}),this.#d.add(I),I}let c=this.#E.claimReply({key:e,actor:i,messageId:o,text:Yy(r)||sC(r)?"":gC(r),addressed:r.kind!=="group"||r.rawEventType==="GROUP_AT_MESSAGE_CREATE",hasPendingQuestion:!!a,questionCompletion:a?.submitting||a?.claimedReplyMessageId?a.queue:null,isQuestionPending:()=>this.#g.has(e),send:I=>this.#e.sendText(r.replyTarget,I)});if(c){let I;return I=c.process(async()=>this.#r.hasSeen(o)?!1:(await this.#r.markSeen(o),this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString(),!0)).finally(()=>{this.#p.delete(o),this.#h.delete(I)}),this.#h.add(I),I}if(a&&i!==a.actor)return this.#C(r,o,e);if(a?.submitting||a?.claimedReplyMessageId)return this.#C(r,o,e);if(a){xMe(r,a)&&(a.claimedReplyMessageId=o);let E=(a.queue??Promise.resolve()).catch(()=>{}).then(()=>this.#m(r,o,e,a)).catch(B=>this.#O(r,o,B)).finally(()=>{this.#p.delete(o),a.claimedReplyMessageId===o&&(a.claimedReplyMessageId=null),a.queue===E&&(a.queue=null)});return a.queue=E,E}return this.#C(r,o,e)}#C(r,o,i,{releaseMessageId:e=!0,alreadyRecorded:a=!1}={}){let A=this.#A==="*"||r.senderId===this.#A,t=r.kind!=="group"||r.rawEventType==="GROUP_AT_MESSAGE_CREATE",s=A&&t?dl(Z8(r,{fetchImpl:this.#l}),{signal:this.#o}):void 0,c=(this.#n.get(i)??Promise.resolve()).catch(()=>{}).then(()=>this.#Q(r,i,{alreadyRecorded:a,preparedMessage:s})).finally(()=>{e&&this.#p.delete(o),this.#n.get(i)===c&&this.#n.delete(i)});return this.#n.set(i,c),c}async waitForIdle(){await Promise.allSettled([...this.#n.values(),...[...this.#g.values()].flatMap(r=>r.queue?[r.queue]:[]),...this.#h,...this.#d])}async#u(r,o,i,e,a){if(this.#o?.throwIfAborted(),this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString();let A=await a(e,this.#t,this.#r,i,{signal:this.#o,hasImages:Yy(r),hasFiles:sC(r),pendingInteraction:this.#g.has(i)||this.#E.hasPending(i),control:{owner:this,key:i}});A?.stopped&&await Promise.allSettled([this.#T(i),this.#E.closeRoute(i)]);for(let t of A?.messages??[A?.message])t&&await this.#e.sendText(r.replyTarget,t);this.#s.lastError=null}async#B(r,o,i=[],e=null){if(i.length===0)return{receipt:e,failureNoticeVisible:!1};let a=e?[e]:[],A=!1;for(let t of i){this.#o?.throwIfAborted();try{if(typeof this.#e.sendFile!="function"){let I=new Error("QQ file delivery is unavailable");throw I.code="artifact-provider-unavailable",I}let s=await Xi(t,{signal:this.#o});this.#o?.throwIfAborted();let g;try{let I=AbortSignal.timeout(this.#a),E=this.#o?AbortSignal.any([this.#o,I]):I,B=this.#e.sendFile(r,{buffer:s.bytes},{fileName:s.fileName,onProgress:()=>this.#o?.throwIfAborted()});hn(s,B),g=await KMe(B,E)}catch(I){throw this.#o?.aborted?ez(this.#o):X8(I,{dispatched:!0})}this.#o?.throwIfAborted();let c=Ma(g?.message?.id);a.push(Nt({deliveryId:s.deliveryKey,presentation:"qq-file",providerMessageIds:c?[c]:[],artifacts:[{artifactId:s.artifactId,outcome:"sent"}]})),this.#s.artifactsSent=(this.#s.artifactsSent??0)+1}catch(s){if(this.#o?.aborted)throw s;let g=X8(s);this.#s.artifactSendErrors=(this.#s.artifactSendErrors??0)+1,this.#i.warn?.(`[dsh-im:qq] result file delivery failed (${g?.code??g?.name??"unknown"})`);let c=[];try{let I=await this.#e.sendText(r,UMe(t?.fileName,g));A=!0,c=va(I)}catch(I){if(this.#o?.aborted)throw I;this.#i.warn?.("[dsh-im:qq] unable to send the safe result-file failure notice")}a.push(eo({artifactId:t?.artifactId??"unknown",deliveryId:t?.deliveryKey??t?.artifactId??"unknown",error:g,providerMessageIds:c}))}finally{$i(t)}}return{receipt:Ao({deliveryId:o,presentation:e?"qq-text-and-files":"qq-files",receipts:a}),failureNoticeVisible:A}}async#Q(r,o,{alreadyRecorded:i=!1,preparedMessage:e}={}){if(this.#o?.aborted)return;let a=Ma(r?.messageId),A=Ma(r?.senderId);if(!a||!A||r.senderIsBot===!0||!["c2c","group"].includes(r.kind))return;if(!i){if(this.#r.hasSeen(a))return;this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString()}if(this.#A!=="*"&&A!==this.#A){this.#s.messagesRejected+=1,this.#s.lastRejectedAt=new Date().toISOString();return}if(r.kind==="group"&&r.rawEventType!=="GROUP_AT_MESSAGE_CREATE")return;let t=r.replyTarget,s=e??Z8(r,{fetchImpl:this.#l}),g=s.content,c=Er(s),I=Zt(s);try{if(!g&&!c&&!I){await this.#e.sendText(t,"\u76EE\u524D\u652F\u6301\u6587\u5B57\u3001\u56FE\u7247\u548C\u6587\u4EF6\u6D88\u606F\u3002"),await this.#r.markSeen(a);return}let E=g.toLowerCase();if(!c&&!I&&E==="/help"){await this.#e.sendText(t,GMe),await this.#r.markSeen(a);return}if(!c&&!I&&E==="/status"){await this.#t.ensureRunning({signal:this.#o}),await this.#e.sendText(t,"QQ \u673A\u5668\u4EBA\u4E0E DeepSeek Harness \u8FDE\u63A5\u6B63\u5E38\u3002"),await this.#r.markSeen(a);return}if(!c&&!I&&E==="/new"){await this.#r.clearSession(o),await this.#e.sendText(t,"\u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002\u8BF7\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002"),await this.#r.markSeen(a);return}let B=c||I?null:await qi(g,this.#t,o);if(B){for(let F of B.messages??[B.message])await this.#e.sendText(t,F);await this.#r.markSeen(a);return}let f=c||I?null:await ji(g,this.#t,this.#r,o,{signal:this.#o});if(f){await this.#e.sendText(t,f.message),await this.#r.markSeen(a);return}let Q=c?await xi(s,{signal:this.#o}):void 0,y=null,m=async F=>{try{await this.#e.sendText(t,F)}catch(v){this.#i.warn?.("[dsh-im:qq] unable to send a turn progress notice:",v)}},_,N=[];try{({answer:_,artifacts:N=[]}=await Xa({harness:this.#t,state:this.#r,key:o,...c?{content:Q}:{text:g},createOptions:{signal:this.#o},existsOptions:{signal:this.#o},askOptions:{timeoutMs:this.#I,signal:this.#o,control:{owner:this,key:o},onUpdate:async F=>{if(F.type==="text"){y=F.text;return}if(F.type==="tool"){Ma(y)&&await m(y.trim()),y=null,await m(`Tool call ${F.name}`);return}if(F.error){let v=Ma(F.toolName)?`Tool call ${F.toolName}`:"Tool call";await m(`${v} +`);function FMe(n){return`${n.kind}:${n.kind==="group"?n.groupOpenid:n.senderId}`}function gC(n){return typeof n?.content=="string"?n.content.trim():""}function $8(n){let r=Ma(n?.content_type??n?.contentType);return r?r.split(";",1)[0].trim().toLowerCase():null}function Ck(n){return $8(n)?.startsWith("image/")===!0||PMe.test(Ma(n?.filename)??"")}function Yy(n){return Array.isArray(n?.attachments)&&n.attachments.some(Ck)}function sC(n){return Array.isArray(n?.attachments)&&n.attachments.some(r=>!Ck(r))}async function LMe(n,{fetchImpl:r,signal:o}){let i=n.startsWith("//")?`https:${n}`:n,e=await r(new URL(i),{method:"GET",signal:o,redirect:"follow"});if(!e?.ok)throw await e?.body?.cancel?.().catch?.(()=>{}),new Error(`QQ file download failed with HTTP ${e?.status??"unknown"}`);return Buffer.from(await e.arrayBuffer())}function Z8(n,{fetchImpl:r=fetch}={}){if(typeof r!="function")throw new TypeError("fetchImpl must be a function");let o=[],i=[];for(let e of n?.attachments??[]){let a=Ma(e?.url),A=Ma(e?.filename)??void 0,t=$8(e),s=Number(e?.size);if(Ck(e)){o.push({...A?{name:A}:{},...t?.startsWith("image/")?{mediaType:t}:{},...Number.isFinite(s)&&s>=0?{size:s}:{},load:({signal:g,maxBytes:c})=>{if(!a)throw new Error("QQ image attachment has no download URL");return Ki(a,{fetchImpl:r,signal:g,maxBytes:c,allowedHosts:vMe})}});continue}i.push({name:A??(i.length===0?"file":`file-${i.length+1}`),...t?.includes("/")?{mediaType:t}:{},...Number.isFinite(s)&&s>=0?{size:s}:{},load:({signal:g}={})=>{if(!a)throw new Error("QQ file attachment has no download URL");return LMe(a,{fetchImpl:r,signal:g})}})}return{content:gC(n),images:o,files:i}}function Ma(n){return typeof n=="string"&&n.trim()?n.trim():null}function UMe(n,r){let o=String(n??"\u7ED3\u679C\u6587\u4EF6").replace(/[\r\n]+/g," ").trim()||"\u7ED3\u679C\u6587\u4EF6";if(r?.name==="UploadDailyLimitExceededError")return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46 QQ \u4ECA\u65E5\u6587\u4EF6\u4E0A\u4F20\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`;switch(r?.code){case"artifact-delivery-uncertain":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u7684\u53D1\u9001\u7ED3\u679C\u672A\u80FD\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u804A\u5929\u5185\u662F\u5426\u5DF2\u6536\u5230\uFF0C\u4E0D\u8981\u7ACB\u5373\u91CD\u8BD5\u3002`;case"artifact-permission-required":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u5F53\u524D QQ \u673A\u5668\u4EBA\u6CA1\u6709\u6587\u4EF6\u6D88\u606F\u6743\u9650\u3002`;case"artifact-too-large":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u8D85\u8FC7\u5F53\u524D QQ \u673A\u5668\u4EBA\u53EF\u53D1\u9001\u7684\u6587\u4EF6\u5927\u5C0F\uFF0C\u672A\u53D1\u9001\u3002`;case"artifact-empty":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u4E3A\u7A7A\uFF0CQQ \u4E0D\u5141\u8BB8\u53D1\u9001\u7A7A\u6587\u4EF6\u3002`;case"artifact-changed":case"artifact-invalid":case"artifact-unavailable":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u6216\u51C6\u5907\u53D1\u9001\uFF0C\u8BF7\u786E\u8BA4\u6587\u4EF6\u4ECD\u53EF\u8BBF\u95EE\u540E\u91CD\u8BD5\u3002`;case"artifact-rate-limited":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u6682\u65F6\u88AB QQ \u9650\u6D41\uFF0C\u672A\u80FD\u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`;case"artifact-provider-rejected":return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46 QQ \u62D2\u7EDD\u4E86\u8BE5\u6587\u4EF6\u6216\u6587\u4EF6\u6D88\u606F\u3002`;default:return`\u7ED3\u679C\u6587\u4EF6\u300C${o}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u6682\u65F6\u672A\u80FD\u901A\u8FC7 QQ \u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`}}function HMe(n,r){return typeof n=="string"&&n.trim()?n:r.length>0?"\u7ED3\u679C\u6587\u4EF6\u5DF2\u751F\u6210\u3002":n}function X8(n,{dispatched:r=!1}={}){if(n?.code?.startsWith?.("artifact-")||n?.name==="UploadDailyLimitExceededError")return n;let o=Number(n?.httpStatus),i=new Error("QQ file delivery failed",{cause:n});return o===401||o===403?i.code="artifact-permission-required":o===413?i.code="artifact-too-large":o===429?i.code="artifact-rate-limited":o===400||o===404?i.code="artifact-provider-rejected":i.code=r?"artifact-delivery-uncertain":"artifact-provider-failed",i}function ez(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}function KMe(n,r){return r?(r.throwIfAborted(),new Promise((o,i)=>{let e=!1,a=(t,s)=>{e||(e=!0,r.removeEventListener("abort",A),t(s))},A=()=>a(i,ez(r));r.addEventListener("abort",A,{once:!0}),Promise.resolve(n).then(t=>a(o,t),t=>a(i,t)),r.aborted&&A()})):n}function xMe(n,r){return r.questions[r.index]&&Ma(n?.senderId)===r.actor&&(n.kind!=="group"||n.rawEventType==="GROUP_AT_MESSAGE_CREATE")&&!Yy(n)&&!sC(n)&&Ma(gC(n))}function uk(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,artifactsSent:0,artifactSendErrors:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null}}var jy=class{#e;#A;#t;#r;#s;#i;#I;#o;#l;#a;#n=new Map;#g=new Map;#c=new Map;#p=new Set;#h=new Set;#d=new Set;#E;constructor({bot:r,ownerUserOpenid:o,harness:i,state:e,status:a=uk(),logger:A=console,replyTimeoutMs:t=6e5,signal:s,fetchImpl:g=fetch,fileUploadTimeoutMs:c=W8}){if(!r||typeof r.sendText!="function")throw new TypeError("QQ bot client is required");if(!o)throw new TypeError("QQ scanner identity is required");if(!i||!e)throw new TypeError("Harness client and state store are required");if(typeof g!="function")throw new TypeError("fetchImpl must be a function");if(!Number.isInteger(c)||c<1)throw new TypeError("fileUploadTimeoutMs must be a positive integer");this.#e=r,this.#A=o,this.#t=i,this.#r=e,this.#s=a,this.#i=A,this.#I=t,this.#o=s,this.#l=g,this.#a=Math.min(c,W8),this.#E=new Wa({label:"qq",logger:A})}get status(){return structuredClone(this.#s)}accept(r){if(this.#o?.aborted)return Promise.resolve();let o=Ma(r?.messageId),i=Ma(r?.senderId);if(!o||!i||r?.senderIsBot===!0||!["c2c","group"].includes(r?.kind)||this.#r.hasSeen(o)||this.#p.has(o))return Promise.resolve();let e=FMe(r);this.#p.add(o),r.kind==="c2c"&&(this.#A==="*"||i===this.#A)&&r.replyTarget?.scope==="c2c"&&Ma(r.replyTarget.targetId)===i&&Hi(this.#r,r.replyTarget);let a=this.#g.get(e),A=gC(r),t=sC(r)?null:Bi(A)?Ji:fi(A)?zi:Qi(A)?Vi:null,s=this.#A==="*"||i===this.#A,g=r.kind!=="group"||r.rawEventType==="GROUP_AT_MESSAGE_CREATE";if(t&&s&&g){let I;return I=this.#u(r,o,e,A,t).catch(E=>{if(!(E?.code==="turn-stopped"||this.#o?.aborted))return this.#s.lastError=E?.message??String(E),this.#i.error?.("[dsh-im:qq] failed to process a command:",E),this.#e.sendText(r.replyTarget,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002").catch(()=>{})}).finally(()=>{this.#p.delete(o),this.#d.delete(I)}),this.#d.add(I),I}let c=this.#E.claimReply({key:e,actor:i,messageId:o,text:Yy(r)||sC(r)?"":gC(r),addressed:r.kind!=="group"||r.rawEventType==="GROUP_AT_MESSAGE_CREATE",hasPendingQuestion:!!a,questionCompletion:a?.submitting||a?.claimedReplyMessageId?a.queue:null,isQuestionPending:()=>this.#g.has(e),send:I=>this.#e.sendText(r.replyTarget,I)});if(c){let I;return I=c.process(async()=>this.#r.hasSeen(o)?!1:(await this.#r.markSeen(o),this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString(),!0)).finally(()=>{this.#p.delete(o),this.#h.delete(I)}),this.#h.add(I),I}if(a&&i!==a.actor)return this.#C(r,o,e);if(a?.submitting||a?.claimedReplyMessageId)return this.#C(r,o,e);if(a){xMe(r,a)&&(a.claimedReplyMessageId=o);let E=(a.queue??Promise.resolve()).catch(()=>{}).then(()=>this.#m(r,o,e,a)).catch(B=>this.#O(r,o,B)).finally(()=>{this.#p.delete(o),a.claimedReplyMessageId===o&&(a.claimedReplyMessageId=null),a.queue===E&&(a.queue=null)});return a.queue=E,E}return this.#C(r,o,e)}#C(r,o,i,{releaseMessageId:e=!0,alreadyRecorded:a=!1}={}){let A=this.#A==="*"||r.senderId===this.#A,t=r.kind!=="group"||r.rawEventType==="GROUP_AT_MESSAGE_CREATE",s=A&&t?dl(Z8(r,{fetchImpl:this.#l}),{signal:this.#o}):void 0,c=(this.#n.get(i)??Promise.resolve()).catch(()=>{}).then(()=>this.#Q(r,i,{alreadyRecorded:a,preparedMessage:s})).finally(()=>{e&&this.#p.delete(o),this.#n.get(i)===c&&this.#n.delete(i)});return this.#n.set(i,c),c}async waitForIdle(){await Promise.allSettled([...this.#n.values(),...[...this.#g.values()].flatMap(r=>r.queue?[r.queue]:[]),...this.#h,...this.#d])}async#u(r,o,i,e,a){if(this.#o?.throwIfAborted(),this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString();let A=await a(e,this.#t,this.#r,i,{signal:this.#o,hasImages:Yy(r),hasFiles:sC(r),pendingInteraction:this.#g.has(i)||this.#E.hasPending(i),control:{owner:this,key:i}});A?.stopped&&await Promise.allSettled([this.#T(i),this.#E.closeRoute(i)]);for(let t of A?.messages??[A?.message])t&&await this.#e.sendText(r.replyTarget,t);this.#s.lastError=null}async#B(r,o,i=[],e=null){if(i.length===0)return{receipt:e,failureNoticeVisible:!1};let a=e?[e]:[],A=!1;for(let t of i){this.#o?.throwIfAborted();try{if(typeof this.#e.sendFile!="function"){let I=new Error("QQ file delivery is unavailable");throw I.code="artifact-provider-unavailable",I}let s=await Xi(t,{signal:this.#o});this.#o?.throwIfAborted();let g;try{let I=AbortSignal.timeout(this.#a),E=this.#o?AbortSignal.any([this.#o,I]):I,B=this.#e.sendFile(r,{buffer:s.bytes},{fileName:s.fileName,onProgress:()=>this.#o?.throwIfAborted()});hn(s,B),g=await KMe(B,E)}catch(I){throw this.#o?.aborted?ez(this.#o):X8(I,{dispatched:!0})}this.#o?.throwIfAborted();let c=Ma(g?.message?.id);a.push(Nt({deliveryId:s.deliveryKey,presentation:"qq-file",providerMessageIds:c?[c]:[],artifacts:[{artifactId:s.artifactId,outcome:"sent"}]})),this.#s.artifactsSent=(this.#s.artifactsSent??0)+1}catch(s){if(this.#o?.aborted)throw s;let g=X8(s);this.#s.artifactSendErrors=(this.#s.artifactSendErrors??0)+1,this.#i.warn?.(`[dsh-im:qq] result file delivery failed (${g?.code??g?.name??"unknown"})`);let c=[];try{let I=await this.#e.sendText(r,UMe(t?.fileName,g));A=!0,c=va(I)}catch(I){if(this.#o?.aborted)throw I;this.#i.warn?.("[dsh-im:qq] unable to send the safe result-file failure notice")}a.push(eo({artifactId:t?.artifactId??"unknown",deliveryId:t?.deliveryKey??t?.artifactId??"unknown",error:g,providerMessageIds:c}))}finally{$i(t)}}return{receipt:Ao({deliveryId:o,presentation:e?"qq-text-and-files":"qq-files",receipts:a}),failureNoticeVisible:A}}async#Q(r,o,{alreadyRecorded:i=!1,preparedMessage:e}={}){if(this.#o?.aborted)return;let a=Ma(r?.messageId),A=Ma(r?.senderId);if(!a||!A||r.senderIsBot===!0||!["c2c","group"].includes(r.kind))return;if(!i){if(this.#r.hasSeen(a))return;this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString()}if(this.#A!=="*"&&A!==this.#A){this.#s.messagesRejected+=1,this.#s.lastRejectedAt=new Date().toISOString();return}if(r.kind==="group"&&r.rawEventType!=="GROUP_AT_MESSAGE_CREATE")return;let t=r.replyTarget,s=e??Z8(r,{fetchImpl:this.#l}),g=s.content,c=Er(s),I=Zt(s);try{if(!g&&!c&&!I){await this.#e.sendText(t,"\u76EE\u524D\u652F\u6301\u6587\u5B57\u3001\u56FE\u7247\u548C\u6587\u4EF6\u6D88\u606F\u3002"),await this.#r.markSeen(a);return}let E=g.toLowerCase();if(!c&&!I&&E==="/help"){await this.#e.sendText(t,GMe),await this.#r.markSeen(a);return}if(!c&&!I&&E==="/status"){await this.#t.ensureRunning({signal:this.#o}),await this.#e.sendText(t,"QQ \u673A\u5668\u4EBA\u4E0E DeepSeek Harness \u8FDE\u63A5\u6B63\u5E38\u3002"),await this.#r.markSeen(a);return}if(!c&&!I&&E==="/new"){await this.#r.clearSession(o),await this.#e.sendText(t,"\u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002\u8BF7\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002"),await this.#r.markSeen(a);return}let B=c||I?null:await qi(g,this.#t,o);if(B){for(let F of B.messages??[B.message])await this.#e.sendText(t,F);await this.#r.markSeen(a);return}let f=c||I?null:await ji(g,this.#t,this.#r,o,{signal:this.#o});if(f){await this.#e.sendText(t,f.message),await this.#r.markSeen(a);return}let Q=c?await xi(s,{signal:this.#o}):void 0,y=null,m=async F=>{try{await this.#e.sendText(t,F)}catch(v){this.#i.warn?.("[dsh-im:qq] unable to send a turn progress notice:",v)}},_,N=[];try{({answer:_,artifacts:N=[]}=await Xa({harness:this.#t,state:this.#r,key:o,...c?{content:Q}:{text:g},createOptions:{signal:this.#o},existsOptions:{signal:this.#o},askOptions:{timeoutMs:this.#I,signal:this.#o,control:{owner:this,key:o},onUpdate:async F=>{if(F.type==="text"){y=F.text;return}if(F.type==="tool"){Ma(y)&&await m(y.trim()),y=null;return}if(F.error){let v=Ma(F.toolName)?`Tool call ${F.toolName}`:"Tool call";await m(`${v} Error: ${F.error}`)}},onInteraction:F=>this.#f(F,{key:o,actor:A,target:t,requiresMention:r.kind==="group"}),onInteractionResolved:F=>this.#y(F),files:s.files}}))}finally{await Promise.allSettled([this.#T(o),this.#E.closeRoute(o)])}this.#o?.throwIfAborted();let P=HMe(_,N);Ma(y)&&y.trim()!==P.trim()&&await m(y.trim());let Y=P,x=null,H=null;try{let F=await V8(this.#e,t,Y,{logger:this.#i});x=Nt({deliveryId:a,presentation:"qq-text",providerMessageIds:F.flatMap(v=>va(v))})}catch(F){H=F,this.#i.warn?.("[dsh-im:qq] final text delivery failed; continuing with result files:",F)}let j=await this.#B(t,a,N,x),q=j.receipt?.artifacts?.some(({outcome:F})=>F==="sent"||F==="unknown");if(H&&!q&&!j.failureNoticeVisible)throw H;return await this.#r.markSeen(a),this.#s.messagesReplied+=1,this.#s.lastReplyAt=new Date().toISOString(),this.#s.lastError=null,j.receipt}catch(E){if(E?.code==="turn-stopped"){try{await this.#e.sendText(t,"\u5DF2\u505C\u6B62\u3002")}catch(B){this.#i.warn?.("[dsh-im:qq] unable to announce a stopped QQ turn:",B)}await this.#r.markSeen(a);return}if(this.#o?.aborted)return;this.#s.lastError=E?.message??String(E),this.#i.error?.("[dsh-im:qq] failed to process an inbound message:",E);try{await this.#e.sendText(t,Zi(E)??Yi(E)??"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"),await this.#r.markSeen(a)}catch(B){this.#i.error?.("[dsh-im:qq] failed to send the safe error reply:",B)}}}async#m(r,o,i,e){this.#o?.throwIfAborted();let a=this.#g.get(i),A=e.claimedReplyMessageId===o;if(!a||a!==e||a.submitting)return A&&(!a||a!==e)?this.#w(r,o):this.#C(r,o,i,{releaseMessageId:!1});if(this.#r.hasSeen(o)||(await this.#r.markSeen(o),this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString(),r.kind==="group"&&r.rawEventType!=="GROUP_AT_MESSAGE_CREATE"))return;let t=Ma(gC(r));if(!t||Yy(r)||sC(r)){await this.#e.sendText(r.replyTarget,"\u8BF7\u7528\u6587\u5B57\u56DE\u7B54\u5F53\u524D\u95EE\u9898\u3002");return}let s=this.#g.get(i);if(!s||s!==e||s.submitting){if(A&&(!s||s!==e)){await this.#e.sendText(r.replyTarget,xy);return}return this.#C(r,o,i,{releaseMessageId:!1,alreadyRecorded:!0})}if(s.target=r.replyTarget,s.needsPresentation){try{await this.#D(s)}catch{this.#s.lastError="QQ \u4EA4\u4E92\u95EE\u9898\u53D1\u9001\u5931\u8D25\u3002",this.#i.error?.("[dsh-im:qq] failed to retry an interaction question"),s.interaction.reconnect?.();return}let c=this.#g.get(i);if(!c||c!==e||c.submitting){if(A&&(!c||c!==e)){await this.#e.sendText(r.replyTarget,xy).catch(()=>{});return}return this.#C(r,o,i,{releaseMessageId:!1,alreadyRecorded:!0})}}let g=s.questions[s.index];if(g){if(s.answers.push(Va(g,t)),s.index+=1,s.index{});return}if(this.#g.get(i)!==s)return;s.submitting=!1,s.answers.pop(),s.index-=1,this.#s.lastError="\u56DE\u7B54\u63D0\u4EA4\u5931\u8D25\u3002",this.#i.error?.("[dsh-im:qq] failed to answer a Harness interaction"),await this.#e.sendText(s.target,"\u56DE\u7B54\u63D0\u4EA4\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u5F53\u524D\u95EE\u9898\u7684\u7B54\u6848\u3002").catch(()=>{})}}}async#f(r,{key:o,actor:i,target:e,requiresMention:a}){if(r?.kind==="approval")return this.#E.handleRequested(r,{key:o,actor:i,requiresMention:a,send:c=>this.#e.sendText(e,c)});if(r?.kind!=="question")return;let A=r?.payload?.questions,t=typeof r?.interactionId=="string"?r.interactionId:r?.rpcId;if(typeof r?.rpcId!="string"||typeof t!="string"||typeof r.sessionId!="string"||!Array.isArray(A)||A.length===0||A.some(c=>!qa(c))){this.#i.warn?.("[dsh-im:qq] ignored an invalid Harness question interaction");return}if(r.recovered===!0){await r.respond({ok:!1,error:{code:"cancelled",message:"QQ safely cancelled an interaction left by an earlier client.",details:{}}}),await this.#e.sendText(e,"\u68C0\u6D4B\u5230\u8FD9\u4E2A Session \u4E2D\u9057\u7559\u7684\u5F85\u56DE\u7B54\u95EE\u9898\uFF0C\u5DF2\u5B89\u5168\u53D6\u6D88\u5E76\u7EE7\u7EED\u5904\u7406\u4F60\u521A\u624D\u7684\u6D88\u606F\u3002").catch(()=>{});return}let s=this.#g.get(o);if(s?.interactionId===t){s.interaction=r,s.needsPresentation&&await this.#D(s);return}if(this.#c.has(t))return;if(s){await r.respond({ok:!1,error:{code:"cancelled",message:"QQ is already handling another user interaction.",details:{}}});return}let g={kind:"question",interactionId:t,sessionId:r.sessionId,interaction:r,actor:i,requiresMention:a,questions:A,answers:[],index:0,target:e,queue:null,claimedReplyMessageId:null,presentationPromise:null,submitting:!1,needsPresentation:!0};this.#g.set(o,g),this.#c.set(t,o),await this.#D(g)}async#y(r){if(r?.kind==="approval"){await this.#E.handleResolved(r);return}let o=r?.interactionId;if(r?.kind!=="question"||typeof o!="string")return;let i=this.#c.get(o);i&&this.#M(i,o)}#D(r){if(!r.needsPresentation)return Promise.resolve();if(r.presentationPromise)return r.presentationPromise;let o=r.questions[r.index];if(!o)return Promise.resolve();let i=this.#e.sendText(r.target,za(o,r.index,r.questions.length,{requiresMention:r.requiresMention})).then(()=>{r.needsPresentation=!1}).finally(()=>{r.presentationPromise===i&&(r.presentationPromise=null)});return r.presentationPromise=i,i}async#w(r,o){this.#r.hasSeen(o)||(await this.#r.markSeen(o),this.#s.messagesReceived+=1,this.#s.lastMessageAt=new Date().toISOString(),await this.#e.sendText(r.replyTarget,xy).catch(()=>{}))}#N(r,o){let i=this.#g.get(r);return!i||o!==void 0&&i.interactionId!==o?null:(this.#g.delete(r),this.#c.delete(i.interactionId),i)}#M(r,o){return this.#N(r,o)!==null}async#T(r){let o=this.#N(r);if(!(!o||o.kind!=="question"))try{await o.interaction.respond({ok:!1,error:{code:"cancelled",message:"The QQ interaction ended before the user answered.",details:{}}},{signal:AbortSignal.timeout(5e3)})}catch(i){i?.code!=="interaction-not-pending"&&this.#i.warn?.("[dsh-im:qq] failed to cancel a pending Harness interaction")}}async#O(r,o,i){this.#o?.aborted||(this.#s.lastError=i?.message??String(i),this.#i.error?.("[dsh-im:qq] failed to process an interaction reply:",i),this.#r.hasSeen(o)||await this.#r.markSeen(o).catch(()=>{}),await this.#e.sendText(r.replyTarget,"\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002").catch(()=>{}))}};function JMe(){let n=new Error("QQ WebSocket did not become ready in time");return n.code="connect-timeout",n}function qMe(){return{startedAt:null,ready:!1,qqConnectionState:"idle",harnessReachable:!1,lastCheckedAt:null,lastConnectedAt:null,lastError:null,...uk()}}var cC=class{#e;#A;#t;#r;#s;#i;#I;#o;#l;#a=qMe();#n=null;#g=null;#c=null;#p=null;#h=null;constructor({config:r,appSecret:o,harness:i,state:e,logger:a=console,replyTimeoutMs:A=6e5,connectTimeoutMs:t=2e4,createBot:s=c=>new YMe(c),typingMiddleware:g=jMe}){if(!r||!o||!i||!e)throw new TypeError("QqRuntime requires config, app secret, Harness, and state");this.#e=r,this.#A=o,this.#t=i,this.#r=e,this.#s=a,this.#i=A,this.#I=t,this.#o=s,this.#l=g}get status(){return structuredClone(this.#a)}async sendConnectionTest(r){if(!this.#a.ready||!this.#n)throw ir("QQ\u673A\u5668\u4EBA");let o=typeof this.#e.ownerUserOpenid=="string"?this.#e.ownerUserOpenid.trim():"",i=Ed(this.#r),e=i?.scope==="c2c"&&typeof i.targetId=="string"?i.targetId.trim():"",a=e?{scope:"c2c",targetId:e}:o&&o!=="*"?{scope:"c2c",targetId:o}:null;if(!a)throw ir("QQ\u673A\u5668\u4EBA");return await this.#n.sendText(a,r),{sent:!0}}async start(){return this.#a.ready&&this.#n?this.status:this.#h?this.#h:(this.#h=this.#d().finally(()=>{this.#h=null}),this.#h)}async#d(){await this.stop(),this.#a.startedAt=new Date().toISOString(),this.#a.qqConnectionState="connecting",this.#a.lastError=null,await this.#t.ensureRunning(),this.#a.harnessReachable=!0;let r={error:(...E)=>this.#s.error?.(...E),warn:(...E)=>this.#s.warn?.(...E),info:(...E)=>this.#s.info?.(...E),debug:()=>{}},o=this.#o({appId:this.#e.appId,appSecret:this.#A,accountId:this.#e.botId,logger:r,transport:"websocket",tokenPrefetch:"sync"});if(!o||typeof o.start!="function"||typeof o.stop!="function")throw new TypeError("QQ bot factory returned an invalid client");let i=new AbortController;this.#c=i,this.#n=o,this.#g=new jy({bot:o,ownerUserOpenid:this.#e.ownerUserOpenid,harness:this.#t,state:this.#r,status:this.#a,logger:this.#s,replyTimeoutMs:this.#i,signal:i.signal}),o.use?.(this.#l({keepAlive:!0,predicate:E=>this.#e.ownerUserOpenid==="*"||E?.message?.senderId===this.#e.ownerUserOpenid}));let e,a,A=new Promise((E,B)=>{e=E,a=B}),t=()=>{let E=Date.now();this.#a.ready=!0,this.#a.qqConnectionState="connected",this.#a.lastCheckedAt=E,this.#a.lastConnectedAt=E,this.#a.lastError=null,e()},s=E=>{this.#a.ready?(this.#a.lastError=E?.message??String(E),this.#s.warn?.(`[dsh-im:qq] bot ${this.#e.botId} connection error:`,E)):a(E)},g=(E,B)=>{let f=this.#g?.accept(B);f&&f.catch(Q=>{i.signal.aborted||this.#s.error?.(`[dsh-im:qq] bot ${this.#e.botId} message handling failed:`,Q)})};o.on("ready",t),o.on("resumed",t),o.on("error",s),o.on("message",g);let c=Promise.resolve().then(()=>o.start(i.signal));this.#p=c,c.catch(E=>{i.signal.aborted||(a(E),this.#a.ready=!1,this.#a.qqConnectionState="failed",this.#a.lastError=E?.message??String(E),this.#s.error?.(`[dsh-im:qq] bot ${this.#e.botId} connection stopped:`,E))});let I;try{return await Promise.race([A,new Promise((E,B)=>{I=setTimeout(()=>B(JMe()),this.#I)})]),this.#a.ready=!0,this.#a.qqConnectionState="connected",this.#a.lastCheckedAt=Date.now(),this.#a.lastConnectedAt=Date.now(),this.status}catch(E){throw this.#a.ready=!1,this.#a.qqConnectionState="failed",this.#a.lastError=E?.message??String(E),await this.stop(),E}finally{clearTimeout(I)}}async stop(){let r=this.#n,o=this.#g,i=this.#p;this.#c?.abort(),this.#c=null,this.#n=null,this.#g=null,this.#p=null;try{r?.stop()}catch(e){this.#s.warn?.(`[dsh-im:qq] bot ${this.#e.botId} failed to stop cleanly:`,e)}return await Promise.race([i?.catch(()=>{})??Promise.resolve(),new Promise(e=>setTimeout(e,2e3))]),await o?.waitForIdle(),this.#a.ready=!1,this.#a.qqConnectionState="idle",this.status}};import{startQrConnect as zMe}from"@tencent-connect/qqbot-connector";var Jy=class{#e;#A;constructor({start:r=zMe,source:o="deepseek-harness"}={}){if(typeof r!="function")throw new TypeError("QQ QR connector is required");this.#e=r,this.#A=o}start(r,{signal:o}={}){if(!r||typeof r.onSuccess!="function"||typeof r.onFailure!="function")throw new TypeError("QQ QR callbacks are required");return this.#e(r,{displayQrCodeToConsole:!1,source:this.#A,signal:o})}};import{mkdir as VMe,readFile as WMe,rename as ZMe,unlink as XMe,writeFile as $Me}from"node:fs/promises";import{dirname as e_e}from"node:path";var qy=Object.freeze({version:1,sessions:{},seenMessageIds:[]});function A_e(n){if(!n||typeof n!="object")return structuredClone(qy);let r={};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&&(r[o]=i);return{version:1,sessions:r,seenMessageIds:Array.isArray(n.seenMessageIds)?n.seenMessageIds.filter(o=>typeof o=="string").slice(-1e3):[]}}var zy=class{#e;#A=structuredClone(qy);#t=Promise.resolve();constructor(r){this.#e=r}async load(){try{this.#A=A_e(JSON.parse(await WMe(this.#e,"utf8")))}catch(r){if(r?.code!=="ENOENT")throw r;this.#A=structuredClone(qy),await this.#r()}return this}sessionFor(r){return this.#A.sessions[r]??null}async setSession(r,o){this.#A.sessions[r]=o,await this.#r()}async clearSession(r){delete this.#A.sessions[r],await this.#r()}async clearSessions(){this.#A.sessions={},await this.#r()}hasSeen(r){return this.#A.seenMessageIds.includes(r)}async markSeen(r){this.hasSeen(r)||(this.#A.seenMessageIds.push(r),this.#A.seenMessageIds.length>1e3&&this.#A.seenMessageIds.splice(0,this.#A.seenMessageIds.length-1e3),await this.#r())}snapshot(){return structuredClone(this.#A)}async remove(){try{await XMe(this.#e)}catch(r){if(r?.code!=="ENOENT")throw r}this.#A=structuredClone(qy)}async#r(){let r=`${JSON.stringify(this.#A,null,2)} `,o=this.#t.then(async()=>{await VMe(e_e(this.#e),{recursive:!0,mode:448});let i=`${this.#e}.tmp`;await $Me(i,r,{encoding:"utf8",mode:384}),await ZMe(i,this.#e)});this.#t=o.then(()=>{},()=>{}),await o}};var Az=Object.freeze([250,1e3,3e3,5e3,1e4,3e4]);function t_e(n){if(!Array.isArray(n)||n.length===0)return[...Az];let r=n.filter(o=>Number.isFinite(o)&&o>=0);return r.length>0?r:[...Az]}var Vy=class{#e;#A;#t;#r;#s;#i;#I;#o=null;#l=null;#a=0;#n=!1;#g=!1;#c;#p;constructor({controller:r,harness:o,logger:i=console,retryDelaysMs:e,healthyIntervalMs:a=15e3,setTimeoutImpl:A=setTimeout,clearTimeoutImpl:t=clearTimeout}){if(!r||typeof r.initialize!="function"||typeof r.status!="function")throw new TypeError("ConnectionSupervisor requires a controller");if(!o||typeof o.ensureRunning!="function")throw new TypeError("ConnectionSupervisor requires a Harness client");this.#e=r,this.#A=o,this.#t=i,this.#r=t_e(e),this.#s=Number.isFinite(a)&&a>=0?a:15e3,this.#i=A,this.#I=t,this.#c=new Promise(s=>{this.#p=s})}get ready(){return this.#c}start(){return this.#g||this.#n?this:(this.#g=!0,this.#h(0),this)}async close(){this.#n||(this.#n=!0,this.#o!==null&&this.#I(this.#o),this.#o=null,await this.#l?.catch(()=>{}),this.#p?.(null),this.#p=null)}#h(r){this.#n||(this.#o=this.#i(()=>{this.#o=null,this.#d()},r),this.#o?.unref?.())}async#d(){if(this.#n||this.#l)return;let r=this.#E();this.#l=r;try{await r}finally{this.#l===r&&(this.#l=null)}}async#E(){try{if(await this.#A.ensureRunning(),this.#n)return;let r=await this.#e.initialize();if(this.#n)return;this.#p?.(r),this.#p=null;let{configured:o,connected:i}=r.totals;if(i65535)throw new Error("dsh-im QQ requires an initialized DSH webServer port");return new URL(`http://127.0.0.1:${o}`)}function o_e(n){let r=pI(n.dshHome??process.env.DSH_HOME??IC(a_e(),".dsh")),o=pI(n.dataDir??IC(r,"integrations","dsh-qq"));return{config:pI(n.configPath??IC(o,"config.json")),bots:pI(n.botsDir??IC(o,"bots")),workspaces:pI(n.workspacesPath??IC(o,"workspaces.json"))}}async function fk(n,r={},o={}){if(!n?.credentials)throw new TypeError("dsh-im QQ requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-im QQ requires ctx.webServer");let i=o.ConfigStore??Ly,e=o.StateStore??zy,a=o.HarnessClient??Hy,A=o.Controller??nC,t=o.Runtime??cC,s=o.QrAuth??Jy,g=o.createConnectionSupervisor??Bk,c=typeof n.logger=="function"?n.logger("dsh-im:qq"):n.logger??console,I=()=>ha(n),E=o_e(r),B=await new i(E.config).load(),f=pI(r.workspace??process.cwd()),Q=o.WorkspaceStore??Kr,y=o.workspaces??await new Q(E.workspaces,{defaultWorkspace:f}).load(),m=B.list();await y.reconcile(m.map(k=>k.botId)),await Promise.all(m.map(k=>y.ensure(k.botId,{defaultAgentPreset:r.agentPreset})));let _=typeof B.remove=="function"?Ca(B,{workspaces:y}):B,N=o.qrAuth??new s({source:r.qrSource??"deepseek-harness"}),P=new Map,Y=k=>pI(E.bots,k,"state.json"),x=async k=>{let Z=P.get(k);return Z||(Z=await new e(Y(k)).load(),P.set(k,Z)),Z},H=fa(n,o.commandExecutor),{controlExecutor:j,sessionMaintenanceExecutor:q,fileIngressExecutor:F}=Qa(n,{controlExecutor:o.controlExecutor,sessionMaintenanceExecutor:o.sessionMaintenanceExecutor,fileIngressExecutor:o.fileIngressExecutor}),v=new a({baseUrl:i_e(n.webServer,r.harnessBaseUrl),workspace:f,autostart:!1,dshBin:r.dshBin??"dsh",...H?{commandExecutor:H}:{},...j?{controlExecutor:j}:{},...q?{sessionMaintenanceExecutor:q}:{},...F?{fileIngressExecutor:F}:{}}),V=new A({qrAuth:N,credentials:n.credentials,configStore:_,logger:c,createRuntime:async({botId:k,config:Z,appSecret:ge})=>{let fe=await x(k);await y.ensure(k,{defaultAgentPreset:r.agentPreset});let _e=ua(v,{botId:k,workspaces:y,state:fe,agentPresetCatalog:I});return new t({config:Z,appSecret:ge,harness:_e.harness,state:_e.state,replyTimeoutMs:r.replyTimeoutMs??6e5,connectTimeoutMs:r.connectTimeoutMs??2e4,logger:{error:(...de)=>c.error?.(`[${k}]`,...de),warn:(...de)=>c.warn?.(`[${k}]`,...de),info:(...de)=>c.info?.(`[${k}]`,...de),debug:(...de)=>c.debug?.(`[${k}]`,...de)}})},deleteState:async({botId:k})=>{let Z=P.get(k);if(P.delete(k),Z&&typeof Z.remove=="function")await Z.remove();else try{await r_e(Y(k))}catch(ge){if(ge?.code!=="ENOENT")throw ge}}}),K=Ba(V,{workspaces:y,stateFor:x,agentPresetCatalog:I}),M=g({controller:K,harness:v,logger:c,retryDelaysMs:r.retryDelaysMs,healthyIntervalMs:r.healthyIntervalMs}).start();return{controller:K,ready:M.ready,async close(){await M.close(),await K.close(),v.stopManagedProcess()}}}import n_e from"qrcode";var rz="/qq",Or=Object.freeze({status:"connection.status",beginProvisioning:"provision.begin",pollProvisioning:"provision.poll",cancelProvisioning:"provision.cancel",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete",setWorkspace:ei,setAgentPreset:Ai}),az=Object.freeze(Object.values(Or)),s_e=new Set(["appSecret","app_secret","secretRef","ownerUserOpenid","userOpenid","verificationUrl"]);function mk(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function Sp(n,r){return mk(n)&&Object.keys(n).every(o=>r.includes(o))}function Qk(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n)}function tz(n,r){return typeof n=="string"&&n.trim().length>0&&n.length<=r}function g_e(n,r){return mk(r)?n===Or.status?Sp(r,[])?null:"connection.status does not accept fields.":n===Or.beginProvisioning?Sp(r,["locale"])&&(r.locale===void 0||r.locale==="zh-CN")?null:"provision.begin received unsupported fields.":[Or.pollProvisioning,Or.cancelProvisioning].includes(n)?Sp(r,["attemptId"])&&Qk(r.attemptId)?null:`${n} requires an attemptId.`:n===Or.bindCredentials?Sp(r,["appId","appSecret"])&&tz(r.appId,256)&&tz(r.appSecret,1024)?null:"bot.bind-credentials requires AppID and AppSecret.":n===Or.reconnectBot?Sp(r,["botId","sendTest"])&&Qk(r.botId)&&(r.sendTest===void 0||r.sendTest===!0)?null:"bot.reconnect requires a botId and accepts only sendTest=true.":n===Or.deleteBot?Sp(r,["botId","confirm"])&&Qk(r.botId)&&r.confirm===!0?null:"bot.delete requires a botId and confirm=true.":n===Or.setWorkspace?ya(r)?null:"\u8BF7\u8F93\u5165\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84\u3002":n===Or.setAgentPreset?Sa(r)?null:"\u8BF7\u9009\u62E9 Agent Preset\u3002":"Unknown QQ endpoint.":"Payload must be an object."}function wp(n){if(Array.isArray(n))return n.map(wp);if(!mk(n))return n;let r={};for(let[o,i]of Object.entries(n))s_e.has(o)||(r[o]=wp(i));return r}async function c_e(n){return n_e.toDataURL(n,{type:"image/png",errorCorrectionLevel:"M",margin:2,width:320})}async function yk(n,r){return!n||typeof n.verificationUrl!="string"?wp(n):wp({...n,qrCodeDataUrl:await r(n.verificationUrl)})}async function Dp(n,r){let o=structuredClone(n);return o?.provisioning&&(o.provisioning=await yk(o.provisioning,r)),wp(o)}function iz(n,{encodeQr:r=c_e}={}){for(let e of["status","startProvisioning","registrationStatus","cancelProvisioning","bindCredentials","reconnectBot","deleteBot"])if(typeof n?.[e]!="function")throw new TypeError(`A complete QQ controller is required (${e})`);let o=new Map,i=e=>{let a=o.get(e);return a||(o.size>=16&&o.delete(o.keys().next().value),a=Promise.resolve().then(()=>r(e)),o.set(e,a)),a};return async(e,a,A)=>{if(A?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};if(!az.includes(e))return{ok:!1,error:{code:"bad-request",message:"Unknown QQ endpoint."}};let t=g_e(e,a);if(t)return{ok:!1,error:{code:"bad-request",message:t}};try{let s;if(e===Or.status)s=await Dp(await n.status(),i);else if(e===Or.beginProvisioning)s=await yk(await n.startProvisioning(),i);else if(e===Or.pollProvisioning){let g=await n.registrationStatus(a.attemptId);if(!g)return{ok:!1,error:{code:"bad-request",message:"The provisioning attempt no longer exists."}};s=await yk(g,i)}else if(e===Or.cancelProvisioning)s=wp(await n.cancelProvisioning(a.attemptId));else if(e===Or.bindCredentials)s=await Dp(await n.bindCredentials(a),i);else if(e===Or.reconnectBot){let g=await n.reconnectBot(a.botId);if(A?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};let c;if(a.sendTest===!0)if(!(g?.bots?.some(E=>E?.botId===a.botId&&E?.connected===!0)===!0)||typeof n.sendConnectionTest!="function")c=Wt(ir("QQ\u673A\u5668\u4EBA"));else{let E=null;try{await n.sendConnectionTest(a.botId)}catch(B){E=B}c=Wt(E)}s=await Dp({...g,...c?{testMessage:c}:{}},i)}else if(e===Or.setWorkspace){if(typeof n.updateWorkspace!="function")throw new Error("Workspace update is unavailable");s=await Dp(await n.updateWorkspace(a.botId,a.workspace),i)}else if(e===Or.setAgentPreset){if(typeof n.updateAgentPreset!="function")throw new Error("Agent preset update is unavailable");s=await Dp(await n.updateAgentPreset(a.botId,a.agentPreset),i)}else s=await Dp(await n.deleteBot(a.botId),i);return A?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!0,value:s}}catch(s){let g=ma(s);return A?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!1,error:g??{code:"qq-operation-failed",message:"QQ \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}}}function Wy(n,r,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(rz,iz(r,o),{authority:Cr(i)})}async function oz(n,r={}){if(r?.controller)return Wy(n,r.controller,r.rpcOptions,r.rpcAuthority);let o=await fk(n,r,r.internals),i=Wy(n,o.controller,r.rpcOptions,r.rpcAuthority);return n.effect(()=>async()=>o.close(),"dsh-im: close QQ bot connections"),i}import{unlink as j_e}from"node:fs/promises";import{resolve as uz}from"node:path";import{createHash as I_e}from"node:crypto";import{mkdir as l_e,readFile as p_e,rename as E_e,unlink as d_e,writeFile as h_e}from"node:fs/promises";import{dirname as C_e}from"node:path";var Sk=Object.freeze({version:1,bots:Object.freeze([])}),nz=/^slack_[a-f0-9]{24}$/,u_e=/^DSH_SLACK_BOT_TOKEN_[A-F0-9]{24}$/,B_e=/^DSH_SLACK_APP_TOKEN_[A-F0-9]{24}$/;function po(n){return typeof n=="string"&&n.trim()?n.trim():null}function Dk(n){let r=po(n);if(!r)throw new TypeError("platformId is required");let o=I_e("sha256").update(r).digest("hex").slice(0,24),i=o.toUpperCase();return{botId:`slack_${o}`,botTokenRef:`DSH_SLACK_BOT_TOKEN_${i}`,appTokenRef:`DSH_SLACK_APP_TOKEN_${i}`}}function wk(n){let r=po(n)??"",[o,i]=r.split(":");return o&&i?`${o.slice(0,5)}\u2022\u2022\u2022 \xB7 ${i.slice(0,5)}\u2022\u2022\u2022`:r?`${r.slice(0,6)}\u2022\u2022\u2022\u2022`:"Slack\u673A\u5668\u4EBA"}var Zy=class{#e;#A=Sk;#t=Promise.resolve();constructor(r){this.#e=r}async load(){try{let r=this.#s(JSON.parse(await p_e(this.#e,"utf8")));if(!r)throw new Error("dsh-im Slack config contains invalid bot data");this.#A=r}catch(r){if(r?.code!=="ENOENT")throw r;this.#A=Sk}return this}list(){return structuredClone(this.#A.bots)}get(r){let o=this.#A.bots.find(i=>i.botId===r);return o?structuredClone(o):null}getByPlatformId(r){let o=this.#A.bots.find(i=>i.platformId===r);return o?structuredClone(o):null}async save(r){let o=this.#r(r);if(!o)throw new Error("Refusing to persist incomplete Slack bot data");return this.#i(i=>{if(i.find(A=>A.botId!==o.botId&&(A.platformId===o.platformId||A.botTokenRef===o.botTokenRef||A.appTokenRef===o.appTokenRef)))throw new Error("Duplicate Slack bot identity");let a=i.findIndex(A=>A.botId===o.botId);return a===-1?i.push(o):i[a]=o,structuredClone(o)})}async remove(r){if(!nz.test(r))throw new TypeError("Invalid Slack bot id");return this.#i(o=>{let i=o.findIndex(e=>e.botId===r);return i===-1?null:structuredClone(o.splice(i,1)[0])})}async clear(){let r=this.#t.then(async()=>{try{await d_e(this.#e)}catch(o){if(o?.code!=="ENOENT")throw o}this.#A=Sk});this.#t=r.then(()=>{},()=>{}),await r}#r(r){if(!r||typeof r!="object")return null;let o=po(r.botId),i=po(r.platformId),e=po(r.botTokenRef),a=po(r.appTokenRef),A=po(r.name);if(!o||!i||!e||!a||!A||!nz.test(o)||!u_e.test(e)||!B_e.test(a))return null;let t=Dk(i);return t.botId!==o||t.botTokenRef!==e||t.appTokenRef!==a?null:Object.freeze({botId:o,platformId:i,botTokenRef:e,appTokenRef:a,name:A,username:po(r.username),teamId:po(r.teamId),teamName:po(r.teamName),createdAt:po(r.createdAt)??new Date().toISOString(),connectedAt:po(r.connectedAt)})}#s(r){if(!r||r.version!==1||!Array.isArray(r.bots))return null;let o=r.bots.map(A=>this.#r(A));if(o.some(A=>A===null))return null;let i=new Set,e=new Set,a=new Set;for(let A of o){if(i.has(A.botId)||e.has(A.platformId)||a.has(A.botTokenRef)||a.has(A.appTokenRef))return null;i.add(A.botId),e.add(A.platformId),a.add(A.botTokenRef),a.add(A.appTokenRef)}return Object.freeze({version:1,bots:Object.freeze(o)})}async#i(r){let o,i=this.#t.then(async()=>{let e=[...this.#A.bots];o=r(e);let a=Object.freeze({version:1,bots:Object.freeze(e)});await l_e(C_e(this.#e),{recursive:!0,mode:448});let A=`${this.#e}.tmp`;await h_e(A,`${JSON.stringify(a,null,2)} `,{encoding:"utf8",mode:384}),await E_e(A,this.#e),this.#A=a});return this.#t=i.then(()=>{},()=>{}),await i,o}};var f_e="https://slack.com/api/",EC="files.slack.com",Q_e="slack.com",sz="/files-pri/",y_e=Object.freeze([EC]),m_e="/upload/",S_e=12e4;function Nn(n){return typeof n=="string"&&n.trim()?n.trim():null}function gz(n,r){let o=AbortSignal.timeout(r);return n?AbortSignal.any([n,o]):o}function lC(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}function D_e(n,r){if(!Number.isInteger(n)||n<1)throw new TypeError(`${r} must be a positive integer`);return n}function cz(n,r){return r?.providerCode!==void 0&&(n.providerCode=r.providerCode),Number.isInteger(r?.status)&&(n.status=r.status),n}function EI(n){let r="artifact-provider-failed",o="Slack file upload preparation failed";n?.code==="slack-file_upload_size_restricted"?(r="artifact-too-large",o="Slack rejected the result file because it is too large"):n?.code==="slack-missing-scope"?(r="artifact-permission-required",o="Slack file delivery requires the files:write scope"):n?.code?.startsWith?.("slack-")&&(r="artifact-provider-rejected",o="Slack rejected file upload preparation");let i=new Error(o,{cause:n});return i.code=r,cz(i,n)}function w_e(n){let r=new Error("Slack file completion result is uncertain",{cause:n});return r.code="artifact-delivery-uncertain",cz(r,n)}function O_e(n){return Number.isInteger(n)&&n>=300&&n<400}async function Ok(n){try{await n?.body?.cancel?.()}catch{}}function b_e(n){let r=new URL(n);if(r.protocol!=="https:")throw new Error("Image download URL must use HTTPS");if(r.username||r.password||r.port&&r.port!=="443")throw new Error("Image download URL is not hosted by the messaging platform");if(r.hostname===Q_e&&r.pathname.startsWith(sz)&&(r.hostname=EC),r.hostname!==EC||!r.pathname.startsWith(sz))throw new Error("Image download URL is not hosted by the messaging platform");return r.hash="",r}function M_e(n){let r=new URL(n);if(r.protocol!=="https:"||r.username||r.password||r.port&&r.port!=="443"||r.hostname!==EC||!r.pathname.startsWith(m_e))throw new Error("Slack returned an unsafe file upload URL");return r.hash="",r}function __e(n,r){let o=n?.headers?.get?.("location");if(!o)return null;try{return new URL(o,r)}catch{return null}}function N_e(n){let r=n?.headers?.get?.("x-oauth-scopes");return r==null?null:new Set(r.split(",").map(o=>o.trim()).filter(Boolean))}function T_e(n){return n?.protocol==="https:"&&!n.username&&!n.password&&(!n.port||n.port==="443")&&n.hostname.endsWith(".slack.com")&&n.hostname!==EC&&n.pathname==="/"&&n.searchParams.has("redir")}function R_e(n,r){return new Promise((o,i)=>{if(r?.aborted){i(r.reason??new DOMException("Aborted","AbortError"));return}let e=setTimeout(o,n);e?.unref?.(),r?.addEventListener("abort",()=>{clearTimeout(e),i(r.reason??new DOMException("Aborted","AbortError"))},{once:!0})})}function ks(n,r){let o=Nn(n);if(!o||!/^[A-Z][A-Z0-9]{4,30}$/i.test(o))throw new TypeError(`Invalid Slack ${r}`);return o}function Op(n,r){let o=Nn(n);if(!o)throw new TypeError(`Slack ${r} is required`);return o}function pC(n,{trim:r=!0}={}){let o=typeof n=="string"?n:"",i=r?o.trim():o;if(!i)throw new TypeError("Slack message text is required");return i.replace(/<@([A-Z0-9]+)>/gi,"@$1").replace(/]*)?>/gi,"@$1")}function k_e(n,r,o){let i=Nn(r?.error)??"unknown_error",e=new Error(`Slack ${n} failed: ${i.replaceAll("_"," ")}`);return e.providerCode=i,["invalid_auth","not_authed","token_revoked","account_inactive"].includes(i)?e.code=o==="app"?"slack-invalid-app-token":"slack-invalid-bot-token":i==="missing_scope"?e.code="slack-missing-scope":i==="method_not_supported_for_channel_type"||i==="channel_type_not_supported"||i==="deprecated_endpoint"?e.code="slack-stream-unavailable":e.code=`slack-${i}`,e}function Iz(n){return typeof n=="string"&&/^xoxb-[A-Za-z0-9-]{16,}$/.test(n.trim())}function lz(n){return typeof n=="string"&&/^xapp-[A-Za-z0-9-]{16,}$/.test(n.trim())}var dC=class{#e;#A;#t;#r;#s=null;#i;constructor({botToken:r,appToken:o,fetchImpl:i=fetch,baseUrl:e=f_e,fileUploadTimeoutMs:a=S_e}){if(r!==void 0&&!Iz(r))throw new TypeError("Slack Bot Token is invalid");if(o!==void 0&&!lz(o))throw new TypeError("Slack App Token is invalid");if(!r&&!o)throw new TypeError("SlackApi requires a token");if(typeof i!="function")throw new TypeError("SlackApi requires fetch");this.#e=r?.trim(),this.#A=o?.trim(),this.#t=i,this.#r=new URL(e),this.#i=D_e(a,"fileUploadTimeoutMs")}authTest(r={}){return this.#o("auth.test",{...r,tokenKind:"bot"})}openConnection(r={}){return this.#o("apps.connections.open",{...r,tokenKind:"app",body:void 0})}async fileInfo({fileId:r,signal:o}={}){let i=await this.#o("files.info",{tokenKind:"bot",signal:o,body:{file:ks(r,"file id")}});if(!i?.file||typeof i.file!="object"||Array.isArray(i.file))throw new Error("Slack files.info returned no file object");return i.file}postMessage({channelId:r,text:o,threadTs:i,signal:e}){return this.#o("chat.postMessage",{tokenKind:"bot",signal:e,body:{channel:ks(r,"channel id"),text:pC(o),...i?{thread_ts:Nn(i)}:{},mrkdwn:!0,link_names:!1,unfurl_links:!1,unfurl_media:!1}})}updateMessage({channelId:r,ts:o,text:i,signal:e}){return this.#o("chat.update",{tokenKind:"bot",signal:e,body:{channel:ks(r,"channel id"),ts:Op(o,"message timestamp"),text:pC(i),parse:"none",link_names:!1}})}startStream({channelId:r,threadTs:o,recipientTeamId:i,recipientUserId:e,markdownText:a,signal:A}){return this.#o("chat.startStream",{tokenKind:"bot",signal:A,body:{channel:ks(r,"channel id"),thread_ts:Op(o,"thread timestamp"),...i?{recipient_team_id:ks(i,"team id")}:{},...e?{recipient_user_id:ks(e,"user id")}:{},...Nn(a)?{markdown_text:pC(a)}:{}}})}appendStream({channelId:r,ts:o,markdownText:i,signal:e}){return this.#o("chat.appendStream",{tokenKind:"bot",signal:e,body:{channel:ks(r,"channel id"),ts:Op(o,"stream timestamp"),markdown_text:pC(i,{trim:!1})}})}stopStream({channelId:r,ts:o,markdownText:i,signal:e}){return this.#o("chat.stopStream",{tokenKind:"bot",signal:e,body:{channel:ks(r,"channel id"),ts:Op(o,"stream timestamp"),...Nn(i)?{markdown_text:pC(i,{trim:!1})}:{}}})}async uploadFile({channelId:r,threadTs:o,file:i,signal:e}){if(!i||typeof i!="object"||typeof i.fileName!="string"||!i.fileName||!Buffer.isBuffer(i.bytes))throw new TypeError("A Slack file is required");if(e?.aborted)throw lC(e);let a=gz(e,this.#i),A;try{A=await this.#o("files.getUploadURLExternal",{tokenKind:"bot",signal:a,timeoutMs:this.#i,body:{filename:i.fileName,length:i.bytes.byteLength}})}catch(I){throw e?.aborted?lC(e):EI(I)}let t,s;try{t=Op(A?.file_id,"file id"),s=M_e(A?.upload_url)}catch(I){throw EI(I)}let g;try{g=await this.#t(s,{method:"POST",headers:{"content-type":i.mediaType??"application/octet-stream"},body:i.bytes,signal:a,redirect:"error"})}catch(I){throw e?.aborted?lC(e):EI(I)}if(!Number.isInteger(g?.status))throw EI(new Error("Slack file upload returned an invalid response"));if(g.status!==200){await Ok(g);let I=new Error(`Slack file upload failed with HTTP ${g.status}`);throw I.status=g.status,g.status===413?I.code="artifact-too-large":g.status===429?I.code="artifact-rate-limited":I.code="artifact-provider-rejected",I}await Ok(g);let c;try{c={files:[{id:t,title:i.fileName}],channel_id:ks(r,"channel id"),...o?{thread_ts:Op(o,"thread timestamp")}:{}}}catch(I){throw EI(I)}if(a.aborted)throw e?.aborted?lC(e):EI(a.reason);try{let I=await this.#o("files.completeUploadExternal",{tokenKind:"bot",signal:a,timeoutMs:this.#i,retry:!1,body:c});if(!Array.isArray(I?.files)||!I.files.some(E=>Nn(E?.id)===t))throw new Error("Slack file completion did not confirm the uploaded file");return I}catch(I){throw e?.aborted?lC(e):I?.code==="slack-missing-scope"?EI(I):w_e(I)}}async downloadFile({url:r,signal:o,maxBytes:i}){return this.#I({url:r,signal:o,maxBytes:i,stream:!1})}async downloadFileStream({url:r,signal:o}){return this.#I({url:r,signal:o,stream:!0})}async#I({url:r,signal:o,maxBytes:i,stream:e}){if(!this.#e)throw new TypeError("Slack bot token is required for file download");let a=b_e(r),t={fetchImpl:async(s,g)=>{let c=await this.#t(s,g);if(!O_e(c?.status))return c;let I=__e(c,s);if(this.#s&&!this.#s.has("files:read")||T_e(I))throw await Ok(c),new lt("slack-file-access-required","Slack redirected a private file request to the workspace because file access was not granted","Slack \u672A\u6388\u6743\u673A\u5668\u4EBA\u8BFB\u53D6\u8BE5\u6587\u4EF6\u3002\u8BF7\u4E3A\u5E94\u7528\u6DFB\u52A0 files:read \u540E\u91CD\u65B0\u5B89\u88C5\uFF0C\u518D\u91CD\u65B0\u53D1\u9001\u56FE\u7247\u3002");return c},headers:{authorization:`Bearer ${this.#e}`},signal:o,allowedHosts:y_e};return e?yl(a,t):Ki(a,{...t,maxBytes:i})}async#o(r,{tokenKind:o,body:i,signal:e,timeoutMs:a=15e3,retry:A=!0}){let t=o==="app"?this.#A:this.#e;if(!t)throw new TypeError(`Slack ${o} token is required for ${r}`);let s=r==="files.getUploadURLExternal"||r==="files.info",g;try{g=await this.#t(new URL(r,this.#r),{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":i===void 0||s?"application/x-www-form-urlencoded;charset=utf-8":"application/json;charset=utf-8","user-agent":"DeepSeek-Harness-dsh-im (https://github.com/xmanrui/dsh-im, 0.2.2)"},...i===void 0?{}:{body:s?new URLSearchParams(i).toString():JSON.stringify(i)},signal:gz(e,a),redirect:"error"})}catch(I){throw I?.name==="AbortError"||I?.name==="TimeoutError"?I:new Error(`Slack ${r} transport failed`)}if(o==="bot"){let I=N_e(g);I&&(this.#s=I)}let c;try{c=await g.json()}catch{throw new Error(`Slack ${r} returned invalid JSON`)}if(g.status===429&&A){let I=Number(g.headers.get("retry-after"))||1;return await R_e(Math.min(1e4,Math.max(100,I*1e3)),e),this.#o(r,{tokenKind:o,body:i,signal:e,timeoutMs:a,retry:!1})}if(!g.ok||c?.ok!==!0){let I=k_e(r,c,o);throw I.status=g.status,I}return c}};async function pz({botToken:n,appToken:r},o={}){if(!Iz(n)){let t=new TypeError("Slack Bot Token \u5FC5\u987B\u4EE5 xoxb- \u5F00\u5934\u3002");throw t.code="slack-invalid-bot-token",t}if(!lz(r)){let t=new TypeError("Slack App Token \u5FC5\u987B\u4EE5 xapp- \u5F00\u5934\u3002");throw t.code="slack-invalid-app-token",t}let i=new dC({botToken:n,appToken:r,...o}),[e,a]=await Promise.all([i.authTest(),i.openConnection()]);if(!e?.team_id||!e?.user_id||!e?.bot_id)throw new Error("Slack Bot Token \u6CA1\u6709\u8FD4\u56DE\u5B8C\u6574\u7684\u673A\u5668\u4EBA\u8EAB\u4EFD\u3002");let A;try{A=new URL(a?.url)}catch{A=null}if(!A||A.protocol!=="wss:"){let t=new Error("Slack App Token \u65E0\u6CD5\u521B\u5EFA Socket Mode \u8FDE\u63A5\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u542F\u7528 Socket Mode \u548C connections:write\u3002");throw t.code="slack-socket-mode",t}return{platformId:`${e.team_id}:${e.user_id}`,name:Nn(e.user)??"DeepSeek Harness",username:Nn(e.user),teamId:String(e.team_id),teamName:Nn(e.team)}}var bk=Object.freeze({key:"slack",label:"Slack",connectionLabel:" Socket Mode \u957F\u8FDE\u63A5"}),Xy=class extends Cn{constructor(r){super({descriptor:bk,...r})}};function vs(n){return typeof n=="string"&&n.trim()?n.trim():null}function $y(n,r){return Object.freeze({code:n,message:r})}var hC=class{#e;#A;#t;#r;#s;#i;#I=new Map;#o=new Map;#l=new Map;#a=0;#n=!1;constructor({credentials:r,configStore:o,inspectCredentials:i=pz,createRuntime:e,deleteState:a=async()=>{},logger:A=console}){if(!r||typeof r.resolve!="function"||typeof r.set!="function"||typeof r.unset!="function")throw new TypeError("Slack requires the DSH credential provider");if(!o||typeof o.list!="function"||typeof o.save!="function"||typeof o.remove!="function")throw new TypeError("Slack requires a config store");if(typeof i!="function"||typeof e!="function")throw new TypeError("Slack controller dependencies are incomplete");this.#e=r,this.#A=o,this.#t=i,this.#r=e,this.#s=a,this.#i=A}async initialize(){if(this.#n)return this.status();for(let r of this.#A.list())await this.#d(r.botId,async()=>{if(this.#n||this.#I.get(r.botId)?.status?.ready)return;let o=await this.#p(r);if(!o){this.#o.set(r.botId,$y("missing-token","Slack\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u79FB\u9664\u540E\u91CD\u65B0\u63A5\u5165\u3002"));return}try{await this.#g(r,o),this.#o.delete(r.botId)}catch(i){this.#o.set(r.botId,$y("connection-failed","Slack Socket Mode \u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002")),this.#i.warn?.(`[dsh-im:slack] bot ${r.botId} failed to initialize:`,i)}finally{this.#E()}});return this.status()}async bindCredentials({botToken:r,appToken:o}={}){if(this.#n)throw new Error("Slack controller is closed");let i=vs(r),e=vs(o);if(!i||!e)throw new TypeError("Slack Bot Token and App Token are required");let a=await this.#t({botToken:i,appToken:e}),A=vs(a?.platformId),t=vs(a?.name);if(!A||!t)throw new Error("Slack returned an invalid bot identity");let s=Dk(A);return await this.#d(s.botId,async()=>{if(this.#n)throw new Error("Slack controller is closed");let g=this.#A.getByPlatformId(A),c=await this.#e.resolve(s.botTokenRef).catch(()=>{}),I=await this.#e.resolve(s.appTokenRef).catch(()=>{}),E={...s,platformId:A,name:t,username:vs(a.username),teamId:vs(a.teamId),teamName:vs(a.teamName),createdAt:g?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()};try{await this.#e.set(s.botTokenRef,i),await this.#e.set(s.appTokenRef,e),await this.#A.save(E)}catch(B){throw await Promise.all([this.#h(s.botTokenRef,c),this.#h(s.appTokenRef,I)]),B}try{await this.#g(E,{botToken:i,appToken:e}),this.#o.delete(s.botId)}catch(B){this.#o.set(s.botId,$y("connection-failed","Slack\u673A\u5668\u4EBA\u5DF2\u63A5\u5165\uFF0CSocket Mode \u8FDE\u63A5\u6682\u672A\u5C31\u7EEA\u3002")),this.#i.warn?.(`[dsh-im:slack] bot ${s.botId} credential connection failed:`,B)}this.#E()}),this.status()}async reconnectBot(r){let o=this.#A.get(r);if(!o)throw new Error("Unknown Slack bot");return await this.#d(r,async()=>{let i=await this.#p(o);if(!i)throw new Error("Slack bot credentials are missing");try{await this.#g(o,i),this.#o.delete(r)}catch(e){throw this.#o.set(r,$y("connection-failed","Slack Socket Mode \u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u68C0\u67E5\u4E24\u4E2A Token\u3002")),e}finally{this.#E()}}),this.status()}async sendConnectionTest(r){let o=this.#A.get(r);if(!o)throw new Error("Unknown Slack bot");return this.#d(r,async()=>{let i=this.#I.get(r);if(!i?.status?.ready||typeof i.sendConnectionTest!="function"){let e=new Error("Slack\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw e.code="test-target-unavailable",e}return await i.sendConnectionTest(la(`${o.name}\uFF08${wk(o.platformId)}\uFF09`,"Slack\u673A\u5668\u4EBA")),{sent:!0}})}async deleteBot(r){let o=this.#A.get(r);if(!o)throw new Error("Unknown Slack bot");return await this.#d(r,async()=>{let i=await this.#e.resolve(o.botTokenRef).catch(()=>{}),e=await this.#e.resolve(o.appTokenRef).catch(()=>{});await this.#c(r);try{await this.#e.unset(o.botTokenRef),await this.#e.unset(o.appTokenRef),await this.#A.remove(r)}catch(a){throw await Promise.all([this.#h(o.botTokenRef,i),this.#h(o.appTokenRef,e)]),i?.value&&e?.value&&await this.#g(o,{botToken:i.value,appToken:e.value}).catch(()=>{}),new Error("Unable to remove the Slack bot safely.",{cause:a})}await this.#s({botId:r,config:o}).catch(a=>{this.#i.warn?.(`[dsh-im:slack] bot ${r} state cleanup failed:`,a)}),this.#o.delete(r),this.#E()}),this.status()}status(){let r=this.#A.list().map(i=>{let e=this.#I.get(i.botId)?.status??null,a=e?.ready===!0&&e.connectionState==="connected"&&e.harnessReachable===!0,A=a?"connected":e?.connectionState==="connecting"?"connecting":this.#o.has(i.botId)||e?.connectionState==="failed"?"error":"offline";return{botId:i.botId,state:A,connected:a,configured:!0,bot:{name:i.name,username:i.username,teamName:i.teamName,idMasked:wk(i.platformId)},health:{status:a?"healthy":A==="error"?"error":"offline",summary:a?`Slack${bk.connectionLabel}\u8FD0\u884C\u6B63\u5E38`:A==="error"?"Slack\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5":"Slack\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.#o.get(i.botId)??null)}}),o=r.filter(i=>i.connected).length;return{schemaVersion:1,revision:this.#a,state:r.length===0?"disconnected":o===r.length?"connected":o>0?"degraded":"offline",bots:r,totals:{configured:r.length,connected:o}}}async close(){this.#n||(this.#n=!0,await Promise.allSettled([...this.#l.values()]),await Promise.allSettled([...this.#I.keys()].map(r=>this.#c(r))))}async#g(r,{botToken:o,appToken:i}){if(this.#n)throw new Error("Slack controller is closed");if(await this.#c(r.botId),this.#n)throw new Error("Slack controller is closed");let e=await this.#r({botId:r.botId,config:r,botToken:o,appToken:i});if(!e||typeof e.start!="function"||typeof e.stop!="function")throw new TypeError("createRuntime returned an invalid Slack runtime");this.#I.set(r.botId,e);try{await e.start()}catch(a){throw await e.stop().catch(()=>{}),this.#I.delete(r.botId),a}}async#c(r){let o=this.#I.get(r);this.#I.delete(r),await o?.stop().catch(i=>{this.#i.warn?.(`[dsh-im:slack] bot ${r} failed to stop cleanly:`,i)})}async#p(r){let[o,i]=await Promise.all([this.#e.resolve(r.botTokenRef).catch(()=>{}),this.#e.resolve(r.appTokenRef).catch(()=>{})]),e=vs(o?.value),a=vs(i?.value);return e&&a?{botToken:e,appToken:a}:null}async#h(r,o){o?.value?await this.#e.set(r,o.value).catch(()=>{}):await this.#e.unset(r).catch(()=>{})}#d(r,o){let a=(this.#l.get(r)??Promise.resolve()).catch(()=>{}).then(o).finally(()=>{this.#l.get(r)===a&&this.#l.delete(r)});return this.#l.set(r,a),a}#E(){this.#a+=1}};var em=class extends or{constructor(r){super({...r,rpcIdPrefix:"slack",logPrefix:"dsh-slack"})}};var Ez=Object.freeze([1e3,3e3,5e3,1e4,3e4]),_k=38e3,dz=11e3,Cz=new Set(["image/jpeg","image/png","image/webp","image/gif"]);function Mk(n,r,o){if(typeof n.addEventListener=="function")n.addEventListener(r,o);else if(typeof n.on=="function")n.on(r,o);else throw new TypeError("Slack WebSocket does not support events")}function v_e(n){let r=n?.data??n;return typeof r=="string"?r:Buffer.isBuffer(r)?r.toString("utf8"):r instanceof ArrayBuffer?Buffer.from(r).toString("utf8"):ArrayBuffer.isView(r)?Buffer.from(r.buffer,r.byteOffset,r.byteLength).toString("utf8"):null}function P_e(n){let r=new URL(n);if(r.protocol!=="wss:")throw new Error("Slack returned an insecure Socket Mode URL");return r.href}function G_e(n){return typeof n=="string"?n.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">"):""}function F_e(n,r){return G_e(n).replace(new RegExp(`<@${r}>`,"gi"),"").trim()}function Nk(n){return typeof n?.url_private_download=="string"&&n.url_private_download?n.url_private_download:n?.url_private}function L_e(n,r){let o=typeof n?.mimetype=="string"?n.mimetype.toLowerCase():"",i=Nk(n);return!Cz.has(o)||typeof i!="string"||!i?null:{name:typeof n.name=="string"?n.name:void 0,mediaType:o,size:Number.isSafeInteger(n.size)&&n.size>=0?n.size:void 0,load:e=>r(i,e)}}function U_e(n,r,o){let i=typeof n?.mimetype=="string"&&n.mimetype?n.mimetype.toLowerCase():void 0,e=Nk(n);if(Cz.has(i))return null;let a=n?.file_access==="check_file_info"&&typeof n?.id=="string"&&n.id;return(typeof e!="string"||!e)&&!a?null:{name:typeof n?.name=="string"&&n.name?n.name:typeof n?.title=="string"&&n.title?n.title:a?n.id:"slack-file",...i?{mediaType:i}:{},size:Number.isSafeInteger(n?.size)&&n.size>=0?n.size:void 0,load:async({signal:A}={})=>{if(!a)return r(e,{signal:A});let t=await o(n.id,{signal:A}),s=Nk(t);if(typeof s!="string"||!s)throw new Error("Slack files.info returned no downloadable URL");let g=await r(s,{signal:A}),c=typeof t?.name=="string"&&t.name?t.name:typeof t?.title=="string"&&t.title?t.title:n.id,I=typeof t?.mimetype=="string"&&t.mimetype?t.mimetype.toLowerCase():void 0;return Buffer.isBuffer(g)||g instanceof Uint8Array?{data:g,name:c,...I?{mediaType:I}:{}}:{...g,name:c,...I?{mediaType:I}:{}}}}}function H_e(n,r,{loadFile:o=async()=>{throw new Error("Slack file downloader is unavailable")},loadFileStream:i=o,loadFileInfo:e=async()=>{throw new Error("Slack file metadata loader is unavailable")}}={}){let a=n?.event;if(!a||!n?.event_id||!a.channel||!a.user||!a.ts)return null;let A=a.type==="message"&&a.channel_type==="im",t=a.type==="app_mention";if(!A&&!t||a.subtype&&a.subtype!=="file_share"||a.bot_id||a.app_id)return null;let s=String(a.thread_ts??a.ts);return{messageId:String(n.event_id),senderId:String(a.user),senderIsBot:String(a.user)===String(r),kind:A?"direct":"group",conversationId:A?String(a.channel):`${a.channel}:${s}`,content:F_e(a.text??"",r),images:Array.isArray(a.files)?a.files.map(g=>L_e(g,o)).filter(Boolean):[],files:Array.isArray(a.files)?a.files.map(g=>U_e(g,i,e)).filter(Boolean):[],addressed:A||t,replyTarget:{channelId:String(a.channel),threadTs:s,recipientUserId:String(a.user),recipientTeamId:String(a.user_team??n.team_id??"")},connectionTestTarget:{channelId:String(a.channel)}}}function K_e(n){return typeof n=="string"&&/^正在使用.+…$/.test(n.trim())}async function hz(n,r,o,i,e){if(i)for(let a=0;a{let y=to(Q,_k)[0]??"";if(!y||!y.startsWith(A))return;let m=y.slice(A.length);m&&(await hz(n,r,a,m,o),A=y)},f=()=>{I||c||s!==null||g||!t||(s=setTimeout(()=>{s=null;let Q=t;t="",g=B(Q).catch(y=>{c=!0,i.warn?.("[dsh-im:slack] streaming append failed:",y)}).finally(()=>{g=null,f()})},350),s?.unref?.())};return{messageId:a,get providerMessageIds(){return[...E]},update(Q){I||c||typeof Q!="string"||!Q.trim()||K_e(Q)||(t=Q,f())},async finish(Q){if(I)throw new Error("Slack message stream is already closed");I=!0,s!==null&&clearTimeout(s),s=null,t="",await g?.catch(()=>{});let y=to(Q,_k),m=y[0]??"\u5904\u7406\u5B8C\u6210\u3002";!c&&m.startsWith(A)?(await hz(n,r,a,m.slice(A.length),o),await n.stopStream({channelId:r.channelId,ts:a,signal:o})):(await n.stopStream({channelId:r.channelId,ts:a,signal:o}).catch(()=>{}),await n.updateMessage({channelId:r.channelId,ts:a,text:m,signal:o}));for(let _ of y.slice(1)){let N=await n.postMessage({channelId:r.channelId,threadTs:r.threadTs,text:_,signal:o});typeof N?.ts=="string"&&N.ts&&E.push(N.ts)}},cancel(){I=!0,t="",s!==null&&clearTimeout(s),s=null,n.stopStream({channelId:r.channelId,ts:a,signal:o}).catch(()=>{})}}}var Tk=class{#e;#A;#t;constructor({api:r,signal:o,logger:i}){this.#e=r,this.#A=o,this.#t=i}async sendText(r,o){let i=to(o,_k),e=[];for(let a of i){let A=await this.#e.postMessage({channelId:r.channelId,threadTs:r.threadTs,text:a,signal:this.#A});typeof A?.ts=="string"&&A.ts&&e.push(A.ts)}return{providerMessageIds:e}}openStream(r){return x_e({api:this.#e,target:r,signal:this.#A,logger:this.#t})}sendFile(r,o){return this.#e.uploadFile({channelId:r.channelId,threadTs:r.threadTs,file:o,signal:this.#A})}};function Y_e(){return{startedAt:null,ready:!1,connectionState:"idle",harnessReachable:!1,lastCheckedAt:null,lastConnectedAt:null,lastError:null,...mi()}}var CC=class{#e;#A;#t;#r;#s;#i;#I;#o;#l;#a;#n=Y_e();#g=null;#c=null;#p=null;#h=null;#d=null;#E=null;#C=0;#u=0;#B=!0;#Q=null;constructor({config:r,botToken:o,appToken:i,harness:e,state:a,logger:A=console,replyTimeoutMs:t=6e5,connectTimeoutMs:s=2e4,createApi:g=I=>new dC(I),createWebSocket:c=I=>new WebSocket(I)}){if(!r||!o||!i||!e||!a)throw new TypeError("SlackRuntime requires config, both tokens, Harness, and state");if(typeof c!="function")throw new TypeError("SlackRuntime requires WebSocket");this.#e=r,this.#A=o,this.#t=i,this.#r=e,this.#s=a,this.#i=A,this.#I=t,this.#o=s,this.#l=g,this.#a=c}get status(){return structuredClone(this.#n)}async sendConnectionTest(r){if(!this.#n.ready||!this.#c){let o=new Error("Slack bot is not connected");throw o.code="test-target-unavailable",o}return this.#c.sendConnectionTest(r)}async start(){return this.#n.ready&&this.#h?this.status:this.#Q?this.#Q:(this.#Q=this.#m().finally(()=>{this.#Q=null}),this.#Q)}async#m(){await this.stop(),this.#B=!1,this.#C=0,this.#n.startedAt=new Date().toISOString(),this.#n.connectionState="connecting",this.#n.lastError=null,await this.#r.ensureRunning(),this.#n.harnessReachable=!0;let r=new AbortController;this.#p=r;let o=this.#l({botToken:this.#A,appToken:this.#t});this.#g=o;try{let i=await o.authTest({signal:r.signal});if(`${i?.team_id}:${i?.user_id}`!==this.#e.platformId)throw new Error("Slack Bot Token identity does not match the saved bot");let e=new Tk({api:o,signal:r.signal,logger:this.#i});this.#c=new Xy({bot:e,harness:this.#r,state:this.#s,status:this.#n,logger:this.#i,replyTimeoutMs:this.#I,signal:r.signal});let a;try{await Promise.race([this.#f(),new Promise((A,t)=>{a=setTimeout(()=>t(new Error("Slack Socket Mode did not become ready in time")),this.#o),a?.unref?.()})])}finally{clearTimeout(a)}return this.status}catch(i){throw this.#n.ready=!1,this.#n.connectionState="failed",this.#n.lastError=i?.message??String(i),await this.stop(),i}}async#f(){if(this.#B)throw new Error("Slack runtime is stopped");let r=await this.#g.openConnection({signal:this.#p?.signal});return this.#y(r?.url)}#y(r){if(this.#B)return Promise.reject(new Error("Slack runtime is stopped"));let o=++this.#u,i=this.#a(P_e(r));this.#h=i;let e=!1;return new Promise((a,A)=>{let t=s=>{if(e||o!==this.#u)return;e=!0,this.#d=s?.connection_info?.app_id??null,this.#C=0;let g=Date.now();this.#n.ready=!0,this.#n.connectionState="connected",this.#n.lastCheckedAt=g,this.#n.lastConnectedAt=g,this.#n.lastError=null,a()};Mk(i,"message",s=>{if(o!==this.#u||this.#B)return;let g=v_e(s);if(!g)return;let c;try{c=JSON.parse(g)}catch{this.#i.warn?.("[dsh-im:slack] ignored malformed Socket Mode JSON");return}if(c.type==="hello"){t(c);return}if(c.envelope_id&&i.readyState===1&&(i.send(JSON.stringify({envelope_id:c.envelope_id})),this.#n.lastCheckedAt=Date.now()),c.type==="disconnect"){i.close(4e3,"Slack requested reconnect");return}if(c.type!=="events_api"||c.payload?.type!=="event_callback"||this.#d&&c.payload.api_app_id&&c.payload.api_app_id!==this.#d)return;let I=H_e(c.payload,this.#e.platformId.split(":")[1],{loadFile:(B,f)=>this.#g.downloadFile({url:B,...f}),loadFileStream:(B,f)=>this.#g.downloadFileStream({url:B,...f}),loadFileInfo:(B,f)=>this.#g.fileInfo({fileId:B,...f})}),E=this.#c;I&&E&&E.accept(I).catch(B=>{o!==this.#u||this.#B||this.#i.error?.(`[dsh-im:slack] bot ${this.#e.botId} message handling failed:`,B)})}),Mk(i,"close",(s={})=>{if(o!==this.#u)return;if(this.#h===i&&(this.#h=null),this.#B){e||A(new DOMException("Stopped","AbortError"));return}let g=Number(s.code)||0,c=new Error(`Slack Socket Mode closed (${g||"unknown"})`);this.#n.ready=!1,this.#n.connectionState="connecting",this.#n.lastError=c.message,e||(e=!0,A(c)),this.#D()}),Mk(i,"error",()=>{o!==this.#u||this.#B||(this.#n.lastError="Slack Socket Mode WebSocket error")})})}#D(){if(this.#B||this.#E!==null)return;let r=Ez[Math.min(this.#C,Ez.length-1)];this.#C+=1,this.#E=setTimeout(()=>{this.#E=null,this.#f().catch(o=>{this.#B||(this.#i.warn?.("[dsh-im:slack] Socket Mode reconnect failed:",o),this.#D())})},r),this.#E?.unref?.()}async stop(){this.#B=!0,this.#u+=1,this.#p?.abort(),this.#p=null,this.#E!==null&&clearTimeout(this.#E),this.#E=null;let r=this.#h,o=this.#c;this.#h=null,this.#c=null,this.#g=null,this.#d=null;try{r&&r.readyState<2&&r.close(1e3,"Plugin stopped")}catch(i){this.#i.warn?.(`[dsh-im:slack] bot ${this.#e.botId} failed to close Socket Mode:`,i)}return await Promise.race([o?.waitForIdle()??Promise.resolve(),new Promise(i=>setTimeout(i,2e3))]),this.#n.ready=!1,this.#n.connectionState="idle",this.status}};var Am=class extends un{};async function Rk(n,r={},o={}){if(!n?.credentials)throw new TypeError("dsh-im slack requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-im slack requires ctx.webServer");let i=o.ConfigStore??Zy,e=o.StateStore??Am,a=o.HarnessClient??em,A=o.Controller??hC,t=o.Runtime??CC,s=o.createConnectionSupervisor??ml,g=typeof n.logger=="function"?n.logger("dsh-im:slack"):n.logger??console,c=()=>ha(n),I=Rb(r,"slack"),E=await new i(I.config).load(),B=uz(r.workspace??process.cwd()),f=o.WorkspaceStore??Kr,Q=o.workspaces??await new f(I.workspaces,{defaultWorkspace:B}).load(),y=E.list();await Q.reconcile(y.map(K=>K.botId)),await Promise.all(y.map(K=>Q.ensure(K.botId,{defaultAgentPreset:r.agentPreset})));let m=typeof E.remove=="function"?Ca(E,{workspaces:Q}):E,_=new Map,N=K=>uz(I.bots,K,"state.json"),P=async K=>{let M=_.get(K);return M||(M=await new e(N(K)).load(),_.set(K,M)),M},Y=fa(n,o.commandExecutor),{controlExecutor:x,sessionMaintenanceExecutor:H,fileIngressExecutor:j}=Qa(n,{controlExecutor:o.controlExecutor,sessionMaintenanceExecutor:o.sessionMaintenanceExecutor,fileIngressExecutor:o.fileIngressExecutor}),q=new a({baseUrl:Pd(n.webServer,r.harnessBaseUrl),workspace:B,autostart:!1,dshBin:r.dshBin??"dsh",...Y?{commandExecutor:Y}:{},...x?{controlExecutor:x}:{},...H?{sessionMaintenanceExecutor:H}:{},...j?{fileIngressExecutor:j}:{}}),F=new A({credentials:n.credentials,configStore:m,logger:g,...o.inspectCredentials?{inspectCredentials:o.inspectCredentials}:{},createRuntime:async({botId:K,config:M,botToken:k,appToken:Z})=>{let ge=await P(K);await Q.ensure(K,{defaultAgentPreset:r.agentPreset});let fe=ua(q,{botId:K,workspaces:Q,state:ge,agentPresetCatalog:c});return new t({config:M,botToken:k,appToken:Z,harness:fe.harness,state:fe.state,replyTimeoutMs:r.replyTimeoutMs??6e5,connectTimeoutMs:r.connectTimeoutMs??2e4,logger:{error:(..._e)=>g.error?.(`[${K}]`,..._e),warn:(..._e)=>g.warn?.(`[${K}]`,..._e),info:(..._e)=>g.info?.(`[${K}]`,..._e),debug:(..._e)=>g.debug?.(`[${K}]`,..._e)}})},deleteState:async({botId:K})=>{let M=_.get(K);if(_.delete(K),M&&typeof M.remove=="function")await M.remove();else try{await j_e(N(K))}catch(k){if(k?.code!=="ENOENT")throw k}}}),v=Ba(F,{workspaces:Q,stateFor:P,agentPresetCatalog:c}),V=s({channel:"slack",controller:v,harness:q,logger:g,retryDelaysMs:r.retryDelaysMs,healthyIntervalMs:r.healthyIntervalMs}).start();return{controller:v,ready:V.ready,async close(){await V.close(),await v.close(),q.stopManagedProcess()}}}var fz="/slack",_i=Object.freeze({status:"connection.status",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete",setWorkspace:ei,setAgentPreset:Ai}),Qz=Object.freeze(Object.values(_i)),J_e=new Set(["token","botToken","appToken","botTokenRef","appTokenRef","tokenRef","platformId","secret","secretRef"]);function vk(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function tm(n,r){return vk(n)&&Object.keys(n).every(o=>r.includes(o))}function Bz(n){return typeof n=="string"&&/^slack_[a-f0-9]{24}$/.test(n)}function q_e(n){return typeof n=="string"&&/^xoxb-[A-Za-z0-9-]{16,}$/.test(n.trim())&&n.length<=4096}function z_e(n){return typeof n=="string"&&/^xapp-[A-Za-z0-9-]{16,}$/.test(n.trim())&&n.length<=4096}function V_e(n,r){return vk(r)?n===_i.status?tm(r,[])?null:"connection.status does not accept fields.":n===_i.bindCredentials?tm(r,["botToken","appToken"])&&q_e(r.botToken)&&z_e(r.appToken)?null:"bot.bind-credentials requires xoxb Bot Token and xapp App Token.":n===_i.reconnectBot?tm(r,["botId","sendTest"])&&Bz(r.botId)&&(r.sendTest===void 0||typeof r.sendTest=="boolean")?null:"bot.reconnect requires a botId.":n===_i.deleteBot?tm(r,["botId","confirm"])&&Bz(r.botId)&&r.confirm===!0?null:"bot.delete requires a botId and confirm=true.":n===_i.setWorkspace?ya(r)?null:"\u8BF7\u8F93\u5165\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84\u3002":n===_i.setAgentPreset?Sa(r)?null:"\u8BF7\u9009\u62E9 Agent Preset\u3002":"Unknown Slack endpoint.":"Payload must be an object."}function kk(n){if(Array.isArray(n))return n.map(kk);if(!vk(n))return n;let r={};for(let[o,i]of Object.entries(n))J_e.has(o)||(r[o]=kk(i));return r}function W_e(n){let r=ma(n);return r||(n?.code==="slack-invalid-bot-token"?{code:"invalid-bot-token",message:"Slack Bot Token \u65E0\u6548\uFF0C\u8BF7\u786E\u8BA4\u4F7F\u7528\u4EE5 xoxb- \u5F00\u5934\u7684\u4EE4\u724C\u3002"}:n?.code==="slack-invalid-app-token"?{code:"invalid-app-token",message:"Slack App Token \u65E0\u6548\uFF0C\u8BF7\u786E\u8BA4\u4F7F\u7528\u4EE5 xapp- \u5F00\u5934\u7684\u4EE4\u724C\u3002"}:n?.code==="slack-missing-scope"?{code:"missing-scope",message:"Slack \u5E94\u7528\u6743\u9650\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u65B0\u5BFC\u5165 Manifest \u5E76\u5B89\u88C5\u5230\u5DE5\u4F5C\u533A\u3002"}:n?.code==="slack-socket-mode"?{code:"socket-mode-unavailable",message:n.message}:{code:"slack-operation-failed",message:"Slack \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"})}function yz(n){for(let r of["status","bindCredentials","reconnectBot","deleteBot"])if(typeof n?.[r]!="function")throw new TypeError(`A complete Slack controller is required (${r})`);return async(r,o,i)=>{if(i?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};if(!Qz.includes(r))return{ok:!1,error:{code:"bad-request",message:"Unknown Slack endpoint."}};let e=V_e(r,o);if(e)return{ok:!1,error:{code:"bad-request",message:e}};try{let a;if(r===_i.status)a=await n.status();else if(r===_i.bindCredentials)a=await n.bindCredentials(o);else if(r===_i.reconnectBot){if(a=await n.reconnectBot(o.botId),i?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};if(o.sendTest===!0){let A=null;try{if(a?.bots?.find(t=>t?.botId===o.botId)?.connected!==!0){let t=new Error("Bot is not connected");throw t.code="test-target-unavailable",t}if(typeof n.sendConnectionTest!="function"){let t=new Error("Connection test is unavailable");throw t.code="test-target-unavailable",t}await n.sendConnectionTest(o.botId)}catch(t){A=t}a={...a,testMessage:Wt(A)}}}else if(r===_i.setWorkspace){if(typeof n.updateWorkspace!="function")throw new Error("Workspace update is unavailable");a=await n.updateWorkspace(o.botId,o.workspace)}else if(r===_i.setAgentPreset){if(typeof n.updateAgentPreset!="function")throw new Error("Agent preset update is unavailable");a=await n.updateAgentPreset(o.botId,o.agentPreset)}else a=await n.deleteBot(o.botId);return i?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!0,value:kk(a)}}catch(a){return i?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!1,error:W_e(a)}}}}function rm(n,r,o){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(fz,yz(r),{authority:Cr(o)})}async function mz(n,r={}){if(r?.controller)return rm(n,r.controller,r.rpcAuthority);let o=await Rk(n,r,r.internals??{}),i=rm(n,o.controller,r.rpcAuthority);return n.effect(()=>async()=>o.close(),"dsh-im: close Slack bot connections"),i}var Sz=Object.freeze({botPrefix:"telegram",tokenRefPrefix:"DSH_TELEGRAM_BOT_TOKEN"}),uC=Object.freeze({compatible:"compatible",privateAllowlist:"private-allowlist"}),Z_e=/^[1-9]\d{0,15}$/;function Dz(n){if(n===void 0)return Object.freeze([]);if(!Array.isArray(n))throw new TypeError("allowedUsers must be an array of numeric Telegram User IDs");let r=n.map(o=>{let i=typeof o=="number"&&Number.isSafeInteger(o)?String(o):typeof o=="string"?o.trim():"";if(!Z_e.test(i))throw new TypeError("allowedUsers contains an invalid Telegram User ID");return i});return Object.freeze([...new Set(r)])}function vg(n={}){if(!n||typeof n!="object"||Array.isArray(n))throw new TypeError("Telegram access policy must be an object");let r=n.accessMode??uC.compatible;if(!Object.values(uC).includes(r))throw new TypeError("Telegram accessMode must be compatible or private-allowlist");return Object.freeze({accessMode:r,allowedUsers:Dz(n.allowedUsers)})}function X_e(n){let r=Object.hasOwn(n,"accessMode"),o=Object.hasOwn(n,"allowedUsers");if(!r&&!o)return{};try{let i=vg(n);return{...r?{accessMode:i.accessMode}:{},...o||r?{allowedUsers:i.allowedUsers}:{}}}catch{return null}}function wz(n){return Md(n,Sz)}function Oz(n){return qB(n,"Telegram\u673A\u5668\u4EBA")}var am=class extends fl{constructor(r){super(r,{channel:"Telegram",...Sz,normalizeBotExtension:X_e})}async save(r){let o=r?.platformId?this.getByPlatformId(String(r.platformId)):null;return super.save({...o,...r})}};var im=class extends or{constructor(r){super({...r,rpcIdPrefix:"telegram",logPrefix:"dsh-telegram"})}};var $_e="https://api.telegram.org/",bz=Object.freeze(["api.telegram.org"]),e0e=12e4;function Pg(n){return typeof n=="string"&&n.trim()?n.trim():null}function Mz(n,r){let o=AbortSignal.timeout(r);return n?AbortSignal.any([n,o]):o}function _z(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}function A0e(n,r){if(!Number.isInteger(n)||n<1)throw new TypeError(`${r} must be a positive integer`);return n}function Nz(n,r){return r?.providerCode!==void 0&&(n.providerCode=r.providerCode),r?.retry_after!==void 0&&(n.retry_after=r.retry_after,n.retryAfter=r.retry_after),Number.isInteger(r?.status)&&(n.status=r.status),n}function t0e(n){let r=Number(n?.providerCode),o=Number(n?.status),i=Pg(n?.message)??"",e="artifact-provider-rejected",a="Telegram rejected the document.";r===401||r===403||o===401||o===403?(e="artifact-permission-required",a="Telegram denied permission to send the document."):r===413||o===413||/(?:file|request|entity).{0,20}(?:too (?:big|large)|size limit)|too (?:big|large)/i.test(i)?(e="artifact-too-large",a="The document exceeds Telegram's size limit."):r===429||o===429?(e="artifact-rate-limited",a="Telegram rate-limited document delivery."):(r>=500||o>=500)&&(e="artifact-delivery-uncertain",a="Telegram document delivery result is uncertain.");let A=new Error(a,{cause:n});return A.code=e,Nz(A,n)}function r0e(n){let r=new Error("Telegram document delivery result is uncertain",{cause:n});return r.code="artifact-delivery-uncertain",Nz(r,n)}function a0e(n){return typeof n=="string"&&/^\d{5,20}:[A-Za-z0-9_-]{20,}$/.test(n.trim())}var i0e=/^[a-z0-9_]{1,32}$/;function o0e(n){return!!n&&typeof n=="object"&&!Array.isArray(n)&&typeof n.command=="string"&&i0e.test(n.command)&&typeof n.description=="string"&&n.description.length>=1&&n.description.length<=256}var Pk=Object.freeze({type:"commands"}),BC=class{#e;#A;#t;#r;constructor({token:r,fetchImpl:o=fetch,baseUrl:i=$_e,fileUploadTimeoutMs:e=e0e}){if(!a0e(r))throw new TypeError("Telegram Bot Token is invalid");if(typeof o!="function")throw new TypeError("TelegramApi requires fetch");this.#e=r.trim(),this.#A=o,this.#t=new URL(i),this.#r=A0e(e,"fileUploadTimeoutMs")}async getMe(r={}){return this.#i("getMe",{},r)}async getWebhookInfo(r={}){return this.#i("getWebhookInfo",{},r)}async getUpdates({offset:r,timeout:o=25,signal:i}={}){let e={timeout:o,limit:100,allowed_updates:["message"],...Number.isSafeInteger(r)?{offset:r}:{}};return this.#i("getUpdates",e,{signal:i,timeoutMs:Math.max(1e4,(o+10)*1e3)})}async getFile({fileId:r,signal:o}={}){let i=Pg(r);if(!i||!/^[A-Za-z0-9_-]{1,512}$/.test(i))throw new TypeError("Telegram file id is invalid");return this.#i("getFile",{file_id:i},{signal:o})}async downloadFile({fileId:r,signal:o,maxBytes:i}={}){let e=await this.#s(r,o);return Ki(e,{fetchImpl:this.#A,signal:o,maxBytes:i,allowedHosts:bz})}async downloadFileStream({fileId:r,signal:o}={}){let i=await this.#s(r,o);return yl(i,{fetchImpl:this.#A,signal:o,allowedHosts:bz})}async#s(r,o){let i=await this.getFile({fileId:r,signal:o}),e=Pg(i?.file_path);if(!e||e.startsWith("/")||e.includes("\\")||e.includes("?")||e.includes("#"))throw new Error("Telegram returned an invalid file path");let a;try{a=e.split("/").map(t=>decodeURIComponent(t))}catch{throw new Error("Telegram returned an invalid file path")}if(a.some(t=>!t||t==="."||t===".."))throw new Error("Telegram returned an invalid file path");let A=new URL(this.#t);return A.pathname=`/file/bot${this.#e}/${e}`,A}async sendMessage({chatId:r,text:o,replyToMessageId:i,messageThreadId:e,signal:a}){return this.#i("sendMessage",{chat_id:r,text:o,link_preview_options:{is_disabled:!0},...i?{reply_parameters:{message_id:i,allow_sending_without_reply:!0}}:{},...e?{message_thread_id:e}:{}},{signal:a})}async sendDocument({chatId:r,file:o,replyToMessageId:i,messageThreadId:e,signal:a}){if(!o||typeof o!="object"||typeof o.fileName!="string"||!o.fileName||!Buffer.isBuffer(o.bytes))throw new TypeError("A Telegram document is required");let A=new FormData;if(A.append("chat_id",String(r)),A.append("document",new Blob([o.bytes],{type:o.mediaType??"application/octet-stream"}),o.fileName),i&&A.append("reply_parameters",JSON.stringify({message_id:i,allow_sending_without_reply:!0})),e&&A.append("message_thread_id",String(e)),a?.aborted)throw _z(a);let t=Mz(a,this.#r);try{return await this.#i("sendDocument",A,{signal:t,timeoutMs:this.#r,multipart:!0})}catch(s){throw a?.aborted?_z(a):s?.code?.startsWith?.("telegram-")?t0e(s):r0e(s)}}async editMessageText({chatId:r,messageId:o,text:i,signal:e}){return this.#i("editMessageText",{chat_id:r,message_id:o,text:i,link_preview_options:{is_disabled:!0}},{signal:e})}async sendChatAction({chatId:r,messageThreadId:o,signal:i}){return this.#i("sendChatAction",{chat_id:r,action:"typing",...o?{message_thread_id:o}:{}},{signal:i})}async setMyCommands({commands:r,scope:o,languageCode:i,signal:e}={}){if(!Array.isArray(r)||r.length===0||r.some(a=>!o0e(a)))throw new TypeError("Telegram bot commands are invalid");return this.#i("setMyCommands",{commands:r,...o?{scope:o}:{},...Pg(i)?{language_code:Pg(i)}:{}},{signal:e})}async setChatMenuButton({menuButton:r=Pk,signal:o}={}){if(!r||typeof r!="object"||Array.isArray(r))throw new TypeError("Telegram menu button is invalid");return this.#i("setChatMenuButton",{menu_button:r},{signal:o})}async#i(r,o,{signal:i,timeoutMs:e=15e3,multipart:a=!1}={}){let A=new URL(this.#t);A.pathname=`${A.pathname.replace(/\/$/,"")}/bot${this.#e}/${r}`;let t;try{t=await this.#A(A,{method:"POST",...a?{}:{headers:{"content-type":"application/json"}},body:a?o:JSON.stringify(o),signal:Mz(i,e),redirect:"error"})}catch(g){throw g?.name==="AbortError"||g?.name==="TimeoutError"?g:new Error(`Telegram ${r} transport failed`)}let s;try{s=await t.json()}catch{let g=new Error(`Telegram ${r} returned invalid JSON`);throw g.status=t?.status,g}if(!t.ok||s?.ok!==!0){let g=Pg(s?.description),c=new Error(g??`Telegram ${r} failed`);c.code=Number.isInteger(s?.error_code)?`telegram-${s.error_code}`:"telegram-api-error",c.status=t.status,Number.isInteger(s?.error_code)&&(c.providerCode=s.error_code);let I=Number(s?.parameters?.retry_after);throw Number.isFinite(I)&&I>=0&&(c.retry_after=I,c.retryAfter=I),c}return s.result}};async function Tz(n,r={}){let i=await new BC({token:n,...r}).getMe();if(!i?.id||i?.is_bot!==!0)throw new Error("Telegram token does not belong to a bot");return{platformId:String(i.id),name:Pg([i.first_name,i.last_name].filter(Boolean).join(" "))??"Telegram\u673A\u5668\u4EBA",username:Pg(i.username)}}var Gk=Object.freeze({key:"telegram",label:"Telegram",connectionLabel:" Bot API \u957F\u8F6E\u8BE2"}),om=class extends Cn{constructor(r){super({descriptor:Gk,...r})}};var fC=class extends Ql{#e;constructor(r){super({...r,descriptor:Gk,inspectToken:r.inspectToken??Tz,deriveIdentity:wz,maskPlatformId:Oz}),this.#e=r.configStore}status(){let r=super.status();return{...r,bots:r.bots.map(o=>{let i=this.#e.get(o.botId),e=vg(i??{});return{...o,accessPolicy:e}})}}async setAccessPolicy(r,o){let i=vg(o);return this.updateBotConfig(r,e=>({...e,...i}))}};var n0e=Object.freeze([{command:"new",description:"\u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD"},{command:"compact",description:"\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u7684\u8F83\u65E9\u4E0A\u4E0B\u6587"},{command:"workspace",description:"\u5207\u6362\u5DE5\u4F5C\u533A"},{command:"workspacelist",description:"\u5217\u51FA\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84"},{command:"sessionlist",description:"\u5217\u51FA\u4F1A\u8BDD ID \u548C\u6807\u9898"},{command:"session",description:"\u5C06\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u5230\u6307\u5B9A\u4F1A\u8BDD"},{command:"models",description:"\u6309\u5E8F\u53F7\u5217\u51FA\u6240\u6709\u53EF\u7528\u6A21\u578B"},{command:"model",description:"\u67E5\u770B\u6216\u5207\u6362\u5F53\u524D\u4F1A\u8BDD\u6A21\u578B"},{command:"presetlist",description:"\u5217\u51FA\u53EF\u7528 Agent Preset"},{command:"preset",description:"\u67E5\u770B\u6216\u8BBE\u7F6E\u65B0\u4F1A\u8BDD Agent Preset"},{command:"stop",description:"\u505C\u6B62\u5F53\u524D\u4EFB\u52A1"},{command:"steer",description:"\u7EA0\u504F\u5F53\u524D\u4EFB\u52A1"},{command:"status",description:"\u68C0\u67E5\u8FDE\u63A5\u72B6\u6001"},{command:"help",description:"\u663E\u793A\u5E2E\u52A9"}]);function s0e(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function g0e(n,r){return r?[[n?.text,n?.entities],[n?.caption,n?.caption_entities]].some(([o,i])=>typeof o=="string"&&Array.isArray(i)&&i.some(e=>e?.type!=="mention"||!Number.isInteger(e.offset)||!Number.isInteger(e.length)?!1:o.slice(e.offset,e.offset+e.length).toLowerCase()===`@${r.toLowerCase()}`)):!1}function c0e(n,r){return!r||typeof n!="string"?n:n.replace(new RegExp(`@${s0e(r)}\\b`,"ig"),"").trim()}var I0e=new Set(["image/jpeg","image/png","image/webp","image/gif"]),l0e=new Map([[".jpg","image/jpeg"],[".jpeg","image/jpeg"],[".png","image/png"],[".webp","image/webp"],[".gif","image/gif"]]);function kz(n){let r=n?.mime_type??n?.mimetype,o=typeof r=="string"?r.toLowerCase():"";if(I0e.has(o))return o;let i=typeof n?.file_name=="string"?n.file_name.toLowerCase():"";for(let[e,a]of l0e)if(i.endsWith(e))return a;return null}function Lk(n){return Number.isSafeInteger(n)&&n>=0?n:void 0}function Rz(n){return Lk(n?.file_size)??(Number(n?.width)||0)*(Number(n?.height)||0)}function p0e(n,r){let o,i,e;if(Array.isArray(n?.photo)&&n.photo.length>0)o=n.photo.reduce((a,A)=>Rz(A)>Rz(a)?A:a),i="image/jpeg",e=`${o.file_unique_id??o.file_id??"telegram-photo"}.jpg`;else if(n?.document){let a=kz(n.document);if(!a)return null;o=n.document,i=a,e=typeof o.file_name=="string"?o.file_name:void 0}return!o||typeof o.file_id!="string"?null:{name:e,mediaType:i,size:Lk(o.file_size),load:a=>r(o.file_id,a)}}function E0e(n,r){let o=n?.document;if(!o||kz(o)||typeof o.file_id!="string"||!o.file_id)return null;let i=typeof o.mime_type=="string"&&o.mime_type?o.mime_type.toLowerCase():void 0;return{name:typeof o.file_name=="string"&&o.file_name?o.file_name:String(o.file_unique_id??o.file_id),...i?{mediaType:i}:{},size:Lk(o.file_size),load:({signal:e}={})=>r(o.file_id,{signal:e})}}function d0e(n,{botId:r,username:o,loadFile:i=async()=>{throw new Error("Telegram file downloader is unavailable")},loadFileStream:e=i}){let a=n?.message,A=a?.chat?.id,t=a?.from?.id,s=a?.message_id;if(!Number.isSafeInteger(n?.update_id)||A===void 0||t===void 0||!Number.isSafeInteger(s)||!["private","group","supergroup"].includes(a.chat?.type))return null;let g=a.chat.type==="private",c=g||String(a.reply_to_message?.from?.id??"")===String(r)||g0e(a,o),I=Number.isSafeInteger(a.message_thread_id)?a.message_thread_id:void 0,E=p0e(a,i),B=E0e(a,e);return{messageId:String(n.update_id),senderId:String(t),senderIsBot:a.from?.is_bot===!0,kind:g?"direct":"group",conversationId:I===void 0?String(A):`${A}:${I}`,content:c0e(a.text??a.caption??"",o),images:E?[E]:[],files:B?[B]:[],addressed:c,replyTarget:{chatId:A,replyToMessageId:s,messageThreadId:I},connectionTestTarget:{chatId:A,messageThreadId:I}}}function h0e(n,{accessMode:r=uC.compatible,allowedPrivateUserIds:o=new Set}={}){return r!==uC.privateAllowlist?!0:n?.kind==="direct"&&o instanceof Set&&o.has(String(n.senderId))}var Fk=class{#e;#A;constructor({api:r,signal:o}){this.#e=r,this.#A=o}async sendText(r,o){let i=to(o,4e3),e=[];for(let[a,A]of i.entries()){let t=await this.#e.sendMessage({chatId:r.chatId,text:A,replyToMessageId:a===0?r.replyToMessageId:void 0,messageThreadId:r.messageThreadId,signal:this.#A});Number.isSafeInteger(t?.message_id)&&e.push(String(t.message_id))}return{providerMessageIds:e}}sendTyping(r){return this.#e.sendChatAction({chatId:r.chatId,messageThreadId:r.messageThreadId,signal:this.#A})}sendFile(r,o){return this.#e.sendDocument({chatId:r.chatId,file:o,replyToMessageId:r.replyToMessageId,messageThreadId:r.messageThreadId,signal:this.#A})}async openStream(r){return ZB({limit:4e3,create:async i=>(await this.#e.sendMessage({chatId:r.chatId,text:i,replyToMessageId:r.replyToMessageId,messageThreadId:r.messageThreadId,signal:this.#A})).message_id,edit:(i,e)=>this.#e.editMessageText({chatId:r.chatId,messageId:i,text:e,signal:this.#A}),sendRemainder:i=>this.#e.sendMessage({chatId:r.chatId,text:i,messageThreadId:r.messageThreadId,signal:this.#A}),messageIdForResult:i=>i?.message_id}).start()}};function C0e(){return{startedAt:null,ready:!1,connectionState:"idle",harnessReachable:!1,lastCheckedAt:null,lastConnectedAt:null,lastError:null,...mi()}}var QC=class{#e;#A;#t;#r;#s;#i;#I;#o;#l;#a=C0e();#n=null;#g=null;#c=null;#p=null;#h=null;constructor({config:r,token:o,harness:i,state:e,logger:a=console,replyTimeoutMs:A=6e5,createApi:t=s=>new BC(s)}){if(!r||!o||!i||!e)throw new TypeError("TelegramRuntime requires config, token, Harness, and state");this.#e=r,this.#A=o,this.#t=i,this.#r=e,this.#s=a,this.#i=A,this.#I=t;let s=vg(r);this.#o=s.accessMode,this.#l=new Set(s.allowedUsers)}get status(){return structuredClone(this.#a)}async sendConnectionTest(r){if(!this.#a.ready||!this.#g){let o=new Error("Telegram bot is not connected");throw o.code="test-target-unavailable",o}return this.#g.sendConnectionTest(r)}async start(){return this.#a.ready&&this.#p?this.status:this.#h?this.#h:(this.#h=this.#d().finally(()=>{this.#h=null}),this.#h)}async#d(){await this.stop(),this.#a.startedAt=new Date().toISOString(),this.#a.connectionState="connecting",this.#a.lastError=null,await this.#t.ensureRunning(),this.#a.harnessReachable=!0;let r=new AbortController;this.#c=r;let o=this.#I({token:this.#A});this.#n=o;try{let i=await o.getMe({signal:r.signal});if(String(i?.id??"")!==this.#e.platformId||i?.is_bot!==!0)throw new Error("Telegram token identity does not match the saved bot");let e=await o.getWebhookInfo({signal:r.signal});if(typeof e?.url=="string"&&e.url){let s=new Error("\u8BE5 Telegram \u673A\u5668\u4EBA\u5DF2\u914D\u7F6E Webhook\uFF0C\u8BF7\u5148\u5728\u539F\u670D\u52A1\u4E2D\u79FB\u9664 Webhook \u540E\u91CD\u8BD5\u3002");throw s.code="webhook-configured",s}try{await o.setMyCommands({commands:n0e,signal:r.signal}),await o.setChatMenuButton({menuButton:Pk,signal:r.signal})}catch(s){this.#s.warn?.(`[dsh-im:telegram] bot ${this.#e.botId} command menu setup failed:`,s)}let a=new Fk({api:o,signal:r.signal});this.#g=new om({bot:a,harness:this.#t,state:this.#r,status:this.#a,logger:this.#s,replyTimeoutMs:this.#i,signal:r.signal});let A=this.#r.cursor();if(A===null){let s=await o.getUpdates({offset:-1,timeout:0,signal:r.signal});A=s.length>0?s.at(-1).update_id+1:0,await this.#r.setCursor(A)}let t=Date.now();return this.#a.ready=!0,this.#a.connectionState="connected",this.#a.lastCheckedAt=t,this.#a.lastConnectedAt=t,this.#p=this.#E(A,r.signal),this.#p.catch(s=>{r.signal.aborted||(this.#a.ready=!1,this.#a.connectionState="failed",this.#a.lastError=s?.message??String(s),this.#s.error?.(`[dsh-im:telegram] bot ${this.#e.botId} polling stopped:`,s))}),this.status}catch(i){throw this.#a.ready=!1,this.#a.connectionState="failed",this.#a.lastError=i?.message??String(i),await this.stop(),i}}async#E(r,o){let i=r;for(;!o.aborted;){let e=await this.#n.getUpdates({offset:i,timeout:25,signal:o});this.#a.lastCheckedAt=Date.now();for(let a of e){if(o.aborted)return;let A=d0e(a,{botId:this.#e.platformId,username:this.#e.username,loadFile:(t,s)=>this.#n.downloadFile({fileId:t,...s}),loadFileStream:(t,s)=>this.#n.downloadFileStream({fileId:t,...s})});A&&h0e(A,{accessMode:this.#o,allowedPrivateUserIds:this.#l})?this.#g.accept(A).catch(t=>{o.aborted||this.#s.error?.(`[dsh-im:telegram] bot ${this.#e.botId} message handling failed:`,t)}):A&&(this.#a.messagesRejected+=1,this.#a.lastRejectedAt=new Date().toISOString()),i=a.update_id+1,await this.#r.setCursor(i)}}}async stop(){let r=this.#p,o=this.#g;return this.#c?.abort(),this.#c=null,this.#p=null,this.#n=null,this.#g=null,await Promise.race([r?.catch(()=>{})??Promise.resolve(),new Promise(i=>setTimeout(i,2e3))]),await Promise.race([o?.waitForIdle()??Promise.resolve(),new Promise(i=>setTimeout(i,2e3))]),this.#a.ready=!1,this.#a.connectionState="idle",this.status}};var nm=class extends un{};function Uk(n,r={},o={}){return ef(n,r,o,{channel:"telegram",ConfigStore:am,StateStore:nm,HarnessClient:im,Controller:fC,Runtime:QC})}var vz="/telegram",Hk=Object.freeze({...Da,setAccessPolicy:"bot.access-policy.set"}),u0e=Object.freeze(Object.values(Hk));function Pz(n){if(typeof n?.setAccessPolicy!="function")throw new TypeError("A complete Telegram controller is required (setAccessPolicy)");let r=tf(n,{channel:"Telegram"});return async(o,i,e)=>{if(o!==Hk.setAccessPolicy)return r(o,i,e);if(e?.aborted)return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}};let a=i&&typeof i=="object"&&!Array.isArray(i)?Object.keys(i):[];if(a.length!==3||!a.every(t=>["botId","accessMode","allowedUsers"].includes(t))||typeof i.botId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(i.botId))return{ok:!1,error:{code:"bad-request",message:"bot.access-policy.set requires a valid policy."}};let A;try{A=vg(i)}catch{return{ok:!1,error:{code:"bad-request",message:"\u8BF7\u8F93\u5165\u6709\u6548\u7684 Telegram \u8BBF\u95EE\u6A21\u5F0F\u548C\u6570\u5B57 User ID\u3002"}}}try{let t=await n.setAccessPolicy(i.botId,A);return e?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!0,value:t}}catch{return e?.aborted?{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}:{ok:!1,error:{code:"telegram-operation-failed",message:"Telegram \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}}}function sm(n,r,o){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(vz,Pz(r),{authority:Cr(o)})}async function Gz(n,r={}){if(r?.controller)return sm(n,r.controller,r.rpcAuthority);let o=await Uk(n,r,r.internals??{}),i=sm(n,o.controller,r.rpcAuthority);return n.effect(()=>async()=>o.close(),"dsh-im: close Telegram bot connections"),i}import{unlink as oNe}from"node:fs/promises";import{homedir as nNe}from"node:os";import{join as DC,resolve as uI}from"node:path";import{createHash as B0e}from"node:crypto";import{mkdir as f0e,readFile as Q0e,rename as y0e,unlink as m0e,writeFile as S0e}from"node:fs/promises";import{dirname as D0e}from"node:path";var Kk=Object.freeze({version:1,bots:Object.freeze([])});function dI(n){return typeof n=="string"&&n.trim()?n.trim():null}function Fz(n){let r=dI(n);return r&&/^wecom_[a-f0-9]{24}$/.test(r)?r:null}function w0e(n){let r=dI(n);return r&&/^DSH_WECOM_BOT_SECRET_[A-F0-9]{24}$/.test(r)?r:null}function cm(n){let r=dI(n);if(!r)throw new TypeError("Enterprise WeChat bot ID is required");let o=B0e("sha256").update(r).digest("hex").slice(0,24);return{botId:`wecom_${o}`,secretRef:`DSH_WECOM_BOT_SECRET_${o.toUpperCase()}`}}function xk(n){let r=dI(n)??"";return r?r.length<=10?`${r.slice(0,3)}\u2022\u2022\u2022`:`${r.slice(0,6)}\u2022\u2022\u2022\u2022${r.slice(-4)}`:"\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA"}function Lz(n){if(!n||typeof n!="object")return null;let r=Fz(n.botId),o=dI(n.remoteBotId),i=w0e(n.secretRef);if(!r||!o||!i)return null;let e=cm(o);return e.botId!==r||e.secretRef!==i?null:Object.freeze({botId:r,remoteBotId:o,secretRef:i,createdAt:dI(n.createdAt)??new Date().toISOString(),connectedAt:dI(n.connectedAt)})}function O0e(n){if(!n||n.version!==1||!Array.isArray(n.bots))return null;let r=n.bots.map(Lz);if(r.some(a=>a===null))return null;let o=new Set,i=new Set,e=new Set;for(let a of r){if(o.has(a.botId)||i.has(a.remoteBotId)||e.has(a.secretRef))return null;o.add(a.botId),i.add(a.remoteBotId),e.add(a.secretRef)}return Object.freeze({version:1,bots:Object.freeze(r)})}var gm=class{#e;#A=Kk;#t=Promise.resolve();constructor(r){this.#e=r}async load(){try{let r=O0e(JSON.parse(await Q0e(this.#e,"utf8")));if(!r)throw new Error("dsh-im Enterprise WeChat config contains invalid bot data");this.#A=r}catch(r){if(r?.code!=="ENOENT")throw r;this.#A=Kk}return this}list(){return structuredClone(this.#A.bots)}get(r){let o=this.#A.bots.find(i=>i.botId===r);return o?structuredClone(o):null}getByRemoteBotId(r){let o=this.#A.bots.find(i=>i.remoteBotId===r);return o?structuredClone(o):null}async save(r){let o=Lz(r);if(!o)throw new Error("Refusing to persist incomplete Enterprise WeChat bot data");return this.#r(i=>{let e=i.find(t=>t.remoteBotId===o.remoteBotId&&t.botId!==o.botId),a=i.find(t=>t.secretRef===o.secretRef&&t.botId!==o.botId);if(e||a)throw new Error("Duplicate Enterprise WeChat bot identity");let A=i.findIndex(t=>t.botId===o.botId);return A===-1?i.push(o):i[A]=o,structuredClone(o)})}async remove(r){if(!Fz(r))throw new TypeError("Invalid Enterprise WeChat bot ID");return this.#r(o=>{let i=o.findIndex(a=>a.botId===r);if(i===-1)return null;let[e]=o.splice(i,1);return structuredClone(e)})}async clear(){let r=this.#t.then(async()=>{try{await m0e(this.#e)}catch(o){if(o?.code!=="ENOENT")throw o}this.#A=Kk});this.#t=r.then(()=>{},()=>{}),await r}async#r(r){let o,i=this.#t.then(async()=>{let e=[...this.#A.bots];o=r(e);let a=Object.freeze({version:1,bots:Object.freeze(e)});await this.#s(a),this.#A=a});return this.#t=i.then(()=>{},()=>{}),await i,o}async#s(r){await f0e(D0e(this.#e),{recursive:!0,mode:448});let o=`${this.#e}.tmp`;await S0e(o,`${JSON.stringify(r,null,2)} diff --git a/src/channels/qq/qq-bridge.mjs b/src/channels/qq/qq-bridge.mjs index f6acedd..57e06a0 100644 --- a/src/channels/qq/qq-bridge.mjs +++ b/src/channels/qq/qq-bridge.mjs @@ -675,11 +675,12 @@ export class QqHarnessBridge { return; } if (update.type === 'tool') { + // 工具调用本身不推送:agent 任务工具调用频繁,逐条推送会刷屏; + // 它只作为边界把上一段说明文本定稿推送。失败时随错误详情带出工具名。 if (nonEmptyString(pendingStepText)) { await pushNotice(pendingStepText.trim()); } pendingStepText = null; - await pushNotice(`Tool call ${update.name}`); return; } if (update.error) { diff --git a/test/channels/qq/bridge.test.mjs b/test/channels/qq/bridge.test.mjs index 02a43ba..ac3171c 100644 --- a/test/channels/qq/bridge.test.mjs +++ b/test/channels/qq/bridge.test.mjs @@ -616,7 +616,8 @@ test('QQ pushes one notice per tool call and ignores status frames', async () => }); await bridge.accept(message({ messageId: 'msg-status-frame' })); - assert.deepEqual(sent, ['Tool call bash', 'Tool call read', '最终回答']); + // 工具调用本身不推送,避免多工具任务刷屏。 + assert.deepEqual(sent, ['最终回答']); }); test('QQ pushes a failed tool error and any interim explanation text', async () => { @@ -637,6 +638,7 @@ test('QQ pushes a failed tool error and any interim explanation text', async () toolName: 'add_observations', error: 'Error calling add_observations. Status code: 404.', }); + await onUpdate({ type: 'text', text: '改用创建实体的方式:' }); await onUpdate({ type: 'tool', name: 'create_entities' }); await onUpdate({ type: 'status', text: '正在整理结果…', toolName: 'create_entities' }); return '已存入两套记忆。'; @@ -654,9 +656,8 @@ test('QQ pushes a failed tool error and any interim explanation text', async () await bridge.accept(message({ messageId: 'msg-tool-error' })); assert.deepEqual(sent, [ '实体不存在,先创建再添加观察:', - 'Tool call add_observations', 'Tool call add_observations\nError: Error calling add_observations. Status code: 404.', - 'Tool call create_entities', + '改用创建实体的方式:', '已存入两套记忆。', ]); }); @@ -757,7 +758,7 @@ test('QQ announces a stopped turn after any tool notices already pushed', async await bridge.accept(message({ messageId: 'qq-stopped-stream' })); - assert.deepEqual(sent, ['Tool call bash', '已停止。']); + assert.deepEqual(sent, ['已停止。']); assert.equal(loggedErrors, 0); assert.equal(fixture.seen.has('qq-stopped-stream'), true); });