From fdab438a93e6c86c40dd6288c32d36b6ff70209f Mon Sep 17 00:00:00 2001 From: evanfang0054 <380616679@qq.com> Date: Mon, 31 Aug 2026 20:10:53 +0800 Subject: [PATCH] fix(feishu): thread card-action confirmations to the card message Card-button sub-flows (bind session, watch/unwatch, workspace switch, compact, stop, steer, preset/model selection and their confirmations) sent fresh messages keyed only by chat_id, so in topic groups the confirmations landed in the group's default area instead of the topic containing the card. - #handleCardAction anchors every confirmation and sub-flow to the card's message id; #handleMenuPick anchors to the replying message - #bindSession / #switchWorkspace / #handleCompact / #handleStop / #handlePreset* / #handleModelSelect / #sendSteer accept and forward the anchor; the expired-menu and steer-form notices follow suit - lib/index.js: regenerated host bundle --- lib/index.js | 10 +-- src/channels/feishu/bridge.mjs | 115 +++++++++++++++++---------------- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/lib/index.js b/lib/index.js index 6e8a9fc..d30d4be 100644 --- a/lib/index.js +++ b/lib/index.js @@ -432,11 +432,11 @@ ${i.appendMessage}`:dt(e);return await this.#O(t,a).catch(()=>{}),e}async#J(t,o, ${e.batchInputMessage}`:dt(A);await this.#O(t.message.chat_id,r).catch(()=>{})}async waitForIdle(){for(;;){let t=[...this.#a.values(),...[...this.#i.values()].flatMap(o=>o.queue?[o.queue]:[]),...this.#s,...this.#c,...this.#p,...this.#z.values(),...[...this.#F.values()].map(o=>o.promise)];if(t.length===0||(await Promise.allSettled(t),this.#a.size===0&&this.#s.size===0&&this.#c.size===0&&this.#p.size===0&&this.#z.size===0&&this.#F.size===0&&![...this.#i.values()].some(o=>o.queue)))return}}#V(){let t=AbortSignal.timeout(this.#$);return this.#w?AbortSignal.any([this.#w,t]):t}#ae(t){return this.#i.has(t)||this.#m.hasPending(t)}async#Le(t,o,i,e,a){if(this.#w?.throwIfAborted(),this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#u.lastMessageAt=new Date().toISOString(),this.#u.messagesReceived+=1;let A=await a(pA(e.content)??"",this.#t,this.#r,i,{signal:this.#w,isDirect:t.message.chat_type==="p2p",hasImages:Wt(e),hasFiles:Lt(e),pendingInteraction:this.#ae(i),control:{owner:this,key:i}});A?.stopped&&await Promise.allSettled([this.#we(i),this.#m.closeRoute(i)]);for(let r of A?.messages??[A?.message])r&&await this.#O(t.message.chat_id,r,{replyTo:t.message.message_id});this.#u.lastError=null}async#De(t,o,{alreadyRecorded:i=!1}={}){this.#w?.throwIfAborted();let e=t.message.message_id;if(!i){if(this.#r.hasSeen(e))return;await this.#r.markSeen(e),this.#u.lastMessageAt=new Date().toISOString(),this.#u.messagesReceived+=1}let a=Jv(t,this.#e),A=a.content,r=Wt(a),s=Lt(a),g=!r&&!s&&A?A.trim():null;if(!A&&!r&&!s){await this.#O(t.message.chat_id,w("\u76EE\u524D\u652F\u6301\u6587\u5B57\u3001\u56FE\u7247\u548C\u6587\u4EF6\u6D88\u606F\u3002"),{replyTo:t.message.message_id});return}if(g!==null&&QRe.test(g)){await this.#Oe(t,g);return}if(g==="/help"){await this.#O(t.message.chat_id,zW(),{replyTo:t.message.message_id});return}if(fRe.test(g)){await this.#Z(o,t.message.chat_id,{replyTo:t.message.message_id});return}if(g==="/new"){if(this.#a.has(o)||this.#ae(o)){await this.#O(t.message.chat_id,w("\u5F53\u524D\u4EFB\u52A1\u4ECD\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u4EFB\u52A1\u6216\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210\u540E\u518D\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002"),{replyTo:t.message.message_id});return}await this.#r.clearSession(o),await this.#O(t.message.chat_id,w("\u5DF2\u5F00\u542F\u5168\u65B0 Harness \u4F1A\u8BDD\u3002"),{replyTo:t.message.message_id}),await this.#Z(o,t.message.chat_id,{replyTo:t.message.message_id});return}if(g==="/status"){await this.#$e(o,t.message.chat_id,t.message.message_id);return}if(g==="/compact"){let f=await Bi(g,this.#t,this.#r,o,{signal:this.#w});f&&await this.#O(t.message.chat_id,f.message,{replyTo:t.message.message_id});return}if(SRe.test(g)){let f=g.replace(/^\/(?:sessionlist|sessions)/i,"").trim()||null;await this.#ce({chatId:t.message.chat_id,key:o,replyTo:t.message.message_id},f,0);return}if(wRe.test(g)){await this.#_e({chatId:t.message.chat_id,key:o,replyTo:t.message.message_id});return}if(r6.test(g)){let f=(r6.exec(g)?.[1]??"").trim()||null;await this.#Ce(o,t.message.chat_id,f,{replyTo:t.message.message_id});return}if(a6.test(g)){let f=(a6.exec(g)?.[1]??"").trim()||null;await this.#ue(o,t.message.chat_id,f,{replyTo:t.message.message_id});return}if(mRe.test(g)){await this.#Be(o,t.message.chat_id,{replyTo:t.message.message_id});return}if(o6.test(g)){let Q=o6.exec(g)[1]?.toLowerCase();if(Q!=="on"&&Q!=="off"){await this.#O(t.message.chat_id,w("\u7528\u6CD5\uFF1A/archived on\uFF08\u5305\u542B\u5F52\u6863\u4F1A\u8BDD\uFF09\u6216 /archived off\uFF08\u9690\u85CF\u5F52\u6863\u4F1A\u8BDD\uFF09"),{replyTo:t.message.message_id});return}typeof this.#r?.setIncludeArchivedSessions=="function"&&await this.#r.setIncludeArchivedSessions(Q==="on"),await this.#O(t.message.chat_id,Q==="on"?w("\u5DF2\u5F00\u542F\uFF1A\u4F1A\u8BDD\u5217\u8868\u5305\u542B\u5F52\u6863\u4F1A\u8BDD\u3002"):w("\u5DF2\u5173\u95ED\uFF1A\u4F1A\u8BDD\u5217\u8868\u9690\u85CF\u5F52\u6863\u4F1A\u8BDD\u3002"),{replyTo:t.message.message_id});return}if(DRe.test(g)){let f=this.#qe(o);if(f){await this.#ze(f,Number(g),{chatId:t.message.chat_id,key:o,event:t});return}}let c=g===null?null:await Qo(A,this.#t,o);if(c){for(let f of c.messages??[c.message])await this.#O(t.message.chat_id,f,{replyTo:t.message.message_id});return}let I=g===null?null:await Bi(g,this.#t,this.#r,o,{signal:this.#w});if(I){await this.#O(t.message.chat_id,I.message,{replyTo:t.message.message_id});return}this.#D.info?.(`[dsh-feishu] processing ${t.message.chat_type} message ${e}`);let d=t.batchSubmission??null,B=!1;try{let{receipt:f,artifactSendErrors:Q,textDeliveryErrors:y=0}=await this.#lA(t,o,a,{onAskComplete:d?()=>{B=this.#n.complete(o,d.token).completed}:void 0});return this.#u.messagesReplied+=1,this.#u.lastReplyAt=new Date().toISOString(),this.#u.lastError=null,y===0&&Q===0&&Co(this.#u),f}catch(f){if(d&&!B){if(f?.code==="turn-stopped")throw this.#n.complete(o,d.token),f;let Q=this.#n.fail(o,d.token);if(Q.retained){let y=new Error(f?.message??String(f),{cause:f});throw y.code=f?.code,y.providerCode=f?.providerCode,y.method=f?.method,Number.isInteger(f?.status)&&(y.status=f.status),y.batchInputMessage=Q.message,y}}throw f}finally{await this.#we(o),await this.#m.closeRoute(o)}}async#Oe(t,o){if(t?.message?.chat_type!=="p2p"){await this.#O(t.message.chat_id,w("\u4E3A\u907F\u514D\u6388\u6743\u94FE\u63A5\u66B4\u9732\uFF0C\u8BF7\u79C1\u804A\u673A\u5668\u4EBA\u53D1\u9001 /repair\u3002"));return}let i=jRe(t);if(!i){await this.#O(t.message.chat_id,w("\u65E0\u6CD5\u8BC6\u522B\u5F53\u524D\u53D1\u9001\u8005\uFF0C\u672A\u53D1\u8D77\u4FEE\u590D\u3002"));return}if(!this.#_){await this.#O(t.message.chat_id,w("\u5F53\u524D Host \u7248\u672C\u6682\u4E0D\u652F\u6301\u804A\u5929\u5185\u4FEE\u590D\uFF0C\u8BF7\u5148\u66F4\u65B0\u63D2\u4EF6\u3002"));return}let e=yRe.exec(o);if(!e){await this.#O(t.message.chat_id,w("\u7528\u6CD5\uFF1A/repair\u3001/repair qr\u3001/repair status\u3001/repair cancel \u6216 /repair verify"));return}let a=e[1]?.toLowerCase()??"start",A=t.message.chat_id;if(a==="start"){await this.#Ue({actorOpenId:i,chatId:A});return}let r=this.#U;if(!r){await this.#O(A,w("\u5F53\u524D Runtime \u6CA1\u6709\u53EF\u6062\u590D\u7684\u4FEE\u590D\u4EFB\u52A1\u8BB0\u5F55\uFF08\u673A\u5668\u4EBA\u53EF\u80FD\u521A\u5B8C\u6210\u5BC6\u94A5\u66F4\u65B0\u5E76\u91CD\u542F\uFF09\u3002\u672C\u547D\u4EE4\u4E0D\u4F1A\u542F\u52A8\u65B0\u7684\u6388\u6743\uFF1B\u8BF7\u67E5\u770B\u673A\u5668\u4EBA\u53D1\u9001\u7684\u9A8C\u8BC1\u7ED3\u679C\uFF0C\u786E\u8BA4\u4E0A\u4E00\u6B21\u4EFB\u52A1\u5DF2\u7ED3\u675F\u540E\u518D\u53D1\u9001 /repair\u3002"));return}if(r.actorOpenId!==i){await this.#O(A,w("\u53E6\u4E00\u4F4D\u7528\u6237\u6B63\u5728\u4FEE\u590D\u8BE5\u673A\u5668\u4EBA\uFF0C\u672C\u6B21\u4E0D\u4F1A\u663E\u793A\u5176\u6388\u6743\u4FE1\u606F\u3002"));return}if(a==="cancel"){let g;try{let c=await this.#_.cancel(this.#ge(r));g=Bu(c,{botId:this.#T}),r.snapshot=g}catch{await this.#O(A,w("\u6682\u65F6\u65E0\u6CD5\u53D6\u6D88\u4FEE\u590D\u4EFB\u52A1\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));return}g.state==="cancelled"&&(r.stopped=!0,this.#v+=1),await this.#O(A,this.#re(g));return}let s;try{s=await this.#pe(r)}catch{await this.#O(A,w("\u6682\u65F6\u65E0\u6CD5\u67E5\u8BE2\u4FEE\u590D\u72B6\u6001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));return}if(a==="qr"){if(!Vv.has(s.state)||!r.verificationUrl){await this.#O(A,this.#re(s,{verificationFocused:!0}));return}await this.#Ye(A,r.verificationUrl,s);return}await this.#O(A,this.#re(s,{verificationFocused:a==="verify"}))}#ge(t){return{botId:this.#T,attemptId:t.attemptId,actorOpenId:t.actorOpenId,chatId:t.chatId}}async#Ue({actorOpenId:t,chatId:o}){let i=this.#U,e=!1;if(i&&Vv.has(i.snapshot.state)){if(i.actorOpenId!==t){await this.#O(o,w("\u53E6\u4E00\u4F4D\u7528\u6237\u6B63\u5728\u4FEE\u590D\u8BE5\u673A\u5668\u4EBA\uFF0C\u672C\u6B21\u4E0D\u4F1A\u663E\u793A\u5176\u6388\u6743\u4FE1\u606F\u3002"));return}let r;try{r=await this.#pe(i)}catch{await this.#O(o,w("\u6682\u65F6\u65E0\u6CD5\u67E5\u8BE2\u4FEE\u590D\u72B6\u6001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));return}if(r.state==="saving"){await this.#O(o,this.#re(r));return}if(c6.has(r.state)){let s;try{s=Bu(await this.#_.cancel(this.#ge(i)),{botId:this.#T}),i.snapshot=s}catch{await this.#O(o,w("\u6682\u65F6\u65E0\u6CD5\u53D6\u6D88\u65E7\u4FEE\u590D\u4EFB\u52A1\uFF0C\u672A\u751F\u6210\u65B0\u94FE\u63A5\uFF1B\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));return}if(!eS.has(s.state)){await this.#O(o,this.#re(s));return}i.stopped=!0,this.#v+=1,e=s.state==="cancelled"}else eS.has(r.state)&&(i.stopped=!0,this.#v+=1)}let a;try{a=Bu(await this.#_.start({botId:this.#T,actorOpenId:t,chatId:o}),{botId:this.#T}),a=await this.#He(a,{actorOpenId:t,chatId:o})}catch{await this.#O(o,w("\u4FEE\u590D\u6D41\u7A0B\u6682\u65F6\u5931\u8D25\uFF0C\u73B0\u6709\u673A\u5668\u4EBA\u8FDE\u63A5\u4E0D\u53D7\u5F71\u54CD\uFF1B\u8BF7\u7A0D\u540E\u53D1\u9001 /repair \u91CD\u8BD5\u3002"));return}let A={attemptId:a.attemptId,actorOpenId:t,chatId:o,snapshot:a,verificationUrl:null,stopped:!1,announcedSaving:!1,announcedTerminal:!1};if(this.#U=A,a.verificationUrl)try{A.verificationUrl=g6(a.verificationUrl,this.#k)}catch{A.stopped=!0,await this.#_.cancel(this.#ge(A)).catch(()=>{}),await this.#O(o,w("\u98DE\u4E66\u8FD4\u56DE\u4E86\u65E0\u6CD5\u5B89\u5168\u9A8C\u8BC1\u7684\u6388\u6743\u94FE\u63A5\uFF0C\u5DF2\u4E2D\u6B62\u672C\u6B21\u4FEE\u590D\u3002"));return}if(eS.has(a.state)){A.announcedTerminal=!0,a.state!=="succeeded"&&await this.#O(o,this.#re(a));return}if(!A.verificationUrl){A.stopped=!0,await this.#O(o,w("\u98DE\u4E66\u672A\u8FD4\u56DE\u6388\u6743\u94FE\u63A5\uFF0C\u5DF2\u4E2D\u6B62\u672C\u6B21\u4FEE\u590D\u3002"));return}await this.#xe(o,A.verificationUrl,a,{restarted:e}),this.#Ke(A)}async#He(t,o){let i=t,e=Date.now()+this.#N;for(;!i.verificationUrl&&Vv.has(i.state);){if(Date.now()>=e)throw new Error("Feishu repair link timed out");await s6(Math.min(100,this.#P),this.#w),i=Bu(await this.#_.status({botId:this.#T,attemptId:i.attemptId,actorOpenId:o.actorOpenId,chatId:o.chatId}),{botId:this.#T})}return i}async#pe(t){let o=Bu(await this.#_.status(this.#ge(t)),{botId:this.#T});if(o.attemptId!==t.attemptId)throw new Error("Feishu repair attempt changed unexpectedly");return t.snapshot=o,o.verificationUrl&&(t.verificationUrl=g6(o.verificationUrl,this.#k)),o}#Ke(t){let o=++this.#v;(async()=>{for(;!t.stopped&&this.#U===t&&this.#v===o&&!this.#w?.aborted;){let i=Math.max(250,Math.min(1e4,t.snapshot.pollIntervalMs??this.#P));if(await s6(i,this.#w),t.stopped||this.#U!==t||this.#v!==o)return;let e=await this.#pe(t);if(e.state==="saving"&&!t.announcedSaving&&(t.announcedSaving=!0,await this.#O(t.chatId,w("\u6388\u6743\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u53D1\u9001\u5E76\u7B49\u5F85\u6D4B\u8BD5\u6309\u94AE\u56DE\u8C03\uFF1B\u6536\u5230\u771F\u5B9E\u56DE\u8C03\u540E\u624D\u4F1A\u5B8C\u6210\u3002"))),eS.has(e.state)){t.stopped=!0,e.state!=="succeeded"&&!t.announcedTerminal&&(t.announcedTerminal=!0,await this.#O(t.chatId,this.#re(e)));return}}})().catch(async()=>{this.#w?.aborted||t.stopped||this.#U!==t||(t.stopped=!0,this.#D.warn?.("[dsh-feishu] callback repair status monitoring failed"),await this.#O(t.chatId,w("\u4FEE\u590D\u72B6\u6001\u67E5\u8BE2\u4E2D\u65AD\uFF0C\u73B0\u6709\u673A\u5668\u4EBA\u8FDE\u63A5\u4E0D\u53D7\u5F71\u54CD\uFF1B\u53D1\u9001 /repair status \u91CD\u8BD5\u67E5\u8BE2\u3002")).catch(()=>{}))})}async#xe(t,o,i,{restarted:e=!1}={}){let a=i.remainingSeconds??(i.expiresAt?Math.max(0,Math.ceil((i.expiresAt-Date.now())/1e3)):null),A=a===null?w("\u94FE\u63A5\u4E3A\u77ED\u671F\u6709\u6548"):w("\u94FE\u63A5\u7EA6 {minutes} \u5206\u949F\u540E\u8FC7\u671F",{minutes:Math.max(1,Math.ceil(a/60))});await this.#O(t,[e?w("\u65E7\u6388\u6743\u94FE\u63A5\u5DF2\u4F5C\u5E9F\uFF0C\u5DF2\u751F\u6210\u65B0\u7684\u4FEE\u590D\u94FE\u63A5\u3002"):w("\u{1F527} \u51C6\u5907\u8865\u5168\u6743\u9650\u4E0E\u56DE\u8C03\u3002"),w("\u672C\u6B21\u4F1A\u589E\u91CF\u6DFB\u52A0\u5F53\u524D\u7F3A\u5C11\u9879\uFF1A\u5361\u7247\u56DE\u8C03 card.action.trigger\uFF1B\u98DE\u4E66\u663E\u793A\u4E3A\u201C\u83B7\u53D6\u5355\u804A\u3001\u7FA4\u7EC4\u6D88\u606F\u201D\u7684\u79DF\u6237\u6743\u9650 im:message:readonly\uFF08\u7528\u4E8E\u8BFB\u53D6\u7528\u6237\u6D88\u606F\u4E2D\u7684\u56FE\u7247\u6216\u6587\u4EF6\uFF09\uFF1Bim:resource\uFF08\u7528\u4E8E\u4E0A\u4F20\u673A\u5668\u4EBA\u53D1\u9001\u7684\u56FE\u7247\u6216\u6587\u4EF6\uFF09\uFF1B\u4EE5\u53CA\u539F\u751F\u547D\u4EE4\u9762\u677F\u6240\u9700\u7684 application:app_slash_command:read / write\u3002\u786E\u8BA4\u9875\u53EA\u4F1A\u663E\u793A\u5F53\u524D\u7F3A\u5C11\u7684\u9879\uFF1B\u82E5\u51FA\u73B0\u4E0A\u8FF0\u8303\u56F4\u4E4B\u5916\u7684\u914D\u7F6E\uFF0C\u8BF7\u53D6\u6D88\u3002"),"",w("\u5F53\u524D\u8BBE\u5907\u76F4\u63A5\u6253\u5F00\uFF1A"),o,"",w("\u82E5\u8981\u7528\u53E6\u4E00\u53F0\u8BBE\u5907\u626B\u7801\uFF0C\u53D1\u9001 /repair qr\u3002{expiry}\u3002",{expiry:A})].join(` `))}async#Ye(t,o,i){try{let e=await uRe.toBuffer(o,{errorCorrectionLevel:"M",margin:1,width:480,type:"png"}),a=await this.#e.im.v1.image.create({data:{image_type:"message",image:e}}),A=pA(a?.image_key)??pA(a?.data?.image_key);if(!A)throw new Error("Feishu QR upload returned no image key");let r=i.remainingSeconds??(i.expiresAt?Math.max(0,Math.ceil((i.expiresAt-Date.now())/1e3)):null),s=r===null?"":w("\uFF08\u5269\u4F59\u7EA6 {minutes} \u5206\u949F\uFF09",{minutes:Math.max(1,Math.ceil(r/60))});await this.#O(t,w("\u8BF7\u7528\u53E6\u4E00\u53F0\u8BBE\u5907\u626B\u7801\u5B8C\u6210\u6388\u6743{remaining}\u3002",{remaining:s}));let g=await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"image",content:JSON.stringify({image_key:A})}});if(g?.code&&g.code!==0)throw new Error("Feishu QR message send failed")}catch{await this.#O(t,w(`\u4E8C\u7EF4\u7801\u6682\u65F6\u65E0\u6CD5\u53D1\u9001\uFF0C\u8BF7\u76F4\u63A5\u6253\u5F00\u6388\u6743\u94FE\u63A5\uFF1A -{url}`,{url:o}))}}#re(t,{verificationFocused:o=!1}={}){if(t.state==="succeeded")return w("\u2705 \u4FEE\u590D\u5B8C\u6210\uFF1A\u5DF2\u5B9E\u6D4B\u6536\u5230 card.action.trigger\uFF0C\u83DC\u5355\u6309\u94AE\u73B0\u5728\u53EF\u7528\u3002");if(t.state==="expired"||t.error?.code==="expired_token")return w("\u6388\u6743\u94FE\u63A5\u5DF2\u8FC7\u671F\uFF1B\u5E73\u53F0\u672A\u8FD4\u56DE\u6210\u529F\u7ED3\u679C\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5DF2\u4FEE\u590D\u3002\u53D1\u9001 /repair \u751F\u6210\u65B0\u94FE\u63A5\u3002");if(t.state==="cancelled"||t.error?.code==="abort")return w("\u5DF2\u53D6\u6D88\u672C\u6B21\u4FEE\u590D\u6388\u6743\uFF0C\u672A\u786E\u8BA4\u5B8C\u6210\u4FEE\u590D\u3002");if(t.error?.code==="access_denied")return w("\u4F60\u5DF2\u53D6\u6D88\u6216\u62D2\u7EDD\u6388\u6743\uFF0C\u6CA1\u6709\u786E\u8BA4\u4FEE\u590D\uFF1B\u53D1\u9001 /repair \u53EF\u91CD\u8BD5\u3002");if(t.error?.code==="card_action_probe_timeout"||t.error?.code==="card-action-probe-timeout")return w("\u6388\u6743\u5DF2\u63D0\u4EA4\uFF0C\u4F46\u672A\u6536\u5230\u6D4B\u8BD5\u6309\u94AE\u56DE\u8C03\u3002\u53EF\u80FD\u5C1A\u672A\u70B9\u51FB\u6216\u914D\u7F6E\u4ECD\u5728\u4F20\u64AD\uFF1B\u7A0D\u540E\u53D1\u9001 /repair verify \u67E5\u8BE2\uFF0C\u4E0D\u8981\u76F2\u76EE\u91CD\u590D\u6388\u6743\u3002");if(t.state==="error")return w("\u4FEE\u590D\u6D41\u7A0B\u6682\u65F6\u5931\u8D25\uFF0C\u73B0\u6709\u673A\u5668\u4EBA\u8FDE\u63A5\u4E0D\u53D7\u5F71\u54CD\uFF1B\u53D1\u9001 /repair \u53EF\u91CD\u8BD5\u3002");if(t.state==="saving")return w("\u6388\u6743\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u7B49\u5F85\u4E13\u7528\u6D4B\u8BD5\u6309\u94AE\u7684\u771F\u5B9E\u56DE\u8C03\uFF1B\u56DE\u8C03\u5230\u8FBE\u524D\u4E0D\u4F1A\u5BA3\u544A\u6210\u529F\u3002");if(o)return w("\u6388\u6743\u5C1A\u672A\u5B8C\u6210\uFF0C\u6682\u65F6\u4E0D\u80FD\u9A8C\u8BC1\u5361\u7247\u6309\u94AE\u3002\u8BF7\u5148\u6253\u5F00\u6388\u6743\u94FE\u63A5\u5E76\u786E\u8BA4\u3002");let i=t.remainingSeconds===null?"":w("\uFF0C\u5269\u4F59\u7EA6 {minutes} \u5206\u949F",{minutes:Math.max(1,Math.ceil(t.remainingSeconds/60))});return w("\u4FEE\u590D\u4EFB\u52A1\u6B63\u5728\u7B49\u5F85\u6388\u6743{remaining}\u3002\u53D1\u9001 /repair qr \u53EF\u83B7\u53D6\u4E8C\u7EF4\u7801\uFF0C/repair cancel \u53EF\u53D6\u6D88\u3002",{remaining:i})}onCardAction(t){let o=pA(t?.operator?.open_id)??pA(t?.operator?.user_id)??pA(t?.operator?.operator_id?.open_id)??pA(t?.operator?.operator_id?.user_id)??pA(t?.open_id)??pA(t?.user_id);if(!(o!==null&&(this.#b.has("*")||this.#b.has(o))))return this.#D.warn?.("[dsh-feishu] ignoring card action from an unallowed sender"),Promise.resolve();let e=n6(t?.action?.value),a=n6(t?.action?.form_value),A=pA(e.action)??pA(t?.action?.action);if(!A)return Promise.resolve();let r=fu(t?.action?.option)??(A.endsWith("_pick")?Qg(t?.action?.options)[0]:null),s=[...new Set([...Qg(e.options),...Qg(t?.action?.options),...Qg(a[A]),...A==="watch_add"||A==="watch_remove"?Qg(t?.action?.option):[]])],g=A==="workspace_pick"&&typeof r=="string"?`workspace:${r}`:A==="session_pick"&&typeof r=="string"?`use:${r}`:A==="preset_pick"&&typeof r=="string"?`preset:select:${r}`:A==="model_pick"&&typeof r=="string"?`model:select:${r}`:A==="archive_pick"&&typeof r=="string"?`archive:${r}`:A==="steer_pick"&&typeof r=="string"?`steer:${r}`:A,c=pA(t?.context?.open_message_id)??pA(t?.open_message_id)??pA(t?.message_id),I=c?this.#H.get(c):null;if(!I){let L=pA(t?.context?.open_chat_id)??pA(t?.open_chat_id)??pA(t?.chat_id);return L&&this.#O(L,w("\u8FD9\u4E2A\u83DC\u5355\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u56DE\u590D /m \u91CD\u65B0\u6253\u5F00\u3002")).catch(()=>{}),Promise.resolve()}this.#H.delete(c),this.#H.set(c,I);let d={...I,messageId:c,selections:s,operatorOpenId:o},B=pA(e.source),f=pA(a.steer_text),Q=pA(t?.event_id)??pA(t?.header?.event_id)??pA(t?.uuid)??pA(t?.header?.uuid),y=JSON.stringify({messageId:c,resolvedAction:g,option:r,multiValues:s,source:B,formText:f}),m=g==="stop",_=g.startsWith("steer:")?g.slice(6):null,R=A==="steer"&&B==="quick"&&r!==null&&r!==Cu||A==="steer"&&B==="form"&&f!==null||_!==null&&_!==""&&!(_==="custom"||_===Cu);return this.#Je(d,y,async()=>{if(A==="steer"){if(B==="quick"&&r){if(r===Cu){await this.#W(d.chatId,qv(),{key:d.key,updateMessageId:d.messageId});return}await this.#he(d,r);return}if(B==="form"){if(f){await this.#he(d,f);return}await this.#O(d.chatId,w("\u8BF7\u8F93\u5165\u8865\u5145\u6307\u4EE4\u540E\u518D\u63D0\u4EA4\u3002"));return}}await this.#ie(g,d)},{lane:m||R?"control":"regular",coalesceStop:m,eventId:Q,operatorOpenId:o})}#be(t=Date.now()){for(let[o,i]of this.#S)i<=t&&this.#S.delete(o);for(;this.#S.size>i6;){let o=this.#S.keys().next().value;if(o===void 0)break;this.#S.delete(o)}}#Me(t,o=Date.now()){t&&(this.#S.delete(t),this.#S.set(t,o+TRe),this.#be(o))}#je(t){let o=t.key,i=Date.now(),e=this.#Q.get(o);if(e?.task||e&&i-e.at{}).finally(()=>{this.#p.delete(a);let A=this.#Q.get(o);A?.task===a&&this.#Q.set(o,{at:A.at,task:null})}),this.#Q.delete(o),this.#Q.set(o,{at:i,task:a}),this.#p.add(a);this.#Q.size>200;){let A=this.#Q.keys().next().value;if(A===void 0)break;this.#Q.delete(A)}return a}#Je(t,o,i,{lane:e="regular",coalesceStop:a=!1,eventId:A=null,operatorOpenId:r=null}={}){let s=t.key,g=A?`${s}\0${r??""}\0event:${A}`:null,c=g??`${s}\0${r??""}\0action:${o}`,I=Date.now();if(this.#be(I),g&&(this.#S.get(g)??0)>I)return Promise.resolve();let d=this.#f.get(c);if(d)return d;if(a){let U=this.#B.get(s);if(U){if(g)for(this.#y.delete(g),this.#y.set(g,U);this.#y.size>i6;){let F=this.#y.keys().next().value;if(F===void 0)break;this.#y.delete(F)}return U}}let B=e==="control",f=B?this.#h:this.#d,Q=B?this.#C:this.#E,y=B?_Re:MRe,m=Q.get(s)??0,_=a?y+1:y;if(m>=_)return this.#je(t);let T=f.get(s)??Promise.resolve();Q.set(s,m+1);let R,L=!1;return R=T.catch(()=>{}).then(async()=>{this.#w?.throwIfAborted(),L=!0,await i()}).catch(async U=>{this.#w?.aborted||await this.#x(t.chatId,U,{logLabel:"card action"})}).finally(()=>{if(this.#f.get(c)===R&&this.#f.delete(c),L&&g&&this.#Me(g),a&&this.#B.get(s)===R&&this.#B.delete(s),a){let F=Date.now();for(let[q,z]of this.#y)z===R&&(this.#y.delete(q),this.#Me(q,F))}f.get(s)===R&&f.delete(s);let U=(Q.get(s)??1)-1;U>0?Q.set(s,U):Q.delete(s),this.#p.delete(R)}),this.#f.set(c,R),a&&this.#B.set(s,R),this.#p.add(R),f.set(s,R),R}async#ie(t,{chatId:o,key:i,messageId:e=null,sessionWorkspace:a=null,sessionPage:A=0,selections:r=[]}){if(t==="sessions"||/^sessions:\d+$/.test(t)){let s=t==="sessions"?0:Number(t.slice(9));await this.#ce({chatId:o,key:i},a,s,{updateMessageId:e});return}if(t==="workspaces"){await this.#_e({chatId:o,key:i},{updateMessageId:e});return}if(t==="watchlist"){await this.#Be(i,o,{updateMessageId:e});return}if(t==="watch_add"||t==="watch_remove"){if(r.length===0){await this.#O(o,w("\u8BF7\u5148\u9009\u62E9\u81F3\u5C11\u4E00\u4E2A\u4F1A\u8BDD\u3002"));return}let s=0,g=0;if(t==="watch_add"){let I=new Map;try{I=await this.#gA(a)}catch(d){this.#D.warn?.("[dsh-feishu] batch watch validation failed:",d.message)}for(let d of r){let B=I.get(d);if(!B){g+=1;continue}let f=await this.#Ce(i,o,d,{notify:!1,validatedTarget:B});f.changed?s+=1:f.ok||(g+=1)}}else for(let I of r){let d=await this.#ue(i,o,I,{notify:!1});d.changed?s+=1:d.ok||(g+=1)}let c=s>0&&g>0?t==="watch_add"?w("\u5DF2\u6279\u91CF\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u53E6\u6709 {failed} \u4E2A\u672A\u6210\u529F\u3002",{count:s,failed:g}):w("\u5DF2\u53D6\u6D88\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u53E6\u6709 {failed} \u4E2A\u672A\u6210\u529F\u3002",{count:s,failed:g}):s>0?t==="watch_add"?w("\u5DF2\u6279\u91CF\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:s}):w("\u5DF2\u53D6\u6D88\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:s}):g>0?w("\u6240\u9009\u4F1A\u8BDD\u5747\u672A\u5904\u7406\u6210\u529F\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"):t==="watch_add"?w("\u6240\u9009\u4F1A\u8BDD\u5DF2\u5728\u5173\u6CE8\u5217\u8868\u4E2D\u3002"):w("\u6240\u9009\u4F1A\u8BDD\u5DF2\u4E0D\u5728\u5173\u6CE8\u5217\u8868\u4E2D\u3002");try{await this.#Be(i,o,{updateMessageId:e})}catch(I){this.#D.warn?.("[dsh-feishu] watch list refresh failed:",I.message)}await this.#O(o,c).catch(I=>{this.#D.warn?.("[dsh-feishu] watch batch summary failed:",I.message)});return}if(t==="new"){if(this.#a.has(i)||this.#ae(i)){await this.#O(o,w("\u5F53\u524D\u4EFB\u52A1\u4ECD\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u4EFB\u52A1\u6216\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210\u540E\u518D\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002"));return}await this.#r.clearSession(i),await this.#O(o,w("\u5DF2\u5F00\u542F\u5168\u65B0 Harness \u4F1A\u8BDD\u3002")),await this.#Z(i,o,{updateMessageId:e});return}if(t==="use:current"){let s=this.#r.sessionFor(i);if(typeof s!="string"||!s){await this.#O(o,w("\u5F53\u524D\u6CA1\u6709\u7ED1\u5B9A\u7684\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u4ECE\u4F1A\u8BDD\u5217\u8868\u9009\u62E9\u3002"));return}await this.#O(o,w("\u5DF2\u5C31\u7EEA\uFF0C\u76F4\u63A5\u53D1\u6D88\u606F\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002"));return}if(t==="archive_toggle"||t==="archive:on"||t==="archive:off"){let s=t==="archive:on"?!0:t==="archive:off"?!1:!(this.#r?.includesArchivedSessions?.()??!1);await this.#r?.setIncludeArchivedSessions?.(s),await this.#O(o,s?w("\u5DF2\u5F00\u542F\uFF1A\u4F1A\u8BDD\u5217\u8868\u5305\u542B\u5F52\u6863\u4F1A\u8BDD\u3002"):w("\u5DF2\u5173\u95ED\uFF1A\u4F1A\u8BDD\u5217\u8868\u9690\u85CF\u5F52\u6863\u4F1A\u8BDD\u3002")),await this.#Z(i,o,{updateMessageId:e});return}if(t==="repair"){await this.#O(o,w("\u4FEE\u590D\u9700\u5728\u79C1\u804A\u4E2D\u9A8C\u8BC1\u63A5\u5165\u8005\u8EAB\u4EFD\uFF0C\u8BF7\u76F4\u63A5\u53D1\u9001 /repair \u5F00\u59CB\u3002"));return}if(t==="compact"){await this.#tA(i,o);return}if(t==="stop"){await this.#rA(i,o);return}if(t==="steer"){await this.#aA(i,o,{updateMessageId:e});return}if(t.startsWith("steer:")){let s=t.slice(6);if(s==="custom"){await this.#W(o,qv(),{key:i,updateMessageId:e});return}await this.#he({key:i,chatId:o},s);return}if(t==="presets"){await this.#Ze(i,o,{updateMessageId:e});return}if(t==="models"){await this.#Xe(i,o,{updateMessageId:e});return}if(t==="status"){await this.#eA(i,o,{updateMessageId:e});return}if(t==="help"){await this.#AA(i,o,{updateMessageId:e});return}if(t==="back_to_menu"){await this.#Z(i,o,{updateMessageId:e});return}if(t==="preset_default"){await this.#Te(i,o,{updateMessageId:e});return}if(t.startsWith("preset:select:")){let s=t.slice(14);if(s===qm){await this.#Te(i,o,{updateMessageId:e});return}await this.#iA(i,o,s,{updateMessageId:e});return}if(t.startsWith("model:select:")){let s=t.slice(13);await this.#oA(i,o,s,{updateMessageId:e});return}if(t.startsWith("use:")){await this.#Ve(i,o,t.slice(4),{updateMessageId:e});return}if(t.startsWith("workspace:")){await this.#We(i,o,t.slice(10),{updateMessageId:e});return}if(t.startsWith("unwatch:")){(await this.#ue(i,o,t.slice(8))).ok&&e&&await this.#ce({chatId:o,key:i},a,A,{updateMessageId:e});return}if(t.startsWith("watch:")){let s=t.slice(6);(await this.#Ce(i,o,s,{workspaceHint:a})).ok&&e&&await this.#ce({chatId:o,key:i},a,A,{updateMessageId:e})}}#oe(t,o){if(this.#Y.size>=bRe){let i=this.#Y.keys().next().value;i!==void 0&&this.#Y.delete(i)}this.#Y.delete(t),this.#Y.set(t,{...o,expiresAt:Date.now()+ORe})}#qe(t){let o=this.#Y.get(t);return o?o.expiresAto.archived!==!0):t}async#ce({chatId:t,key:o,replyTo:i=null},e,a=0,{updateMessageId:A=null}={}){try{let r=this.#V(),s=await YM(e??"",this.#t,{signal:r});if(s.error){await this.#O(t,s.error,{replyTo:i});return}let g=await this.#t.listWorkspaceSessions(s.workspace,{signal:r}),c=this.#ne(Array.isArray(g?.sessions)?g.sessions:[]),I=g?.workspace??s.workspace;if(c.length===0){await this.#O(t,w(`\u5DE5\u4F5C\u533A\uFF1A{workspace} -\u8BE5\u5DE5\u4F5C\u533A\u6682\u65E0\u4F1A\u8BDD\u3002`,{workspace:I}),{replyTo:i});return}let d=Math.ceil(c.length/wc),B=Number.isSafeInteger(a)&&a>0?Math.min(a,d-1):0,f=new Set((this.#r.watchEntries?.(o)??[]).map(y=>y.sessionId)),Q=c.slice(B*wc,(B+1)*wc);this.#oe(o,{kind:"sessions",sessions:Q.map(y=>({...y,watched:f.has(y.sessionId)}))}),await this.#W(t,ZW(I,c,B,c.length,f),{key:o,updateMessageId:A,replyTo:i,sessionWorkspace:s.workspace,sessionPage:B})}catch(r){await this.#x(t,r,{logLabel:"session list"})}}async#_e({chatId:t,key:o,replyTo:i=null},{updateMessageId:e=null}={}){try{let{current:a,paths:A}=await TE(this.#t,{signal:this.#V()});this.#oe(o,{kind:"workspaces",paths:A}),await this.#W(t,XW(A,a),{key:o,updateMessageId:e,replyTo:i})}catch(a){await this.#x(t,a,{logLabel:"workspace list"})}}async#Ve(t,o,i,{updateMessageId:e=null}={}){try{let a=await this.#t.bindWorkspaceSession(t,i),A=String(a?.title??"").replace(/\s+/gu," ").trim()||w("\u6682\u65E0\u6807\u9898");await this.#O(o,[w(`\u5DF2\u7ED1\u5B9A\u4F1A\u8BDD\u300C{title}\u300D -ID\uFF1A{id}`,{title:A,id:a?.sessionId??i}),w("\u53D1\u9001 /history \u67E5\u770B\u6700\u8FD1\u5BF9\u8BDD\u3002")].join(` -`)),await this.#Z(t,o,{updateMessageId:e})}catch(a){await this.#x(o,a,{logLabel:"session binding",userMessage:w("\u7ED1\u5B9A\u5931\u8D25\uFF1A{message}",{message:uu(a)})})}}async#We(t,o,i,{updateMessageId:e=null}={}){try{let a=await this.#t.switchWorkspace(i);await this.#O(o,w("\u5DE5\u4F5C\u533A\u5DF2\u5207\u6362\u4E3A\uFF1A{workspace}",{workspace:a})),await this.#Z(t,o,{updateMessageId:e})}catch(a){await this.#x(o,a,{logLabel:"workspace switch",userMessage:w("\u5207\u6362\u5931\u8D25\uFF1A{message}",{message:uu(a)})})}}#de(t,o,i){if(!(!i.key||!t)&&(this.#H.delete(t),this.#H.set(t,{key:i.key,chatId:o,sessionWorkspace:typeof i.sessionWorkspace=="string"&&i.sessionWorkspace?i.sessionWorkspace:null,sessionPage:Number.isSafeInteger(i.sessionPage)&&i.sessionPage>=0?i.sessionPage:0}),this.#H.size>200)){let e=this.#H.keys().next().value;e!==void 0&&this.#H.delete(e)}}async#W(t,o,i={}){let e=pA(i.updateMessageId),a=pA(i.replyTo);if(e)try{let g=await this.#e.im.v1.message.patch({path:{message_id:e},data:{content:o}});if(g?.code&&g.code!==0)throw new Error(`Feishu card update failed: ${g.msg||g.code}`);return this.#de(e,t,i),e}catch(g){this.#D.warn?.("[dsh-feishu] card update failed:",g?.code??g?.message??g,"sending new")}let A=o;if(a)try{let g=await this.#e.im.v1.message.reply({path:{message_id:a},data:{msg_type:"interactive",content:A}});if(g?.code&&g.code!==0)throw new Error(`Feishu card reply failed: ${g.msg||g.code}`);let c=pA(g?.data?.message_id);if(c)return this.#de(c,t,i),c}catch(g){this.#D.warn?.("[dsh-feishu] threaded card reply failed; sending a plain card:",g?.message??String(g))}let r=await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"interactive",content:o}});if(r?.code&&r.code!==0)throw new Error(`Feishu card send failed: ${r.msg||r.code}`);let s=pA(r?.data?.message_id);return this.#de(s,t,i),s}async#Z(t,o,{updateMessageId:i=null,replyTo:e=null}={}){let a=null,A=null;try{let U=this.#r.sessionFor(t);if(typeof U=="string"&&U){a=U;let F=this.#t.workspaceSession?.(U);A=pA(F?.title)??pA(F?.name)??pA(F?.displayName)}}catch{}let r=this.#V(),s=TE(this.#t,{signal:r}).catch(()=>{let U=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;return{current:U,paths:U?[U]:[]}}),g=(async()=>{let U=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;if(!U||typeof this.#t.listWorkspaceSessions!="function")return[];try{let F=await this.#t.listWorkspaceSessions(U,{signal:r});return this.#ne(Array.isArray(F?.sessions)?F.sessions:[])}catch{return[]}})(),c=(async()=>{try{let U=await this.#t.agentPresetSettings({signal:r});return{...U.agentPresetCatalog,_currentId:U.agentPreset}}catch{return null}})(),I=(async()=>{try{if(a){let U=this.#t.workspaceSession?.(a);if(typeof U?.models=="function")return await U.models({signal:r})}return await this.#t.listModels({signal:r})}catch{return null}})(),[d,B,f,Q]=await Promise.all([s,g,c,I]),y=Array.isArray(d.paths)?d.paths:[],m=d.current??null,_=B.find(U=>U.sessionId===a),T=a?pA(_?.title)??pA(_?.name)??A??a:null,R=B.map(U=>({id:U.sessionId,title:U.title??U.name??U.sessionId})).slice(0,20);a&&(R=R.filter(U=>U.id!==a),R.unshift({id:a,title:T??a}),R=R.slice(0,20));let L=this.#r?.includesArchivedSessions?.()??!1;this.#oe(t,{kind:"menu",chatId:o}),await this.#W(o,YW({workspaces:y,currentWorkspace:m,currentSession:a?{id:a,title:T}:null,sessions:R,archiveVisible:L,presetCatalog:f,modelCatalog:Q}),{key:t,updateMessageId:i,replyTo:e})}async#uA(t,o){try{if(typeof this.#t.workspaceSession=="function"){let e=this.#t.workspaceSession(o);if(e&&typeof e=="object"){let a=pA(e.title)??pA(e.name)??pA(e.displayName);if(a)return a}}let i=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;if(i&&typeof this.#t.listWorkspaceSessions=="function"){let e=await this.#t.listWorkspaceSessions(i),a=(Array.isArray(e?.sessions)?e.sessions:[]).find(A=>A.sessionId===o);if(a){let A=pA(a.title)??pA(a.name);if(A)return A}}}catch{}return null}async#Ze(t,o,{updateMessageId:i=null}={}){try{let e=await this.#t.agentPresetSettings({signal:this.#V()}),a=e.agentPresetCatalog;a._currentId=e.agentPreset,await this.#W(o,jW(a),{key:t,updateMessageId:i})}catch(e){await this.#x(o,e,{logLabel:"preset card"})}}async#Xe(t,o,{updateMessageId:i=null}={}){try{let e=this.#V();await this.#t.ensureRunning({signal:e});let a=this.#r?.sessionFor?.(t),A;if(typeof a=="string"&&a){let r=this.#t.workspaceSession(a);r?.models&&(A=await r.models({signal:e}))}A||(A=await this.#t.listModels({signal:e})),await this.#W(o,JW(A),{key:t,updateMessageId:i})}catch(e){await this.#x(o,e,{logLabel:"model card"})}}async#$e(t,o,i=null){try{await this.#t.ensureRunning({signal:this.#w});let e=[w("\u8FDE\u63A5\u6B63\u5E38")],a=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;a&&e.push(w("\u5DE5\u4F5C\u533A\uFF1A{workspace}",{workspace:a}));let A=typeof this.#t.agentPresetSettings=="function"?await this.#t.agentPresetSettings({signal:this.#w}).catch(()=>null):null;if(A){let r=A.agentPresetCatalog?.items?.find(s=>s.id===A.agentPreset);e.push(w("\u9884\u8BBE\uFF1A{preset}",{preset:r?`${r.label}\uFF08${r.id}\uFF09`:A.agentPreset||w("\u8DDF\u968F\u9ED8\u8BA4")}))}await this.#O(o,e.join(` -`),{replyTo:i})}catch(e){await this.#x(o,e,{logLabel:"status text"})}}async#eA(t,o,{updateMessageId:i=null}={}){try{let e=this.#V();await this.#t.ensureRunning({signal:e});let a={connected:!0,workspace:null,preset:null,model:null,sessionCount:0};try{let A=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;a.workspace=A||w("\u672A\u77E5")}catch{}try{let A=await this.#t.agentPresetSettings({signal:e}),r=A.agentPresetCatalog.items.find(s=>s.id===A.agentPreset);a.preset=r?`${r.label}\uFF08${r.id}\uFF09`:A.agentPreset||w("\u8DDF\u968F\u9ED8\u8BA4")}catch{}try{let A=this.#r?.sessionFor?.(t);if(typeof A=="string"&&A){let r=this.#t.workspaceSession(A);if(r?.models){let s=await r.models({signal:e});s.current&&(a.model=`${s.current.provider}/${s.current.model}`)}}}catch{}try{let A=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;if(A){let r=await this.#t.listWorkspaceSessions(A,{signal:e});Array.isArray(r?.sessions)&&(a.sessionCount=r.sessions.length)}}catch{}await this.#W(o,qW(a),{key:t,updateMessageId:i})}catch(e){await this.#x(o,e,{logLabel:"status card"})}}async#AA(t,o,{updateMessageId:i=null}={}){await this.#W(o,VW(KRe.map(e=>w(e))),{key:t,updateMessageId:i})}async#tA(t,o){try{let i=await Bi("/compact",this.#t,this.#r,t,{signal:this.#w});await this.#O(o,i?.message||w("\u4E0A\u4E0B\u6587\u538B\u7F29\u5931\u8D25\u3002"))}catch(i){await this.#x(o,i,{logLabel:"compact"})}}async#rA(t,o){try{let i=await Qi("/stop",this.#t,this.#r,t,{signal:this.#w,control:{owner:this,key:t}});i?.stopped&&await Promise.allSettled([this.#we(t),this.#m.closeRoute(t)]),await this.#O(o,i?.message||w("/stop \u6267\u884C\u5B8C\u6210\u3002"))}catch(i){await this.#x(o,i,{logLabel:"stop"})}}async#aA(t,o,{updateMessageId:i=null}={}){let e=!!this.#r.sessionFor?.(t);this.#oe(t,{kind:"steer"}),await this.#W(o,t6({hasSession:e}),{key:t,updateMessageId:i})}async#he(t,o){let{key:i,chatId:e}=t,a=await Qi(`/steer ${o}`,this.#t,this.#r,i,{signal:this.#w,pendingInteraction:this.#ae(i),control:{owner:this,key:i}});await this.#O(e,a?.message||w("\u5DF2\u63D0\u4EA4\u8865\u5145\u6307\u4EE4\u3002"))}async#Te(t,o,{updateMessageId:i=null}={}){try{let e=await yi("/preset --default",this.#t,this.#r,t,{signal:this.#w});for(let a of e?.messages??[e?.message])a&&await this.#O(o,a)}catch(e){await this.#x(o,e,{logLabel:"preset reset"});return}try{await this.#Z(t,o,{updateMessageId:i})}catch(e){this.#D.warn?.("[dsh-feishu] menu refresh failed after preset reset:",e.message)}}async#iA(t,o,i,{updateMessageId:e=null}={}){try{let a=/^\d+$/u.test(i)?`id:${i}`:i,A=await yi(`/preset ${a}`,this.#t,this.#r,t,{signal:this.#w});for(let r of A?.messages??[A?.message])r&&await this.#O(o,r)}catch(a){await this.#x(o,a,{logLabel:"preset selection"});return}try{await this.#Z(t,o,{updateMessageId:e})}catch(a){this.#D.warn?.("[dsh-feishu] menu refresh failed after preset select:",a.message)}}async#oA(t,o,i,{updateMessageId:e=null}={}){try{let a=await Wi(`/model ${i}`,this.#t,this.#r,t,{signal:this.#w,pendingInteraction:this.#ae(t),control:{owner:this,key:t}});for(let A of a?.messages??[a?.message])A&&await this.#O(o,A)}catch(a){await this.#x(o,a,{logLabel:"model selection"});return}try{await this.#Z(t,o,{updateMessageId:e})}catch(a){this.#D.warn?.("[dsh-feishu] menu refresh failed after model select:",a.message)}}#Ne(){if(this.#q||typeof this.#t?.watchHarnessEvents!="function"||this.#w?.aborted)return;let t=this.#w??new AbortController().signal;try{this.#q=this.#t.watchHarnessEvents({signal:t,onSessionEvent:o=>this.#cA(o),onReconnect:()=>{this.#IA()}}),Promise.resolve(this.#q).catch(o=>{t.aborted||this.#D.warn?.("[dsh-feishu] event watcher stopped:",o.message)})}catch(o){this.#q=null,this.#D.warn?.("[dsh-feishu] event watcher failed to start:",o.message)}}#Re(t,o){let i=this.#z.get(t)??Promise.resolve(),e;return e=i.then(o,o).catch(a=>{this.#w?.aborted||this.#D.warn?.("[dsh-feishu] completion event failed:",a.message)}).finally(()=>{this.#z.get(t)===e&&this.#z.delete(t)}),this.#z.set(t,e),e}#Ee(t=Date.now()){let o=0;for(let[i,e]of this.#K){for(let[a,A]of e)(!Number.isSafeInteger(A?.arrivalAt)||A.arrivalAt<0||A.arrivalAt+NRe<=t)&&e.delete(a);for(;e.size>kRe;){let a=e.keys().next().value;if(a===void 0)break;e.delete(a)}e.size===0?this.#K.delete(i):o+=e.size}for(;this.#K.size>RRe;){let i=this.#K.keys().next().value;if(i===void 0)break;o-=this.#K.get(i)?.size??0,this.#K.delete(i)}for(;o>vRe;){let i=this.#K.keys().next().value;if(i===void 0)break;let e=this.#K.get(i),a=e?.keys().next().value;if(a===void 0){this.#K.delete(i);continue}e.delete(a),o-=1,e.size===0&&this.#K.delete(i)}}#nA(t,o,i=Date.now()){this.#Ee(i);let e=this.#K.get(t);e||(e=new Map);let a=o?.data?.reason,A=typeof a=="string"?a:typeof a?.kind=="string"?{kind:a.kind}:null;e.delete(o.seq),e.set(o.seq,{arrivalAt:i,event:{type:"turn/end",seq:o.seq,...Number.isSafeInteger(o.time)&&o.time>=0?{time:o.time}:{},data:{reason:A}}}),this.#K.delete(t),this.#K.set(t,e),this.#Ee(i)}async#sA(t,{workspaceHint:o=null,signal:i=this.#w}={}){if(typeof t!="string"||t==="")return{error:w("\u7528\u6CD5\uFF1A/watch ")};let e=/^\d{1,4}$/.test(t)?Number(t):null,a=typeof this.#t?.currentWorkspace=="function"?this.#t.currentWorkspace():null,A=async s=>{let g=await this.#t.listWorkspaceSessions(s,{signal:i});return Array.isArray(g?.sessions)?g.sessions:[]};if(e!==null){if(!a)return{error:w("\u5F53\u524D\u673A\u5668\u4EBA\u6CA1\u6709\u53EF\u7528\u7684\u5DE5\u4F5C\u533A\uFF0C\u65E0\u6CD5\u6309\u5E8F\u53F7\u89E3\u6790\u4F1A\u8BDD\u3002")};let s=this.#ne(await A(a)),g=s[e-1];return g?.sessionId?{sessionId:g.sessionId,title:g.title??w("\u6682\u65E0\u6807\u9898"),workspace:a,...Qn(g.lastSeq)?{lastSeq:g.lastSeq}:{}}:{error:w("\u5F53\u524D\u5DE5\u4F5C\u533A\u53EA\u6709 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:s.length})}}let r;if(pA(o))r=[o];else{let s=typeof this.#t?.listWorkspaces=="function"?(await this.#t.listWorkspaces({signal:i})).filter(g=>g!==a):[];r=[a,...s].filter(Boolean)}for(let s of r){let c=(await A(s)).find(I=>I.sessionId===t);if(c)return{sessionId:t,title:c.title??w("\u6682\u65E0\u6807\u9898"),workspace:s,...Qn(c.lastSeq)?{lastSeq:c.lastSeq}:{}}}return{error:w("\u6CA1\u6709\u627E\u5230\u8FD9\u4E2A\u4F1A\u8BDD\uFF0C\u8BF7\u7528 /sessionlist \u67E5\u770B\u53EF\u7528\u4F1A\u8BDD\u3002")}}async#gA(t){let o=pA(t)??(typeof this.#t?.currentWorkspace=="function"?pA(this.#t.currentWorkspace()):null);if(!o||typeof this.#t?.listWorkspaceSessions!="function")return new Map;let i=await this.#t.listWorkspaceSessions(o,{signal:this.#V()});return new Map(this.#ne(Array.isArray(i?.sessions)?i.sessions:[]).filter(e=>pA(e?.sessionId)).map(e=>[e.sessionId,{sessionId:e.sessionId,title:e.title??e.name??w("\u6682\u65E0\u6807\u9898"),workspace:o,...Qn(e.lastSeq)?{lastSeq:e.lastSeq}:{}}]))}#ke(t){let o=this.#F.get(t);if(o)return o.requested=!0,o.promise;let i={requested:!0,promise:null};return this.#F.set(t,i),i.promise=Promise.resolve().then(async()=>{try{do i.requested=!1,await this.#Re(t,()=>this.#Pe(t));while(i.requested&&!this.#w?.aborted)}finally{this.#F.get(t)===i&&this.#F.delete(t)}}),i.promise}async#Ce(t,o,i,{notify:e=!0,validatedTarget:a=null,workspaceHint:A=null,replyTo:r=null}={}){let s=Date.now(),g=async y=>{e&&await this.#O(o,y,{replyTo:r}).catch(m=>{this.#D.warn?.("[dsh-feishu] watch notification failed:",m.message)})};if(this.#Ne(),typeof this.#r?.setWatch!="function")return await g(w("\u5F53\u524D\u72B6\u6001\u5B58\u50A8\u4E0D\u652F\u6301\u5173\u6CE8\u3002")),{ok:!1,changed:!1,reason:"unsupported"};let c;try{c=a?.sessionId===i?a:await this.#sA(i,{workspaceHint:A,signal:A?this.#V():this.#w})}catch(y){return await g(w("\u65E0\u6CD5\u89E3\u6790\u4F1A\u8BDD\uFF1A{message}",{message:uu(y)})),{ok:!1,changed:!1,reason:"resolve"}}if(c.error)return await g(c.error),{ok:!1,changed:!1,reason:"not-found"};let I=this.#r.watchEntries?.(t)??[],d=I.find(y=>y.sessionId===c.sessionId);if(!d&&I.length>=Zm)return await g(w("\u6BCF\u4E2A\u804A\u5929\u6700\u591A\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:Zm})),{ok:!1,changed:!1,reason:"limit"};let B=Qn(d?.lastSeq)?d.lastSeq:Qn(c.lastSeq)?c.lastSeq:null,Q=rS(d)??(d?null:s);try{await this.#r.setWatch(t,{sessionId:c.sessionId,title:c.title,chatId:o,lastSeq:B,...Q!==null?{watchStartedAt:Q}:{}})}catch(y){return await g(w("\u5173\u6CE8\u5931\u8D25\uFF1A{message}",{message:uu(y)})),{ok:!1,changed:!1,reason:"persist"}}return(!d||Q!==null||!Qn(B))&&this.#ke(c.sessionId),await g(w("\u5DF2\u5173\u6CE8\u4F1A\u8BDD\u300C{title}\u300D\uFF0C\u4EFB\u52A1\u5B8C\u6210\u4F1A\u63A8\u9001\u7ED3\u679C\u3002",{title:String(c.title).replace(/\s+/gu," ")})),{ok:!0,changed:!d,entry:this.#r.watchEntry?.(t,c.sessionId)}}async#ue(t,o,i,{notify:e=!0,replyTo:a=null}={}){let A=async g=>{e&&await this.#O(o,g,{replyTo:a}).catch(c=>{this.#D.warn?.("[dsh-feishu] unwatch notification failed:",c.message)})};if(typeof this.#r?.removeWatch!="function")return{ok:!1,changed:!1,reason:"unsupported"};let r=this.#r.watchEntries?.(t)??[],s=typeof i=="string"&&/^\d{1,4}$/.test(i)?r[Number(i)-1]:r.find(g=>g.sessionId===i);if(!s)return await A(w("\u5173\u6CE8\u5217\u8868\u91CC\u6CA1\u6709\u8FD9\u4E2A\u4F1A\u8BDD\uFF0C\u56DE\u590D /watchlist \u67E5\u770B\u3002")),{ok:!0,changed:!1,reason:"absent"};try{await this.#r.removeWatch(t,s.sessionId),this.#G.delete(`${t}\0${s.sessionId}`)}catch(g){return await A(w("\u53D6\u6D88\u5931\u8D25\uFF1A{message}",{message:uu(g)})),{ok:!1,changed:!1,reason:"persist"}}return await A(w("\u5DF2\u53D6\u6D88\u5173\u6CE8\u300C{title}\u300D\u3002",{title:String(s.title??"").replace(/\s+/gu," ")})),{ok:!0,changed:!0,entry:s}}async#Be(t,o,{updateMessageId:i=null,replyTo:e=null}={}){let a=this.#r.watchEntries?.(t)??[],A=[],r=null;try{if(r=typeof this.#t?.currentWorkspace=="function"?this.#t.currentWorkspace():null,r&&typeof this.#t?.listWorkspaceSessions=="function"){let s=await this.#t.listWorkspaceSessions(r,{signal:this.#V()});A=this.#ne(Array.isArray(s?.sessions)?s.sessions:[]).map(g=>({sessionId:g.sessionId,title:g.title??g.name??g.sessionId}))}}catch{}this.#oe(t,{kind:"watches",entries:a}),await this.#W(o,$W(a,A),{key:t,updateMessageId:i,replyTo:e,sessionWorkspace:r})}#cA({sessionId:t,event:o}){this.#w?.aborted||!t||!o||typeof o!="object"||o.type!=="turn/end"||!Qu(o.seq)||(this.#nA(t,o),this.#Re(t,async()=>{let i=this.#r.keysWatching?.(t)??[],e=i.some(A=>tS(this.#r.watchEntry?.(A,t))),a=i.some(A=>this.#G.has(`${A}\0${t}`));(e||a)&&await this.#Pe(t),await this.#ve(t,o)}))}async#ve(t,o,{keys:i=null}={}){if(this.#w?.aborted||typeof this.#r?.keysWatching!="function")return;let e=o?.data?.reason?.kind??o?.data?.reason??null,a=i??this.#r.keysWatching(t);for(let A of a){if(this.#w?.aborted)return;let r=this.#r.watchEntry?.(A,t),s=`${A}\0${t}`,g=this.#G.get(s);if(Qu(g)&&Qn(r?.lastSeq)&&r.lastSeq>=g&&(this.#G.delete(s),g=void 0),!(!r?.chatId||tS(r)||Qn(r.lastSeq)&&r.lastSeq>=o.seq||Qu(g)&&o.seq>g))try{await this.#W(r.chatId,e6(t,r.title,e),{key:A});let c=this.#r.watchEntry?.(A,t);if(!c||c.chatId!==r.chatId||tS(c)||Qn(c.lastSeq)&&c.lastSeq>=o.seq)continue;await this.#r.setWatch(A,{...c,lastSeq:o.seq}),g===o.seq&&this.#G.delete(s)}catch(c){this.#G.set(s,Qu(g)?Math.min(g,o.seq):o.seq),this.#D.warn?.("[dsh-feishu] completion push failed:",c.message)}}}async#Pe(t){if(!(this.#w?.aborted||typeof this.#t?.rpc!="function"))try{let o=await this.#t.rpc("session.history",{sessionId:t,maxMessages:20},3e4,{signal:this.#w}),i=YRe(o);this.#Ee();let e=this.#K.get(t)??new Map,a=new Map(i.map(g=>[g.seq,g]));for(let[g,c]of e)a.has(g)||a.set(g,c.event);let A=[...a.values()].sort((g,c)=>g.seq-c.seq),r=A.at(-1)?.seq??-1,s=typeof this.#r?.keysWatching=="function"?this.#r.keysWatching(t):[];for(let g of s){let c=this.#r.watchEntry?.(g,t);if(!tS(c))continue;let I=rS(c),d=Qn(c.lastSeq)?c.lastSeq:-1,B=I===null?null:A.find(_=>{if(_.seq<=d)return!1;let T=Number.isSafeInteger(_.time)&&_.time>=0?_.time:e.get(_.seq)?.arrivalAt;return Number.isSafeInteger(T)&&T>=I}),f=B?Math.max(d,B.seq-1):Math.max(d,r),Q=this.#r.watchEntry?.(g,t);if(!Q||Q.chatId!==c.chatId||Q.lastSeq!==c.lastSeq||rS(Q)!==I)continue;let{watchStartedAt:y,...m}=Q;await this.#r.setWatch(g,{...m,lastSeq:f})}for(let g of A)g.type==="turn/end"&&await this.#ve(t,g,{keys:s})}catch(o){this.#w?.aborted||this.#D.warn?.(`[dsh-feishu] watch compensation failed for ${t}:`,o.message)}}async#IA(){let t=typeof this.#r?.watchedSessionIds=="function"?this.#r.watchedSessionIds():[];this.#w?.aborted||await Promise.allSettled(t.map(o=>this.#ke(o)))}#fe(t,o,i){return{timeoutMs:this.#R,signal:this.#w,control:{owner:this,key:o},onInteraction:e=>this.#dA(e,{key:o,actor:yu(t),chatId:t.message.chat_id,requiresMention:t.message.chat_type!=="p2p",replyToMessageId:t.message.message_id}),onInteractionResolved:e=>this.#hA(e),files:i}}async#Qe(t,o,{deliveryId:i,presentation:e,replyTo:a=null}){let A=[];for(let r of HW(o)){this.#w?.throwIfAborted();let s=await this.#O(t,r,{replyTo:a});s&&A.push(s)}return Zt({deliveryId:i,presentation:e,providerMessageIds:A})}async#Ie(t,o,i=[],e){let a=await bo({artifacts:i,baseReceipt:e,deliveryId:e?.deliveryId??i[0]?.deliveryKey??o,aggregatePresentation:e?"feishu-text-and-files":"feishu-files",channelKey:"feishu",signal:this.#w,sendImage:typeof this.#A?.sendImage=="function"?A=>this.#A.sendImage(t,A,{replyTo:o,signal:this.#w}):void 0,sendFile:typeof this.#A?.sendFile=="function"?A=>this.#A.sendFile(t,A,{replyTo:o,signal:this.#w}):void 0,onFailure:(A,r)=>tt(this.#u,r,{userMessage:xRe(A?.fileName,r),reason:r?.code}),sendFailureNotice:async(A,r,s)=>({messageId:await this.#O(t,dt(s))}),logger:this.#D});return this.#u.artifactsSent=(this.#u.artifactsSent??0)+a.artifactsSent,this.#u.artifactSendErrors=(this.#u.artifactSendErrors??0)+a.artifactSendErrors,a.receipt?{receipt:a.receipt,failureNoticeVisible:a.failureNoticeVisible,artifactSendErrors:a.artifactSendErrors}:{receipt:Zt({deliveryId:o,presentation:"feishu-files"}),failureNoticeVisible:a.failureNoticeVisible,artifactSendErrors:a.artifactSendErrors}}async#lA(t,o,i,{onAskComplete:e}={}){let a=t.message.chat_id,A=t.message.message_id,r=i.content,s=!1,g=()=>{s||(s=!0,e?.())},c=Wt(i)?await Bo(i,{signal:this.#w}):void 0,I=this.#o.get(A);if(I&&(c=mo(c??r,I,()=>({channel:"feishu",senderId:yu(t)}))),!this.#A?.stream){let{answer:m,artifacts:_=[]}=await ui({harness:this.#t,state:this.#r,key:o,text:r,content:c,createOptions:{signal:this.#w},existsOptions:{signal:this.#w},askOptions:this.#fe(t,o,i.files)});g();let T,R=null;try{T=await this.#Qe(a,AS(m,_),{deliveryId:A,presentation:"feishu-text",replyTo:A})}catch(F){R=Ma(F),this.#D.warn?.("[dsh-feishu] final text delivery failed; continuing with result files:",F)}let L=await this.#Ie(a,A,_,T),U=L.receipt.artifacts.some(({outcome:F})=>F==="sent"||F==="unknown");if(R&&!U&&!L.failureNoticeVisible)throw R;return R&&L.artifactSendErrors===0&&tt(this.#u,R),this.#u.streamFallbacks=(this.#u.streamFallbacks??0)+1,{...L,textDeliveryErrors:R?1:0}}let d=!1,B="",f=[],Q;try{Q=await this.#A.stream(a,{markdown:async m=>{d=!0;let _={...this.#fe(t,o,i.files),onUpdate:async R=>{await m.setContent(this.#EA(R)),this.#u.streamUpdates=(this.#u.streamUpdates??0)+1}},T=await ui({harness:this.#t,state:this.#r,key:o,text:r,content:c,createOptions:{signal:this.#w},existsOptions:{signal:this.#w},askOptions:_});g(),B=T.answer,f=T.artifacts??[],await m.setContent(AS(B,f))}},{replyTo:A})}catch(m){if(this.#u.streamErrors=(this.#u.streamErrors??0)+1,B||f.length>0){this.#D.warn?.("[dsh-feishu] native stream failed after generation; sending final text:",m.message);let q,z=null;try{q=await this.#Qe(a,AS(B,f),{deliveryId:A,presentation:"feishu-text-fallback",replyTo:A})}catch(J){z=Ma(J),this.#D.warn?.("[dsh-feishu] fallback text delivery failed; continuing with result files:",J)}let j=await this.#Ie(a,A,f,q),P=j.receipt.artifacts.some(({outcome:J})=>J==="sent"||J==="unknown");if(z&&!P&&!j.failureNoticeVisible)throw z;return z&&j.artifactSendErrors===0&&tt(this.#u,z),this.#u.streamFallbacks=(this.#u.streamFallbacks??0)+1,{...j,textDeliveryErrors:z?1:0}}if(d)throw m;this.#D.warn?.("[dsh-feishu] native stream unavailable; using text fallback:",m.message);let{answer:_,artifacts:T=[]}=await ui({harness:this.#t,state:this.#r,key:o,text:r,content:c,createOptions:{signal:this.#w},existsOptions:{signal:this.#w},askOptions:this.#fe(t,o,i.files)});g();let R,L=null;try{R=await this.#Qe(a,AS(_,T),{deliveryId:A,presentation:"feishu-text-fallback",replyTo:A})}catch(q){L=Ma(q),this.#D.warn?.("[dsh-feishu] fallback text delivery failed; continuing with result files:",q)}let U=await this.#Ie(a,A,T,R),F=U.receipt.artifacts.some(({outcome:q})=>q==="sent"||q==="unknown");if(L&&!F&&!U.failureNoticeVisible)throw L;return L&&U.artifactSendErrors===0&&tt(this.#u,L),this.#u.streamFallbacks=(this.#u.streamFallbacks??0)+1,{...U,textDeliveryErrors:L?1:0}}let y=await this.#Ie(a,A,f,Zt({deliveryId:A,presentation:"feishu-cardkit",providerMessageIds:ka(Q)}));return this.#u.streamResponses=(this.#u.streamResponses??0)+1,y}async#pA(t,o,i,e,a){this.#w?.throwIfAborted();let A=this.#i.get(i),r=e.claimedReplyMessageId===o;if(!A||A!==e||A.submitting)return this.#ye(t,i)?this.#me(t,o):r&&(!A||A!==e)?this.#me(t,o):this.#j(t,o,i,a,{releaseMessageId:!1,finalize:!1});if(this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#u.lastMessageAt=new Date().toISOString(),this.#u.messagesReceived+=1;let s=Td(t);if(!s){await this.#O(t.message.chat_id,w("\u8BF7\u7528\u6587\u5B57\u56DE\u7B54\u5F53\u524D\u95EE\u9898\u3002"));return}let g=this.#i.get(i);if(!g||g!==e||g.submitting){if(this.#ye(t,i)){await this.#O(t.message.chat_id,$m(),{replyTo:t.message.message_id}).catch(()=>{});return}if(r&&(!g||g!==e)){await this.#O(t.message.chat_id,$m(),{replyTo:t.message.message_id});return}return this.#j(t,o,i,a,{releaseMessageId:!1,alreadyRecorded:!0,finalize:!1})}if(g.chatId=t.message.chat_id,g.needsPresentation){try{await this.#le(g)}catch{this.#u.lastError="\u98DE\u4E66\u4EA4\u4E92\u95EE\u9898\u53D1\u9001\u5931\u8D25\u3002",this.#D.error?.("[dsh-feishu] failed to retry an interaction question"),g.interaction.reconnect?.()}return}let c=g.questions[g.index];if(c){if(g.answers.push(Ei(c,s)),g.index+=1,g.index{});return}g.submitting=!1,g.answers.pop(),g.index-=1,this.#u.lastError="\u56DE\u7B54\u63D0\u4EA4\u5931\u8D25\u3002",this.#D.error?.("[dsh-feishu] failed to answer a Harness interaction"),await this.#O(t.message.chat_id,w("\u56DE\u7B54\u63D0\u4EA4\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u5F53\u524D\u95EE\u9898\u7684\u7B54\u6848\u3002")).catch(()=>{})}}}async#dA(t,{key:o,actor:i,chatId:e,requiresMention:a,replyToMessageId:A}){if(await this.#m.handleRequested(t,{key:o,actor:i,requiresMention:a,send:I=>this.#O(e,I,{replyTo:A})})||t?.kind!=="question")return;let r=t?.payload?.questions,s=typeof t?.interactionId=="string"?t.interactionId:t?.rpcId;if(typeof t.rpcId!="string"||typeof s!="string"||typeof t.sessionId!="string"||!Array.isArray(r)||r.length===0||r.some(I=>!di(I))){this.#D.warn?.("[dsh-feishu] ignored an invalid Harness question interaction");return}if(t.recovered===!0){await t.respond({ok:!1,error:{code:"cancelled",message:"Feishu safely cancelled an interaction left by an earlier client.",details:{}}}),await this.#O(e,w("\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"),{replyTo:A}).catch(()=>{});return}let g=this.#i.get(o);if(g?.interactionId===s){g.interaction=t,g.needsPresentation&&await this.#le(g);return}if(this.#I.has(s))return;if(g){await t.respond({ok:!1,error:{code:"cancelled",message:"Feishu is already handling another user interaction.",details:{}}});return}let c={kind:"question",interactionId:s,sessionId:t.sessionId,interaction:t,key:o,actor:i,requiresMention:a,questions:r,answers:[],index:0,chatId:e,replyToMessageId:A,queue:null,claimedReplyMessageId:null,submitting:!1,needsPresentation:!0,questionMessageIds:new Set,inactive:!1};this.#i.set(o,c),this.#I.set(c.interactionId,o),await this.#le(c)}async#hA(t){if(await this.#m.handleResolved(t))return;let o=t?.interactionId;if(t?.kind!=="question"||typeof o!="string")return;let i=this.#I.get(o);if(!i)return;let e=this.#i.get(i);e&&this.#se(i,e),this.#Se(i,o)}async#le(t){let o=t.questions[t.index];if(!o)return;let i=await this.#O(t.chatId,hi(o,t.index,t.questions.length,{requiresMention:t.requiresMention}),{replyTo:t.replyToMessageId});i&&(t.questionMessageIds.add(i),t.inactive&&this.#se(t.key,t)),t.needsPresentation=!1}#se(t,o){let i=Date.now()+BRe;for(let e of o.questionMessageIds??[])this.#l.set(e,{key:t,expiresAt:i})}#ye(t,o){let i=Date.now();for(let[e,a]of this.#l)a.expiresAt<=i&&this.#l.delete(e);for(let e of[t?.message?.parent_id,t?.message?.root_id]){let a=this.#l.get(e);if(a?.key===o&&a.expiresAt>i)return!0}return!1}async#me(t,o){this.#r.hasSeen(o)||(await this.#r.markSeen(o),this.#u.lastMessageAt=new Date().toISOString(),this.#u.messagesReceived+=1,await this.#O(t.message.chat_id,$m(),{replyTo:t.message.message_id}).catch(()=>{}))}#Ge(t,o){let i=this.#i.get(t);return!i||o!==void 0&&i.interactionId!==o?null:(this.#i.delete(t),this.#I.delete(i.interactionId),i.inactive=!0,i)}#Se(t,o){return this.#Ge(t,o)!==null}async#we(t){let o=this.#Ge(t);if(!(!o||o.kind!=="question")){this.#se(t,o);try{await o.interaction.respond({ok:!1,error:{code:"cancelled",message:"The Feishu interaction ended before the user answered.",details:{}}},{signal:AbortSignal.timeout(5e3)})}catch(i){i?.code!=="interaction-not-pending"&&this.#D.warn?.("[dsh-feishu] failed to cancel a pending Harness interaction")}}}#EA(t){return t.type==="text"&&t.text?t.text:t.type==="tool"?t.name==="web_search"?w("_\u6B63\u5728\u641C\u7D22\u7F51\u7EDC\u5E76\u6574\u7406\u4FE1\u606F\u2026_"):w("_\u6B63\u5728\u4F7F\u7528 {name}\u2026_",{name:t.name||w("\u5DE5\u5177")}):w("_{text}_",{text:t.text||w("\u6B63\u5728\u5904\u7406\u2026")})}#CA(t){return PQ({adapter:this.#A,target:t,reactions:{processing:"OnIt",success:"DONE",error:"ERROR"},status:this.#u,logger:this.#D,label:"feishu"})}#Fe(t,o){o.clear()}#ee(t,o,i){i==="ERROR"?o.error():o.success()}async#O(t,o,{replyTo:i}={}){let e=JSON.stringify({text:o});if(i)try{let A=await this.#e.im.v1.message.reply({path:{message_id:i},data:{msg_type:"text",content:e}});if(A?.code&&A.code!==0)throw new Error(`Feishu reply failed: ${A.msg||A.code}`);return pA(A?.data?.message_id)}catch(A){this.#D.warn?.("[dsh-feishu] threaded reply failed; falling back to a plain message:",A?.message??String(A))}let a=await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"text",content:e}});if(a?.code&&a.code!==0)throw new Error(`Feishu send failed: ${a.msg||a.code}`);return pA(a?.data?.message_id)}};import{createHash as zRe}from"node:crypto";var d6="stream_md",VRe="\u5DF2\u8FDE\u63A5 DeepSeek Harness\uFF0C\u6B63\u5728\u601D\u8003\u2026",Su=28e3,iS=12e4,h6=new Map([[99991672,["artifact-permission-required","Feishu file delivery requires the im:resource permission."]],[234006,["artifact-too-large","The result file exceeds Feishu's size limit."]],[234010,["artifact-empty","Feishu does not accept empty files."]],[230017,["artifact-provider-rejected","Feishu rejected the uploaded file ownership."]],[230020,["artifact-rate-limited","Feishu temporarily rate-limited file delivery."]],[230049,["artifact-delivery-uncertain","Feishu could not confirm the file message result."]],[230055,["artifact-provider-rejected","Feishu rejected the file message type."]]]);function sl(n,t){if(t?.code&&t.code!==0)throw new Error(`${n} failed: ${t.msg||t.code}`);return t}function E6(n){let t=[n],o=new Set,i;for(;t.length>0;){let e=t.shift();if(!e||o.has(e))continue;if(typeof e=="object"&&o.add(e),Array.isArray(e)){t.push(...e);continue}let a=Number(e?.code);if(Number.isFinite(a)&&a!==0){if(h6.has(a))return a;i??=a}t.push(e?.response?.data,e?.data,e?.error,e?.cause)}return i}function mu(n,t,o,{uncertain:i=!1}={}){let e=o==null?void 0:Number(o),a=Number.isFinite(e)&&e!==0?e:E6(t),A=Number.isFinite(a)?["artifact-provider-rejected",`Feishu rejected file ${n}.`]:i?["artifact-delivery-uncertain","Feishu could not confirm the file message result."]:["artifact-provider-failed",`Feishu file ${n} failed.`],[r,s]=h6.get(a)??A,g=new Error(s,{cause:t});return g.code=r,Number.isFinite(a)&&(g.providerCode=a),g}function I6(n,t){if(!Number.isInteger(n)||n<1||n>iS)throw new TypeError(`${t} must be an integer between 1 and ${iS}`);return n}function Wv(n){return n?.reason??new DOMException("The operation was aborted","AbortError")}function WRe(n){let t=new Error(`Feishu file ${n} timed out.`);return t.code="provider-timeout",t}function l6(n,{signal:t,timeoutMs:o,stage:i}){t?.throwIfAborted();let e=new AbortController,a=t?AbortSignal.any([t,e.signal]):e.signal;return new Promise((A,r)=>{let s=!1,g=(d,B)=>{s||(s=!0,clearTimeout(I),a.removeEventListener("abort",c),d(B))},c=()=>g(r,t?.aborted?Wv(t):WRe(i)),I=setTimeout(()=>e.abort(),o);a.addEventListener("abort",c,{once:!0}),Promise.resolve().then(()=>n(a)).then(d=>g(A,d),d=>g(r,d)),a.aborted&&c()})}function ZRe(n,t,o){let i=`${n.deliveryKey}\0${t}`;return`dshim_${zRe("sha256").update(o==="file"?i:`${i}\0${o}`).digest("hex").slice(0,40)}`}function XRe(n){let t=String(n??"").replace(/\s+/g," ").trim();return t.length<=50?t:`${Zv(t,49)}\u2026`}function Zv(n,t){let o=Math.min(n.length,t),i=n.charCodeAt(o-1),e=n.charCodeAt(o);return i>=55296&&i<=56319&&e>=56320&&e<=57343&&(o-=1),n.slice(0,o)}function p6(n){if(n.length<=Su)return n;let t=` +{url}`,{url:o}))}}#re(t,{verificationFocused:o=!1}={}){if(t.state==="succeeded")return w("\u2705 \u4FEE\u590D\u5B8C\u6210\uFF1A\u5DF2\u5B9E\u6D4B\u6536\u5230 card.action.trigger\uFF0C\u83DC\u5355\u6309\u94AE\u73B0\u5728\u53EF\u7528\u3002");if(t.state==="expired"||t.error?.code==="expired_token")return w("\u6388\u6743\u94FE\u63A5\u5DF2\u8FC7\u671F\uFF1B\u5E73\u53F0\u672A\u8FD4\u56DE\u6210\u529F\u7ED3\u679C\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5DF2\u4FEE\u590D\u3002\u53D1\u9001 /repair \u751F\u6210\u65B0\u94FE\u63A5\u3002");if(t.state==="cancelled"||t.error?.code==="abort")return w("\u5DF2\u53D6\u6D88\u672C\u6B21\u4FEE\u590D\u6388\u6743\uFF0C\u672A\u786E\u8BA4\u5B8C\u6210\u4FEE\u590D\u3002");if(t.error?.code==="access_denied")return w("\u4F60\u5DF2\u53D6\u6D88\u6216\u62D2\u7EDD\u6388\u6743\uFF0C\u6CA1\u6709\u786E\u8BA4\u4FEE\u590D\uFF1B\u53D1\u9001 /repair \u53EF\u91CD\u8BD5\u3002");if(t.error?.code==="card_action_probe_timeout"||t.error?.code==="card-action-probe-timeout")return w("\u6388\u6743\u5DF2\u63D0\u4EA4\uFF0C\u4F46\u672A\u6536\u5230\u6D4B\u8BD5\u6309\u94AE\u56DE\u8C03\u3002\u53EF\u80FD\u5C1A\u672A\u70B9\u51FB\u6216\u914D\u7F6E\u4ECD\u5728\u4F20\u64AD\uFF1B\u7A0D\u540E\u53D1\u9001 /repair verify \u67E5\u8BE2\uFF0C\u4E0D\u8981\u76F2\u76EE\u91CD\u590D\u6388\u6743\u3002");if(t.state==="error")return w("\u4FEE\u590D\u6D41\u7A0B\u6682\u65F6\u5931\u8D25\uFF0C\u73B0\u6709\u673A\u5668\u4EBA\u8FDE\u63A5\u4E0D\u53D7\u5F71\u54CD\uFF1B\u53D1\u9001 /repair \u53EF\u91CD\u8BD5\u3002");if(t.state==="saving")return w("\u6388\u6743\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u7B49\u5F85\u4E13\u7528\u6D4B\u8BD5\u6309\u94AE\u7684\u771F\u5B9E\u56DE\u8C03\uFF1B\u56DE\u8C03\u5230\u8FBE\u524D\u4E0D\u4F1A\u5BA3\u544A\u6210\u529F\u3002");if(o)return w("\u6388\u6743\u5C1A\u672A\u5B8C\u6210\uFF0C\u6682\u65F6\u4E0D\u80FD\u9A8C\u8BC1\u5361\u7247\u6309\u94AE\u3002\u8BF7\u5148\u6253\u5F00\u6388\u6743\u94FE\u63A5\u5E76\u786E\u8BA4\u3002");let i=t.remainingSeconds===null?"":w("\uFF0C\u5269\u4F59\u7EA6 {minutes} \u5206\u949F",{minutes:Math.max(1,Math.ceil(t.remainingSeconds/60))});return w("\u4FEE\u590D\u4EFB\u52A1\u6B63\u5728\u7B49\u5F85\u6388\u6743{remaining}\u3002\u53D1\u9001 /repair qr \u53EF\u83B7\u53D6\u4E8C\u7EF4\u7801\uFF0C/repair cancel \u53EF\u53D6\u6D88\u3002",{remaining:i})}onCardAction(t){let o=pA(t?.operator?.open_id)??pA(t?.operator?.user_id)??pA(t?.operator?.operator_id?.open_id)??pA(t?.operator?.operator_id?.user_id)??pA(t?.open_id)??pA(t?.user_id);if(!(o!==null&&(this.#b.has("*")||this.#b.has(o))))return this.#D.warn?.("[dsh-feishu] ignoring card action from an unallowed sender"),Promise.resolve();let e=n6(t?.action?.value),a=n6(t?.action?.form_value),A=pA(e.action)??pA(t?.action?.action);if(!A)return Promise.resolve();let r=fu(t?.action?.option)??(A.endsWith("_pick")?Qg(t?.action?.options)[0]:null),s=[...new Set([...Qg(e.options),...Qg(t?.action?.options),...Qg(a[A]),...A==="watch_add"||A==="watch_remove"?Qg(t?.action?.option):[]])],g=A==="workspace_pick"&&typeof r=="string"?`workspace:${r}`:A==="session_pick"&&typeof r=="string"?`use:${r}`:A==="preset_pick"&&typeof r=="string"?`preset:select:${r}`:A==="model_pick"&&typeof r=="string"?`model:select:${r}`:A==="archive_pick"&&typeof r=="string"?`archive:${r}`:A==="steer_pick"&&typeof r=="string"?`steer:${r}`:A,c=pA(t?.context?.open_message_id)??pA(t?.open_message_id)??pA(t?.message_id),I=c?this.#H.get(c):null;if(!I){let L=pA(t?.context?.open_chat_id)??pA(t?.open_chat_id)??pA(t?.chat_id);return L&&this.#O(L,w("\u8FD9\u4E2A\u83DC\u5355\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u56DE\u590D /m \u91CD\u65B0\u6253\u5F00\u3002"),{replyTo:c}).catch(()=>{}),Promise.resolve()}this.#H.delete(c),this.#H.set(c,I);let d={...I,messageId:c,selections:s,operatorOpenId:o},B=pA(e.source),f=pA(a.steer_text),Q=pA(t?.event_id)??pA(t?.header?.event_id)??pA(t?.uuid)??pA(t?.header?.uuid),y=JSON.stringify({messageId:c,resolvedAction:g,option:r,multiValues:s,source:B,formText:f}),m=g==="stop",_=g.startsWith("steer:")?g.slice(6):null,R=A==="steer"&&B==="quick"&&r!==null&&r!==Cu||A==="steer"&&B==="form"&&f!==null||_!==null&&_!==""&&!(_==="custom"||_===Cu);return this.#Je(d,y,async()=>{if(A==="steer"){if(B==="quick"&&r){if(r===Cu){await this.#W(d.chatId,qv(),{key:d.key,updateMessageId:d.messageId});return}await this.#he(d,r);return}if(B==="form"){if(f){await this.#he(d,f);return}await this.#O(d.chatId,w("\u8BF7\u8F93\u5165\u8865\u5145\u6307\u4EE4\u540E\u518D\u63D0\u4EA4\u3002"),{replyTo:d.messageId??null});return}}await this.#ie(g,d)},{lane:m||R?"control":"regular",coalesceStop:m,eventId:Q,operatorOpenId:o})}#be(t=Date.now()){for(let[o,i]of this.#S)i<=t&&this.#S.delete(o);for(;this.#S.size>i6;){let o=this.#S.keys().next().value;if(o===void 0)break;this.#S.delete(o)}}#Me(t,o=Date.now()){t&&(this.#S.delete(t),this.#S.set(t,o+TRe),this.#be(o))}#je(t){let o=t.key,i=Date.now(),e=this.#Q.get(o);if(e?.task||e&&i-e.at{}).finally(()=>{this.#p.delete(a);let A=this.#Q.get(o);A?.task===a&&this.#Q.set(o,{at:A.at,task:null})}),this.#Q.delete(o),this.#Q.set(o,{at:i,task:a}),this.#p.add(a);this.#Q.size>200;){let A=this.#Q.keys().next().value;if(A===void 0)break;this.#Q.delete(A)}return a}#Je(t,o,i,{lane:e="regular",coalesceStop:a=!1,eventId:A=null,operatorOpenId:r=null}={}){let s=t.key,g=A?`${s}\0${r??""}\0event:${A}`:null,c=g??`${s}\0${r??""}\0action:${o}`,I=Date.now();if(this.#be(I),g&&(this.#S.get(g)??0)>I)return Promise.resolve();let d=this.#f.get(c);if(d)return d;if(a){let U=this.#B.get(s);if(U){if(g)for(this.#y.delete(g),this.#y.set(g,U);this.#y.size>i6;){let F=this.#y.keys().next().value;if(F===void 0)break;this.#y.delete(F)}return U}}let B=e==="control",f=B?this.#h:this.#d,Q=B?this.#C:this.#E,y=B?_Re:MRe,m=Q.get(s)??0,_=a?y+1:y;if(m>=_)return this.#je(t);let T=f.get(s)??Promise.resolve();Q.set(s,m+1);let R,L=!1;return R=T.catch(()=>{}).then(async()=>{this.#w?.throwIfAborted(),L=!0,await i()}).catch(async U=>{this.#w?.aborted||await this.#x(t.chatId,U,{logLabel:"card action"})}).finally(()=>{if(this.#f.get(c)===R&&this.#f.delete(c),L&&g&&this.#Me(g),a&&this.#B.get(s)===R&&this.#B.delete(s),a){let F=Date.now();for(let[q,z]of this.#y)z===R&&(this.#y.delete(q),this.#Me(q,F))}f.get(s)===R&&f.delete(s);let U=(Q.get(s)??1)-1;U>0?Q.set(s,U):Q.delete(s),this.#p.delete(R)}),this.#f.set(c,R),a&&this.#B.set(s,R),this.#p.add(R),f.set(s,R),R}async#ie(t,{chatId:o,key:i,messageId:e=null,sessionWorkspace:a=null,sessionPage:A=0,selections:r=[]}){let s=g=>this.#O(o,g,{replyTo:e});if(t==="sessions"||/^sessions:\d+$/.test(t)){let g=t==="sessions"?0:Number(t.slice(9));await this.#ce({chatId:o,key:i,replyTo:e},a,g,{updateMessageId:e});return}if(t==="workspaces"){await this.#_e({chatId:o,key:i,replyTo:e},{updateMessageId:e});return}if(t==="watchlist"){await this.#Be(i,o,{updateMessageId:e,replyTo:e});return}if(t==="watch_add"||t==="watch_remove"){if(r.length===0){await s(w("\u8BF7\u5148\u9009\u62E9\u81F3\u5C11\u4E00\u4E2A\u4F1A\u8BDD\u3002"));return}let g=0,c=0;if(t==="watch_add"){let d=new Map;try{d=await this.#gA(a)}catch(B){this.#D.warn?.("[dsh-feishu] batch watch validation failed:",B.message)}for(let B of r){let f=d.get(B);if(!f){c+=1;continue}let Q=await this.#Ce(i,o,B,{notify:!1,validatedTarget:f});Q.changed?g+=1:Q.ok||(c+=1)}}else for(let d of r){let B=await this.#ue(i,o,d,{notify:!1});B.changed?g+=1:B.ok||(c+=1)}let I=g>0&&c>0?t==="watch_add"?w("\u5DF2\u6279\u91CF\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u53E6\u6709 {failed} \u4E2A\u672A\u6210\u529F\u3002",{count:g,failed:c}):w("\u5DF2\u53D6\u6D88\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u53E6\u6709 {failed} \u4E2A\u672A\u6210\u529F\u3002",{count:g,failed:c}):g>0?t==="watch_add"?w("\u5DF2\u6279\u91CF\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:g}):w("\u5DF2\u53D6\u6D88\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:g}):c>0?w("\u6240\u9009\u4F1A\u8BDD\u5747\u672A\u5904\u7406\u6210\u529F\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"):t==="watch_add"?w("\u6240\u9009\u4F1A\u8BDD\u5DF2\u5728\u5173\u6CE8\u5217\u8868\u4E2D\u3002"):w("\u6240\u9009\u4F1A\u8BDD\u5DF2\u4E0D\u5728\u5173\u6CE8\u5217\u8868\u4E2D\u3002");try{await this.#Be(i,o,{updateMessageId:e,replyTo:e})}catch(d){this.#D.warn?.("[dsh-feishu] watch list refresh failed:",d.message)}await s(I).catch(d=>{this.#D.warn?.("[dsh-feishu] watch batch summary failed:",d.message)});return}if(t==="new"){if(this.#a.has(i)||this.#ae(i)){await s(w("\u5F53\u524D\u4EFB\u52A1\u4ECD\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u505C\u6B62\u4EFB\u52A1\u6216\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210\u540E\u518D\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002"));return}await this.#r.clearSession(i),await s(w("\u5DF2\u5F00\u542F\u5168\u65B0 Harness \u4F1A\u8BDD\u3002")),await this.#Z(i,o,{updateMessageId:e,replyTo:e});return}if(t==="use:current"){let g=this.#r.sessionFor(i);if(typeof g!="string"||!g){await s(w("\u5F53\u524D\u6CA1\u6709\u7ED1\u5B9A\u7684\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u4ECE\u4F1A\u8BDD\u5217\u8868\u9009\u62E9\u3002"));return}await s(w("\u5DF2\u5C31\u7EEA\uFF0C\u76F4\u63A5\u53D1\u6D88\u606F\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002"));return}if(t==="archive_toggle"||t==="archive:on"||t==="archive:off"){let g=t==="archive:on"?!0:t==="archive:off"?!1:!(this.#r?.includesArchivedSessions?.()??!1);await this.#r?.setIncludeArchivedSessions?.(g),await s(g?w("\u5DF2\u5F00\u542F\uFF1A\u4F1A\u8BDD\u5217\u8868\u5305\u542B\u5F52\u6863\u4F1A\u8BDD\u3002"):w("\u5DF2\u5173\u95ED\uFF1A\u4F1A\u8BDD\u5217\u8868\u9690\u85CF\u5F52\u6863\u4F1A\u8BDD\u3002")),await this.#Z(i,o,{updateMessageId:e,replyTo:e});return}if(t==="repair"){await s(w("\u4FEE\u590D\u9700\u5728\u79C1\u804A\u4E2D\u9A8C\u8BC1\u63A5\u5165\u8005\u8EAB\u4EFD\uFF0C\u8BF7\u76F4\u63A5\u53D1\u9001 /repair \u5F00\u59CB\u3002"));return}if(t==="compact"){await this.#tA(i,o,e);return}if(t==="stop"){await this.#rA(i,o,e);return}if(t==="steer"){await this.#aA(i,o,{updateMessageId:e});return}if(t.startsWith("steer:")){let g=t.slice(6);if(g==="custom"){await this.#W(o,qv(),{key:i,updateMessageId:e,replyTo:e});return}await this.#he({key:i,chatId:o,messageId:e},g);return}if(t==="presets"){await this.#Ze(i,o,{updateMessageId:e});return}if(t==="models"){await this.#Xe(i,o,{updateMessageId:e});return}if(t==="status"){await this.#eA(i,o,{updateMessageId:e});return}if(t==="help"){await this.#AA(i,o,{updateMessageId:e});return}if(t==="back_to_menu"){await this.#Z(i,o,{updateMessageId:e,replyTo:e});return}if(t==="preset_default"){await this.#Te(i,o,{updateMessageId:e});return}if(t.startsWith("preset:select:")){let g=t.slice(14);if(g===qm){await this.#Te(i,o,{updateMessageId:e});return}await this.#iA(i,o,g,{updateMessageId:e});return}if(t.startsWith("model:select:")){let g=t.slice(13);await this.#oA(i,o,g,{updateMessageId:e});return}if(t.startsWith("use:")){await this.#Ve(i,o,t.slice(4),{updateMessageId:e,replyTo:e});return}if(t.startsWith("workspace:")){await this.#We(i,o,t.slice(10),{updateMessageId:e,replyTo:e});return}if(t.startsWith("unwatch:")){(await this.#ue(i,o,t.slice(8),{replyTo:e})).ok&&e&&await this.#ce({chatId:o,key:i,replyTo:e},a,A,{updateMessageId:e});return}if(t.startsWith("watch:")){let g=t.slice(6);(await this.#Ce(i,o,g,{workspaceHint:a,replyTo:e})).ok&&e&&await this.#ce({chatId:o,key:i,replyTo:e},a,A,{updateMessageId:e})}}#oe(t,o){if(this.#Y.size>=bRe){let i=this.#Y.keys().next().value;i!==void 0&&this.#Y.delete(i)}this.#Y.delete(t),this.#Y.set(t,{...o,expiresAt:Date.now()+ORe})}#qe(t){let o=this.#Y.get(t);return o?o.expiresAtthis.#O(i,s,{replyTo:A});if(t.kind==="menu"){let g=["workspaces","new","sessions","status","repair","help"][o-1];if(!g){await r(w("\u83DC\u5355\u6CA1\u6709\u8FD9\u4E2A\u7F16\u53F7\uFF0C\u56DE\u590D /m \u91CD\u65B0\u6253\u5F00\u3002"));return}if(g==="repair"){await this.#Oe(a,"/repair");return}await this.#ie(g,{chatId:i,key:e,messageId:A});return}if(t.kind==="sessions"){let s=t.sessions[o-1];if(!s?.sessionId){await r(w("\u672C\u9875\u53EA\u6709 {count} \u4E2A\u4F1A\u8BDD\uFF0C\u56DE\u590D /sessionlist \u91CD\u65B0\u67E5\u770B\u3002",{count:t.sessions.length}));return}await this.#ie(`use:${s.sessionId}`,{chatId:i,key:e,messageId:A});return}if(t.kind==="workspaces"){let s=t.paths[o-1];if(!s){await r(w("\u53EA\u6709 {count} \u4E2A\u5DE5\u4F5C\u533A\uFF0C\u56DE\u590D /workspacelist \u91CD\u65B0\u67E5\u770B\u3002",{count:t.paths.length}));return}await this.#ie(`workspace:${s}`,{chatId:i,key:e,messageId:A});return}if(t.kind==="watches"){let s=t.entries[o-1];if(!s?.sessionId){await r(w("\u5173\u6CE8\u5217\u8868\u53EA\u6709 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:t.entries.length}));return}await this.#ie(`unwatch:${s.sessionId}`,{chatId:i,key:e,messageId:A})}}#ne(t){return this.#r?.includesArchivedSessions?.()===!1?t.filter(o=>o.archived!==!0):t}async#ce({chatId:t,key:o,replyTo:i=null},e,a=0,{updateMessageId:A=null}={}){try{let r=this.#V(),s=await YM(e??"",this.#t,{signal:r});if(s.error){await this.#O(t,s.error,{replyTo:i});return}let g=await this.#t.listWorkspaceSessions(s.workspace,{signal:r}),c=this.#ne(Array.isArray(g?.sessions)?g.sessions:[]),I=g?.workspace??s.workspace;if(c.length===0){await this.#O(t,w(`\u5DE5\u4F5C\u533A\uFF1A{workspace} +\u8BE5\u5DE5\u4F5C\u533A\u6682\u65E0\u4F1A\u8BDD\u3002`,{workspace:I}),{replyTo:i});return}let d=Math.ceil(c.length/wc),B=Number.isSafeInteger(a)&&a>0?Math.min(a,d-1):0,f=new Set((this.#r.watchEntries?.(o)??[]).map(y=>y.sessionId)),Q=c.slice(B*wc,(B+1)*wc);this.#oe(o,{kind:"sessions",sessions:Q.map(y=>({...y,watched:f.has(y.sessionId)}))}),await this.#W(t,ZW(I,c,B,c.length,f),{key:o,updateMessageId:A,replyTo:i,sessionWorkspace:s.workspace,sessionPage:B})}catch(r){await this.#x(t,r,{logLabel:"session list"})}}async#_e({chatId:t,key:o,replyTo:i=null},{updateMessageId:e=null}={}){try{let{current:a,paths:A}=await TE(this.#t,{signal:this.#V()});this.#oe(o,{kind:"workspaces",paths:A}),await this.#W(t,XW(A,a),{key:o,updateMessageId:e,replyTo:i})}catch(a){await this.#x(t,a,{logLabel:"workspace list"})}}async#Ve(t,o,i,{updateMessageId:e=null,replyTo:a=null}={}){try{let A=await this.#t.bindWorkspaceSession(t,i),r=String(A?.title??"").replace(/\s+/gu," ").trim()||w("\u6682\u65E0\u6807\u9898");await this.#O(o,[w(`\u5DF2\u7ED1\u5B9A\u4F1A\u8BDD\u300C{title}\u300D +ID\uFF1A{id}`,{title:r,id:A?.sessionId??i}),w("\u53D1\u9001 /history \u67E5\u770B\u6700\u8FD1\u5BF9\u8BDD\u3002")].join(` +`),{replyTo:a}),await this.#Z(t,o,{updateMessageId:e,replyTo:a})}catch(A){await this.#x(o,A,{logLabel:"session binding",userMessage:w("\u7ED1\u5B9A\u5931\u8D25\uFF1A{message}",{message:uu(A)})})}}async#We(t,o,i,{updateMessageId:e=null,replyTo:a=null}={}){try{let A=await this.#t.switchWorkspace(i);await this.#O(o,w("\u5DE5\u4F5C\u533A\u5DF2\u5207\u6362\u4E3A\uFF1A{workspace}",{workspace:A}),{replyTo:a}),await this.#Z(t,o,{updateMessageId:e,replyTo:a})}catch(A){await this.#x(o,A,{logLabel:"workspace switch",userMessage:w("\u5207\u6362\u5931\u8D25\uFF1A{message}",{message:uu(A)})})}}#de(t,o,i){if(!(!i.key||!t)&&(this.#H.delete(t),this.#H.set(t,{key:i.key,chatId:o,sessionWorkspace:typeof i.sessionWorkspace=="string"&&i.sessionWorkspace?i.sessionWorkspace:null,sessionPage:Number.isSafeInteger(i.sessionPage)&&i.sessionPage>=0?i.sessionPage:0}),this.#H.size>200)){let e=this.#H.keys().next().value;e!==void 0&&this.#H.delete(e)}}async#W(t,o,i={}){let e=pA(i.updateMessageId),a=pA(i.replyTo);if(e)try{let g=await this.#e.im.v1.message.patch({path:{message_id:e},data:{content:o}});if(g?.code&&g.code!==0)throw new Error(`Feishu card update failed: ${g.msg||g.code}`);return this.#de(e,t,i),e}catch(g){this.#D.warn?.("[dsh-feishu] card update failed:",g?.code??g?.message??g,"sending new")}let A=o;if(a)try{let g=await this.#e.im.v1.message.reply({path:{message_id:a},data:{msg_type:"interactive",content:A}});if(g?.code&&g.code!==0)throw new Error(`Feishu card reply failed: ${g.msg||g.code}`);let c=pA(g?.data?.message_id);if(c)return this.#de(c,t,i),c}catch(g){this.#D.warn?.("[dsh-feishu] threaded card reply failed; sending a plain card:",g?.message??String(g))}let r=await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"interactive",content:o}});if(r?.code&&r.code!==0)throw new Error(`Feishu card send failed: ${r.msg||r.code}`);let s=pA(r?.data?.message_id);return this.#de(s,t,i),s}async#Z(t,o,{updateMessageId:i=null,replyTo:e=null}={}){let a=null,A=null;try{let U=this.#r.sessionFor(t);if(typeof U=="string"&&U){a=U;let F=this.#t.workspaceSession?.(U);A=pA(F?.title)??pA(F?.name)??pA(F?.displayName)}}catch{}let r=this.#V(),s=TE(this.#t,{signal:r}).catch(()=>{let U=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;return{current:U,paths:U?[U]:[]}}),g=(async()=>{let U=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;if(!U||typeof this.#t.listWorkspaceSessions!="function")return[];try{let F=await this.#t.listWorkspaceSessions(U,{signal:r});return this.#ne(Array.isArray(F?.sessions)?F.sessions:[])}catch{return[]}})(),c=(async()=>{try{let U=await this.#t.agentPresetSettings({signal:r});return{...U.agentPresetCatalog,_currentId:U.agentPreset}}catch{return null}})(),I=(async()=>{try{if(a){let U=this.#t.workspaceSession?.(a);if(typeof U?.models=="function")return await U.models({signal:r})}return await this.#t.listModels({signal:r})}catch{return null}})(),[d,B,f,Q]=await Promise.all([s,g,c,I]),y=Array.isArray(d.paths)?d.paths:[],m=d.current??null,_=B.find(U=>U.sessionId===a),T=a?pA(_?.title)??pA(_?.name)??A??a:null,R=B.map(U=>({id:U.sessionId,title:U.title??U.name??U.sessionId})).slice(0,20);a&&(R=R.filter(U=>U.id!==a),R.unshift({id:a,title:T??a}),R=R.slice(0,20));let L=this.#r?.includesArchivedSessions?.()??!1;this.#oe(t,{kind:"menu",chatId:o}),await this.#W(o,YW({workspaces:y,currentWorkspace:m,currentSession:a?{id:a,title:T}:null,sessions:R,archiveVisible:L,presetCatalog:f,modelCatalog:Q}),{key:t,updateMessageId:i,replyTo:e})}async#uA(t,o){try{if(typeof this.#t.workspaceSession=="function"){let e=this.#t.workspaceSession(o);if(e&&typeof e=="object"){let a=pA(e.title)??pA(e.name)??pA(e.displayName);if(a)return a}}let i=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;if(i&&typeof this.#t.listWorkspaceSessions=="function"){let e=await this.#t.listWorkspaceSessions(i),a=(Array.isArray(e?.sessions)?e.sessions:[]).find(A=>A.sessionId===o);if(a){let A=pA(a.title)??pA(a.name);if(A)return A}}}catch{}return null}async#Ze(t,o,{updateMessageId:i=null}={}){try{let e=await this.#t.agentPresetSettings({signal:this.#V()}),a=e.agentPresetCatalog;a._currentId=e.agentPreset,await this.#W(o,jW(a),{key:t,updateMessageId:i})}catch(e){await this.#x(o,e,{logLabel:"preset card"})}}async#Xe(t,o,{updateMessageId:i=null}={}){try{let e=this.#V();await this.#t.ensureRunning({signal:e});let a=this.#r?.sessionFor?.(t),A;if(typeof a=="string"&&a){let r=this.#t.workspaceSession(a);r?.models&&(A=await r.models({signal:e}))}A||(A=await this.#t.listModels({signal:e})),await this.#W(o,JW(A),{key:t,updateMessageId:i})}catch(e){await this.#x(o,e,{logLabel:"model card"})}}async#$e(t,o,i=null){try{await this.#t.ensureRunning({signal:this.#w});let e=[w("\u8FDE\u63A5\u6B63\u5E38")],a=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;a&&e.push(w("\u5DE5\u4F5C\u533A\uFF1A{workspace}",{workspace:a}));let A=typeof this.#t.agentPresetSettings=="function"?await this.#t.agentPresetSettings({signal:this.#w}).catch(()=>null):null;if(A){let r=A.agentPresetCatalog?.items?.find(s=>s.id===A.agentPreset);e.push(w("\u9884\u8BBE\uFF1A{preset}",{preset:r?`${r.label}\uFF08${r.id}\uFF09`:A.agentPreset||w("\u8DDF\u968F\u9ED8\u8BA4")}))}await this.#O(o,e.join(` +`),{replyTo:i})}catch(e){await this.#x(o,e,{logLabel:"status text"})}}async#eA(t,o,{updateMessageId:i=null}={}){try{let e=this.#V();await this.#t.ensureRunning({signal:e});let a={connected:!0,workspace:null,preset:null,model:null,sessionCount:0};try{let A=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;a.workspace=A||w("\u672A\u77E5")}catch{}try{let A=await this.#t.agentPresetSettings({signal:e}),r=A.agentPresetCatalog.items.find(s=>s.id===A.agentPreset);a.preset=r?`${r.label}\uFF08${r.id}\uFF09`:A.agentPreset||w("\u8DDF\u968F\u9ED8\u8BA4")}catch{}try{let A=this.#r?.sessionFor?.(t);if(typeof A=="string"&&A){let r=this.#t.workspaceSession(A);if(r?.models){let s=await r.models({signal:e});s.current&&(a.model=`${s.current.provider}/${s.current.model}`)}}}catch{}try{let A=typeof this.#t.currentWorkspace=="function"?this.#t.currentWorkspace():null;if(A){let r=await this.#t.listWorkspaceSessions(A,{signal:e});Array.isArray(r?.sessions)&&(a.sessionCount=r.sessions.length)}}catch{}await this.#W(o,qW(a),{key:t,updateMessageId:i})}catch(e){await this.#x(o,e,{logLabel:"status card"})}}async#AA(t,o,{updateMessageId:i=null}={}){await this.#W(o,VW(KRe.map(e=>w(e))),{key:t,updateMessageId:i})}async#tA(t,o,i=null){try{let e=await Bi("/compact",this.#t,this.#r,t,{signal:this.#w});await this.#O(o,e?.message||w("\u4E0A\u4E0B\u6587\u538B\u7F29\u5931\u8D25\u3002"),{replyTo:i})}catch(e){await this.#x(o,e,{logLabel:"compact"})}}async#rA(t,o,i=null){try{let e=await Qi("/stop",this.#t,this.#r,t,{signal:this.#w,control:{owner:this,key:t}});e?.stopped&&await Promise.allSettled([this.#we(t),this.#m.closeRoute(t)]),await this.#O(o,e?.message||w("/stop \u6267\u884C\u5B8C\u6210\u3002"),{replyTo:i})}catch(e){await this.#x(o,e,{logLabel:"stop"})}}async#aA(t,o,{updateMessageId:i=null}={}){let e=!!this.#r.sessionFor?.(t);this.#oe(t,{kind:"steer"}),await this.#W(o,t6({hasSession:e}),{key:t,updateMessageId:i})}async#he(t,o){let{key:i,chatId:e}=t,a=await Qi(`/steer ${o}`,this.#t,this.#r,i,{signal:this.#w,pendingInteraction:this.#ae(i),control:{owner:this,key:i}});await this.#O(e,a?.message||w("\u5DF2\u63D0\u4EA4\u8865\u5145\u6307\u4EE4\u3002"),{replyTo:t.messageId??null})}async#Te(t,o,{updateMessageId:i=null,replyTo:e=null}={}){try{let a=await yi("/preset --default",this.#t,this.#r,t,{signal:this.#w});for(let A of a?.messages??[a?.message])A&&await this.#O(o,A,{replyTo:e})}catch(a){await this.#x(o,a,{logLabel:"preset reset"});return}try{await this.#Z(t,o,{updateMessageId:i,replyTo:e})}catch(a){this.#D.warn?.("[dsh-feishu] menu refresh failed after preset reset:",a.message)}}async#iA(t,o,i,{updateMessageId:e=null,replyTo:a=null}={}){try{let A=/^\d+$/u.test(i)?`id:${i}`:i,r=await yi(`/preset ${A}`,this.#t,this.#r,t,{signal:this.#w});for(let s of r?.messages??[r?.message])s&&await this.#O(o,s,{replyTo:a})}catch(A){await this.#x(o,A,{logLabel:"preset selection"});return}try{await this.#Z(t,o,{updateMessageId:e,replyTo:a})}catch(A){this.#D.warn?.("[dsh-feishu] menu refresh failed after preset select:",A.message)}}async#oA(t,o,i,{updateMessageId:e=null,replyTo:a=null}={}){try{let A=await Wi(`/model ${i}`,this.#t,this.#r,t,{signal:this.#w,pendingInteraction:this.#ae(t),control:{owner:this,key:t}});for(let r of A?.messages??[A?.message])r&&await this.#O(o,r,{replyTo:a})}catch(A){await this.#x(o,A,{logLabel:"model selection"});return}try{await this.#Z(t,o,{updateMessageId:e,replyTo:a})}catch(A){this.#D.warn?.("[dsh-feishu] menu refresh failed after model select:",A.message)}}#Ne(){if(this.#q||typeof this.#t?.watchHarnessEvents!="function"||this.#w?.aborted)return;let t=this.#w??new AbortController().signal;try{this.#q=this.#t.watchHarnessEvents({signal:t,onSessionEvent:o=>this.#cA(o),onReconnect:()=>{this.#IA()}}),Promise.resolve(this.#q).catch(o=>{t.aborted||this.#D.warn?.("[dsh-feishu] event watcher stopped:",o.message)})}catch(o){this.#q=null,this.#D.warn?.("[dsh-feishu] event watcher failed to start:",o.message)}}#Re(t,o){let i=this.#z.get(t)??Promise.resolve(),e;return e=i.then(o,o).catch(a=>{this.#w?.aborted||this.#D.warn?.("[dsh-feishu] completion event failed:",a.message)}).finally(()=>{this.#z.get(t)===e&&this.#z.delete(t)}),this.#z.set(t,e),e}#Ee(t=Date.now()){let o=0;for(let[i,e]of this.#K){for(let[a,A]of e)(!Number.isSafeInteger(A?.arrivalAt)||A.arrivalAt<0||A.arrivalAt+NRe<=t)&&e.delete(a);for(;e.size>kRe;){let a=e.keys().next().value;if(a===void 0)break;e.delete(a)}e.size===0?this.#K.delete(i):o+=e.size}for(;this.#K.size>RRe;){let i=this.#K.keys().next().value;if(i===void 0)break;o-=this.#K.get(i)?.size??0,this.#K.delete(i)}for(;o>vRe;){let i=this.#K.keys().next().value;if(i===void 0)break;let e=this.#K.get(i),a=e?.keys().next().value;if(a===void 0){this.#K.delete(i);continue}e.delete(a),o-=1,e.size===0&&this.#K.delete(i)}}#nA(t,o,i=Date.now()){this.#Ee(i);let e=this.#K.get(t);e||(e=new Map);let a=o?.data?.reason,A=typeof a=="string"?a:typeof a?.kind=="string"?{kind:a.kind}:null;e.delete(o.seq),e.set(o.seq,{arrivalAt:i,event:{type:"turn/end",seq:o.seq,...Number.isSafeInteger(o.time)&&o.time>=0?{time:o.time}:{},data:{reason:A}}}),this.#K.delete(t),this.#K.set(t,e),this.#Ee(i)}async#sA(t,{workspaceHint:o=null,signal:i=this.#w}={}){if(typeof t!="string"||t==="")return{error:w("\u7528\u6CD5\uFF1A/watch ")};let e=/^\d{1,4}$/.test(t)?Number(t):null,a=typeof this.#t?.currentWorkspace=="function"?this.#t.currentWorkspace():null,A=async s=>{let g=await this.#t.listWorkspaceSessions(s,{signal:i});return Array.isArray(g?.sessions)?g.sessions:[]};if(e!==null){if(!a)return{error:w("\u5F53\u524D\u673A\u5668\u4EBA\u6CA1\u6709\u53EF\u7528\u7684\u5DE5\u4F5C\u533A\uFF0C\u65E0\u6CD5\u6309\u5E8F\u53F7\u89E3\u6790\u4F1A\u8BDD\u3002")};let s=this.#ne(await A(a)),g=s[e-1];return g?.sessionId?{sessionId:g.sessionId,title:g.title??w("\u6682\u65E0\u6807\u9898"),workspace:a,...Qn(g.lastSeq)?{lastSeq:g.lastSeq}:{}}:{error:w("\u5F53\u524D\u5DE5\u4F5C\u533A\u53EA\u6709 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:s.length})}}let r;if(pA(o))r=[o];else{let s=typeof this.#t?.listWorkspaces=="function"?(await this.#t.listWorkspaces({signal:i})).filter(g=>g!==a):[];r=[a,...s].filter(Boolean)}for(let s of r){let c=(await A(s)).find(I=>I.sessionId===t);if(c)return{sessionId:t,title:c.title??w("\u6682\u65E0\u6807\u9898"),workspace:s,...Qn(c.lastSeq)?{lastSeq:c.lastSeq}:{}}}return{error:w("\u6CA1\u6709\u627E\u5230\u8FD9\u4E2A\u4F1A\u8BDD\uFF0C\u8BF7\u7528 /sessionlist \u67E5\u770B\u53EF\u7528\u4F1A\u8BDD\u3002")}}async#gA(t){let o=pA(t)??(typeof this.#t?.currentWorkspace=="function"?pA(this.#t.currentWorkspace()):null);if(!o||typeof this.#t?.listWorkspaceSessions!="function")return new Map;let i=await this.#t.listWorkspaceSessions(o,{signal:this.#V()});return new Map(this.#ne(Array.isArray(i?.sessions)?i.sessions:[]).filter(e=>pA(e?.sessionId)).map(e=>[e.sessionId,{sessionId:e.sessionId,title:e.title??e.name??w("\u6682\u65E0\u6807\u9898"),workspace:o,...Qn(e.lastSeq)?{lastSeq:e.lastSeq}:{}}]))}#ke(t){let o=this.#F.get(t);if(o)return o.requested=!0,o.promise;let i={requested:!0,promise:null};return this.#F.set(t,i),i.promise=Promise.resolve().then(async()=>{try{do i.requested=!1,await this.#Re(t,()=>this.#Pe(t));while(i.requested&&!this.#w?.aborted)}finally{this.#F.get(t)===i&&this.#F.delete(t)}}),i.promise}async#Ce(t,o,i,{notify:e=!0,validatedTarget:a=null,workspaceHint:A=null,replyTo:r=null}={}){let s=Date.now(),g=async y=>{e&&await this.#O(o,y,{replyTo:r}).catch(m=>{this.#D.warn?.("[dsh-feishu] watch notification failed:",m.message)})};if(this.#Ne(),typeof this.#r?.setWatch!="function")return await g(w("\u5F53\u524D\u72B6\u6001\u5B58\u50A8\u4E0D\u652F\u6301\u5173\u6CE8\u3002")),{ok:!1,changed:!1,reason:"unsupported"};let c;try{c=a?.sessionId===i?a:await this.#sA(i,{workspaceHint:A,signal:A?this.#V():this.#w})}catch(y){return await g(w("\u65E0\u6CD5\u89E3\u6790\u4F1A\u8BDD\uFF1A{message}",{message:uu(y)})),{ok:!1,changed:!1,reason:"resolve"}}if(c.error)return await g(c.error),{ok:!1,changed:!1,reason:"not-found"};let I=this.#r.watchEntries?.(t)??[],d=I.find(y=>y.sessionId===c.sessionId);if(!d&&I.length>=Zm)return await g(w("\u6BCF\u4E2A\u804A\u5929\u6700\u591A\u5173\u6CE8 {count} \u4E2A\u4F1A\u8BDD\u3002",{count:Zm})),{ok:!1,changed:!1,reason:"limit"};let B=Qn(d?.lastSeq)?d.lastSeq:Qn(c.lastSeq)?c.lastSeq:null,Q=rS(d)??(d?null:s);try{await this.#r.setWatch(t,{sessionId:c.sessionId,title:c.title,chatId:o,lastSeq:B,...Q!==null?{watchStartedAt:Q}:{}})}catch(y){return await g(w("\u5173\u6CE8\u5931\u8D25\uFF1A{message}",{message:uu(y)})),{ok:!1,changed:!1,reason:"persist"}}return(!d||Q!==null||!Qn(B))&&this.#ke(c.sessionId),await g(w("\u5DF2\u5173\u6CE8\u4F1A\u8BDD\u300C{title}\u300D\uFF0C\u4EFB\u52A1\u5B8C\u6210\u4F1A\u63A8\u9001\u7ED3\u679C\u3002",{title:String(c.title).replace(/\s+/gu," ")})),{ok:!0,changed:!d,entry:this.#r.watchEntry?.(t,c.sessionId)}}async#ue(t,o,i,{notify:e=!0,replyTo:a=null}={}){let A=async g=>{e&&await this.#O(o,g,{replyTo:a}).catch(c=>{this.#D.warn?.("[dsh-feishu] unwatch notification failed:",c.message)})};if(typeof this.#r?.removeWatch!="function")return{ok:!1,changed:!1,reason:"unsupported"};let r=this.#r.watchEntries?.(t)??[],s=typeof i=="string"&&/^\d{1,4}$/.test(i)?r[Number(i)-1]:r.find(g=>g.sessionId===i);if(!s)return await A(w("\u5173\u6CE8\u5217\u8868\u91CC\u6CA1\u6709\u8FD9\u4E2A\u4F1A\u8BDD\uFF0C\u56DE\u590D /watchlist \u67E5\u770B\u3002")),{ok:!0,changed:!1,reason:"absent"};try{await this.#r.removeWatch(t,s.sessionId),this.#G.delete(`${t}\0${s.sessionId}`)}catch(g){return await A(w("\u53D6\u6D88\u5931\u8D25\uFF1A{message}",{message:uu(g)})),{ok:!1,changed:!1,reason:"persist"}}return await A(w("\u5DF2\u53D6\u6D88\u5173\u6CE8\u300C{title}\u300D\u3002",{title:String(s.title??"").replace(/\s+/gu," ")})),{ok:!0,changed:!0,entry:s}}async#Be(t,o,{updateMessageId:i=null,replyTo:e=null}={}){let a=this.#r.watchEntries?.(t)??[],A=[],r=null;try{if(r=typeof this.#t?.currentWorkspace=="function"?this.#t.currentWorkspace():null,r&&typeof this.#t?.listWorkspaceSessions=="function"){let s=await this.#t.listWorkspaceSessions(r,{signal:this.#V()});A=this.#ne(Array.isArray(s?.sessions)?s.sessions:[]).map(g=>({sessionId:g.sessionId,title:g.title??g.name??g.sessionId}))}}catch{}this.#oe(t,{kind:"watches",entries:a}),await this.#W(o,$W(a,A),{key:t,updateMessageId:i,replyTo:e,sessionWorkspace:r})}#cA({sessionId:t,event:o}){this.#w?.aborted||!t||!o||typeof o!="object"||o.type!=="turn/end"||!Qu(o.seq)||(this.#nA(t,o),this.#Re(t,async()=>{let i=this.#r.keysWatching?.(t)??[],e=i.some(A=>tS(this.#r.watchEntry?.(A,t))),a=i.some(A=>this.#G.has(`${A}\0${t}`));(e||a)&&await this.#Pe(t),await this.#ve(t,o)}))}async#ve(t,o,{keys:i=null}={}){if(this.#w?.aborted||typeof this.#r?.keysWatching!="function")return;let e=o?.data?.reason?.kind??o?.data?.reason??null,a=i??this.#r.keysWatching(t);for(let A of a){if(this.#w?.aborted)return;let r=this.#r.watchEntry?.(A,t),s=`${A}\0${t}`,g=this.#G.get(s);if(Qu(g)&&Qn(r?.lastSeq)&&r.lastSeq>=g&&(this.#G.delete(s),g=void 0),!(!r?.chatId||tS(r)||Qn(r.lastSeq)&&r.lastSeq>=o.seq||Qu(g)&&o.seq>g))try{await this.#W(r.chatId,e6(t,r.title,e),{key:A});let c=this.#r.watchEntry?.(A,t);if(!c||c.chatId!==r.chatId||tS(c)||Qn(c.lastSeq)&&c.lastSeq>=o.seq)continue;await this.#r.setWatch(A,{...c,lastSeq:o.seq}),g===o.seq&&this.#G.delete(s)}catch(c){this.#G.set(s,Qu(g)?Math.min(g,o.seq):o.seq),this.#D.warn?.("[dsh-feishu] completion push failed:",c.message)}}}async#Pe(t){if(!(this.#w?.aborted||typeof this.#t?.rpc!="function"))try{let o=await this.#t.rpc("session.history",{sessionId:t,maxMessages:20},3e4,{signal:this.#w}),i=YRe(o);this.#Ee();let e=this.#K.get(t)??new Map,a=new Map(i.map(g=>[g.seq,g]));for(let[g,c]of e)a.has(g)||a.set(g,c.event);let A=[...a.values()].sort((g,c)=>g.seq-c.seq),r=A.at(-1)?.seq??-1,s=typeof this.#r?.keysWatching=="function"?this.#r.keysWatching(t):[];for(let g of s){let c=this.#r.watchEntry?.(g,t);if(!tS(c))continue;let I=rS(c),d=Qn(c.lastSeq)?c.lastSeq:-1,B=I===null?null:A.find(_=>{if(_.seq<=d)return!1;let T=Number.isSafeInteger(_.time)&&_.time>=0?_.time:e.get(_.seq)?.arrivalAt;return Number.isSafeInteger(T)&&T>=I}),f=B?Math.max(d,B.seq-1):Math.max(d,r),Q=this.#r.watchEntry?.(g,t);if(!Q||Q.chatId!==c.chatId||Q.lastSeq!==c.lastSeq||rS(Q)!==I)continue;let{watchStartedAt:y,...m}=Q;await this.#r.setWatch(g,{...m,lastSeq:f})}for(let g of A)g.type==="turn/end"&&await this.#ve(t,g,{keys:s})}catch(o){this.#w?.aborted||this.#D.warn?.(`[dsh-feishu] watch compensation failed for ${t}:`,o.message)}}async#IA(){let t=typeof this.#r?.watchedSessionIds=="function"?this.#r.watchedSessionIds():[];this.#w?.aborted||await Promise.allSettled(t.map(o=>this.#ke(o)))}#fe(t,o,i){return{timeoutMs:this.#R,signal:this.#w,control:{owner:this,key:o},onInteraction:e=>this.#dA(e,{key:o,actor:yu(t),chatId:t.message.chat_id,requiresMention:t.message.chat_type!=="p2p",replyToMessageId:t.message.message_id}),onInteractionResolved:e=>this.#hA(e),files:i}}async#Qe(t,o,{deliveryId:i,presentation:e,replyTo:a=null}){let A=[];for(let r of HW(o)){this.#w?.throwIfAborted();let s=await this.#O(t,r,{replyTo:a});s&&A.push(s)}return Zt({deliveryId:i,presentation:e,providerMessageIds:A})}async#Ie(t,o,i=[],e){let a=await bo({artifacts:i,baseReceipt:e,deliveryId:e?.deliveryId??i[0]?.deliveryKey??o,aggregatePresentation:e?"feishu-text-and-files":"feishu-files",channelKey:"feishu",signal:this.#w,sendImage:typeof this.#A?.sendImage=="function"?A=>this.#A.sendImage(t,A,{replyTo:o,signal:this.#w}):void 0,sendFile:typeof this.#A?.sendFile=="function"?A=>this.#A.sendFile(t,A,{replyTo:o,signal:this.#w}):void 0,onFailure:(A,r)=>tt(this.#u,r,{userMessage:xRe(A?.fileName,r),reason:r?.code}),sendFailureNotice:async(A,r,s)=>({messageId:await this.#O(t,dt(s))}),logger:this.#D});return this.#u.artifactsSent=(this.#u.artifactsSent??0)+a.artifactsSent,this.#u.artifactSendErrors=(this.#u.artifactSendErrors??0)+a.artifactSendErrors,a.receipt?{receipt:a.receipt,failureNoticeVisible:a.failureNoticeVisible,artifactSendErrors:a.artifactSendErrors}:{receipt:Zt({deliveryId:o,presentation:"feishu-files"}),failureNoticeVisible:a.failureNoticeVisible,artifactSendErrors:a.artifactSendErrors}}async#lA(t,o,i,{onAskComplete:e}={}){let a=t.message.chat_id,A=t.message.message_id,r=i.content,s=!1,g=()=>{s||(s=!0,e?.())},c=Wt(i)?await Bo(i,{signal:this.#w}):void 0,I=this.#o.get(A);if(I&&(c=mo(c??r,I,()=>({channel:"feishu",senderId:yu(t)}))),!this.#A?.stream){let{answer:m,artifacts:_=[]}=await ui({harness:this.#t,state:this.#r,key:o,text:r,content:c,createOptions:{signal:this.#w},existsOptions:{signal:this.#w},askOptions:this.#fe(t,o,i.files)});g();let T,R=null;try{T=await this.#Qe(a,AS(m,_),{deliveryId:A,presentation:"feishu-text",replyTo:A})}catch(F){R=Ma(F),this.#D.warn?.("[dsh-feishu] final text delivery failed; continuing with result files:",F)}let L=await this.#Ie(a,A,_,T),U=L.receipt.artifacts.some(({outcome:F})=>F==="sent"||F==="unknown");if(R&&!U&&!L.failureNoticeVisible)throw R;return R&&L.artifactSendErrors===0&&tt(this.#u,R),this.#u.streamFallbacks=(this.#u.streamFallbacks??0)+1,{...L,textDeliveryErrors:R?1:0}}let d=!1,B="",f=[],Q;try{Q=await this.#A.stream(a,{markdown:async m=>{d=!0;let _={...this.#fe(t,o,i.files),onUpdate:async R=>{await m.setContent(this.#EA(R)),this.#u.streamUpdates=(this.#u.streamUpdates??0)+1}},T=await ui({harness:this.#t,state:this.#r,key:o,text:r,content:c,createOptions:{signal:this.#w},existsOptions:{signal:this.#w},askOptions:_});g(),B=T.answer,f=T.artifacts??[],await m.setContent(AS(B,f))}},{replyTo:A})}catch(m){if(this.#u.streamErrors=(this.#u.streamErrors??0)+1,B||f.length>0){this.#D.warn?.("[dsh-feishu] native stream failed after generation; sending final text:",m.message);let q,z=null;try{q=await this.#Qe(a,AS(B,f),{deliveryId:A,presentation:"feishu-text-fallback",replyTo:A})}catch(J){z=Ma(J),this.#D.warn?.("[dsh-feishu] fallback text delivery failed; continuing with result files:",J)}let j=await this.#Ie(a,A,f,q),P=j.receipt.artifacts.some(({outcome:J})=>J==="sent"||J==="unknown");if(z&&!P&&!j.failureNoticeVisible)throw z;return z&&j.artifactSendErrors===0&&tt(this.#u,z),this.#u.streamFallbacks=(this.#u.streamFallbacks??0)+1,{...j,textDeliveryErrors:z?1:0}}if(d)throw m;this.#D.warn?.("[dsh-feishu] native stream unavailable; using text fallback:",m.message);let{answer:_,artifacts:T=[]}=await ui({harness:this.#t,state:this.#r,key:o,text:r,content:c,createOptions:{signal:this.#w},existsOptions:{signal:this.#w},askOptions:this.#fe(t,o,i.files)});g();let R,L=null;try{R=await this.#Qe(a,AS(_,T),{deliveryId:A,presentation:"feishu-text-fallback",replyTo:A})}catch(q){L=Ma(q),this.#D.warn?.("[dsh-feishu] fallback text delivery failed; continuing with result files:",q)}let U=await this.#Ie(a,A,T,R),F=U.receipt.artifacts.some(({outcome:q})=>q==="sent"||q==="unknown");if(L&&!F&&!U.failureNoticeVisible)throw L;return L&&U.artifactSendErrors===0&&tt(this.#u,L),this.#u.streamFallbacks=(this.#u.streamFallbacks??0)+1,{...U,textDeliveryErrors:L?1:0}}let y=await this.#Ie(a,A,f,Zt({deliveryId:A,presentation:"feishu-cardkit",providerMessageIds:ka(Q)}));return this.#u.streamResponses=(this.#u.streamResponses??0)+1,y}async#pA(t,o,i,e,a){this.#w?.throwIfAborted();let A=this.#i.get(i),r=e.claimedReplyMessageId===o;if(!A||A!==e||A.submitting)return this.#ye(t,i)?this.#me(t,o):r&&(!A||A!==e)?this.#me(t,o):this.#j(t,o,i,a,{releaseMessageId:!1,finalize:!1});if(this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#u.lastMessageAt=new Date().toISOString(),this.#u.messagesReceived+=1;let s=Td(t);if(!s){await this.#O(t.message.chat_id,w("\u8BF7\u7528\u6587\u5B57\u56DE\u7B54\u5F53\u524D\u95EE\u9898\u3002"));return}let g=this.#i.get(i);if(!g||g!==e||g.submitting){if(this.#ye(t,i)){await this.#O(t.message.chat_id,$m(),{replyTo:t.message.message_id}).catch(()=>{});return}if(r&&(!g||g!==e)){await this.#O(t.message.chat_id,$m(),{replyTo:t.message.message_id});return}return this.#j(t,o,i,a,{releaseMessageId:!1,alreadyRecorded:!0,finalize:!1})}if(g.chatId=t.message.chat_id,g.needsPresentation){try{await this.#le(g)}catch{this.#u.lastError="\u98DE\u4E66\u4EA4\u4E92\u95EE\u9898\u53D1\u9001\u5931\u8D25\u3002",this.#D.error?.("[dsh-feishu] failed to retry an interaction question"),g.interaction.reconnect?.()}return}let c=g.questions[g.index];if(c){if(g.answers.push(Ei(c,s)),g.index+=1,g.index{});return}g.submitting=!1,g.answers.pop(),g.index-=1,this.#u.lastError="\u56DE\u7B54\u63D0\u4EA4\u5931\u8D25\u3002",this.#D.error?.("[dsh-feishu] failed to answer a Harness interaction"),await this.#O(t.message.chat_id,w("\u56DE\u7B54\u63D0\u4EA4\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u5F53\u524D\u95EE\u9898\u7684\u7B54\u6848\u3002")).catch(()=>{})}}}async#dA(t,{key:o,actor:i,chatId:e,requiresMention:a,replyToMessageId:A}){if(await this.#m.handleRequested(t,{key:o,actor:i,requiresMention:a,send:I=>this.#O(e,I,{replyTo:A})})||t?.kind!=="question")return;let r=t?.payload?.questions,s=typeof t?.interactionId=="string"?t.interactionId:t?.rpcId;if(typeof t.rpcId!="string"||typeof s!="string"||typeof t.sessionId!="string"||!Array.isArray(r)||r.length===0||r.some(I=>!di(I))){this.#D.warn?.("[dsh-feishu] ignored an invalid Harness question interaction");return}if(t.recovered===!0){await t.respond({ok:!1,error:{code:"cancelled",message:"Feishu safely cancelled an interaction left by an earlier client.",details:{}}}),await this.#O(e,w("\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"),{replyTo:A}).catch(()=>{});return}let g=this.#i.get(o);if(g?.interactionId===s){g.interaction=t,g.needsPresentation&&await this.#le(g);return}if(this.#I.has(s))return;if(g){await t.respond({ok:!1,error:{code:"cancelled",message:"Feishu is already handling another user interaction.",details:{}}});return}let c={kind:"question",interactionId:s,sessionId:t.sessionId,interaction:t,key:o,actor:i,requiresMention:a,questions:r,answers:[],index:0,chatId:e,replyToMessageId:A,queue:null,claimedReplyMessageId:null,submitting:!1,needsPresentation:!0,questionMessageIds:new Set,inactive:!1};this.#i.set(o,c),this.#I.set(c.interactionId,o),await this.#le(c)}async#hA(t){if(await this.#m.handleResolved(t))return;let o=t?.interactionId;if(t?.kind!=="question"||typeof o!="string")return;let i=this.#I.get(o);if(!i)return;let e=this.#i.get(i);e&&this.#se(i,e),this.#Se(i,o)}async#le(t){let o=t.questions[t.index];if(!o)return;let i=await this.#O(t.chatId,hi(o,t.index,t.questions.length,{requiresMention:t.requiresMention}),{replyTo:t.replyToMessageId});i&&(t.questionMessageIds.add(i),t.inactive&&this.#se(t.key,t)),t.needsPresentation=!1}#se(t,o){let i=Date.now()+BRe;for(let e of o.questionMessageIds??[])this.#l.set(e,{key:t,expiresAt:i})}#ye(t,o){let i=Date.now();for(let[e,a]of this.#l)a.expiresAt<=i&&this.#l.delete(e);for(let e of[t?.message?.parent_id,t?.message?.root_id]){let a=this.#l.get(e);if(a?.key===o&&a.expiresAt>i)return!0}return!1}async#me(t,o){this.#r.hasSeen(o)||(await this.#r.markSeen(o),this.#u.lastMessageAt=new Date().toISOString(),this.#u.messagesReceived+=1,await this.#O(t.message.chat_id,$m(),{replyTo:t.message.message_id}).catch(()=>{}))}#Ge(t,o){let i=this.#i.get(t);return!i||o!==void 0&&i.interactionId!==o?null:(this.#i.delete(t),this.#I.delete(i.interactionId),i.inactive=!0,i)}#Se(t,o){return this.#Ge(t,o)!==null}async#we(t){let o=this.#Ge(t);if(!(!o||o.kind!=="question")){this.#se(t,o);try{await o.interaction.respond({ok:!1,error:{code:"cancelled",message:"The Feishu interaction ended before the user answered.",details:{}}},{signal:AbortSignal.timeout(5e3)})}catch(i){i?.code!=="interaction-not-pending"&&this.#D.warn?.("[dsh-feishu] failed to cancel a pending Harness interaction")}}}#EA(t){return t.type==="text"&&t.text?t.text:t.type==="tool"?t.name==="web_search"?w("_\u6B63\u5728\u641C\u7D22\u7F51\u7EDC\u5E76\u6574\u7406\u4FE1\u606F\u2026_"):w("_\u6B63\u5728\u4F7F\u7528 {name}\u2026_",{name:t.name||w("\u5DE5\u5177")}):w("_{text}_",{text:t.text||w("\u6B63\u5728\u5904\u7406\u2026")})}#CA(t){return PQ({adapter:this.#A,target:t,reactions:{processing:"OnIt",success:"DONE",error:"ERROR"},status:this.#u,logger:this.#D,label:"feishu"})}#Fe(t,o){o.clear()}#ee(t,o,i){i==="ERROR"?o.error():o.success()}async#O(t,o,{replyTo:i}={}){let e=JSON.stringify({text:o});if(i)try{let A=await this.#e.im.v1.message.reply({path:{message_id:i},data:{msg_type:"text",content:e}});if(A?.code&&A.code!==0)throw new Error(`Feishu reply failed: ${A.msg||A.code}`);return pA(A?.data?.message_id)}catch(A){this.#D.warn?.("[dsh-feishu] threaded reply failed; falling back to a plain message:",A?.message??String(A))}let a=await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"text",content:e}});if(a?.code&&a.code!==0)throw new Error(`Feishu send failed: ${a.msg||a.code}`);return pA(a?.data?.message_id)}};import{createHash as zRe}from"node:crypto";var d6="stream_md",VRe="\u5DF2\u8FDE\u63A5 DeepSeek Harness\uFF0C\u6B63\u5728\u601D\u8003\u2026",Su=28e3,iS=12e4,h6=new Map([[99991672,["artifact-permission-required","Feishu file delivery requires the im:resource permission."]],[234006,["artifact-too-large","The result file exceeds Feishu's size limit."]],[234010,["artifact-empty","Feishu does not accept empty files."]],[230017,["artifact-provider-rejected","Feishu rejected the uploaded file ownership."]],[230020,["artifact-rate-limited","Feishu temporarily rate-limited file delivery."]],[230049,["artifact-delivery-uncertain","Feishu could not confirm the file message result."]],[230055,["artifact-provider-rejected","Feishu rejected the file message type."]]]);function sl(n,t){if(t?.code&&t.code!==0)throw new Error(`${n} failed: ${t.msg||t.code}`);return t}function E6(n){let t=[n],o=new Set,i;for(;t.length>0;){let e=t.shift();if(!e||o.has(e))continue;if(typeof e=="object"&&o.add(e),Array.isArray(e)){t.push(...e);continue}let a=Number(e?.code);if(Number.isFinite(a)&&a!==0){if(h6.has(a))return a;i??=a}t.push(e?.response?.data,e?.data,e?.error,e?.cause)}return i}function mu(n,t,o,{uncertain:i=!1}={}){let e=o==null?void 0:Number(o),a=Number.isFinite(e)&&e!==0?e:E6(t),A=Number.isFinite(a)?["artifact-provider-rejected",`Feishu rejected file ${n}.`]:i?["artifact-delivery-uncertain","Feishu could not confirm the file message result."]:["artifact-provider-failed",`Feishu file ${n} failed.`],[r,s]=h6.get(a)??A,g=new Error(s,{cause:t});return g.code=r,Number.isFinite(a)&&(g.providerCode=a),g}function I6(n,t){if(!Number.isInteger(n)||n<1||n>iS)throw new TypeError(`${t} must be an integer between 1 and ${iS}`);return n}function Wv(n){return n?.reason??new DOMException("The operation was aborted","AbortError")}function WRe(n){let t=new Error(`Feishu file ${n} timed out.`);return t.code="provider-timeout",t}function l6(n,{signal:t,timeoutMs:o,stage:i}){t?.throwIfAborted();let e=new AbortController,a=t?AbortSignal.any([t,e.signal]):e.signal;return new Promise((A,r)=>{let s=!1,g=(d,B)=>{s||(s=!0,clearTimeout(I),a.removeEventListener("abort",c),d(B))},c=()=>g(r,t?.aborted?Wv(t):WRe(i)),I=setTimeout(()=>e.abort(),o);a.addEventListener("abort",c,{once:!0}),Promise.resolve().then(()=>n(a)).then(d=>g(A,d),d=>g(r,d)),a.aborted&&c()})}function ZRe(n,t,o){let i=`${n.deliveryKey}\0${t}`;return`dshim_${zRe("sha256").update(o==="file"?i:`${i}\0${o}`).digest("hex").slice(0,40)}`}function XRe(n){let t=String(n??"").replace(/\s+/g," ").trim();return t.length<=50?t:`${Zv(t,49)}\u2026`}function Zv(n,t){let o=Math.min(n.length,t),i=n.charCodeAt(o-1),e=n.charCodeAt(o);return i>=55296&&i<=56319&&e>=56320&&e<=57343&&(o-=1),n.slice(0,o)}function p6(n){if(n.length<=Su)return n;let t=` ${w("\u5185\u5BB9\u8F83\u957F\uFF0C\u751F\u6210\u5B8C\u6210\u540E\u5C06\u5206\u6BB5\u53D1\u9001\u5B8C\u6574\u56DE\u7B54\u3002")}`;return Zv(n,Su-t.length)+t}function $Re(n){let t=[],o=n;for(;o.length>Su;){let i=Zv(o,Su),e=i.lastIndexOf(` `)+1;e{let c=String(g??"")||"\u2026";await this.#n(a,p6(c)),A=c}};await o.markdown(r);let s=$Re(A);for(let[g,c]of s.entries()){let I=g===0?a:await this.#a(t,i.replyTo);g>0&&e.push(I),await this.#n(I,c),await this.#i(I)}return{messageId:a.messageId,providerMessageIds:e.map(g=>g.messageId)}}catch(a){for(let A of e)await this.#l(A.messageId);throw a}}async sendFile(t,o,{replyTo:i,signal:e}={}){return this.#g(t,o,{replyTo:i,signal:e,messageType:"file",presentation:"feishu-file"})}async sendImage(t,o,{replyTo:i,signal:e}={}){return this.#g(t,o,{replyTo:i,signal:e,messageType:"image",presentation:"feishu-image"})}async#g(t,o,{replyTo:i,signal:e,messageType:a,presentation:A}){if(e?.throwIfAborted(),typeof t!="string"||!t)throw new TypeError("chatId is required");if(!o||typeof o!="object"||typeof o.artifactId!="string"||!o.artifactId||typeof o.deliveryKey!="string"||!o.deliveryKey||typeof o.fileName!="string"||!o.fileName||!Buffer.isBuffer(o.bytes))throw new TypeError("A materialized result file is required");let r;try{r=await l6(Q=>{Q.throwIfAborted();let y=a==="image"?this.#e.im.v1.image.create({data:{image_type:"message",image:o.bytes}}):this.#e.im.v1.file.create({data:{file_type:"stream",file_name:o.fileName,file:o.bytes}});return ln(o,y),y},{signal:e,timeoutMs:this.#t,stage:"upload"})}catch(Q){throw e?.aborted?Wv(e):mu("upload",Q)}e?.throwIfAborted();let s=a==="image"?r?.image_key??r?.data?.image_key:r?.file_key??r?.data?.file_key;if(typeof s!="string"||!s)throw mu("upload",void 0,r?.code);let g=ZRe(o,t,a),c=JSON.stringify(a==="image"?{image_key:s}:{file_key:s}),I=i?{path:{message_id:i},data:{msg_type:a,content:c,uuid:g}}:{params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:a,content:c,uuid:g}},d=()=>{let Q=i?this.#e.im.v1.message.reply(I):this.#e.im.v1.message.create(I);return ln(o,Q),Q},B;try{B=await l6(async Q=>{Q.throwIfAborted();let y;try{y=await d()}catch(m){if(E6(m)!==230049)throw m;y={code:230049}}return Q.throwIfAborted(),Number(y?.code)===230049&&(y=await d(),Q.throwIfAborted()),y},{signal:e,timeoutMs:this.#r,stage:"message send"})}catch(Q){throw e?.aborted?Wv(e):mu("message send",Q,void 0,{uncertain:!0})}if(Number.isFinite(Number(B?.code))&&Number(B.code)!==0)throw mu("message send",void 0,B.code,{uncertain:!0});let f=B?.data?.message_id;if(typeof f!="string"||!f)throw mu("message send",void 0,void 0,{uncertain:!0});return Zt({deliveryId:o.deliveryKey,presentation:A,providerMessageIds:[f],artifacts:[{artifactId:o.artifactId,outcome:"sent"}]})}async#a(t,o){let i=p6(this.#A),a=sl("Feishu card.create",await this.#e.cardkit.v1.card.create({data:{type:"card_json",data:JSON.stringify(eke(i))}}))?.data?.card_id;if(!a)throw new Error("Feishu card.create returned no card_id");let A=await this.#I(t,a,o);return{cardId:a,messageId:A,content:i,sequence:0}}async#n(t,o){if(o===t.content)return;let i=await this.#e.cardkit.v1.cardElement.content({path:{card_id:t.cardId,element_id:d6},data:{content:o,sequence:++t.sequence,uuid:`content_${t.cardId}_${t.sequence}`}});sl("Feishu cardElement.content",i),t.content=o}async#i(t){let o=await this.#e.cardkit.v1.card.settings({path:{card_id:t.cardId},data:{settings:JSON.stringify({config:{streaming_mode:!1,summary:{content:XRe(t.content)||w("\u56DE\u7B54\u5B8C\u6210")}}}),sequence:++t.sequence,uuid:`settings_${t.cardId}_${t.sequence}`}});sl("Feishu card.settings",o)}async#I(t,o,i){let e=JSON.stringify({type:"card",data:{card_id:o}}),a=i?await this.#e.im.v1.message.reply({path:{message_id:i},data:{msg_type:"interactive",content:e}}):await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"interactive",content:e}});sl("Feishu message send",a);let A=a?.data?.message_id;if(!A)throw new Error("Feishu message send returned no message_id");return A}async#l(t){try{let o=await this.#e.im.v1.message.delete({path:{message_id:t}});sl("Feishu message delete",o)}catch(o){console.warn("[bridge] unable to recall a failed streaming card:",o.message)}}async addReaction(t,o){let e=sl("Feishu reaction.create",await this.#e.im.v1.messageReaction.create({path:{message_id:t},data:{reaction_type:{emoji_type:o}}}))?.data?.reaction_id;if(!e)throw new Error("Feishu reaction.create returned no reaction_id");return e}async removeReaction(t,o){sl("Feishu reaction.delete",await this.#e.im.v1.messageReaction.delete({path:{message_id:t,reaction_id:o}}))}};var u6="/open-apis/application/v7/app_slash_commands",Ake=new Set(["99991640","99991672"]),nS=Object.freeze(["application:app_slash_command:read","application:app_slash_command:write"]),B6="ai-agent_outlined",Xv=Object.freeze([{command:"menu",icon:"skill_outlined",default:"\u6253\u5F00\u529F\u80FD\u83DC\u5355",en_us:"Open the feature menu"},{command:"new",icon:"ai-deepthink_outlined",default:"\u5F00\u542F\u5168\u65B0\u4F1A\u8BDD",en_us:"Start a fresh session"},{command:"help",icon:"promptword_outlined",default:"\u67E5\u770B\u5E2E\u52A9",en_us:"Show help"},{command:"status",icon:"ai-functions_outlined",default:"\u67E5\u770B\u673A\u5668\u4EBA\u72B6\u6001",en_us:"Show bot status"},{command:"compact",icon:"ai-block_outlined",default:"\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587",en_us:"Compact the current session"},{command:"sessionlist",icon:"chat-ai_outlined",default:"\u5217\u51FA\u4F1A\u8BDD",en_us:"List sessions"},{command:"workspacelist",icon:"folder_outlined",default:"\u5217\u51FA\u5DE5\u4F5C\u533A",en_us:"List workspaces"},{command:"watch",icon:"flag_outlined",default:"\u5173\u6CE8\u4E00\u4E2A\u4F1A\u8BDD",en_us:"Watch a session"},{command:"unwatch",icon:"clear_outlined",default:"\u53D6\u6D88\u5173\u6CE8\u4F1A\u8BDD",en_us:"Unwatch a session"},{command:"watchlist",icon:"flag_outlined",default:"\u67E5\u770B\u5173\u6CE8\u5217\u8868",en_us:"List watched sessions"},{command:"archived",icon:"folder_outlined",default:"\u8BBE\u7F6E\u5F52\u6863\u4F1A\u8BDD\u663E\u9690\uFF08on/off\uFF09",en_us:"Show or hide archived sessions (on/off)"}]);function $v(n,t){let o=n==="lark"?"https://open.larksuite.com":"https://open.feishu.cn";return new URL(t,o)}function C6(n,t){if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`${t} returned a non-JSON response`);if(n.code!==0){let o=new Error(`${t} failed: ${n.msg||`code ${n.code}`}`);throw o.code=String(n.code),o.msg=n.msg,o}return n}function eP(n,t){let o=AbortSignal.timeout(t);return n?AbortSignal.any([n,o]):o}async function AP(n,t,o){try{return C6(await n.request(t),o)}catch(i){let e=i?.response?.data;if(e&&typeof e=="object"&&!Array.isArray(e)&&Object.hasOwn(e,"code"))return C6(e,o);throw i}}async function tke({appId:n,appSecret:t,domain:o,httpInstance:i,timeoutMs:e,signal:a}){if(!n||!t)throw new Error("Feishu slash registration requires app credentials");if(!i||typeof i.request!="function")throw new TypeError("Feishu slash registration requires an HTTP instance");let A=await AP(i,{method:"POST",url:$v(o,"/open-apis/auth/v3/tenant_access_token/internal").href,headers:{"content-type":"application/json; charset=utf-8"},data:{app_id:n,app_secret:t},signal:eP(a,e),timeout:e},"Feishu authentication");if(!A.tenant_access_token)throw new Error("Feishu authentication returned no tenant access token");return A.tenant_access_token}async function rke({tenantAccessToken:n,domain:t,httpInstance:o,timeoutMs:i,signal:e}){let a=await AP(o,{method:"GET",url:$v(t,u6).href,headers:{authorization:`Bearer ${n}`,"content-type":"application/json; charset=utf-8"},signal:eP(e,i),timeout:i},"Feishu slash command list");return Array.isArray(a.data?.items)?a.data.items:[]}async function ake({tenantAccessToken:n,domain:t,httpInstance:o,timeoutMs:i,signal:e,command:a,description:A,icon:r=B6}){let s={command:a};return A&&(A.default_value||A.i18n)?s.description=A:typeof A=="string"&&A.trim()&&(s.description={default_value:A.trim()}),r&&(s.description={...s.description??{},icon:{icon_key:r}}),(await AP(o,{method:"POST",url:$v(t,u6).href,headers:{authorization:`Bearer ${n}`,"content-type":"application/json; charset=utf-8"},data:s,signal:eP(e,i),timeout:i},`Feishu slash command create (/${a})`)).data?.command_id??null}async function f6({appId:n,appSecret:t,domain:o="feishu",httpInstance:i,timeoutMs:e=15e3,signal:a,manifest:A=Xv}){let r=await tke({appId:n,appSecret:t,domain:o,httpInstance:i,timeoutMs:e,signal:a}),s=new Set((await rke({tenantAccessToken:r,domain:o,httpInstance:i,timeoutMs:e,signal:a})).map(I=>I.command)),g=[],c=[];for(let I of A){let d=String(I.command??"").replace(/^\//,"");if(d&&!s.has(d))try{let B={default_value:I.default??I.en_us??d,i18n:{zh_cn:I.default??d,en_us:I.en_us??I.default??d}},f=await ake({tenantAccessToken:r,domain:o,httpInstance:i,timeoutMs:e,signal:a,command:d,description:B,icon:I.icon??B6});g.push({command:d,command_id:f})}catch(B){if(B?.code==="40000000"&&/already exists/i.test(B?.msg??"")){s.add(d);continue}if(Ake.has(B?.code)||/(?:lacks permission|access denied)/i.test(B?.msg??"")){c.push({command:d,error:B});break}c.push({command:d,error:B?.message??String(B)})}}return{created:g,existing:[...s].filter(I=>I!=null),failed:c}}var oke=15e3,nke="\u2705 \u4FEE\u590D\u5B8C\u6210\uFF1A\u5DF2\u5B9E\u6D4B\u6536\u5230 card.action.trigger\uFF0C\u83DC\u5355\u6309\u94AE\u73B0\u5728\u53EF\u7528\u3002",ske="\u26A0\uFE0F \u4FEE\u590D\u9A8C\u8BC1\u8D85\u65F6\uFF1A\u672A\u6536\u5230\u6D4B\u8BD5\u5361\u6309\u94AE\u7684 card.action.trigger\uFF0C\u4E0D\u80FD\u786E\u8BA4\u6309\u94AE\u5DF2\u4FEE\u590D\u3002\u8BF7\u4E0D\u8981\u91CD\u590D\u6388\u6743\uFF1B\u5148\u68C0\u67E5\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u7684\u5361\u7247\u56DE\u8C03\u914D\u7F6E\uFF0C\u786E\u8BA4\u540E\u518D\u53D1\u9001 /repair\u3002",tP="\u26A0\uFE0F \u4FEE\u590D\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u53D1\u9001\u4E13\u7528\u6D4B\u8BD5\u5361\uFF0C\u4E0D\u80FD\u786E\u8BA4 card.action.trigger \u5DF2\u6062\u590D\u3002\u8BF7\u4E0D\u8981\u91CD\u590D\u6388\u6743\uFF1B\u5148\u68C0\u67E5\u673A\u5668\u4EBA\u6D88\u606F\u6743\u9650\u548C\u8FDE\u63A5\u72B6\u6001\u3002",gke="\u26A0\uFE0F \u4FEE\u590D\u9A8C\u8BC1\u4E2D\u65AD\uFF1ARuntime \u5DF2\u505C\u6B62\uFF0C\u672A\u5B8C\u6210 card.action.trigger \u5B9E\u6D4B\uFF0C\u4E0D\u80FD\u786E\u8BA4\u4FEE\u590D\u6210\u529F\u3002\u8BF7\u4E0D\u8981\u91CD\u590D\u6388\u6743\uFF1B\u5148\u7B49\u5F85\u673A\u5668\u4EBA\u6062\u590D\u8FDE\u63A5\u3002",cke=new Set(["connected","connecting","reconnecting"]);function yn(n){return typeof n=="string"&&n.trim()?n.trim():null}function Ike(n){return yn(n?.operator?.open_id)??yn(n?.operator?.operator_id?.open_id)}function lke(n,t){try{let o=n?.getConnectionStatus?.()?.state;return typeof o=="string"&&o?o:t}catch{return t}}function Rd(n,t){let o=new Error(t);return o.code=n,o}function pke(n,t){if(!n||typeof n.request!="function")return;let o=i=>({...i??{},timeout:i?.timeout??t});return{request:i=>n.request(o(i)),get:(i,e)=>n.get(i,o(e)),delete:(i,e)=>n.delete(i,o(e)),head:(i,e)=>n.head(i,o(e)),options:(i,e)=>n.options(i,o(e)),post:(i,e,a)=>n.post(i,e,o(a)),put:(i,e,a)=>n.put(i,e,o(a)),patch:(i,e,a)=>n.patch(i,e,o(a))}}function dke({allowedSenderCount:n=1}={}){return{startedAt:null,ready:!1,feishuLongConnectionState:"idle",harnessReachable:!1,messagesReceived:0,messagesReplied:0,messagesRejected:0,reactionsAdded:0,reactionsRemoved:0,reactionErrors:0,streamResponses:0,streamUpdates:0,streamFallbacks:0,streamErrors:0,cardActionsReceived:0,cardActionProbesVerified:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastCardActionAt:null,lastError:null,agentPreset:"standard",authorizationMode:"sender-open-id-allowlist",allowedSenderCount:n,slashCommandRegistration:"idle",slashCommandsRegistered:0,slashCommandsExisting:0,slashCommandsFailed:0,slashCommandsError:null}}var sS=class{#e;#A;#t;#r;#g;#a;#n;#i;#I;#l;#o;#s;#c;#p;#d;#h;#E;#C=null;#f=null;#B=null;#y=null;#S=null;#Q=null;#m=new Map;#u;#b=!0;constructor({lark:t,botId:o,appId:i,appSecret:e,domain:a="feishu",botOpenId:A,groupResponseMode:r,ownerOpenId:s,ownerOpenIds:g,harness:c,state:I,contextEnhancement:d,repair:B,replyTimeoutMs:f=6e5,connectTimeoutMs:Q=15e3,requestTimeoutMs:y=oke,slashCommands:m=!0,wsAgent:_,logger:T=console}){if(!t)throw new Error("FeishuRuntime requires the Feishu SDK");if(!i||!e)throw new Error("FeishuRuntime requires app credentials");let R=Array.isArray(g)?g:[s],L=[...new Set(R.filter(U=>typeof U=="string"&&U))];if(L.length===0)throw new Error("FeishuRuntime requires at least one owner open_id");if(!c)throw new Error("FeishuRuntime requires a Harness client");if(!I)throw new Error("FeishuRuntime requires a state store");if(B!=null&&!yn(o))throw new TypeError("FeishuRuntime repair capability requires a botId");if(!Number.isFinite(y)||y<=0)throw new TypeError("FeishuRuntime requestTimeoutMs must be a positive number");this.#e=t,this.#A=yn(o),this.#t=i,this.#r=e,this.#g=a,this.#a=yn(A),this.#n=ao(r),this.#i=L,this.#I=c,this.#l=I,this.#o=d,this.#E=B??null,this.#s=f,this.#c=Q,this.#p=y,this.#b=!!m,this.#d=_,this.#h=T,this.#u=dke({allowedSenderCount:L.length})}get status(){return structuredClone(this.#u)}setGroupResponseMode(t){this.#n=ao(t),this.#f?.setGroupResponseMode(this.#n)}async start(){for(;;){for(;this.#S;)await this.#S;if(this.#y)return this.#y;let o=this.#B;if(o){let i=lke(o,this.#u.feishuLongConnectionState);if(cke.has(i))return this.status;await this.stop({preserveError:i==="failed"});continue}if(this.#C||this.#f||this.#Q){await this.stop({preserveError:this.#u.feishuLongConnectionState==="failed"});continue}break}let t;return t=this.#R().finally(()=>{this.#y===t&&(this.#y=null)}),this.#y=t,t}async#R(){let t=new AbortController;this.#Q=t;let{signal:o}=t,i=()=>o.reason??new DOMException("Feishu runtime stopped","AbortError"),e=()=>!o.aborted&&this.#Q===t,a=()=>{if(!e())throw i()};this.#u.startedAt=new Date().toISOString(),this.#u.feishuLongConnectionState="connecting",this.#u.lastError=null;try{await this.#I.ensureRunning({signal:o}),a(),this.#u.harnessReachable=!0;let A=this.#g==="lark"?this.#e.Domain.Lark:this.#e.Domain.Feishu,r={appId:this.#t,appSecret:this.#r,domain:A},s=pke(this.#e.defaultHttpInstance,this.#p);s&&(r.httpInstance=s);let g=new this.#e.Client(r);this.#C=g;let c=new oS({client:g,initialText:w("\u5DF2\u8FDE\u63A5 DeepSeek Harness\uFF0C\u6B63\u5728\u601D\u8003\u2026")}),I=new aS({client:g,channel:c,harness:this.#I,state:this.#l,contextEnhancement:this.#o,status:this.#u,allowedSenderOpenIds:new Set(this.#i),botId:this.#A,appId:this.#t,botOpenId:this.#a,groupResponseMode:this.#n,repair:this.#E,replyTimeoutMs:this.#s,signal:o,logger:this.#h});this.#f=I;let d=new this.#e.EventDispatcher({}).register({"im.message.receive_v1":_=>{e()&&I.accept(_)},"im.message.reaction.created_v1":()=>{},"im.message.reaction.deleted_v1":()=>{},"card.action.trigger":_=>{e()&&(this.#u.cardActionsReceived+=1,this.#u.lastCardActionAt=new Date().toISOString(),this.#D(_)||I.onCardAction(_))}}),B,f,Q=new Promise((_,T)=>{let R=!1,L=()=>{f(i())},U=(q,z)=>{R||(R=!0,clearTimeout(F),o.removeEventListener("abort",L),q(z))},F=setTimeout(()=>{U(T,new Error(`Feishu WebSocket handshake timed out after ${this.#c}ms`))},this.#c);B=()=>{U(_)},f=q=>{U(T,q)},o.addEventListener("abort",L,{once:!0}),o.aborted&&L()});Q.catch(()=>{});let y=new this.#e.WSClient({...r,...this.#d?{agent:this.#d}:{},loggerLevel:this.#e.LoggerLevel.info,handshakeTimeoutMs:this.#c,onReady:()=>{e()&&(this.#u.feishuLongConnectionState="connected",this.#u.ready=!0,this.#u.lastError=null,B())},onError:_=>{e()&&(this.#u.feishuLongConnectionState="failed",this.#u.ready=!1,this.#u.lastError=_?.message??String(_),this.#h.error("[dsh-feishu] Feishu long connection failed:",this.#u.lastError),f(_))},onReconnecting:()=>{e()&&(this.#u.feishuLongConnectionState="reconnecting",this.#u.ready=!1)},onReconnected:()=>{e()&&(this.#u.feishuLongConnectionState="connected",this.#u.ready=!0,this.#u.lastError=null)}});this.#B=y;let m=Promise.resolve().then(()=>y.start({eventDispatcher:d})).catch(_=>{throw f(_),_});return await Promise.all([m,Q]),a(),this.#b&&s&&this.#T(s,e,o),this.status}catch(A){throw o.aborted||(this.#u.ready=!1,this.#u.feishuLongConnectionState="failed",this.#u.lastError=A?.message??String(A),await this.#M({preserveError:!0,abortController:t})),A}}async beginCardActionProbe({expectedOperatorOpenId:t,timeoutMs:o=9e4}={}){if(!this.#u.ready||!this.#C)throw Rd("card_action_probe_unavailable","\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");let i=yn(t);if(!i||i==="*")throw new TypeError("A precise Feishu operator open_id is required");if(!Number.isFinite(o)||o<=0||o>10*6e4)throw new TypeError("Card-action probe timeout must be between 1 and 600000ms");let e=ike().replaceAll("-",""),a;try{a=await this.#C.im.v1.message.create({params:{receive_id_type:"open_id"},data:{receive_id:i,msg_type:"interactive",content:WW(e)}})}catch{throw this.#w(i,w(tP),"failure"),Rd("card_action_probe_send_failed","\u65E0\u6CD5\u53D1\u9001\u98DE\u4E66\u5361\u7247\u56DE\u8C03\u6D4B\u8BD5")}if(a?.code&&a.code!==0)throw this.#w(i,w(tP),"failure"),Rd("card_action_probe_send_failed","\u65E0\u6CD5\u53D1\u9001\u98DE\u4E66\u5361\u7247\u56DE\u8C03\u6D4B\u8BD5");let A=yn(a?.data?.message_id)??yn(a?.message_id);if(!A)throw this.#w(i,w(tP),"failure"),Rd("card_action_probe_send_failed","\u98DE\u4E66\u672A\u8FD4\u56DE\u6D4B\u8BD5\u5361\u7247\u7684\u6D88\u606F ID");return new Promise((r,s)=>{let g=setTimeout(()=>{let c=this.#m.get(A);!c||c.nonce!==e||(this.#m.delete(A),this.#w(i,w(ske),"timeout"),s(Rd("card_action_probe_timeout","\u5728\u89C4\u5B9A\u65F6\u95F4\u5185\u672A\u6536\u5230\u98DE\u4E66\u5361\u7247\u6309\u94AE\u56DE\u8C03")))},o);g.unref?.(),this.#m.set(A,{messageId:A,nonce:e,expectedOperatorOpenId:i,timeout:g,resolve:r,reject:s})})}#D(t){let o=yn(t?.context?.open_message_id);if(!o)return!1;let i=this.#m.get(o);if(!i)return!1;let e=t?.action?.value,a=Ike(t);return e?.action!=="repair_verify"||e?.nonce!==i.nonce||a!==i.expectedOperatorOpenId?!1:(clearTimeout(i.timeout),this.#m.delete(o),this.#u.cardActionProbesVerified+=1,this.#w(a,w(nke),"success").finally(()=>{i.resolve({verified:!0,messageId:o,operatorOpenId:a})}),!0)}#w(t,o,i){let e=this.#C;return e?Promise.resolve().then(async()=>{let a=await e.im.v1.message.create({params:{receive_id_type:"open_id"},data:{receive_id:t,msg_type:"text",content:JSON.stringify({text:o})}});if(a?.code&&a.code!==0)throw new Error("Feishu callback repair notice failed");return!0}).catch(()=>(this.#h.warn?.(`[dsh-feishu] unable to send the callback repair ${i} notice`),!1)):(this.#h.warn?.(`[dsh-feishu] unable to send the callback repair ${i} notice`),Promise.resolve(!1))}async sendConnectionTest(t){if(!this.#u.ready||!this.#C){let e=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw e.code="test-target-unavailable",e}if(typeof t!="string"||!t.trim())throw new TypeError("Feishu connection test text is required");let o=async(e,a,A)=>{let r=await this.#C.im.v1.message.create({params:{receive_id_type:e},data:{receive_id:a,msg_type:"text",content:JSON.stringify({text:A})}});if(r?.code&&r.code!==0)throw new Error(`Feishu connection test failed: ${r.msg||r.code}`)},i=this.#i.find(e=>e!=="*");return i?(await o("open_id",i,t),{sent:!0}):ec({state:this.#l,text:t,channelLabel:w("\u98DE\u4E66\u673A\u5668\u4EBA"),send:async(e,a)=>{let A=typeof e?.chatId=="string"?e.chatId.trim():"";if(!A)throw Ir(w("\u98DE\u4E66\u673A\u5668\u4EBA"));await o("chat_id",A,a)}})}async sendProactiveText(t,o,{signal:i}={}){if(!this.#u.ready||!this.#C){let r=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw r.code="bot-not-connected",r}let e=t?.kind==="user"?"open_id":t?.kind==="group"?"chat_id":null,a=t?.kind==="user"?yn(t?.route?.openId):t?.kind==="group"?yn(t?.route?.chatId):null;if(!e||!a){let r=new TypeError("Invalid Feishu proactive delivery target");throw r.code="invalid-target",r}i?.throwIfAborted();let A=await this.#C.im.v1.message.create({params:{receive_id_type:e},data:{receive_id:a,msg_type:"text",content:JSON.stringify({text:o})}});if(A?.code&&A.code!==0){let r=new Error(`Feishu proactive delivery failed: ${A.msg||A.code}`);throw r.code="target-rejected",r}return{sent:!0}}async#T(t,o,i){this.#u.slashCommandRegistration="registering",this.#u.slashCommandsError=null;try{let e=await f6({appId:this.#t,appSecret:this.#r,domain:this.#g,httpInstance:t,signal:i,manifest:Xv});if(!o())return;this.#u.slashCommandRegistration="done",this.#u.slashCommandsRegistered=e.created.length,this.#u.slashCommandsExisting=e.existing.length,this.#u.slashCommandsFailed=e.failed.length,this.#u.slashCommandsError=e.failed.length>0?e.failed.map(a=>`/${a.command}: ${a.error?.message??String(a.error)}`).join("; "):null,e.created.length>0&&this.#h.info?.(`[dsh-feishu] registered ${e.created.length} slash command(s)`),e.failed.length>0&&this.#h.warn?.(`[dsh-feishu] ${e.failed.length} slash command(s) failed to register: ${this.#u.slashCommandsError}`)}catch(e){if(!o())return;this.#u.slashCommandRegistration="failed",this.#u.slashCommandsError=e?.message??String(e),this.#h.warn?.(`[dsh-feishu] slash command registration skipped: ${this.#u.slashCommandsError}`)}}stop(t={}){if(this.#S)return this.#S;let o;return o=this.#k(t).finally(()=>{this.#S===o&&(this.#S=null)}),this.#S=o,o}async#k({preserveError:t=!1}={}){let o=this.#Q;this.#Q===o&&(this.#Q=null),o?.abort(new DOMException("Feishu runtime stopped","AbortError"));let i=this.#y;return i&&await i.catch(()=>{}),this.#M({preserveError:t,abortController:o})}async#M({preserveError:t=!1,abortController:o}={}){let i=t?this.#u.lastError:null;this.#Q===o&&(this.#Q=null),o?.abort(new DOMException("Feishu runtime stopped","AbortError"));for(let A of this.#m.values())clearTimeout(A.timeout),this.#w(A.expectedOperatorOpenId,w(gke),"abort"),A.reject(Rd("abort","\u98DE\u4E66\u8FD0\u884C\u65F6\u5DF2\u505C\u6B62"));this.#m.clear(),this.#u.ready=!1;let e=this.#B;this.#B=null,e?.close({force:!0});let a=this.#f;return this.#f=null,a&&await a.waitForIdle(),this.#C=null,this.#u.feishuLongConnectionState=t?"failed":"idle",this.#u.slashCommandRegistration="idle",this.#u.lastError=i,this.status}};var gS=class extends lr{constructor(t){super({...t,rpcIdPrefix:"feishu",logPrefix:"dsh-feishu"})}};import{createHash as hke}from"node:crypto";import{mkdir as Eke,readFile as Cke,rename as uke,unlink as Bke,writeFile as fke}from"node:fs/promises";import{dirname as Qke}from"node:path";var lS="DSH_FEISHU_APP_SECRET";function ps(n){return typeof n=="string"&&n.trim()?n.trim():null}function Q6(n){let t=ps(n);return t&&/^[A-Za-z0-9_-]{1,128}$/.test(t)?t:null}function y6(n){return`bot_${hke("sha256").update(n).digest("hex").slice(0,24)}`}function yke(n){let t=Array.isArray(n.ownerOpenIds)?n.ownerOpenIds:[n.ownerOpenId];return[...new Set(t.map(ps).filter(Boolean))]}function cS(n,{legacy:t=!1}={}){if(!n||typeof n!="object")return null;let o=ps(n.appId),i=yke(n);if(!o||i.length===0)return null;let e=Q6(n.id)??(t?y6(o):null),a=ps(n.secretRef)??(t?lS:null);if(!e||!a||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(a))return null;let A=n.domain==="lark"?"lark":"feishu";return Object.freeze({id:e,appId:o,secretRef:a,ownerOpenIds:Object.freeze(i),domain:A,botName:ps(n.botName),botOpenId:ps(n.botOpenId),activated:n.activated??null,groupResponseMode:ao(n.groupResponseMode),groupMessagePermissionGranted:n.groupMessagePermissionGranted===!0,deletionPending:n.deletionPending===!0,connectedAt:ps(n.connectedAt),createdAt:ps(n.createdAt)??ps(n.connectedAt)})}function mke(n){if(!n||typeof n!="object")return null;if(n.version===2&&Array.isArray(n.bots)){let o=n.bots.map(A=>cS(A));if(o.some(A=>A===null))throw new Error("dsh-feishu config contains an invalid bot entry");let i=new Set,e=new Set,a=new Set;for(let A of o){if(i.has(A.id)||e.has(A.secretRef)||a.has(A.appId))throw new Error("dsh-feishu config contains duplicate bot identities");i.add(A.id),e.add(A.secretRef),a.add(A.appId)}return{value:Object.freeze({version:2,bots:Object.freeze(o)}),migrated:!1}}let t=cS(n,{legacy:!0});return t?{value:Object.freeze({version:2,bots:Object.freeze([t])}),migrated:!0}:null}var IS=class{#e;#A=Object.freeze({version:2,bots:Object.freeze([])});#t=Promise.resolve();constructor(t){this.#e=t}async load(){try{let t=JSON.parse(await Cke(this.#e,"utf8")),o=mke(t);if(!o)throw new Error("dsh-feishu config is incomplete or invalid");this.#A=o.value,o.migrated&&await this.#a(this.#A)}catch(t){if(t?.code!=="ENOENT")throw t;this.#A=Object.freeze({version:2,bots:Object.freeze([])})}return this}get(){let t=this.#A.bots[0];if(!t)return null;let o=structuredClone(t);return o.ownerOpenId=o.ownerOpenIds[0],o}list(){return structuredClone(this.#A.bots)}getBot(t){let o=this.#A.bots.find(i=>i.id===t);return o?structuredClone(o):null}async save(t){let o={...t};o.id||(o.id=y6(ps(o.appId)??"invalid")),o.secretRef||(o.secretRef=lS);let i=cS(o);if(!i)throw new Error("Refusing to persist incomplete dsh-feishu configuration");return await this.#r([i]),this.get()}async saveBot(t){let o=cS(t);if(!o)throw new Error("Refusing to persist incomplete dsh-feishu bot configuration");return this.#g(i=>{if(i.find(r=>r.secretRef===o.secretRef&&r.id!==o.id))throw new Error("Refusing to share a credential reference between Feishu bots");if(i.find(r=>r.appId===o.appId&&r.id!==o.id))throw new Error("Refusing to persist the same Feishu app twice");let A=i.findIndex(r=>r.id===o.id);return A===-1?i.push(o):i[A]=o,structuredClone(o)})}async removeBot(t){if(!Q6(t))throw new TypeError("Invalid Feishu bot id");return this.#g(o=>{let i=o.findIndex(a=>a.id===t);if(i===-1)return null;let[e]=o.splice(i,1);return structuredClone(e)})}async clear(){let t=this.#t.then(async()=>{try{await Bke(this.#e)}catch(o){if(o?.code!=="ENOENT")throw o}this.#A=Object.freeze({version:2,bots:Object.freeze([])})});this.#t=t.then(()=>{},()=>{}),await t}async#r(t){let o=Object.freeze({version:2,bots:Object.freeze([...t])}),i=this.#t.then(async()=>{await this.#a(o),this.#A=o});this.#t=i.then(()=>{},()=>{}),await i}async#g(t){let o,i=this.#t.then(async()=>{let e=[...this.#A.bots];o=t(e);let a=Object.freeze({version:2,bots:Object.freeze(e)});await this.#a(a),this.#A=a});return this.#t=i.then(()=>{},()=>{}),await i,o}async#a(t){await Eke(Qke(this.#e),{recursive:!0,mode:448});let o=`${this.#e}.tmp`;await fke(o,`${JSON.stringify(t,null,2)} diff --git a/src/channels/feishu/bridge.mjs b/src/channels/feishu/bridge.mjs index fca0276..d26b956 100644 --- a/src/channels/feishu/bridge.mjs +++ b/src/channels/feishu/bridge.mjs @@ -1537,7 +1537,7 @@ export class FeishuHarnessBridge { ?? nonEmptyString(event?.open_chat_id) ?? nonEmptyString(event?.chat_id); if (chatId) { - this.#send(chatId, t('这个菜单已过期,请回复 /m 重新打开。')).catch(() => undefined); + this.#send(chatId, t('这个菜单已过期,请回复 /m 重新打开。'), { replyTo: messageId }).catch(() => undefined); } return Promise.resolve(); } @@ -1590,7 +1590,7 @@ export class FeishuHarnessBridge { await this.#sendSteer(entry, formText); return; } - await this.#send(entry.chatId, t('请输入补充指令后再提交。')); + await this.#send(entry.chatId, t('请输入补充指令后再提交。'), { replyTo: entry.messageId ?? null }); return; } } @@ -1752,10 +1752,13 @@ export class FeishuHarnessBridge { sessionPage = 0, selections = [], }) { + // Confirmations triggered by a card interaction stay anchored to the + // card's message so they land inside the same Feishu topic. + const reply = (text) => this.#send(chatId, text, { replyTo: messageId }); if (action === 'sessions' || /^sessions:\d+$/.test(action)) { const page = action === 'sessions' ? 0 : Number(action.slice('sessions:'.length)); await this.#showSessions( - { chatId, key }, + { chatId, key, replyTo: messageId }, sessionWorkspace, page, { updateMessageId: messageId }, @@ -1763,17 +1766,17 @@ export class FeishuHarnessBridge { return; } if (action === 'workspaces') { - await this.#showWorkspaces({ chatId, key }, { updateMessageId: messageId }); + await this.#showWorkspaces({ chatId, key, replyTo: messageId }, { updateMessageId: messageId }); return; } if (action === 'watchlist') { - await this.#showWatchList(key, chatId, { updateMessageId: messageId }); + await this.#showWatchList(key, chatId, { updateMessageId: messageId, replyTo: messageId }); return; } // 多选关注下拉:action=watch_add / watch_remove,选中项在 selections 数组 if (action === 'watch_add' || action === 'watch_remove') { if (selections.length === 0) { - await this.#send(chatId, t('请先选择至少一个会话。')); + await reply(t('请先选择至少一个会话。')); return; } let changed = 0; @@ -1819,54 +1822,53 @@ export class FeishuHarnessBridge { ? t('所选会话已在关注列表中。') : t('所选会话已不在关注列表中。'); try { - await this.#showWatchList(key, chatId, { updateMessageId: messageId }); + await this.#showWatchList(key, chatId, { updateMessageId: messageId, replyTo: messageId }); } catch (error) { this.#logger.warn?.('[dsh-feishu] watch list refresh failed:', error.message); } - await this.#send(chatId, summary).catch((error) => { + await reply(summary).catch((error) => { this.#logger.warn?.('[dsh-feishu] watch batch summary failed:', error.message); }); return; } if (action === 'new') { if (this.#queues.has(key) || this.#hasPendingInteraction(key)) { - await this.#send(chatId, t('当前任务仍在运行,请先停止任务或等待任务完成后再开启新会话。')); + await reply(t('当前任务仍在运行,请先停止任务或等待任务完成后再开启新会话。')); return; } await this.#state.clearSession(key); - await this.#send(chatId, t('已开启全新 Harness 会话。')); - await this.#sendMenuCard(key, chatId, { updateMessageId: messageId }); + await reply(t('已开启全新 Harness 会话。')); + await this.#sendMenuCard(key, chatId, { updateMessageId: messageId, replyTo: messageId }); return; } if (action === 'use:current') { const sessionId = this.#state.sessionFor(key); if (typeof sessionId !== 'string' || !sessionId) { - await this.#send(chatId, t('当前没有绑定的会话,请先从会话列表选择。')); + await reply(t('当前没有绑定的会话,请先从会话列表选择。')); return; } - await this.#send(chatId, t('已就绪,直接发消息即可继续当前会话。')); + await reply(t('已就绪,直接发消息即可继续当前会话。')); return; } if (action === 'archive_toggle' || action === 'archive:on' || action === 'archive:off') { const next = action === 'archive:on' ? true : action === 'archive:off' ? false : !(this.#state?.includesArchivedSessions?.() ?? false); await this.#state?.setIncludeArchivedSessions?.(next); - await this.#send( - chatId, + await reply( next ? t('已开启:会话列表包含归档会话。') : t('已关闭:会话列表隐藏归档会话。'), ); - await this.#sendMenuCard(key, chatId, { updateMessageId: messageId }); + await this.#sendMenuCard(key, chatId, { updateMessageId: messageId, replyTo: messageId }); return; } if (action === 'repair') { - await this.#send(chatId, t('修复需在私聊中验证接入者身份,请直接发送 /repair 开始。')); + await reply(t('修复需在私聊中验证接入者身份,请直接发送 /repair 开始。')); return; } if (action === 'compact') { - await this.#handleCompact(key, chatId); + await this.#handleCompact(key, chatId, messageId); return; } if (action === 'stop') { - await this.#handleStop(key, chatId); + await this.#handleStop(key, chatId, messageId); return; } if (action === 'steer') { @@ -1877,10 +1879,10 @@ export class FeishuHarnessBridge { if (action.startsWith('steer:')) { const raw = action.slice('steer:'.length); if (raw === 'custom') { - await this.#sendCard(chatId, customSteerCard(), { key, updateMessageId: messageId }); + await this.#sendCard(chatId, customSteerCard(), { key, updateMessageId: messageId, replyTo: messageId }); return; } - await this.#sendSteer({ key, chatId }, raw); + await this.#sendSteer({ key, chatId, messageId }, raw); return; } if (action === 'presets') { @@ -1900,7 +1902,7 @@ export class FeishuHarnessBridge { return; } if (action === 'back_to_menu') { - await this.#sendMenuCard(key, chatId, { updateMessageId: messageId }); + await this.#sendMenuCard(key, chatId, { updateMessageId: messageId, replyTo: messageId }); return; } if (action === 'preset_default') { @@ -1923,18 +1925,18 @@ export class FeishuHarnessBridge { return; } if (action.startsWith('use:')) { - await this.#bindSession(key, chatId, action.slice('use:'.length), { updateMessageId: messageId }); + await this.#bindSession(key, chatId, action.slice('use:'.length), { updateMessageId: messageId, replyTo: messageId }); return; } if (action.startsWith('workspace:')) { - await this.#switchWorkspace(key, chatId, action.slice('workspace:'.length), { updateMessageId: messageId }); + await this.#switchWorkspace(key, chatId, action.slice('workspace:'.length), { updateMessageId: messageId, replyTo: messageId }); return; } if (action.startsWith('unwatch:')) { - const result = await this.#runUnwatch(key, chatId, action.slice('unwatch:'.length)); + const result = await this.#runUnwatch(key, chatId, action.slice('unwatch:'.length), { replyTo: messageId }); if (result.ok && messageId) { await this.#showSessions( - { chatId, key }, + { chatId, key, replyTo: messageId }, sessionWorkspace, sessionPage, { updateMessageId: messageId }, @@ -1946,10 +1948,11 @@ export class FeishuHarnessBridge { const sessionId = action.slice('watch:'.length); const result = await this.#runWatch(key, chatId, sessionId, { workspaceHint: sessionWorkspace, + replyTo: messageId, }); if (result.ok && messageId) { await this.#showSessions( - { chatId, key }, + { chatId, key, replyTo: messageId }, sessionWorkspace, sessionPage, { updateMessageId: messageId }, @@ -1978,48 +1981,50 @@ export class FeishuHarnessBridge { } async #handleMenuPick(menu, number, { chatId, key, event }) { + const replyTo = event?.message?.message_id ?? null; + const reply = (text) => this.#send(chatId, text, { replyTo }); if (menu.kind === 'menu') { // Number fallback for the total menu: // 1=工作区列表 2=新会话 3=会话列表 4=状态 5=修复 6=帮助 const actions = ['workspaces', 'new', 'sessions', 'status', 'repair', 'help']; const action = actions[number - 1]; if (!action) { - await this.#send(chatId, t('菜单没有这个编号,回复 /m 重新打开。')); + await reply(t('菜单没有这个编号,回复 /m 重新打开。')); return; } if (action === 'repair') { await this.#handleRepairCommand(event, '/repair'); return; } - await this.#handleCardAction(action, { chatId, key }); + await this.#handleCardAction(action, { chatId, key, messageId: replyTo }); return; } if (menu.kind === 'sessions') { const session = menu.sessions[number - 1]; if (!session?.sessionId) { - await this.#send(chatId, t('本页只有 {count} 个会话,回复 /sessionlist 重新查看。', { count: menu.sessions.length })); + await reply(t('本页只有 {count} 个会话,回复 /sessionlist 重新查看。', { count: menu.sessions.length })); return; } // The number label sits on the session (bind) button of the row. - await this.#handleCardAction(`use:${session.sessionId}`, { chatId, key }); + await this.#handleCardAction(`use:${session.sessionId}`, { chatId, key, messageId: replyTo }); return; } if (menu.kind === 'workspaces') { const workspace = menu.paths[number - 1]; if (!workspace) { - await this.#send(chatId, t('只有 {count} 个工作区,回复 /workspacelist 重新查看。', { count: menu.paths.length })); + await reply(t('只有 {count} 个工作区,回复 /workspacelist 重新查看。', { count: menu.paths.length })); return; } - await this.#handleCardAction(`workspace:${workspace}`, { chatId, key }); + await this.#handleCardAction(`workspace:${workspace}`, { chatId, key, messageId: replyTo }); return; } if (menu.kind === 'watches') { const entry = menu.entries[number - 1]; if (!entry?.sessionId) { - await this.#send(chatId, t('关注列表只有 {count} 个会话。', { count: menu.entries.length })); + await reply(t('关注列表只有 {count} 个会话。', { count: menu.entries.length })); return; } - await this.#handleCardAction(`unwatch:${entry.sessionId}`, { chatId, key }); + await this.#handleCardAction(`unwatch:${entry.sessionId}`, { chatId, key, messageId: replyTo }); } } @@ -2096,15 +2101,15 @@ export class FeishuHarnessBridge { } } - async #bindSession(key, chatId, sessionId, { updateMessageId = null } = {}) { + async #bindSession(key, chatId, sessionId, { updateMessageId = null, replyTo = null } = {}) { try { const bound = await this.#harness.bindWorkspaceSession(key, sessionId); const title = String(bound?.title ?? '').replace(/\s+/gu, ' ').trim() || t('暂无标题'); await this.#send(chatId, [ t('已绑定会话「{title}」\nID:{id}', { title, id: bound?.sessionId ?? sessionId }), t('发送 /history 查看最近对话。'), - ].join('\n')); - await this.#sendMenuCard(key, chatId, { updateMessageId }); + ].join('\n'), { replyTo }); + await this.#sendMenuCard(key, chatId, { updateMessageId, replyTo }); } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'session binding', @@ -2113,11 +2118,11 @@ export class FeishuHarnessBridge { } } - async #switchWorkspace(key, chatId, workspace, { updateMessageId = null } = {}) { + async #switchWorkspace(key, chatId, workspace, { updateMessageId = null, replyTo = null } = {}) { try { const current = await this.#harness.switchWorkspace(workspace); - await this.#send(chatId, t('工作区已切换为:{workspace}', { workspace: current })); - await this.#sendMenuCard(key, chatId, { updateMessageId }); + await this.#send(chatId, t('工作区已切换为:{workspace}', { workspace: current }), { replyTo }); + await this.#sendMenuCard(key, chatId, { updateMessageId, replyTo }); } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'workspace switch', @@ -2467,12 +2472,12 @@ export class FeishuHarnessBridge { /** * Run the /compact command and show the result. */ - async #handleCompact(key, chatId) { + async #handleCompact(key, chatId, replyTo = null) { try { const result = await runCompactCommand( '/compact', this.#harness, this.#state, key, { signal: this.#signal }, ); - await this.#send(chatId, result?.message || t('上下文压缩失败。')); + await this.#send(chatId, result?.message || t('上下文压缩失败。'), { replyTo }); } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'compact' }); } @@ -2481,7 +2486,7 @@ export class FeishuHarnessBridge { /** * Stop the running task in the bound session (mirrors `/stop`). */ - async #handleStop(key, chatId) { + async #handleStop(key, chatId, replyTo = null) { try { const result = await runControlCommand( '/stop', this.#harness, this.#state, key, { @@ -2495,7 +2500,7 @@ export class FeishuHarnessBridge { this.#approvals.closeRoute(key), ]); } - await this.#send(chatId, result?.message || t('/stop 执行完成。')); + await this.#send(chatId, result?.message || t('/stop 执行完成。'), { replyTo }); } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'stop' }); } @@ -2522,26 +2527,26 @@ export class FeishuHarnessBridge { control: { owner: this, key }, }, ); - await this.#send(chatId, result?.message || t('已提交补充指令。')); + await this.#send(chatId, result?.message || t('已提交补充指令。'), { replyTo: entry.messageId ?? null }); } /** * Reset the preset to follow the Host default. */ - async #handlePresetDefault(key, chatId, { updateMessageId = null } = {}) { + async #handlePresetDefault(key, chatId, { updateMessageId = null, replyTo = null } = {}) { try { const result = await runPresetCommand( '/preset --default', this.#harness, this.#state, key, { signal: this.#signal }, ); for (const reply of result?.messages ?? [result?.message]) { - if (reply) await this.#send(chatId, reply); + if (reply) await this.#send(chatId, reply, { replyTo }); } } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'preset reset' }); return; } try { - await this.#sendMenuCard(key, chatId, { updateMessageId }); + await this.#sendMenuCard(key, chatId, { updateMessageId, replyTo }); } catch (error) { this.#logger.warn?.('[dsh-feishu] menu refresh failed after preset reset:', error.message); } @@ -2550,21 +2555,21 @@ export class FeishuHarnessBridge { /** * Handle preset selection from the preset dropdown. */ - async #handlePresetSelect(key, chatId, presetId, { updateMessageId = null } = {}) { + async #handlePresetSelect(key, chatId, presetId, { updateMessageId = null, replyTo = null } = {}) { try { const selector = /^\d+$/u.test(presetId) ? `id:${presetId}` : presetId; const result = await runPresetCommand( `/preset ${selector}`, this.#harness, this.#state, key, { signal: this.#signal }, ); for (const reply of result?.messages ?? [result?.message]) { - if (reply) await this.#send(chatId, reply); + if (reply) await this.#send(chatId, reply, { replyTo }); } } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'preset selection' }); return; } try { - await this.#sendMenuCard(key, chatId, { updateMessageId }); + await this.#sendMenuCard(key, chatId, { updateMessageId, replyTo }); } catch (error) { this.#logger.warn?.('[dsh-feishu] menu refresh failed after preset select:', error.message); } @@ -2579,7 +2584,7 @@ export class FeishuHarnessBridge { * catalog validation, busy checks, pending-interaction checks and the * session binding lock stay in one place. */ - async #handleModelSelect(key, chatId, modelId, { updateMessageId = null } = {}) { + async #handleModelSelect(key, chatId, modelId, { updateMessageId = null, replyTo = null } = {}) { try { const result = await runModelCommand( `/model ${modelId}`, this.#harness, this.#state, key, { @@ -2589,14 +2594,14 @@ export class FeishuHarnessBridge { }, ); for (const reply of result?.messages ?? [result?.message]) { - if (reply) await this.#send(chatId, reply); + if (reply) await this.#send(chatId, reply, { replyTo }); } } catch (error) { await this.#sendFailure(chatId, error, { logLabel: 'model selection' }); return; } try { - await this.#sendMenuCard(key, chatId, { updateMessageId }); + await this.#sendMenuCard(key, chatId, { updateMessageId, replyTo }); } catch (error) { this.#logger.warn?.('[dsh-feishu] menu refresh failed after model select:', error.message); }