diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c61ce9..af464c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ This file records the notable changes in each dsh-im release. Its format follows ## [Unreleased] +### Fixed / 修复 + +- `/compact` 同时兼容要求 `images` 字段的新 Harness 与不接受该字段的旧 Harness;仅在网关明确拒绝多余字段、命令尚未执行时回退,避免重复压缩。 + `/compact` now supports both newer Harness endpoints that require `images` and older endpoints that reject it, falling back only after an explicit pre-execution field rejection to avoid duplicate compaction. + ## [3.0.6] - 2026-08-26 ### Fixed / 修复 diff --git a/lib/index.js b/lib/index.js index c5a31b9..d8f6f0a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -211,7 +211,7 @@ ${N}`:J;y&&await Q.finish(H)||await this.#O(g,H)}catch{this.#c.error?.("[dsh-din `).trim()}function pi(n){return typeof n=="string"&&n.trim()?n.trim():null}function lpe(n){if(!n||typeof n!="object")return null;let t=pi(n.message);if(t)return t;let o=pi(n.name),i=pi(n.code);return o||i?[o??"Error",i].filter(Boolean).join(": "):null}function ppe(n,t){let o=[...t].map(i=>i?.event??i).filter(Boolean).sort((i,e)=>(i.seq??-1)-(e.seq??-1));for(let i of o){let e=i.seq??-1;if(e<=n.lastSeq)continue;if(n.lastSeq=e,i.type==="turn/start"){let A=i.data?.turn??null;n.active&&A!==n.turn&&(n.active=!1),n.turn!==null&&A!==n.turn&&(n.completed=!0),n.openTurn=A;continue}if(i.type==="user/message"&&i.data?.source?.rpcId===n.promptRpcId){n.active=!0,n.started=!0,n.completed=!1,n.turn=i.data?.turn??n.openTurn;continue}if(i.type==="turn/end"&&i.data?.turn===n.turn){n.active=!1,n.completed=!0;continue}let a=null;if(i.type==="tool/call"&&n.active&&i.data?.turn===n.turn&&typeof i.data?.callId=="string"&&i.data.callId)a={callId:i.data.callId,name:i.data?.name,arguments:i.data?.arguments};else if(i.type==="tool/code-dispatch-start"&&n.active&&typeof i.data?.subCallId=="string"&&i.data.subCallId){let A;try{A=JSON.stringify(i.data?.arguments)}catch{A=void 0}a={callId:i.data.subCallId,name:i.data?.name,arguments:A}}a&&n.toolCalls.set(a.callId,Object.freeze(a))}}var jl=class{#e;#A;#t=null;#r=null;#a=new Map;#i="";#c=!1;#s=null;#I=new Map;#o=null;constructor({promptRpcId:t,afterSeq:o=-1}){this.#e=t,this.#A=o}get finished(){return this.#c}get answer(){return this.#i.trim()}get reason(){return this.#s}get tracking(){return this.#r!==null&&!this.#c}get turn(){return this.#r}consumeAll(t){let o=[],i=a=>{if(a.type==="text"&&o.length>0&&o[o.length-1].type==="text"){o[o.length-1]=a;return}o.push(a)},e=[...t].map(a=>a?.event??a).filter(Boolean).sort((a,A)=>(a.seq??-1)-(A.seq??-1));for(let a of e){let A=a.seq??-1;if(!(A<=this.#A)){if(this.#A=A,a.type==="turn/start"&&(this.#t=a.data?.turn??null),a.type==="user/message"&&a.data?.source?.rpcId===this.#e){this.#r=this.#t;continue}if(this.#r!==null){if(a.type==="turn/end"){if(a.data?.turn!==this.#r)continue;this.#c=!0,this.#s=a.data?.reason??null,this.#t=null;continue}if(a.data?.turn===this.#r){if(a.type==="assistant/chunk"&&a.data?.chunk?.type==="text-delta"){let r=a.data?.step??0,s=a.data.chunk.index??0,g=`${r}:${s}`;this.#a.set(g,(this.#a.get(g)??"")+a.data.chunk.text);let c=`${r}:`,I=[...this.#a.entries()].filter(([d])=>d.startsWith(c)).sort(([d],[B])=>Number(d.split(":")[1])-Number(B.split(":")[1])).map(([,d])=>d).join(` `).trim();I&&I!==this.#i&&(this.#i=I,i({type:"text",text:I}));continue}if(a.type==="assistant/message"){let r=Ipe(a);r&&r!==this.#i&&(this.#i=r,i({type:"text",text:r}));continue}if(a.type==="tool/call"){let r=pi(a.data?.name)??D("\u5DE5\u5177"),s=pi(a.data?.callId)??pi(a.data?.subCallId);s&&this.#I.set(s,r),this.#o=r,i({type:"tool",name:r,...s?{callId:s}:{}})}else if(a.type==="tool/result"){let r=pi(a.data?.message?.source?.callId)??pi(a.data?.callId)??pi(a.data?.subCallId),s=(r?this.#I.get(r):null)??this.#o,g=lpe(a.data?.error);i({type:"status",text:D("\u6B63\u5728\u6574\u7406\u7ED3\u679C\u2026"),...s?{toolName:s}:{},...g?{error:g}:{}})}}}}}return o}consume(t){return this.consumeAll(t).at(-1)??null}},Xo=class extends Error{constructor(t,o){super(`${t}: ${o?.message??"unknown Harness RPC error"}`),this.name="HarnessRpcError",this.method=t,this.code=o?.code??"internal",this.details=o?.details??{}}},kg=class extends Error{constructor(t,o,{cause:i,status:e}={}){let a=Number.isInteger(e)?`, HTTP ${e}`:"";super(`Harness ${o} transport failed (${t}${a})`,{cause:i}),this.name="HarnessTransportError",this.code=t,this.method=o,Number.isInteger(e)&&(this.status=e)}},IM=class extends Error{constructor(t){super("Harness health RPC was rejected",{cause:t}),this.name="HarnessHealthError",this.code="harness-rpc-rejected",this.method="host.describe"}},Jl=class extends Error{constructor(t,o){super(o),this.name="HarnessInteractionError",this.code=t}},kn=class extends Error{constructor(t,{reason:o,providerCode:i}={}){super(`Harness turn failed (${t})`),this.name="HarnessTurnError",this.code=t,this.promptAccepted=!0,o&&typeof o=="object"&&(this.reason=o),typeof i=="string"&&i&&(this.providerCode=i)}};function Ax(n){let t=pi(n?.kind)??pi(n);if(t==="error"){let o=n?.error??n?.failure;return new kn("harness-turn-failed",{reason:n,providerCode:pi(o?.code)??void 0})}return t==="max-tokens"?new kn("model-max-tokens",{reason:n}):t==="blocked"?new kn("turn-blocked",{reason:n}):["interrupted","stopped","cancelled","canceled"].includes(t)?new kn("turn-interrupted",{reason:n}):t==="aborted"?new kn("turn-aborted",{reason:n}):t==="completed"?new kn("model-empty-response",{reason:n}):new kn("harness-turn-failed",{reason:n})}function dpe(n){return n==null?!0:(pi(n?.kind)??pi(n))==="completed"}var lr=class{#e;#A;#t;#r;#a;#i;#c;#s;#I;#o;#n;#g;#l;#p;#d=null;#h;#E;#u;#B;constructor({baseUrl:t,workspace:o,agentPreset:i,autostart:e=!1,dshBin:a="dsh",fetchImpl:A=fetch,createWebSocket:r=Q=>new WebSocket(Q),interactionReconnectDelayMs:s=500,rpcIdPrefix:g="im",logPrefix:c="dsh-im",commandExecutor:I,controlExecutor:d,sessionMaintenanceExecutor:B,fileIngressExecutor:f}){if(typeof r!="function")throw new TypeError("createWebSocket must be a function");if(!Number.isFinite(s)||s<0)throw new TypeError("interactionReconnectDelayMs must be a non-negative number");if(typeof g!="string"||!g.trim())throw new TypeError("rpcIdPrefix must be a non-empty string");if(typeof c!="string"||!c.trim())throw new TypeError("logPrefix must be a non-empty string");if(I!==void 0&&typeof I!="function")throw new TypeError("commandExecutor must be a function");if(d!==void 0&&typeof d!="function")throw new TypeError("controlExecutor must be a function");if(B!==void 0&&typeof B!="function")throw new TypeError("sessionMaintenanceExecutor must be a function");if(f!==void 0&&typeof f!="function")throw new TypeError("fileIngressExecutor must be a function");this.#e=new URL(t),this.#A=o,this.#t=i??void 0,this.#r=e,this.#a=a,this.#i=A,this.#c=r,this.#s=s,this.#I=g.trim(),this.#o=c.trim(),this.#n=I,this.#g=d,this.#l=B,this.#p=f,this.#h=ape(this.#e.origin),this.#E=this.#h.ownerships,this.#u=this.#h.claims,this.#B=this.#h.controls}async rpc(t,o={},i=3e4,e={}){let a=e.rpcId??`${this.#I}-${WK()}`,A=AbortSignal.timeout(i),r=e.signal?AbortSignal.any([e.signal,A]):A,s;try{s=await this.#i(new URL(`/api/${t}`,this.#e),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({type:"client-request",rpcId:a,method:t,payload:o}),signal:r})}catch(c){throw e.signal?.aborted?c:new kg(A.aborted?"harness-timeout":"harness-connect-failed",t,{cause:c})}if(!s.ok){let c=await rpe(s,this.#e.hostname);throw new kg(c,t,{status:s.status})}let g;try{g=await s.json()}catch(c){throw new kg("harness-response-invalid",t,{cause:c})}if(g?.type!=="server-response"||g?.rpcId!==a)throw new kg("harness-response-invalid",t,{cause:new Error(`Harness returned an invalid response for ${t}`)});if(!g.result||typeof g.result!="object"||typeof g.result.ok!="boolean")throw new kg("harness-response-invalid",t,{cause:new Error(`Harness returned an invalid result for ${t}`)});if(!g.result?.ok)throw new Xo(t,g.result?.error);return g.result.value}async health(t={}){try{return await this.rpc("host.describe",{},5e3,t),!0}catch(o){throw o instanceof Xo?new IM(o):o}}async ensureRunning(t={}){try{return await this.health(t)}catch(e){if(!this.#r)throw e}if(!this.#d||this.#d.exitCode!==null){let e=this.#e.port||(this.#e.protocol==="https:"?"443":"80");this.#d=Xle(this.#a,["web","--host",this.#e.hostname,"--port",e],{cwd:this.#A,env:process.env,stdio:["ignore","inherit","inherit"]}),this.#d.on("error",a=>{console.error(`[${this.#o}] failed to start Harness:`,a.message)})}let o=Date.now()+6e4,i;for(;Date.now(){let r=A&&i.signal?AbortSignal.any([A,i.signal]):A??i.signal;return this.rpc("session.selectModel",{sessionId:t,provider:o.provider,model:o.model,...o.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}},3e4,r?{...i,signal:r}:i)},a=this.#l?await this.#l({sessionId:t,operation:e}):await e();if(!a||typeof a!="object"||!cM(a.selected))throw new Error("Harness returned an invalid response for session.selectModel");return a}async isSessionRunning(t,o={}){if(typeof t!="string"||!t)throw new TypeError("sessionId is required");await this.ensureRunning(o);let i=await this.rpc("session.list",{},3e4,o);if(!i||typeof i!="object"||!Array.isArray(i.items))throw new Error("Harness returned an invalid response for session.list");for(let e of i.items)if(!e||typeof e!="object"||typeof e.sessionId!="string"||!e.sessionId||typeof e.running!="boolean")throw new Error("Harness returned an invalid response for session.list");return i.items.find(e=>e.sessionId===t)?.running??!1}async adoptWorkspaceSession(t,o={}){return VK(this,t,o)}async workspaceId(t={}){let{workspace:o=this.#A,...i}=t,{items:e}=await this.rpc("workspace.list",{},3e4,i),a=e.find(r=>r.path===o);return a?a.workspaceId:(await this.rpc("workspace.create",{path:o},3e4,i)).workspace.workspaceId}async createSession(t={}){let{agentPreset:o,...i}=t;await this.ensureRunning(i);let a={workspaceId:await this.workspaceId(i)},A=o!==void 0?o:this.#t;return A!=null&&(a.agentPreset=A),(await this.rpc("session.create",a,3e4,i)).sessionId}async executeCommand(t,o,i={}){if(typeof t!="string"||!t)throw new TypeError("sessionId is required");if(typeof o!="string"||!o)throw new TypeError("command line is required");if(!this.#n){let e=new Error("Harness command execution is unavailable");throw e.code="commands-unavailable",e}try{return await this.#n(t,o,i)}catch(e){throw e?.failure&&typeof e.failure=="object"?new Xo("commands.execute",e.failure):e}}async sessionExists(t,o={}){try{return await this.rpc("session.history",{sessionId:t,maxMessages:1},3e4,o),!0}catch(i){if(i instanceof Xo&&i.code==="session-not-found")return!1;throw i}}async respondInteraction(t,o,i={}){if(typeof t!="string"||!t)throw new TypeError("rpcId is required");if(!o||typeof o!="object"||typeof o.ok!="boolean")throw new TypeError("A Harness RPC result is required");let e=AbortSignal.timeout(i.timeoutMs??3e4),a=i.signal?AbortSignal.any([i.signal,e]):e,A=await this.#i(new URL("/api/respond",this.#e),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({type:"client-response",rpcId:t,result:o}),signal:a});if(!A.ok)throw new Error(`Harness transport respond failed: HTTP ${A.status}`);let r=await A.json();if(r?.accepted===!0)return r;if(r?.accepted!==!1||r.reason!=="bad-response"&&r.reason!=="not-pending")throw new Error("Harness returned an invalid interaction response receipt");let s=r.reason;throw new Jl(`interaction-${s}`,`Harness interaction response was rejected (${s})`)}async watchInteractions(t,{signal:o,onInteraction:i,onResolved:e,onOpen:a,ownership:A}={}){if(typeof t!="string"||!t)throw new TypeError("sessionId is required");if(!o||typeof o.addEventListener!="function")throw new TypeError("watchInteractions requires an AbortSignal");if(i!==void 0&&typeof i!="function")throw new TypeError("onInteraction must be a function");if(e!==void 0&&typeof e!="function")throw new TypeError("onResolved must be a function");if(a!==void 0&&typeof a!="function")throw new TypeError("onOpen must be a function");for(;!o.aborted;){try{await this.#R(t,{signal:o,onInteraction:i,onResolved:e,onOpen:a,ownership:A})}catch(r){if(o.aborted)return;console.warn(`[${this.#o}] Harness interaction stream disconnected:`,r.message)}if(o.aborted)return;try{await eE(this.#s,o)}catch{if(o.aborted)return;throw new Error("Harness interaction reconnect wait failed")}}}#f(t,o){let i=this.#E.get(t)??new Set;o.order=this.#h.nextOrder,this.#h.nextOrder+=1,i.add(o),this.#E.set(t,i)}#m(t,o){let i=this.#E.get(t);i?.delete(o),i?.size===0&&this.#E.delete(t);for(let[e,a]of this.#u)a.ownership===o&&this.#u.delete(e)}#y(t){if(!t.control)return;let o=this.#B.get(t.control.owner);o||(o=new Map,this.#B.set(t.control.owner,o));let i=o.get(t.control.key)??new Set;i.add(t),o.set(t.control.key,i)}#Q(t){if(!t.control)return;let o=this.#B.get(t.control.owner),i=o?.get(t.control.key);i?.delete(t),i?.size===0&&o.delete(t.control.key),o?.size===0&&this.#B.delete(t.control.owner)}#C(t,o){let i=XK(o);return i?[...this.#B.get(i.owner)?.get(i.key)??[]].filter(a=>a.sessionId===t).sort((a,A)=>a.order-A.order):[]}#b(t,o){return this.#C(t,o).find(i=>i.started&&i.active&&!i.completed&&i.turn!==null)??null}async#M(t,o,i){let e=this.#C(t,o);if(e.length===0)return null;try{let a=await this.rpc("session.history",{sessionId:t,maxMessages:50},3e4,i);this.#w(t,a.events??[])}catch(a){if(!(a instanceof Xo)||a.code!=="session-not-found")throw a;for(let A of e)A.active=!1,A.completed=!0;return null}return this.#b(t,o)}async hasActiveTurn(t,o,i={}){if(typeof t!="string"||!t)throw new TypeError("sessionId is required");return!!await this.#M(t,o,i)}async stopActiveTurn(t,o,i={}){if(typeof t!="string"||!t)throw new TypeError("sessionId is required");let e=await this.#M(t,o,i);if(!e)return!1;if(e.stopRequested)return!0;if(this.#b(t,o)!==e)return!1;e.stopRequested=!0;try{if(this.#g){let a=this.#g({sessionId:t,expectedTurn:e.turn,promptRpcId:e.promptRpcId,action:"stop"});if(a&&typeof a.then=="function")throw new TypeError("controlExecutor must return synchronously");if(a!==void 0){if(typeof a!="boolean")throw new TypeError("controlExecutor must return a boolean or undefined");return a||(e.stopRequested=!1),a}}return await this.rpc("session.cancel",{sessionId:t,keepInbox:!0},3e4,i),!0}catch(a){if(this.#b(t,o)===e&&(e.stopRequested=!1),a instanceof Xo&&a.code==="session-not-found")return!1;throw a}}async steerActiveTurn(t,o,i,e={}){if(typeof t!="string"||!t)throw new TypeError("sessionId is required");if(typeof o!="string"||!o.trim())throw new TypeError("Steering text is required");let a=await this.#M(t,i,e);if(!a||a.stopRequested||this.#b(t,i)!==a)return!1;if(this.#g){let A=this.#g({sessionId:t,expectedTurn:a.turn,promptRpcId:a.promptRpcId,action:"steer",text:o});if(A&&typeof A.then=="function")throw new TypeError("controlExecutor must return synchronously");if(A!==void 0){if(typeof A!="boolean")throw new TypeError("controlExecutor must return a boolean or undefined");return A}}return await this.rpc("session.prompt",{sessionId:t,mode:"steer",content:[{type:"text",text:o}],clientTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone},3e4,e),!0}#w(t,o){for(let i of this.#E.get(t)??[])ppe(i,o)}async#S(t,o){let i=await this.rpc("session.history",{sessionId:t,maxMessages:50},3e4,{signal:o});this.#w(t,i.events??[])}#_(t,o,i){let e=this.#u.get(o);if(e&&this.#E.get(t)?.has(e.ownership))return e;let a=[...this.#E.get(t)??[]],A=a.filter(s=>s.active).sort((s,g)=>s.order-g.order);if(A.length>0)return{ownership:A[0],recovered:!1};let r=a.filter(s=>!s.started&&!s.completed).sort((s,g)=>s.order-g.order)[0]??null;return r?{ownership:r,recovered:!0}:null}async ask(t,o,i={}){typeof i=="number"&&(i={timeoutMs:i});let e=i.timeoutMs??6e5,a=i.signal,A=typeof i.onUpdate=="function"?i.onUpdate:null,r=i.progressMode==="all"?"all":"latest",s=typeof i.onArtifact=="function"?i.onArtifact:null,g=typeof i.onInteraction=="function"?i.onInteraction:void 0,c=typeof i.onInteractionResolved=="function"?i.onInteractionResolved:void 0,I=XK(i.control),d=Array.isArray(i.files)?i.files.filter(Boolean):[];await this.ensureRunning({signal:a});let B=await this.rpc("session.history",{sessionId:t,maxMessages:1},3e4,{signal:a}),f=Math.max(-1,...(B.events??[]).map(({event:V})=>V.seq??-1)),Q=`${this.#I}-${WK()}`,y=new jl({promptRpcId:Q,afterSeq:f}),m=g||c?new AbortController:null,_=m?a?AbortSignal.any([a,m.signal]):m.signal:null,N=m||I?{sessionId:t,promptRpcId:Q,active:!1,started:!1,completed:!1,stopRequested:!1,turn:null,openTurn:null,lastSeq:f,reconnect:null,order:-1,toolCalls:new Map,control:I}:null,G=null,Y=!1,J=0,H=null,j=!1,q=!1,U=async()=>{if(!s||Y||y.turn===null)return J;Y=!0;let V=$c.take(t,y.turn,{signal:a});for(let L of V)try{await s(L),J+=1}catch(T){$c.release(L),console.warn(`[${this.#o}] ignored an artifact handoff failure:`,T.message)}return J};N&&(this.#f(t,N),this.#y(N));let R=$c.openConsumer(t,Q);try{if(d.length>0){if(!this.#p)throw new ho("inbound-file-ingress-unavailable","Harness file ingress is unavailable in this Host process.");let T=(await this.rpc("session.list",{},3e4,{signal:a}))?.items?.find(P=>P?.sessionId===t)?.cwd;H=await this.#p({sessionId:t,workspace:T,files:d,signal:a}),o=_K(o,H)}if(_){let L,T=new Promise(P=>{L=P});G=this.watchInteractions(t,{signal:_,onInteraction:g,onResolved:c,onOpen:L,ownership:N}),G.catch(()=>{}),await Promise.race([T,eE(3e4,_).then(()=>{throw new Error("Harness interaction stream did not open within 30 seconds")})])}let V=typeof o=="string"?[{type:"text",text:o}]:o;if(!Array.isArray(V)||V.length===0)throw new TypeError("Harness prompt content is required");await this.rpc("session.prompt",{sessionId:t,mode:"queue",content:V,clientTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone},3e4,{rpcId:Q,signal:a}),j=!0;try{let L=Date.now()+e;for(;Date.now()0)return"";throw N?.stopRequested?ex():Ax(y.reason)}throw new kn("harness-reply-timeout")}catch(L){if(!N?.stopRequested)throw L;if(y.answer)return y.answer;throw L?.code==="turn-stopped"?L:ex()}}finally{H&&(!j||q)&&await H.cleanup().catch(V=>{console.warn(`[${this.#o}] unable to clean inbound files:`,V.message)}),R(),N&&(this.#Q(N),this.#m(t,N)),y.turn!==null&&$c.discard(t,y.turn),m?.abort(new DOMException("Harness turn finished","AbortError")),G&&await G.catch(()=>{})}}#R(t,{signal:o,onInteraction:i,onResolved:e,onOpen:a,ownership:A}){let r=new URL("/api/events.mux",this.#e);return r.protocol=r.protocol==="https:"?"wss:":"ws:",new Promise((s,g)=>{let c;try{c=this.#c(r.toString())}catch(U){g(U);return}let I=!1,d=!1,B=null,f=Promise.resolve(),Q=A==null,y=[],m=U=>{if(!d){if(d=!0,c.removeEventListener("open",N),c.removeEventListener("message",J),c.removeEventListener("close",H),c.removeEventListener("error",j),o.removeEventListener("abort",q),A?.reconnect===_&&(A.reconnect=null),o.aborted){s();return}f.then(()=>{let R=U??B;R?g(R):s()},g)}},_=()=>{try{(c.readyState===0||c.readyState===1)&&c.close()}catch{}},N=()=>{I=!0,A&&(A.reconnect=_);try{a?.()}catch(U){console.warn(`[${this.#o}] ignored an interaction open callback failure:`,U.message)}A&&this.#S(t,o).then(()=>{if(!d){Q=!0;for(let U of y.splice(0))Y(U)}}).catch(U=>{B??=U,_(),m(U)})},G=(U,R)=>{U&&(f=f.then(()=>U(R)).catch(V=>{B??=V,_(),m(B)}))},Y=U=>{let R=U.payload;if(A&&R.type==="session/event"){this.#w(t,[R.event]);return}if(R.type==="question/requested"||R.type==="approval/requested"){let V=R.type==="question/requested"?"question":"approval",L=V==="question"?U.rpcId:R.approvalId,T=`${V}:${L}`;if(A){let W=this.#_(t,T,V);if(W?.ownership!==A)return;this.#u.set(T,W)}let P=V==="approval"&&A&&typeof R.callId=="string"?this.#u.get(T)?.ownership.toolCalls.get(R.callId):void 0;G(i,Object.freeze({kind:V,interactionId:L,rpcId:U.rpcId,sessionId:t,payload:R,recovered:A?this.#u.get(T)?.recovered===!0:!1,...P?{toolCall:P}:{},reconnect:_,respond:(W,ae={})=>this.respondInteraction(U.rpcId,W,{...ae,signal:ae.signal??o})}));return}if(R.type==="question/resolved"||R.type==="approval/resolved"){let V=R.type==="question/resolved"?"question":"approval",L=V==="question"?R.questionRpcId:R.approvalId,T=`${V}:${L}`;if(A){if(this.#u.get(T)?.ownership!==A)return;this.#u.delete(T)}G(e,Object.freeze({kind:V,interactionId:L,sessionId:t,outcome:R.outcome,payload:R}))}},J=U=>{try{if(typeof U.data!="string")throw new Error("binary WebSocket frame");let R=JSON.parse(U.data),V=R?.payload;if(R?.type!=="server-request"||typeof R.rpcId!="string"||!V||typeof V!="object"||R.method!==V.type)throw new Error("invalid server-request envelope");if(V.sessionId!==t)return;Q?Y(R):y.push(R)}catch(R){console.warn(`[${this.#o}] ignored a malformed Harness interaction frame:`,R.message)}},H=()=>m(I?null:new Error("Harness interaction WebSocket closed before opening")),j=()=>{m(new Error(I?"Harness interaction WebSocket failed":"Harness interaction WebSocket failed before opening")),_()},q=()=>{_(),m()};c.addEventListener("open",N),c.addEventListener("message",J),c.addEventListener("close",H,{once:!0}),c.addEventListener("error",j,{once:!0}),o.addEventListener("abort",q,{once:!0}),o.aborted&&q()})}async watchHarnessEvents({signal:t,onSessionEvent:o,onReconnect:i}={}){if(typeof o!="function")throw new TypeError("watchHarnessEvents requires onSessionEvent");if(!t||typeof t.addEventListener!="function")throw new TypeError("watchHarnessEvents requires an AbortSignal");if(i!==void 0&&typeof i!="function")throw new TypeError("onReconnect must be a function");let e=new URL("/api/events.mux",this.#e);for(e.protocol=e.protocol==="https:"?"wss:":"ws:";!t.aborted;){try{await this.#k(e.toString(),{signal:t,onSessionEvent:o,onReconnect:i})}catch(a){if(t.aborted)return;console.warn(`[${this.#o}] Harness event mux disconnected:`,a.message)}if(t.aborted)return;try{await eE(this.#s,t)}catch{if(t.aborted)return;throw new Error("Harness event mux reconnect wait failed")}}}#k(t,{signal:o,onSessionEvent:i,onReconnect:e}){return new Promise((a,A)=>{let r;try{r=this.#c(t)}catch(m){A(m);return}let s=!1,g=!1,c=()=>{try{r.close()}catch{}},I=m=>{g||(g=!0,r.removeEventListener("open",d),r.removeEventListener("message",B),r.removeEventListener("close",f),r.removeEventListener("error",Q),o.removeEventListener("abort",y),m?A(m):a())},d=()=>{s=!0;try{e?.()}catch(m){console.warn(`[${this.#o}] mux reconnect hook failed:`,m.message)}},B=m=>{try{if(typeof m.data!="string")return;let _=JSON.parse(m.data),N=_?.payload;if(_?.type!=="server-request"||!N||typeof N!="object"||_.method!==N.type||N.type!=="session/event"||typeof N.sessionId!="string"||!N.event||typeof N.event!="object")return;i({sessionId:N.sessionId,event:N.event})}catch(_){console.warn(`[${this.#o}] ignored a malformed global mux frame:`,_.message)}},f=()=>I(s?null:new Error("Harness event mux WebSocket closed before opening")),Q=()=>{I(new Error(s?"Harness event mux WebSocket failed":"Harness event mux WebSocket failed before opening")),c()},y=()=>{c(),I()};r.addEventListener("open",d),r.addEventListener("message",B),r.addEventListener("close",f,{once:!0}),r.addEventListener("error",Q,{once:!0}),o.addEventListener("abort",y,{once:!0}),o.aborted&&y()})}stopManagedProcess(){this.#d?.exitCode===null&&this.#d.kill("SIGTERM")}};var wf=class extends lr{constructor(t){super({...t,rpcIdPrefix:"dingtalk",logPrefix:"dsh-dingtalk"})}};import{randomUUID as hpe}from"node:crypto";import{mkdir as Epe,readFile as Cpe,rename as upe,unlink as Bpe,writeFile as fpe}from"node:fs/promises";import{dirname as Qpe}from"node:path";var Of=Object.freeze({version:1,sessions:{},seenMessageIds:[],pendingSenders:{}});function pr(n){return typeof n=="string"&&n.trim()?n.trim():null}function tx(n){return(pr(n)??D("\u9489\u9489\u7528\u6237")).slice(0,100)}function ype(n,t){if(!n||typeof n!="object")return null;let o=pr(n.requestId)??pr(t),i=pr(n.staffId),e=pr(n.requestedAt)??pr(n.lastSeenAt),a=pr(n.lastSeenAt)??e;return!o||!i||!e||!a?null:{requestId:o,staffId:i,displayName:tx(n.displayName??n.nick),requestedAt:e,lastSeenAt:a}}function mpe(n){if(!n||typeof n!="object")return structuredClone(Of);let t={};if(n.sessions&&typeof n.sessions=="object"&&!Array.isArray(n.sessions))for(let[e,a]of Object.entries(n.sessions)){let A=pr(e),r=pr(a);A&&r&&(t[A]=r)}let o={},i=Array.isArray(n.pendingSenders)?n.pendingSenders.map(e=>[e?.requestId,e]):Object.entries(n.pendingSenders&&typeof n.pendingSenders=="object"?n.pendingSenders:{});for(let[e,a]of i){let A=ype(a,e);if(!A)continue;let r=Object.values(o).find(s=>s.staffId===A.staffId);(!r||r.lastSeenAtnew Date().toISOString()}={}){if(!pr(t))throw new TypeError("state path is required");if(typeof o!="function"||typeof i!="function")throw new TypeError("idFactory and now must be functions");this.#e=t,this.#r=o,this.#a=i}async load(){try{this.#A=mpe(JSON.parse(await Cpe(this.#e,"utf8")))}catch(t){if(t?.code!=="ENOENT")throw t;this.#A=structuredClone(Of),await this.#i()}return this}sessionFor(t){return this.#A.sessions[t]??null}async setSession(t,o){let i=pr(t),e=pr(o);if(!i||!e)throw new TypeError("key and sessionId are required");this.#A.sessions[i]=e,await this.#i()}async clearSession(t){let o=pr(t);!o||!(o in this.#A.sessions)||(delete this.#A.sessions[o],await this.#i())}async clearSessions(){this.#A.sessions={},await this.#i()}hasSeen(t){let o=pr(t);return!!(o&&this.#A.seenMessageIds.includes(o))}async markSeen(t){let o=pr(t);if(!o)throw new TypeError("messageId is required");this.hasSeen(o)||(this.#A.seenMessageIds.push(o),this.#A.seenMessageIds.length>1e3&&this.#A.seenMessageIds.splice(0,this.#A.seenMessageIds.length-1e3),await this.#i())}pendingSenders(){return Object.values(this.#A.pendingSenders).sort((t,o)=>t.requestedAt.localeCompare(o.requestedAt)).map(t=>structuredClone(t))}pendingSender(t){let o=pr(t),i=o?this.#A.pendingSenders[o]:null;return i?structuredClone(i):null}async recordPendingSender(t,o,i){let e=t&&typeof t=="object"?t:{staffId:t,displayName:o,lastSeenAt:i},a=pr(e.staffId);if(!a)throw new TypeError("staffId is required");let A=pr(e.lastSeenAt)??pr(e.requestedAt)??this.#a(),r=Object.values(this.#A.pendingSenders).find(g=>g.staffId===a),s={requestId:r?.requestId??`ding_sender_${this.#r()}`,staffId:a,displayName:tx(e.displayName??e.nick??o),requestedAt:r?.requestedAt??A,lastSeenAt:A};return this.#A.pendingSenders[s.requestId]=s,await this.#i(),structuredClone(s)}async removePendingSender(t){let o=pr(t);return!o||!this.#A.pendingSenders[o]?!1:(delete this.#A.pendingSenders[o],await this.#i(),!0)}async removePendingSenderByStaffId(t){let o=pr(t),i=o?Object.values(this.#A.pendingSenders).find(e=>e.staffId===o):null;return i?this.removePendingSender(i.requestId):!1}snapshot(){return structuredClone(this.#A)}async remove(){await this.#t;try{await Bpe(this.#e)}catch(t){if(t?.code!=="ENOENT")throw t}this.#A=structuredClone(Of)}async#i(){let t=`${JSON.stringify(this.#A,null,2)} `,o=this.#t.then(async()=>{await Epe(Qpe(this.#e),{recursive:!0,mode:448});let i=`${this.#e}.tmp`;await fpe(i,t,{encoding:"utf8",mode:384}),await upe(i,this.#e)});this.#t=o.then(()=>{},()=>{}),await o}};import{mkdir as Spe,readFile as Dpe,realpath as wpe,rename as Ope,stat as bpe,unlink as Mpe,writeFile as _pe}from"node:fs/promises";import{dirname as Tpe,isAbsolute as ix,resolve as AE}from"node:path";var b5e=Object.freeze({version:1,workspaces:Object.freeze({})});function eI(n){let t=new Error(n);return t.code=oi,t}async function lM(n){return AE(await wpe(n))}async function Npe(n,t){if(n===t)return!0;try{return await lM(n)===await lM(t)}catch{return!1}}function di(n){if(typeof n!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(n))throw new TypeError("Invalid bot id");return n}function Rpe(n){if(!n||n.version!==1||!n.workspaces||typeof n.workspaces!="object"||Array.isArray(n.workspaces))return null;let t={};for(let[i,e]of Object.entries(n.workspaces)){if(!/^[A-Za-z0-9_-]{1,128}$/.test(i)||typeof e!="string"||!ix(e))return null;t[i]=AE(e)}let o={};if(n.agentPresets!==void 0){if(!n.agentPresets||typeof n.agentPresets!="object"||Array.isArray(n.agentPresets))return null;for(let[i,e]of Object.entries(n.agentPresets)){if(!/^[A-Za-z0-9_-]{1,128}$/.test(i))return null;try{let a=Kl(e);if(!a)return null;o[i]=a}catch{return null}}}return{version:1,workspaces:t,agentPresets:o}}async function rx(n){if(typeof n!="string"||!n.trim()||!ix(n.trim())){let i=new Error("\u5DE5\u4F5C\u533A\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002");throw i.code="workspace-not-absolute",i}let t=AE(n.trim()),o;try{o=await bpe(t)}catch(i){let e=new Error("\u5DE5\u4F5C\u533A\u8DEF\u5F84\u4E0D\u5B58\u5728\u3002",{cause:i});throw e.code="workspace-not-found",e}if(!o.isDirectory()){let i=new Error("\u5DE5\u4F5C\u533A\u8DEF\u5F84\u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u76EE\u5F55\u3002");throw i.code="workspace-not-directory",i}return t}var Zr=class{#e;#A;#t={};#r={};#a=new Map;#i=1;#c=new Map;#s=1;#I=new Map;#o=new WeakMap;#n=new Set;#g=Promise.resolve();#l=new Map;constructor(t,{defaultWorkspace:o=process.cwd()}={}){if(typeof t!="string"||!t)throw new TypeError("workspace store path is required");this.#e=t,this.#A=AE(o)}async load(){try{let t=Rpe(JSON.parse(await Dpe(this.#e,"utf8")));if(!t)throw new Error("dsh-im workspace config is invalid");this.#t=t.workspaces,this.#r=t.agentPresets}catch(t){if(t?.code!=="ENOENT")throw t;this.#t={},this.#r={}}this.#a.clear(),this.#i=1,this.#c.clear(),this.#s=1,this.#I.clear(),this.#n.clear();for(let t of Object.keys(this.#t))this.#a.set(t,this.#p()),this.#c.set(t,this.#d());return this}has(t){let o=di(t);return Object.hasOwn(this.#t,o)&&!this.#I.has(o)}incarnationFor(t){return this.#c.get(di(t))??null}workspaceFor(t){return this.#t[di(t)]??this.#A}agentPresetFor(t){return this.#r[di(t)]??null}generationFor(t){return this.#a.get(di(t))??null}async whenIdle(){await this.#g}async whenBotIdle(t){let o=di(t);for(;;){let i=this.#l.get(o);if(!i||(await i,this.#l.get(o)===i))return}}async ensure(t,{workspace:o=this.#A,defaultAgentPreset:i}={}){let e=di(t),a=AE(o);return this.#u(e,async()=>{if(this.#t[e])this.#a.has(e)||this.#a.set(e,this.#p());else{let A=Kl(i),r=Object.hasOwn(this.#r,e),s=this.#r[e];this.#t[e]=a,A&&(this.#r[e]=A),this.#a.set(e,this.#p()),this.#c.set(e,this.#d());try{await this.#B()}catch(g){throw delete this.#t[e],r?this.#r[e]=s:delete this.#r[e],this.#a.delete(e),this.#c.delete(e),g}}return this.#t[e]})}async setWorkspace(t,o,{clearSessions:i,incarnation:e}={}){let a=di(t);if(!this.has(a)||e!==void 0&&e!==this.incarnationFor(a)){let r=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw r.code="workspace-bot-not-found",r}let A=await rx(o);return this.#u(a,async()=>{if(!this.has(a)||e!==void 0&&e!==this.incarnationFor(a)){let s=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw s.code="workspace-bot-not-found",s}if(A===this.workspaceFor(a))return A;let r=this.#t[a];this.#a.set(a,this.#p()),await i?.(),this.#t[a]=A;try{await this.#B()}catch(s){throw this.#t[a]=r,s}return A})}async setAgentPreset(t,o,{incarnation:i}={}){let e=di(t);if(!this.has(e)||i!==void 0&&i!==this.incarnationFor(e)){let A=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw A.code="workspace-bot-not-found",A}let a=Kl(o);return this.#u(e,async()=>{if(!this.has(e)||i!==void 0&&i!==this.incarnationFor(e)){let r=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw r.code="workspace-bot-not-found",r}let A=this.#r[e]??null;if(A===a)return a;a?this.#r[e]=a:delete this.#r[e];try{await this.#B()}catch(r){throw A?this.#r[e]=A:delete this.#r[e],r}return a})}async bindWorkspaceSession(t,o,{conversationKey:i,sessionId:e,clearSessions:a,setSession:A,incarnation:r,expectedGeneration:s}={}){let g=di(t);if(typeof i!="string"||!i||typeof e!="string"||!e)throw new TypeError("conversationKey and sessionId are required");if(typeof a!="function"||typeof A!="function")throw new TypeError("session state callbacks are required");if(!this.has(g)||r!==void 0&&r!==this.incarnationFor(g)){let I=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw I.code="workspace-bot-not-found",I}let c=await lM(await rx(o));return this.#u(g,async()=>{if(!this.has(g)||r!==void 0&&r!==this.incarnationFor(g)){let I=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw I.code="workspace-bot-not-found",I}if(s!==void 0&&s!==this.generationFor(g))throw eI("The bot workspace changed before the session binding could be committed.");if(!await Npe(c,this.workspaceFor(g))){let I=this.#t[g];this.#a.set(g,this.#p()),await a(),this.#t[g]=c;try{await this.#B()}catch(d){throw this.#t[g]=I,d}}return await A(i,e),{workspace:c,sessionId:e,generation:this.#a.get(g)}})}async invalidateSessions(t,{clearSessions:o}={}){let i=di(t);return this.#u(i,async()=>{this.#a.set(i,this.#p()),await o?.()})}async beginRemoval(t,{clearSessions:o}={}){let i=di(t);return this.#u(i,async()=>{let e=this.#I.get(i);if(e)return e;let a=Object.freeze({});this.#I.set(i,a),this.#o.set(a,{botId:i,incarnation:this.incarnationFor(i)}),this.#a.set(i,this.#p());try{await o?.()}catch(A){throw this.#I.get(i)===a&&this.#I.delete(i),A}return a})}async abortRemoval(t){let{botId:o}=this.#h(t);return this.#u(o,async()=>this.#I.get(o)!==t?!1:(this.#I.delete(o),Object.hasOwn(this.#t,o)&&(this.#a.set(o,this.#p()),this.#c.has(o)||this.#c.set(o,this.#d())),!0))}async finishRemoval(t){let{botId:o,incarnation:i}=this.#h(t);return this.#u(o,async()=>this.#I.get(o)!==t?{removed:!1,persisted:!0,error:null,stale:!0}:this.incarnationFor(o)!==i?(this.#I.delete(o),{removed:!1,persisted:!0,error:null,stale:!0}):(this.#I.delete(o),this.#E(o)))}async retireAfterConfigCommit(t){let o=di(t);return this.#u(o,async()=>(this.#I.delete(o),this.#E(o)))}async remove(t){let o=await this.retireAfterConfigCommit(t);if(o.error)throw o.error;return o.removed}async reconcile(t){let o=new Set([...t].map(di)),i=new Set([...Object.keys(this.#t),...Object.keys(this.#r),...this.#n]);for(let e of i)o.has(e)||await this.remove(e)}decorateStatus(t){return!t||typeof t!="object"||!Array.isArray(t.bots)?t:{...t,bots:t.bots.map(o=>o?.botId?{...o,workspace:this.workspaceFor(o.botId),agentPreset:this.agentPresetFor(o.botId)}:o)}}#p(){let t=this.#i;return this.#i+=1,t}#d(){let t=this.#s;return this.#s+=1,t}#h(t){if(!t||typeof t!="object")throw new TypeError("Invalid workspace removal transaction");let o=this.#o.get(t);if(!o)throw new TypeError("Invalid workspace removal transaction");return o}async#E(t){let o=Object.hasOwn(this.#t,t),i=Object.hasOwn(this.#r,t),e=o||i||this.#n.has(t);if(delete this.#t[t],delete this.#r[t],this.#a.delete(t),this.#c.delete(t),!e)return{removed:!1,persisted:!0,error:null,stale:!1};try{return await this.#f(),{removed:o,persisted:!0,error:null,stale:!1}}catch(a){return this.#n.add(t),{removed:o,persisted:!1,error:a,stale:!1}}}async#u(t,o){let i=this.#g.then(o,o),e=i.then(()=>{},()=>{});return this.#g=e,this.#l.set(t,e),e.finally(()=>{this.#l.get(t)===e&&this.#l.delete(t)}),i}async#B(){let t={version:1,workspaces:this.#t};Object.keys(this.#r).length>0&&(t.agentPresets=this.#r),await Spe(Tpe(this.#e),{recursive:!0,mode:448});let o=`${this.#e}.tmp`;await _pe(o,`${JSON.stringify(t,null,2)} -`,{encoding:"utf8",mode:384}),await Ope(o,this.#e),this.#n.clear()}async#f(){if(Object.keys(this.#t).length>0||Object.keys(this.#r).length>0){await this.#B();return}try{await Mpe(this.#e),this.#n.clear()}catch(t){if(t?.code!=="ENOENT")throw t;this.#n.clear()}}};function pM(n){if(!n)return null;let t=typeof n=="function"?n():n;return t&&typeof t.then=="function"?t.then(_n):_n(t)}function ox(){let n=new Error("Agent Preset \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\u3002");return n.code="agent-preset-unavailable",n}function ql(n){if(n())return;let t=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw t.code="workspace-bot-not-found",t}function ax(n,t,o){let i=e=>{let a=n.decorateStatus(e);if(!o||!a||typeof a!="object")return a;let A=s=>s?{...a,agentPresetCatalog:s}:a,r=pM(o);return r&&typeof r.then=="function"?r.then(A):A(r)};return t&&typeof t.then=="function"?t.then(i):i(t)}function kpe(n){return Promise.resolve(n.status())}function Ma(n,{workspaces:t,method:o="remove",botIdFromRemoved:i=e=>e?.botId}){if(!n||!t||typeof n[o]!="function")throw new TypeError("configStore removal observer dependencies are required");return new Proxy(n,{get(e,a){let A=Reflect.get(e,a,e);return a===o?async(...r)=>{let s=await A.apply(e,r),g=s?i(s,r):null;return g&&await t.retireAfterConfigCommit(g),s}:typeof A=="function"?A.bind(e):A}})}function _a(n,{botId:t,workspaces:o,state:i,agentPresetCatalog:e}={}){if(!n||!o||!i)throw new TypeError("harness, workspaces, and state are required");let a=o.incarnationFor(t),A=()=>o.has(t)&&o.incarnationFor(t)===a,r=async(I=e)=>{let d;try{d=await pM(I)??_n(null)}catch(B){throw ql(A),B}return ql(A),{agentPreset:o.agentPresetFor(t),agentPresetCatalog:d}},s=new Map,g=new Proxy(n,{get(I,d){if(d==="agentPresetSettings")return async(f={})=>{f?.signal?.throwIfAborted(),ql(A);let Q=await r();return f?.signal?.throwIfAborted(),Q};if(d==="updateAgentPreset")return async(f,Q={})=>{Q?.signal?.throwIfAborted(),ql(A);let y=f==="--default"?null:Kl(f),m=null;if(y&&({agentPresetCatalog:m}=await r(),Q?.signal?.throwIfAborted(),!m.items.some(_=>_.id===y)))throw ox();if(await o.setAgentPreset(t,y,{incarnation:a}),ql(A),m)return{agentPreset:o.agentPresetFor(t),agentPresetCatalog:m};try{return await r()}catch(_){if(_?.code==="workspace-bot-not-found")throw _;return ql(A),{agentPreset:o.agentPresetFor(t),agentPresetCatalog:_n(null)}}};if(d==="currentWorkspace")return()=>{if(!A()){let f=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw f.code="workspace-bot-not-found",f}return o.workspaceFor(t)};if(d==="assertWorkspaceScope")return()=>{if(!A()){let f=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw f.code="workspace-bot-not-found",f}};if((d==="listWorkspaces"||d==="listWorkspaceSessions"||d==="listModels")&&typeof I[d]=="function")return async(...f)=>{if(!A()){let y=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw y.code="workspace-bot-not-found",y}let Q=await I[d](...f);if(!A()){let y=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw y.code="workspace-bot-not-found",y}return Q};if(d==="switchWorkspace")return f=>{if(!A()){let Q=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");return Q.code="workspace-bot-not-found",Promise.reject(Q)}return o.setWorkspace(t,f,{clearSessions:()=>i.clearSessions(),incarnation:a})};if(d==="bindWorkspaceSession")return async(f,Q)=>{if(typeof f!="string"||!f||typeof Q!="string"||!Q)throw new TypeError("conversationKey and sessionId are required");if(!A()){let N=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw N.code="workspace-bot-not-found",N}if(typeof I.adoptWorkspaceSession!="function")throw new TypeError("Harness does not support adopting workspace sessions");let y=o.generationFor(t),m=await I.adoptWorkspaceSession(Q);if(!A()){let N=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw N.code="workspace-bot-not-found",N}if(y!==o.generationFor(t))throw eI("The bot workspace changed while the session was being adopted.");if(!m||typeof m!="object"||m.sessionId!==Q||typeof m.workspace!="string")throw new TypeError("Harness returned an invalid adopted workspace session");let _=await o.bindWorkspaceSession(t,m.workspace,{conversationKey:f,sessionId:Q,clearSessions:()=>i.clearSessions(),setSession:(N,G)=>i.setSession(N,G),incarnation:a,expectedGeneration:y});if(!A()){let N=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw N.code="workspace-bot-not-found",N}if(_.generation!==o.generationFor(t))throw eI("The bot workspace changed before the session binding completed.");return s.set(Q,_.generation),{...m,workspace:_.workspace,sessionId:_.sessionId}};if(d==="createSession")return async(f={})=>{if(await o.whenBotIdle(t),!A()){let _=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw _.code="workspace-bot-not-found",_}let Q=o.generationFor(t),y=o.agentPresetFor(t),m=await I.createSession({...f,workspace:o.workspaceFor(t),...y==null?{}:{agentPreset:y}});return s.set(m,Q),m};if(d==="workspaceSession")return f=>{if(typeof f!="string"||!f)throw new TypeError("sessionId is required");let Q=s.get(f)??o.generationFor(t);s.delete(f);let y=()=>A()&&Q===o.generationFor(t),m=async(N,G,Y)=>{if(!y())throw eI(`The bot workspace changed before this ${Y} started.`);let J=await I[N](f,...G);if(!y())throw eI(`The bot workspace changed while this ${Y} was running.`);return J},_=async(N,G,Y)=>{if(!y())throw eI(`The bot workspace changed before this ${Y} started.`);return I[N](f,...G)};return Object.freeze({sessionId:f,async sessionExists(...N){if(!y())return!1;let G=await I.sessionExists(f,...N);return y()&&G},models(...N){return m("getSessionModels",N,"model listing")},selectModel(...N){return m("selectSessionModel",N,"model selection")},isRunning(...N){return m("isSessionRunning",N,"run-state check")},hasActiveTurn(...N){return m("hasActiveTurn",N,"turn ownership check")},stopActiveTurn(...N){return _("stopActiveTurn",N,"turn stop")},steerActiveTurn(...N){return _("steerActiveTurn",N,"turn steering")},ask(...N){if(!y())throw eI("The bot workspace changed before this prompt started.");return I.ask(f,...N)}})};if(d==="sessionExists")return(f,...Q)=>{if(!A())return!1;let y=s.get(f);return y!==void 0&&y!==o.generationFor(t)?(s.delete(f),!1):I.sessionExists(f,...Q)};if(d==="ask")return(f,...Q)=>{let y=s.get(f);if(s.delete(f),!A()||y!==void 0&&y!==o.generationFor(t)){let m=new Error("The bot workspace changed before this prompt started.");throw m.code=oi,m}return I.ask(f,...Q)};if(d==="executeCommand"&&typeof I.executeCommand=="function")return(f,...Q)=>{let y=s.get(f);if(s.delete(f),!A()||y!==void 0&&y!==o.generationFor(t)){let m=new Error("The bot workspace changed before this command started.");throw m.code=oi,m}return I.executeCommand(f,...Q)};let B=Reflect.get(I,d,I);return typeof B=="function"?B.bind(I):B}}),c=new Proxy(i,{get(I,d){if(d===Ob)return I;if(d==="sessionFor")return(f,...Q)=>{if(!A())return null;let y=I.sessionFor(f,...Q);return y&&!s.has(y)&&s.set(y,o.generationFor(t)),y};if(d==="setSession")return(f,Q,...y)=>{let m=s.get(Q);return!A()||m!==void 0&&m!==o.generationFor(t)?(s.delete(Q),!1):I.setSession(f,Q,...y)};let B=Reflect.get(I,d,I);return typeof B=="function"?B.bind(I):B}});return Object.freeze({harness:g,state:c})}function Ta(n,{workspaces:t,stateFor:o,agentPresetCatalog:i}={}){if(!n||!t||typeof o!="function")throw new TypeError("controller, workspaces, and stateFor are required");let e=new Map,a=(c,I)=>{let B=(e.get(c)??Promise.resolve()).catch(()=>{}).then(I);return e.set(c,B),B.finally(()=>{e.get(c)===B&&e.delete(c)})},A=c=>ax(t,c,i),r=(c,I)=>{let d=t.incarnationFor(c);return a(c,async()=>{if(!(await n.status())?.bots?.some(Q=>Q?.botId===c)){let Q=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw Q.code="workspace-bot-not-found",Q}let f=await o(c);return await t.setWorkspace(c,I,{clearSessions:()=>f.clearSessions(),incarnation:d}),A(await n.status())})},s=(c,I)=>{let d=t.incarnationFor(c),B=Kl(I);return a(c,async()=>{if(!(await n.status())?.bots?.some(y=>y?.botId===c)){let y=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw y.code="workspace-bot-not-found",y}let Q=B&&i?await pM(i):null;if(B&&i&&!Q?.items.some(y=>y.id===B))throw ox();return await t.setAgentPreset(c,B,{incarnation:d}),ax(t,await n.status(),Q??i)})},g=(c,I)=>a(c,async()=>{let d=await t.beginRemoval(c,{clearSessions:async()=>{try{let B=await o(c);if(!B||typeof B.clearSessions!="function")throw new TypeError("bot state does not support session cleanup");await B.clearSessions()}catch(B){console.warn(`[dsh-im] ignored session cleanup failure while deleting bot ${c}:`,B?.message??B)}}});try{let B=await I();return await t.finishRemoval(d),A(B)}catch(B){let f=await kpe(n).catch(()=>null);throw Array.isArray(f?.bots)&&!f.bots.some(y=>y?.botId===c)?await t.finishRemoval(d):await t.abortRemoval(d),B}});return new Proxy(n,{get(c,I){if(I==="updateWorkspace")return r;if(I==="updateAgentPreset")return s;let d=Reflect.get(c,I,c);return typeof d!="function"?d:I==="deleteBot"?(B,...f)=>g(B,()=>d.call(c,B,...f)):I==="disconnect"?async(...B)=>{let Q=(await c.status())?.bots?.[0]?.botId;return Q?g(Q,()=>d.apply(c,B)):A(d.apply(c,B))}:(...B)=>A(d.apply(c,B))}})}var nx=Object.freeze([250,1e3,3e3,5e3,1e4,3e4]);function vpe(n){if(!Array.isArray(n)||n.length===0)return[...nx];let t=n.filter(o=>Number.isFinite(o)&&o>=0);return t.length>0?t:[...nx]}var Mf=class{#e;#A;#t;#r;#a;#i;#c;#s=null;#I=null;#o=0;#n=!1;#g=!1;#l;#p;constructor({controller:t,harness:o,logger:i=console,retryDelaysMs:e,healthyIntervalMs:a=15e3,setTimeoutImpl:A=setTimeout,clearTimeoutImpl:r=clearTimeout}){if(!t||typeof t.initialize!="function"||typeof t.status!="function")throw new TypeError("ConnectionSupervisor requires a controller");if(!o||typeof o.ensureRunning!="function")throw new TypeError("ConnectionSupervisor requires a Harness client");this.#e=t,this.#A=o,this.#t=i,this.#r=vpe(e),this.#a=Number.isFinite(a)&&a>=0?a:15e3,this.#i=A,this.#c=r,this.#l=new Promise(s=>{this.#p=s})}get ready(){return this.#l}start(){return this.#g||this.#n?this:(this.#g=!0,this.#d(0),this)}async close(){this.#n||(this.#n=!0,this.#s!==null&&this.#c(this.#s),this.#s=null,await this.#I?.catch(()=>{}),this.#p?.(null),this.#p=null)}#d(t){this.#n||(this.#s=this.#i(()=>{this.#s=null,this.#h()},t),this.#s?.unref?.())}async#h(){if(this.#n||this.#I)return;let t=this.#E();this.#I=t;try{await t}finally{this.#I===t&&(this.#I=null)}}async#E(){try{if(await this.#A.ensureRunning(),this.#n)return;let t=await this.#e.initialize();if(this.#n)return;this.#p?.(t),this.#p=null;let{configured:o,connected:i}=t.totals;if(io.invoke({namespace:"commands",method:"execute",args:{agentId:i,line:e,images:[]},signal:a.signal})}}import{randomUUID as Ppe}from"node:crypto";function Gpe(n){if(typeof n?.get!="function")return;let t;try{t=n.get("agents")}catch{return}if(t!=null){if(typeof t.get!="function")throw new TypeError('dsh-im requires a callable AgentRegistry when ctx.get("agents") is present');return t}}function Fpe(n,t,o){if(n?.status!=="running")return!1;let i=n?.session?.events;if(!Array.isArray(i))return!1;let e=null,a=!1;for(let A of i){if(A?.type==="turn/start"){e=A.data?.turn??null,a=!1;continue}if(A?.type==="turn/end"&&A.data?.turn===e){e=null,a=!1;continue}e===t&&A?.type==="user/message"&&A.data?.source?.rpcId===o&&(a=!0)}return e===t&&a}function sx(n){if(!n||typeof n!="object"||Object.isFrozen(n))return n;for(let t of Object.values(n))sx(t);return Object.freeze(n)}function Lpe(n){return sx({id:Ppe(),role:"user",content:[{type:"text",text:n}],source:{kind:"user"}})}function Upe(n){let t=new Error("Session is busy with an active turn or maintenance task",{cause:n});return t.code="agent-busy",t}function Hpe(n){return({sessionId:t,expectedTurn:o,promptRpcId:i,action:e,text:a})=>{let A=n.get(t);if(A){if(!Fpe(A,o,i))return!1;if(e==="stop")return A.cancel({kind:"user"},{keepInbox:!0}),!0;if(e==="steer")return typeof a!="string"||!a.trim()?!1:(A.inject(Lpe(a)),!0);throw new TypeError(`Unsupported Harness control action: ${String(e)}`)}}}function Kpe(n){return({sessionId:t,operation:o})=>{if(typeof o!="function")throw new TypeError("maintenance operation is required");let i=n.get(t);if(!i)return o();try{return i.runMaintenance(e=>{if(n.get(t)!==i){let a=new Error("Session agent changed before maintenance started");throw a.code="agent-unavailable",a}return o(e)})}catch(e){throw Upe(e)}}}function xpe(n){return({sessionId:t,workspace:o,files:i,signal:e})=>{let A=n.get(t)?.session?.header?.cwd,r=typeof A=="string"&&A?A:o;if(typeof r!="string"||!r)throw new ho("inbound-file-workspace-unavailable","The Harness Session workspace is unavailable for inbound files.");return MK({files:i},{workspace:r,signal:e})}}function Ra(n,t={}){let{controlExecutor:o,sessionMaintenanceExecutor:i,fileIngressExecutor:e}=t;if(o!==void 0&&typeof o!="function")throw new TypeError("controlExecutor must be a function");if(i!==void 0&&typeof i!="function")throw new TypeError("sessionMaintenanceExecutor must be a function");if(e!==void 0&&typeof e!="function")throw new TypeError("fileIngressExecutor must be a function");let a=o&&i&&e?void 0:Gpe(n);return{controlExecutor:o??(a?Hpe(a):void 0),sessionMaintenanceExecutor:i??(a?Kpe(a):void 0),fileIngressExecutor:e??xpe(a??{get:()=>{}})}}function Jpe(n,t){if(t!==void 0)return new URL(t);let o=n?.port;if(!Number.isInteger(o)||o<1||o>65535)throw new Error("dsh-dingtalk requires an initialized DSH webServer port");return new URL(`http://127.0.0.1:${o}`)}function qpe(n){let t=AI(n.dshHome??process.env.DSH_HOME??tE(jpe(),".dsh")),o=AI(n.dataDir??tE(t,"integrations","dsh-dingtalk"));return{root:o,config:AI(n.configPath??tE(o,"config.json")),bots:AI(n.botsDir??tE(o,"bots")),workspaces:AI(n.workspacesPath??tE(o,"workspaces.json"))}}async function hM(n,t={},o={}){if(!n?.credentials)throw new TypeError("dsh-dingtalk requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-dingtalk requires ctx.webServer");let i=o.ConfigStore??cf,e=o.DeviceAuth??lf,a=o.StateStore??bf,A=o.HarnessClient??wf,r=o.Controller??xh,s=o.Runtime??Xh,g=o.createConnectionSupervisor??dM,c=typeof n.logger=="function"?n.logger("dsh-dingtalk"):n.logger??console,I=()=>Oa(n),d=qpe(t),B=await new i(d.config).load(),f=AI(t.workspace??process.cwd()),Q=o.WorkspaceStore??Zr,y=o.workspaces??await new Q(d.workspaces,{defaultWorkspace:f}).load(),m=typeof B.list=="function",_=m?B.list():[];m&&await y.reconcile(_.map(W=>W.botId)),await Promise.all(_.map(W=>y.ensure(W.botId,{defaultAgentPreset:t.agentPreset})));let N=typeof B.remove=="function"?Ma(B,{workspaces:y}):B,G=o.deviceAuth??new e({baseUrl:t.registrationBaseUrl}),Y=new Map,J=W=>AI(d.bots,W,"state.json"),H=async W=>{let ae=Y.get(W);return ae||(ae=await new a(J(W)).load(),Y.set(W,ae)),ae},j=Na(n,o.commandExecutor),{controlExecutor:q,sessionMaintenanceExecutor:U,fileIngressExecutor:R}=Ra(n,{controlExecutor:o.controlExecutor,sessionMaintenanceExecutor:o.sessionMaintenanceExecutor,fileIngressExecutor:o.fileIngressExecutor}),V=new A({baseUrl:Jpe(n.webServer,t.harnessBaseUrl),workspace:f,autostart:!1,dshBin:t.dshBin??"dsh",...j?{commandExecutor:j}:{},...q?{controlExecutor:q}:{},...U?{sessionMaintenanceExecutor:U}:{},...R?{fileIngressExecutor:R}:{}}),L=new r({deviceAuth:G,credentials:n.credentials,configStore:N,logger:c,createRuntime:async({botId:W,config:ae,clientSecret:ge})=>{let Se=await H(W);await y.ensure(W,{defaultAgentPreset:t.agentPreset});let de=_a(V,{botId:W,workspaces:y,state:Se,agentPresetCatalog:I});return new s({config:ae,clientSecret:ge,harness:de.harness,state:de.state,replyTimeoutMs:t.replyTimeoutMs??6e5,maxMessageChars:t.maxMessageChars??4e3,connectTimeoutMs:t.connectTimeoutMs??15e3,logger:{error:(...De)=>c.error?.(`[${W}]`,...De),warn:(...De)=>c.warn?.(`[${W}]`,...De),info:(...De)=>c.info?.(`[${W}]`,...De),debug:(...De)=>c.debug?.(`[${W}]`,...De)}})},deleteState:async({botId:W})=>{let ae=Y.get(W);if(Y.delete(W),ae&&typeof ae.remove=="function")await ae.remove();else try{await Ype(J(W))}catch(ge){if(ge?.code!=="ENOENT")throw ge}}}),T=Ta(L,{workspaces:y,stateFor:H,agentPresetCatalog:I}),P=g({controller:T,harness:V,logger:c,retryDelaysMs:t.retryDelaysMs,healthyIntervalMs:t.healthyIntervalMs}).start();return{controller:T,ready:P.ready,async close(){await P.close(),await T.close(),V.stopManagedProcess()}}}import Zpe from"qrcode";var zpe=new Set(["loopback","trusted-host"]);function yr(n){if(n===void 0)return"loopback";if(zpe.has(n))return n;throw new TypeError('dsh-im rpcAuthority must be "loopback" or "trusted-host"')}import{isAbsolute as Vpe}from"node:path";var hi="bot.workspace.set";function ka(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)&&Object.keys(n).every(t=>["botId","workspace"].includes(t))&&typeof n.botId=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n.botId)&&typeof n.workspace=="string"&&n.workspace.length<=4096&&Vpe(n.workspace.trim())}function va(n){return["workspace-not-absolute","workspace-not-found","workspace-not-directory","workspace-bot-not-found","agent-preset-invalid","agent-preset-unavailable"].includes(n?.code)?{code:n.code,message:n.message}:null}var Ei="bot.preset.set";function Wpe(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function Pa(n){return Wpe(n)&&Object.keys(n).every(t=>["botId","agentPreset"].includes(t))&&typeof n.botId=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n.botId)&&(n.agentPreset===null||typeof n.agentPreset=="string"&&zb.test(n.agentPreset))}var cx="/dingtalk",ar=Object.freeze({status:"connection.status",beginProvisioning:"provision.begin",pollProvisioning:"provision.poll",cancelProvisioning:"provision.cancel",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete",setWorkspace:hi,setAgentPreset:Ei,approveSender:"bot.sender.approve",revokeSender:"bot.sender.revoke"}),Ix=Object.freeze(Object.values(ar)),Xpe=new Set(["clientSecret","client_secret","deviceCode","device_code","secretRef","staffId","senderStaffId","verificationUrl","verificationUri","userCode"]);function CM(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function vg(n,t){return CM(n)&&Object.keys(n).every(o=>t.includes(o))}function tI(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n)}function gx(n,t){return typeof n=="string"&&n.trim().length>0&&n.length<=t}function $pe(n,t){return CM(t)?n===ar.status?vg(t,[])?null:"connection.status does not accept fields.":n===ar.beginProvisioning?vg(t,["locale"])&&(t.locale===void 0||t.locale==="zh-CN")?null:"provision.begin received unsupported fields.":[ar.pollProvisioning,ar.cancelProvisioning].includes(n)?vg(t,["attemptId"])&&tI(t.attemptId)?null:`${n} requires an attemptId.`:n===ar.bindCredentials?vg(t,["clientId","clientSecret"])&&gx(t.clientId,256)&&gx(t.clientSecret,1024)?null:"bot.bind-credentials requires Client ID and Client Secret.":n===ar.reconnectBot?vg(t,["botId","sendTest"])&&tI(t.botId)&&(t.sendTest===void 0||t.sendTest===!0)?null:"bot.reconnect requires a botId and optional sendTest=true.":n===ar.deleteBot?vg(t,["botId","confirm"])&&tI(t.botId)&&t.confirm===!0?null:"bot.delete requires a botId and confirm=true.":n===ar.setWorkspace?ka(t)?null:"\u8BF7\u8F93\u5165\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84\u3002":n===ar.setAgentPreset?Pa(t)?null:"\u8BF7\u9009\u62E9 Agent Preset\u3002":n===ar.approveSender?vg(t,["botId","requestId","confirm"])&&tI(t.botId)&&tI(t.requestId)&&t.confirm===!0?null:"bot.sender.approve requires botId, requestId, and confirm=true.":n===ar.revokeSender?vg(t,["botId","senderKey","confirm"])&&tI(t.botId)&&tI(t.senderKey)&&t.confirm===!0?null:"bot.sender.revoke requires botId, senderKey, and confirm=true.":"Unknown DingTalk endpoint.":"Payload must be an object."}function _f(n){return{ok:!1,error:{code:"bad-request",message:n}}}function rE(){return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}}function ede(){return{ok:!1,error:{code:"dingtalk-operation-failed",message:"\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}function zl(n){if(Array.isArray(n))return n.map(zl);if(!CM(n))return n;let t={};for(let[o,i]of Object.entries(n))Xpe.has(o)||(t[o]=zl(i));return t}async function Ade(n){return Zpe.toDataURL(n,{type:"image/png",errorCorrectionLevel:"M",margin:2,width:320})}async function EM(n,t){return!n||typeof n.verificationUrl!="string"?zl(n):zl({...n,qrCodeDataUrl:await t(n.verificationUrl)})}async function Pg(n,t){let o=structuredClone(n);return o?.provisioning&&(o.provisioning=await EM(o.provisioning,t)),zl(o)}function tde(n){for(let t of["status","startProvisioning","registrationStatus","cancelProvisioning","bindCredentials","reconnectBot","deleteBot","approveSender","revokeSender"])if(typeof n?.[t]!="function")throw new TypeError(`A complete DingTalk controller is required (${t})`)}function lx(n,{encodeQr:t=Ade}={}){tde(n);let o=new Map,i=e=>{let a=o.get(e);return a||(o.size>=16&&o.delete(o.keys().next().value),a=Promise.resolve().then(()=>t(e)),o.set(e,a)),a};return async(e,a,A)=>{if(A?.aborted)return rE();if(!Ix.includes(e))return _f("Unknown DingTalk endpoint.");let r=$pe(e,a);if(r)return _f(r);try{let s;if(e===ar.status)s=await Pg(await n.status(),i);else if(e===ar.beginProvisioning){let g=await n.startProvisioning({signal:A});if(A?.aborted)return await n.cancelProvisioning(g.attemptId),rE();s=await EM(g,i)}else if(e===ar.pollProvisioning){let g=await n.registrationStatus(a.attemptId);if(!g)return _f("The provisioning attempt no longer exists.");s=await EM(g,i)}else if(e===ar.cancelProvisioning){if(s=await n.cancelProvisioning(a.attemptId),!s)return _f("The provisioning attempt no longer exists.");s=zl(s)}else if(e===ar.bindCredentials)s=await Pg(await n.bindCredentials(a),i);else if(e===ar.reconnectBot){let g=await n.reconnectBot(a.botId);if(A?.aborted)return rE();let c;if(a.sendTest===!0)if(!g?.bots?.some(d=>d?.botId===a.botId&&d?.connected===!0)||typeof n.sendConnectionTest!="function")c=rr(Ir("\u9489\u9489\u673A\u5668\u4EBA"));else try{await n.sendConnectionTest(a.botId),c=rr()}catch(d){c=rr(d)}s=await Pg({...g,...c?{testMessage:c}:{}},i)}else if(e===ar.deleteBot)s=await Pg(await n.deleteBot(a.botId),i);else if(e===ar.setWorkspace){if(typeof n.updateWorkspace!="function")throw new Error("Workspace update is unavailable");s=await Pg(await n.updateWorkspace(a.botId,a.workspace),i)}else if(e===ar.setAgentPreset){if(typeof n.updateAgentPreset!="function")throw new Error("Agent preset update is unavailable");s=await Pg(await n.updateAgentPreset(a.botId,a.agentPreset),i)}else e===ar.approveSender?s=await Pg(await n.approveSender(a.botId,a.requestId),i):s=await Pg(await n.revokeSender(a.botId,a.senderKey),i);return A?.aborted?rE():{ok:!0,value:s}}catch(s){let g=va(s);return A?.aborted?rE():g?{ok:!1,error:g}:ede()}}}function Tf(n,t,o,i){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(cx,lx(t,o),{authority:yr(i)})}async function px(n,t={}){if(t?.controller)return Tf(n,t.controller,t.rpcOptions,t.rpcAuthority);let o=await hM(n,t,t.internals),i=Tf(n,o.controller,t.rpcOptions,t.rpcAuthority);return n.effect(()=>async()=>{await o.close()},"dsh-dingtalk: close bot connections"),i}import{createHash as rde}from"node:crypto";import{mkdir as ade,readFile as ide,rename as ode,unlink as nde,writeFile as sde}from"node:fs/promises";import{dirname as gde}from"node:path";var uM=Object.freeze({version:1,bots:Object.freeze([])});function Gs(n){return typeof n=="string"&&n.trim()?n.trim():null}function dx(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function aE(n,{botPrefix:t,tokenRefPrefix:o}){let i=Gs(n);if(!i)throw new TypeError("platformId is required");let e=rde("sha256").update(i).digest("hex").slice(0,24);return{botId:`${t}_${e}`,tokenRef:`${o}_${e.toUpperCase()}`}}function Nf(n,t){let o=Gs(n)??"";return o.length<=10?o?`${o.slice(0,3)}\u2022\u2022\u2022`:t:`${o.slice(0,6)}\u2022\u2022\u2022\u2022${o.slice(-4)}`}var Vl=class{#e;#A;#t;#r;#a;#i;#c;#s=uM;#I=Promise.resolve();constructor(t,{channel:o,botPrefix:i,tokenRefPrefix:e,normalizeBotExtension:a=()=>({})}){if(typeof a!="function")throw new TypeError("normalizeBotExtension must be a function");this.#e=t,this.#A=o,this.#t=i,this.#r=e,this.#a=a,this.#i=new RegExp(`^${dx(i)}_[a-f0-9]{24}$`),this.#c=new RegExp(`^${dx(e)}_[A-F0-9]{24}$`)}async load(){try{let t=this.#n(JSON.parse(await ide(this.#e,"utf8")));if(!t)throw new Error(`dsh-im ${this.#A} config contains invalid bot data`);this.#s=t}catch(t){if(t?.code!=="ENOENT")throw t;this.#s=uM}return this}list(){return structuredClone(this.#s.bots)}get(t){let o=this.#s.bots.find(i=>i.botId===t);return o?structuredClone(o):null}getByPlatformId(t){let o=this.#s.bots.find(i=>i.platformId===t);return o?structuredClone(o):null}async save(t){let o=this.#o(t);if(!o)throw new Error(`Refusing to persist incomplete ${this.#A} bot data`);return this.#g(i=>{let e=i.find(r=>r.platformId===o.platformId&&r.botId!==o.botId),a=i.find(r=>r.tokenRef===o.tokenRef&&r.botId!==o.botId);if(e||a)throw new Error(`Duplicate ${this.#A} bot identity`);let A=i.findIndex(r=>r.botId===o.botId);return A===-1?i.push(o):i[A]=o,structuredClone(o)})}async remove(t){if(!this.#i.test(t))throw new TypeError(`Invalid ${this.#A} bot id`);return this.#g(o=>{let i=o.findIndex(a=>a.botId===t);if(i===-1)return null;let[e]=o.splice(i,1);return structuredClone(e)})}async clear(){let t=this.#I.then(async()=>{try{await nde(this.#e)}catch(o){if(o?.code!=="ENOENT")throw o}this.#s=uM});this.#I=t.then(()=>{},()=>{}),await t}#o(t){if(!t||typeof t!="object")return null;let o=Gs(t.platformId),i=Gs(t.botId),e=Gs(t.tokenRef),a=Gs(t.name);if(!o||!i||!e||!a||!this.#i.test(i)||!this.#c.test(e))return null;let A=aE(o,{botPrefix:this.#t,tokenRefPrefix:this.#r});if(A.botId!==i||A.tokenRef!==e)return null;let r=this.#a(t);return!r||typeof r!="object"||Array.isArray(r)?null:Object.freeze({botId:i,platformId:o,tokenRef:e,name:a,username:Gs(t.username),createdAt:Gs(t.createdAt)??new Date().toISOString(),connectedAt:Gs(t.connectedAt),...r})}#n(t){if(!t||t.version!==1||!Array.isArray(t.bots))return null;let o=t.bots.map(A=>this.#o(A));if(o.some(A=>A===null))return null;let i=new Set,e=new Set,a=new Set;for(let A of o){if(i.has(A.botId)||e.has(A.platformId)||a.has(A.tokenRef))return null;i.add(A.botId),e.add(A.platformId),a.add(A.tokenRef)}return Object.freeze({version:1,bots:Object.freeze(o)})}async#g(t){let o,i=this.#I.then(async()=>{let e=[...this.#s.bots];o=t(e);let a=Object.freeze({version:1,bots:Object.freeze(e)});await this.#l(a),this.#s=a});return this.#I=i.then(()=>{},()=>{}),await i,o}async#l(t){await ade(gde(this.#e),{recursive:!0,mode:448});let o=`${this.#e}.tmp`;await sde(o,`${JSON.stringify(t,null,2)} +`,{encoding:"utf8",mode:384}),await Ope(o,this.#e),this.#n.clear()}async#f(){if(Object.keys(this.#t).length>0||Object.keys(this.#r).length>0){await this.#B();return}try{await Mpe(this.#e),this.#n.clear()}catch(t){if(t?.code!=="ENOENT")throw t;this.#n.clear()}}};function pM(n){if(!n)return null;let t=typeof n=="function"?n():n;return t&&typeof t.then=="function"?t.then(_n):_n(t)}function ox(){let n=new Error("Agent Preset \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\u3002");return n.code="agent-preset-unavailable",n}function ql(n){if(n())return;let t=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw t.code="workspace-bot-not-found",t}function ax(n,t,o){let i=e=>{let a=n.decorateStatus(e);if(!o||!a||typeof a!="object")return a;let A=s=>s?{...a,agentPresetCatalog:s}:a,r=pM(o);return r&&typeof r.then=="function"?r.then(A):A(r)};return t&&typeof t.then=="function"?t.then(i):i(t)}function kpe(n){return Promise.resolve(n.status())}function Ma(n,{workspaces:t,method:o="remove",botIdFromRemoved:i=e=>e?.botId}){if(!n||!t||typeof n[o]!="function")throw new TypeError("configStore removal observer dependencies are required");return new Proxy(n,{get(e,a){let A=Reflect.get(e,a,e);return a===o?async(...r)=>{let s=await A.apply(e,r),g=s?i(s,r):null;return g&&await t.retireAfterConfigCommit(g),s}:typeof A=="function"?A.bind(e):A}})}function _a(n,{botId:t,workspaces:o,state:i,agentPresetCatalog:e}={}){if(!n||!o||!i)throw new TypeError("harness, workspaces, and state are required");let a=o.incarnationFor(t),A=()=>o.has(t)&&o.incarnationFor(t)===a,r=async(I=e)=>{let d;try{d=await pM(I)??_n(null)}catch(B){throw ql(A),B}return ql(A),{agentPreset:o.agentPresetFor(t),agentPresetCatalog:d}},s=new Map,g=new Proxy(n,{get(I,d){if(d==="agentPresetSettings")return async(f={})=>{f?.signal?.throwIfAborted(),ql(A);let Q=await r();return f?.signal?.throwIfAborted(),Q};if(d==="updateAgentPreset")return async(f,Q={})=>{Q?.signal?.throwIfAborted(),ql(A);let y=f==="--default"?null:Kl(f),m=null;if(y&&({agentPresetCatalog:m}=await r(),Q?.signal?.throwIfAborted(),!m.items.some(_=>_.id===y)))throw ox();if(await o.setAgentPreset(t,y,{incarnation:a}),ql(A),m)return{agentPreset:o.agentPresetFor(t),agentPresetCatalog:m};try{return await r()}catch(_){if(_?.code==="workspace-bot-not-found")throw _;return ql(A),{agentPreset:o.agentPresetFor(t),agentPresetCatalog:_n(null)}}};if(d==="currentWorkspace")return()=>{if(!A()){let f=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw f.code="workspace-bot-not-found",f}return o.workspaceFor(t)};if(d==="assertWorkspaceScope")return()=>{if(!A()){let f=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw f.code="workspace-bot-not-found",f}};if((d==="listWorkspaces"||d==="listWorkspaceSessions"||d==="listModels")&&typeof I[d]=="function")return async(...f)=>{if(!A()){let y=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw y.code="workspace-bot-not-found",y}let Q=await I[d](...f);if(!A()){let y=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw y.code="workspace-bot-not-found",y}return Q};if(d==="switchWorkspace")return f=>{if(!A()){let Q=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");return Q.code="workspace-bot-not-found",Promise.reject(Q)}return o.setWorkspace(t,f,{clearSessions:()=>i.clearSessions(),incarnation:a})};if(d==="bindWorkspaceSession")return async(f,Q)=>{if(typeof f!="string"||!f||typeof Q!="string"||!Q)throw new TypeError("conversationKey and sessionId are required");if(!A()){let N=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw N.code="workspace-bot-not-found",N}if(typeof I.adoptWorkspaceSession!="function")throw new TypeError("Harness does not support adopting workspace sessions");let y=o.generationFor(t),m=await I.adoptWorkspaceSession(Q);if(!A()){let N=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw N.code="workspace-bot-not-found",N}if(y!==o.generationFor(t))throw eI("The bot workspace changed while the session was being adopted.");if(!m||typeof m!="object"||m.sessionId!==Q||typeof m.workspace!="string")throw new TypeError("Harness returned an invalid adopted workspace session");let _=await o.bindWorkspaceSession(t,m.workspace,{conversationKey:f,sessionId:Q,clearSessions:()=>i.clearSessions(),setSession:(N,G)=>i.setSession(N,G),incarnation:a,expectedGeneration:y});if(!A()){let N=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw N.code="workspace-bot-not-found",N}if(_.generation!==o.generationFor(t))throw eI("The bot workspace changed before the session binding completed.");return s.set(Q,_.generation),{...m,workspace:_.workspace,sessionId:_.sessionId}};if(d==="createSession")return async(f={})=>{if(await o.whenBotIdle(t),!A()){let _=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw _.code="workspace-bot-not-found",_}let Q=o.generationFor(t),y=o.agentPresetFor(t),m=await I.createSession({...f,workspace:o.workspaceFor(t),...y==null?{}:{agentPreset:y}});return s.set(m,Q),m};if(d==="workspaceSession")return f=>{if(typeof f!="string"||!f)throw new TypeError("sessionId is required");let Q=s.get(f)??o.generationFor(t);s.delete(f);let y=()=>A()&&Q===o.generationFor(t),m=async(N,G,Y)=>{if(!y())throw eI(`The bot workspace changed before this ${Y} started.`);let J=await I[N](f,...G);if(!y())throw eI(`The bot workspace changed while this ${Y} was running.`);return J},_=async(N,G,Y)=>{if(!y())throw eI(`The bot workspace changed before this ${Y} started.`);return I[N](f,...G)};return Object.freeze({sessionId:f,async sessionExists(...N){if(!y())return!1;let G=await I.sessionExists(f,...N);return y()&&G},models(...N){return m("getSessionModels",N,"model listing")},selectModel(...N){return m("selectSessionModel",N,"model selection")},isRunning(...N){return m("isSessionRunning",N,"run-state check")},hasActiveTurn(...N){return m("hasActiveTurn",N,"turn ownership check")},stopActiveTurn(...N){return _("stopActiveTurn",N,"turn stop")},steerActiveTurn(...N){return _("steerActiveTurn",N,"turn steering")},ask(...N){if(!y())throw eI("The bot workspace changed before this prompt started.");return I.ask(f,...N)}})};if(d==="sessionExists")return(f,...Q)=>{if(!A())return!1;let y=s.get(f);return y!==void 0&&y!==o.generationFor(t)?(s.delete(f),!1):I.sessionExists(f,...Q)};if(d==="ask")return(f,...Q)=>{let y=s.get(f);if(s.delete(f),!A()||y!==void 0&&y!==o.generationFor(t)){let m=new Error("The bot workspace changed before this prompt started.");throw m.code=oi,m}return I.ask(f,...Q)};if(d==="executeCommand"&&typeof I.executeCommand=="function")return(f,...Q)=>{let y=s.get(f);if(s.delete(f),!A()||y!==void 0&&y!==o.generationFor(t)){let m=new Error("The bot workspace changed before this command started.");throw m.code=oi,m}return I.executeCommand(f,...Q)};let B=Reflect.get(I,d,I);return typeof B=="function"?B.bind(I):B}}),c=new Proxy(i,{get(I,d){if(d===Ob)return I;if(d==="sessionFor")return(f,...Q)=>{if(!A())return null;let y=I.sessionFor(f,...Q);return y&&!s.has(y)&&s.set(y,o.generationFor(t)),y};if(d==="setSession")return(f,Q,...y)=>{let m=s.get(Q);return!A()||m!==void 0&&m!==o.generationFor(t)?(s.delete(Q),!1):I.setSession(f,Q,...y)};let B=Reflect.get(I,d,I);return typeof B=="function"?B.bind(I):B}});return Object.freeze({harness:g,state:c})}function Ta(n,{workspaces:t,stateFor:o,agentPresetCatalog:i}={}){if(!n||!t||typeof o!="function")throw new TypeError("controller, workspaces, and stateFor are required");let e=new Map,a=(c,I)=>{let B=(e.get(c)??Promise.resolve()).catch(()=>{}).then(I);return e.set(c,B),B.finally(()=>{e.get(c)===B&&e.delete(c)})},A=c=>ax(t,c,i),r=(c,I)=>{let d=t.incarnationFor(c);return a(c,async()=>{if(!(await n.status())?.bots?.some(Q=>Q?.botId===c)){let Q=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw Q.code="workspace-bot-not-found",Q}let f=await o(c);return await t.setWorkspace(c,I,{clearSessions:()=>f.clearSessions(),incarnation:d}),A(await n.status())})},s=(c,I)=>{let d=t.incarnationFor(c),B=Kl(I);return a(c,async()=>{if(!(await n.status())?.bots?.some(y=>y?.botId===c)){let y=new Error("\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002");throw y.code="workspace-bot-not-found",y}let Q=B&&i?await pM(i):null;if(B&&i&&!Q?.items.some(y=>y.id===B))throw ox();return await t.setAgentPreset(c,B,{incarnation:d}),ax(t,await n.status(),Q??i)})},g=(c,I)=>a(c,async()=>{let d=await t.beginRemoval(c,{clearSessions:async()=>{try{let B=await o(c);if(!B||typeof B.clearSessions!="function")throw new TypeError("bot state does not support session cleanup");await B.clearSessions()}catch(B){console.warn(`[dsh-im] ignored session cleanup failure while deleting bot ${c}:`,B?.message??B)}}});try{let B=await I();return await t.finishRemoval(d),A(B)}catch(B){let f=await kpe(n).catch(()=>null);throw Array.isArray(f?.bots)&&!f.bots.some(y=>y?.botId===c)?await t.finishRemoval(d):await t.abortRemoval(d),B}});return new Proxy(n,{get(c,I){if(I==="updateWorkspace")return r;if(I==="updateAgentPreset")return s;let d=Reflect.get(c,I,c);return typeof d!="function"?d:I==="deleteBot"?(B,...f)=>g(B,()=>d.call(c,B,...f)):I==="disconnect"?async(...B)=>{let Q=(await c.status())?.bots?.[0]?.botId;return Q?g(Q,()=>d.apply(c,B)):A(d.apply(c,B))}:(...B)=>A(d.apply(c,B))}})}var nx=Object.freeze([250,1e3,3e3,5e3,1e4,3e4]);function vpe(n){if(!Array.isArray(n)||n.length===0)return[...nx];let t=n.filter(o=>Number.isFinite(o)&&o>=0);return t.length>0?t:[...nx]}var Mf=class{#e;#A;#t;#r;#a;#i;#c;#s=null;#I=null;#o=0;#n=!1;#g=!1;#l;#p;constructor({controller:t,harness:o,logger:i=console,retryDelaysMs:e,healthyIntervalMs:a=15e3,setTimeoutImpl:A=setTimeout,clearTimeoutImpl:r=clearTimeout}){if(!t||typeof t.initialize!="function"||typeof t.status!="function")throw new TypeError("ConnectionSupervisor requires a controller");if(!o||typeof o.ensureRunning!="function")throw new TypeError("ConnectionSupervisor requires a Harness client");this.#e=t,this.#A=o,this.#t=i,this.#r=vpe(e),this.#a=Number.isFinite(a)&&a>=0?a:15e3,this.#i=A,this.#c=r,this.#l=new Promise(s=>{this.#p=s})}get ready(){return this.#l}start(){return this.#g||this.#n?this:(this.#g=!0,this.#d(0),this)}async close(){this.#n||(this.#n=!0,this.#s!==null&&this.#c(this.#s),this.#s=null,await this.#I?.catch(()=>{}),this.#p?.(null),this.#p=null)}#d(t){this.#n||(this.#s=this.#i(()=>{this.#s=null,this.#h()},t),this.#s?.unref?.())}async#h(){if(this.#n||this.#I)return;let t=this.#E();this.#I=t;try{await t}finally{this.#I===t&&(this.#I=null)}}async#E(){try{if(await this.#A.ensureRunning(),this.#n)return;let t=await this.#e.initialize();if(this.#n)return;this.#p?.(t),this.#p=null;let{configured:o,connected:i}=t.totals;if(i{let A={namespace:"commands",method:"execute",args:{agentId:i,line:e,images:[]},signal:a.signal};try{return await o.invoke(A)}catch(r){if(r?.name!=="TypertGatewayError"||r.code!=="arguments-invalid"||r.endpoint!=="commands/execute"||r.message!=='typert gateway: commands/execute: args fields do not match the descriptor: unexpected "images"')throw r;return a.signal?.throwIfAborted(),o.invoke({...A,args:{agentId:i,line:e}})}}}}import{randomUUID as Ppe}from"node:crypto";function Gpe(n){if(typeof n?.get!="function")return;let t;try{t=n.get("agents")}catch{return}if(t!=null){if(typeof t.get!="function")throw new TypeError('dsh-im requires a callable AgentRegistry when ctx.get("agents") is present');return t}}function Fpe(n,t,o){if(n?.status!=="running")return!1;let i=n?.session?.events;if(!Array.isArray(i))return!1;let e=null,a=!1;for(let A of i){if(A?.type==="turn/start"){e=A.data?.turn??null,a=!1;continue}if(A?.type==="turn/end"&&A.data?.turn===e){e=null,a=!1;continue}e===t&&A?.type==="user/message"&&A.data?.source?.rpcId===o&&(a=!0)}return e===t&&a}function sx(n){if(!n||typeof n!="object"||Object.isFrozen(n))return n;for(let t of Object.values(n))sx(t);return Object.freeze(n)}function Lpe(n){return sx({id:Ppe(),role:"user",content:[{type:"text",text:n}],source:{kind:"user"}})}function Upe(n){let t=new Error("Session is busy with an active turn or maintenance task",{cause:n});return t.code="agent-busy",t}function Hpe(n){return({sessionId:t,expectedTurn:o,promptRpcId:i,action:e,text:a})=>{let A=n.get(t);if(A){if(!Fpe(A,o,i))return!1;if(e==="stop")return A.cancel({kind:"user"},{keepInbox:!0}),!0;if(e==="steer")return typeof a!="string"||!a.trim()?!1:(A.inject(Lpe(a)),!0);throw new TypeError(`Unsupported Harness control action: ${String(e)}`)}}}function Kpe(n){return({sessionId:t,operation:o})=>{if(typeof o!="function")throw new TypeError("maintenance operation is required");let i=n.get(t);if(!i)return o();try{return i.runMaintenance(e=>{if(n.get(t)!==i){let a=new Error("Session agent changed before maintenance started");throw a.code="agent-unavailable",a}return o(e)})}catch(e){throw Upe(e)}}}function xpe(n){return({sessionId:t,workspace:o,files:i,signal:e})=>{let A=n.get(t)?.session?.header?.cwd,r=typeof A=="string"&&A?A:o;if(typeof r!="string"||!r)throw new ho("inbound-file-workspace-unavailable","The Harness Session workspace is unavailable for inbound files.");return MK({files:i},{workspace:r,signal:e})}}function Ra(n,t={}){let{controlExecutor:o,sessionMaintenanceExecutor:i,fileIngressExecutor:e}=t;if(o!==void 0&&typeof o!="function")throw new TypeError("controlExecutor must be a function");if(i!==void 0&&typeof i!="function")throw new TypeError("sessionMaintenanceExecutor must be a function");if(e!==void 0&&typeof e!="function")throw new TypeError("fileIngressExecutor must be a function");let a=o&&i&&e?void 0:Gpe(n);return{controlExecutor:o??(a?Hpe(a):void 0),sessionMaintenanceExecutor:i??(a?Kpe(a):void 0),fileIngressExecutor:e??xpe(a??{get:()=>{}})}}function Jpe(n,t){if(t!==void 0)return new URL(t);let o=n?.port;if(!Number.isInteger(o)||o<1||o>65535)throw new Error("dsh-dingtalk requires an initialized DSH webServer port");return new URL(`http://127.0.0.1:${o}`)}function qpe(n){let t=AI(n.dshHome??process.env.DSH_HOME??tE(jpe(),".dsh")),o=AI(n.dataDir??tE(t,"integrations","dsh-dingtalk"));return{root:o,config:AI(n.configPath??tE(o,"config.json")),bots:AI(n.botsDir??tE(o,"bots")),workspaces:AI(n.workspacesPath??tE(o,"workspaces.json"))}}async function hM(n,t={},o={}){if(!n?.credentials)throw new TypeError("dsh-dingtalk requires ctx.credentials");if(!n?.webServer)throw new TypeError("dsh-dingtalk requires ctx.webServer");let i=o.ConfigStore??cf,e=o.DeviceAuth??lf,a=o.StateStore??bf,A=o.HarnessClient??wf,r=o.Controller??xh,s=o.Runtime??Xh,g=o.createConnectionSupervisor??dM,c=typeof n.logger=="function"?n.logger("dsh-dingtalk"):n.logger??console,I=()=>Oa(n),d=qpe(t),B=await new i(d.config).load(),f=AI(t.workspace??process.cwd()),Q=o.WorkspaceStore??Zr,y=o.workspaces??await new Q(d.workspaces,{defaultWorkspace:f}).load(),m=typeof B.list=="function",_=m?B.list():[];m&&await y.reconcile(_.map(W=>W.botId)),await Promise.all(_.map(W=>y.ensure(W.botId,{defaultAgentPreset:t.agentPreset})));let N=typeof B.remove=="function"?Ma(B,{workspaces:y}):B,G=o.deviceAuth??new e({baseUrl:t.registrationBaseUrl}),Y=new Map,J=W=>AI(d.bots,W,"state.json"),H=async W=>{let ae=Y.get(W);return ae||(ae=await new a(J(W)).load(),Y.set(W,ae)),ae},j=Na(n,o.commandExecutor),{controlExecutor:q,sessionMaintenanceExecutor:U,fileIngressExecutor:R}=Ra(n,{controlExecutor:o.controlExecutor,sessionMaintenanceExecutor:o.sessionMaintenanceExecutor,fileIngressExecutor:o.fileIngressExecutor}),V=new A({baseUrl:Jpe(n.webServer,t.harnessBaseUrl),workspace:f,autostart:!1,dshBin:t.dshBin??"dsh",...j?{commandExecutor:j}:{},...q?{controlExecutor:q}:{},...U?{sessionMaintenanceExecutor:U}:{},...R?{fileIngressExecutor:R}:{}}),L=new r({deviceAuth:G,credentials:n.credentials,configStore:N,logger:c,createRuntime:async({botId:W,config:ae,clientSecret:ge})=>{let Se=await H(W);await y.ensure(W,{defaultAgentPreset:t.agentPreset});let de=_a(V,{botId:W,workspaces:y,state:Se,agentPresetCatalog:I});return new s({config:ae,clientSecret:ge,harness:de.harness,state:de.state,replyTimeoutMs:t.replyTimeoutMs??6e5,maxMessageChars:t.maxMessageChars??4e3,connectTimeoutMs:t.connectTimeoutMs??15e3,logger:{error:(...De)=>c.error?.(`[${W}]`,...De),warn:(...De)=>c.warn?.(`[${W}]`,...De),info:(...De)=>c.info?.(`[${W}]`,...De),debug:(...De)=>c.debug?.(`[${W}]`,...De)}})},deleteState:async({botId:W})=>{let ae=Y.get(W);if(Y.delete(W),ae&&typeof ae.remove=="function")await ae.remove();else try{await Ype(J(W))}catch(ge){if(ge?.code!=="ENOENT")throw ge}}}),T=Ta(L,{workspaces:y,stateFor:H,agentPresetCatalog:I}),P=g({controller:T,harness:V,logger:c,retryDelaysMs:t.retryDelaysMs,healthyIntervalMs:t.healthyIntervalMs}).start();return{controller:T,ready:P.ready,async close(){await P.close(),await T.close(),V.stopManagedProcess()}}}import Zpe from"qrcode";var zpe=new Set(["loopback","trusted-host"]);function yr(n){if(n===void 0)return"loopback";if(zpe.has(n))return n;throw new TypeError('dsh-im rpcAuthority must be "loopback" or "trusted-host"')}import{isAbsolute as Vpe}from"node:path";var hi="bot.workspace.set";function ka(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)&&Object.keys(n).every(t=>["botId","workspace"].includes(t))&&typeof n.botId=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n.botId)&&typeof n.workspace=="string"&&n.workspace.length<=4096&&Vpe(n.workspace.trim())}function va(n){return["workspace-not-absolute","workspace-not-found","workspace-not-directory","workspace-bot-not-found","agent-preset-invalid","agent-preset-unavailable"].includes(n?.code)?{code:n.code,message:n.message}:null}var Ei="bot.preset.set";function Wpe(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function Pa(n){return Wpe(n)&&Object.keys(n).every(t=>["botId","agentPreset"].includes(t))&&typeof n.botId=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n.botId)&&(n.agentPreset===null||typeof n.agentPreset=="string"&&zb.test(n.agentPreset))}var cx="/dingtalk",ar=Object.freeze({status:"connection.status",beginProvisioning:"provision.begin",pollProvisioning:"provision.poll",cancelProvisioning:"provision.cancel",bindCredentials:"bot.bind-credentials",reconnectBot:"bot.reconnect",deleteBot:"bot.delete",setWorkspace:hi,setAgentPreset:Ei,approveSender:"bot.sender.approve",revokeSender:"bot.sender.revoke"}),Ix=Object.freeze(Object.values(ar)),Xpe=new Set(["clientSecret","client_secret","deviceCode","device_code","secretRef","staffId","senderStaffId","verificationUrl","verificationUri","userCode"]);function CM(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function vg(n,t){return CM(n)&&Object.keys(n).every(o=>t.includes(o))}function tI(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{1,128}$/.test(n)}function gx(n,t){return typeof n=="string"&&n.trim().length>0&&n.length<=t}function $pe(n,t){return CM(t)?n===ar.status?vg(t,[])?null:"connection.status does not accept fields.":n===ar.beginProvisioning?vg(t,["locale"])&&(t.locale===void 0||t.locale==="zh-CN")?null:"provision.begin received unsupported fields.":[ar.pollProvisioning,ar.cancelProvisioning].includes(n)?vg(t,["attemptId"])&&tI(t.attemptId)?null:`${n} requires an attemptId.`:n===ar.bindCredentials?vg(t,["clientId","clientSecret"])&&gx(t.clientId,256)&&gx(t.clientSecret,1024)?null:"bot.bind-credentials requires Client ID and Client Secret.":n===ar.reconnectBot?vg(t,["botId","sendTest"])&&tI(t.botId)&&(t.sendTest===void 0||t.sendTest===!0)?null:"bot.reconnect requires a botId and optional sendTest=true.":n===ar.deleteBot?vg(t,["botId","confirm"])&&tI(t.botId)&&t.confirm===!0?null:"bot.delete requires a botId and confirm=true.":n===ar.setWorkspace?ka(t)?null:"\u8BF7\u8F93\u5165\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84\u3002":n===ar.setAgentPreset?Pa(t)?null:"\u8BF7\u9009\u62E9 Agent Preset\u3002":n===ar.approveSender?vg(t,["botId","requestId","confirm"])&&tI(t.botId)&&tI(t.requestId)&&t.confirm===!0?null:"bot.sender.approve requires botId, requestId, and confirm=true.":n===ar.revokeSender?vg(t,["botId","senderKey","confirm"])&&tI(t.botId)&&tI(t.senderKey)&&t.confirm===!0?null:"bot.sender.revoke requires botId, senderKey, and confirm=true.":"Unknown DingTalk endpoint.":"Payload must be an object."}function _f(n){return{ok:!1,error:{code:"bad-request",message:n}}}function rE(){return{ok:!1,error:{code:"cancelled",message:"The request was cancelled."}}}function ede(){return{ok:!1,error:{code:"dingtalk-operation-failed",message:"\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}}}function zl(n){if(Array.isArray(n))return n.map(zl);if(!CM(n))return n;let t={};for(let[o,i]of Object.entries(n))Xpe.has(o)||(t[o]=zl(i));return t}async function Ade(n){return Zpe.toDataURL(n,{type:"image/png",errorCorrectionLevel:"M",margin:2,width:320})}async function EM(n,t){return!n||typeof n.verificationUrl!="string"?zl(n):zl({...n,qrCodeDataUrl:await t(n.verificationUrl)})}async function Pg(n,t){let o=structuredClone(n);return o?.provisioning&&(o.provisioning=await EM(o.provisioning,t)),zl(o)}function tde(n){for(let t of["status","startProvisioning","registrationStatus","cancelProvisioning","bindCredentials","reconnectBot","deleteBot","approveSender","revokeSender"])if(typeof n?.[t]!="function")throw new TypeError(`A complete DingTalk controller is required (${t})`)}function lx(n,{encodeQr:t=Ade}={}){tde(n);let o=new Map,i=e=>{let a=o.get(e);return a||(o.size>=16&&o.delete(o.keys().next().value),a=Promise.resolve().then(()=>t(e)),o.set(e,a)),a};return async(e,a,A)=>{if(A?.aborted)return rE();if(!Ix.includes(e))return _f("Unknown DingTalk endpoint.");let r=$pe(e,a);if(r)return _f(r);try{let s;if(e===ar.status)s=await Pg(await n.status(),i);else if(e===ar.beginProvisioning){let g=await n.startProvisioning({signal:A});if(A?.aborted)return await n.cancelProvisioning(g.attemptId),rE();s=await EM(g,i)}else if(e===ar.pollProvisioning){let g=await n.registrationStatus(a.attemptId);if(!g)return _f("The provisioning attempt no longer exists.");s=await EM(g,i)}else if(e===ar.cancelProvisioning){if(s=await n.cancelProvisioning(a.attemptId),!s)return _f("The provisioning attempt no longer exists.");s=zl(s)}else if(e===ar.bindCredentials)s=await Pg(await n.bindCredentials(a),i);else if(e===ar.reconnectBot){let g=await n.reconnectBot(a.botId);if(A?.aborted)return rE();let c;if(a.sendTest===!0)if(!g?.bots?.some(d=>d?.botId===a.botId&&d?.connected===!0)||typeof n.sendConnectionTest!="function")c=rr(Ir("\u9489\u9489\u673A\u5668\u4EBA"));else try{await n.sendConnectionTest(a.botId),c=rr()}catch(d){c=rr(d)}s=await Pg({...g,...c?{testMessage:c}:{}},i)}else if(e===ar.deleteBot)s=await Pg(await n.deleteBot(a.botId),i);else if(e===ar.setWorkspace){if(typeof n.updateWorkspace!="function")throw new Error("Workspace update is unavailable");s=await Pg(await n.updateWorkspace(a.botId,a.workspace),i)}else if(e===ar.setAgentPreset){if(typeof n.updateAgentPreset!="function")throw new Error("Agent preset update is unavailable");s=await Pg(await n.updateAgentPreset(a.botId,a.agentPreset),i)}else e===ar.approveSender?s=await Pg(await n.approveSender(a.botId,a.requestId),i):s=await Pg(await n.revokeSender(a.botId,a.senderKey),i);return A?.aborted?rE():{ok:!0,value:s}}catch(s){let g=va(s);return A?.aborted?rE():g?{ok:!1,error:g}:ede()}}}function Tf(n,t,o,i){if(!n?.connection?.rpc||typeof n.connection.rpc.handle!="function")throw new TypeError("DSH Host Connection RPC is required");return n.connection.rpc.handle(cx,lx(t,o),{authority:yr(i)})}async function px(n,t={}){if(t?.controller)return Tf(n,t.controller,t.rpcOptions,t.rpcAuthority);let o=await hM(n,t,t.internals),i=Tf(n,o.controller,t.rpcOptions,t.rpcAuthority);return n.effect(()=>async()=>{await o.close()},"dsh-dingtalk: close bot connections"),i}import{createHash as rde}from"node:crypto";import{mkdir as ade,readFile as ide,rename as ode,unlink as nde,writeFile as sde}from"node:fs/promises";import{dirname as gde}from"node:path";var uM=Object.freeze({version:1,bots:Object.freeze([])});function Gs(n){return typeof n=="string"&&n.trim()?n.trim():null}function dx(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function aE(n,{botPrefix:t,tokenRefPrefix:o}){let i=Gs(n);if(!i)throw new TypeError("platformId is required");let e=rde("sha256").update(i).digest("hex").slice(0,24);return{botId:`${t}_${e}`,tokenRef:`${o}_${e.toUpperCase()}`}}function Nf(n,t){let o=Gs(n)??"";return o.length<=10?o?`${o.slice(0,3)}\u2022\u2022\u2022`:t:`${o.slice(0,6)}\u2022\u2022\u2022\u2022${o.slice(-4)}`}var Vl=class{#e;#A;#t;#r;#a;#i;#c;#s=uM;#I=Promise.resolve();constructor(t,{channel:o,botPrefix:i,tokenRefPrefix:e,normalizeBotExtension:a=()=>({})}){if(typeof a!="function")throw new TypeError("normalizeBotExtension must be a function");this.#e=t,this.#A=o,this.#t=i,this.#r=e,this.#a=a,this.#i=new RegExp(`^${dx(i)}_[a-f0-9]{24}$`),this.#c=new RegExp(`^${dx(e)}_[A-F0-9]{24}$`)}async load(){try{let t=this.#n(JSON.parse(await ide(this.#e,"utf8")));if(!t)throw new Error(`dsh-im ${this.#A} config contains invalid bot data`);this.#s=t}catch(t){if(t?.code!=="ENOENT")throw t;this.#s=uM}return this}list(){return structuredClone(this.#s.bots)}get(t){let o=this.#s.bots.find(i=>i.botId===t);return o?structuredClone(o):null}getByPlatformId(t){let o=this.#s.bots.find(i=>i.platformId===t);return o?structuredClone(o):null}async save(t){let o=this.#o(t);if(!o)throw new Error(`Refusing to persist incomplete ${this.#A} bot data`);return this.#g(i=>{let e=i.find(r=>r.platformId===o.platformId&&r.botId!==o.botId),a=i.find(r=>r.tokenRef===o.tokenRef&&r.botId!==o.botId);if(e||a)throw new Error(`Duplicate ${this.#A} bot identity`);let A=i.findIndex(r=>r.botId===o.botId);return A===-1?i.push(o):i[A]=o,structuredClone(o)})}async remove(t){if(!this.#i.test(t))throw new TypeError(`Invalid ${this.#A} bot id`);return this.#g(o=>{let i=o.findIndex(a=>a.botId===t);if(i===-1)return null;let[e]=o.splice(i,1);return structuredClone(e)})}async clear(){let t=this.#I.then(async()=>{try{await nde(this.#e)}catch(o){if(o?.code!=="ENOENT")throw o}this.#s=uM});this.#I=t.then(()=>{},()=>{}),await t}#o(t){if(!t||typeof t!="object")return null;let o=Gs(t.platformId),i=Gs(t.botId),e=Gs(t.tokenRef),a=Gs(t.name);if(!o||!i||!e||!a||!this.#i.test(i)||!this.#c.test(e))return null;let A=aE(o,{botPrefix:this.#t,tokenRefPrefix:this.#r});if(A.botId!==i||A.tokenRef!==e)return null;let r=this.#a(t);return!r||typeof r!="object"||Array.isArray(r)?null:Object.freeze({botId:i,platformId:o,tokenRef:e,name:a,username:Gs(t.username),createdAt:Gs(t.createdAt)??new Date().toISOString(),connectedAt:Gs(t.connectedAt),...r})}#n(t){if(!t||t.version!==1||!Array.isArray(t.bots))return null;let o=t.bots.map(A=>this.#o(A));if(o.some(A=>A===null))return null;let i=new Set,e=new Set,a=new Set;for(let A of o){if(i.has(A.botId)||e.has(A.platformId)||a.has(A.tokenRef))return null;i.add(A.botId),e.add(A.platformId),a.add(A.tokenRef)}return Object.freeze({version:1,bots:Object.freeze(o)})}async#g(t){let o,i=this.#I.then(async()=>{let e=[...this.#s.bots];o=t(e);let a=Object.freeze({version:1,bots:Object.freeze(e)});await this.#l(a),this.#s=a});return this.#I=i.then(()=>{},()=>{}),await i,o}async#l(t){await ade(gde(this.#e),{recursive:!0,mode:448});let o=`${this.#e}.tmp`;await sde(o,`${JSON.stringify(t,null,2)} `,{encoding:"utf8",mode:384}),await ode(o,this.#e)}};var hx=Object.freeze({botPrefix:"discord",tokenRefPrefix:"DSH_DISCORD_BOT_TOKEN"});function Ex(n){return aE(n,hx)}function Cx(n){return Nf(n,D("Discord\u673A\u5668\u4EBA"))}var Rf=class extends Vl{constructor(t){super(t,{channel:"Discord",...hx})}};function iE(n){return typeof n=="string"&&n.trim()?n.trim():null}function oE(n,t){return Object.freeze({code:n,message:t})}var Wl=class{#e;#A;#t;#r;#a;#i;#c;#s;#I;#o=new Map;#n=new Map;#g=new Map;#l=0;#p=!1;constructor({descriptor:t,credentials:o,configStore:i,inspectToken:e,deriveIdentity:a,maskPlatformId:A,createRuntime:r,deleteState:s=async()=>{},logger:g=console}){if(!t?.key||!t?.label||!t?.connectionLabel)throw new TypeError("TokenBotController requires a channel descriptor");if(!o||typeof o.resolve!="function"||typeof o.set!="function"||typeof o.unset!="function")throw new TypeError(`${t.label} requires the DSH credential provider`);if(!i||typeof i.list!="function"||typeof i.save!="function"||typeof i.remove!="function")throw new TypeError(`${t.label} requires a config store`);if(typeof e!="function"||typeof a!="function"||typeof A!="function"||typeof r!="function")throw new TypeError(`${t.label} controller dependencies are incomplete`);this.#e=t,this.#A=o,this.#t=i,this.#r=e,this.#a=a,this.#i=A,this.#c=r,this.#s=s,this.#I=g}async initialize(){if(this.#p)return this.status();for(let t of this.#t.list())await this.#B(t.botId,async()=>{if(this.#p||this.#o.get(t.botId)?.status?.ready)return;let o=await this.#E(t.tokenRef);if(!o){this.#n.set(t.botId,oE("missing-token",D("{label}\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u79FB\u9664\u540E\u91CD\u65B0\u63A5\u5165\u3002",{label:this.#e.label})));return}try{await this.#d(t,o),this.#n.delete(t.botId)}catch(i){this.#n.set(t.botId,oE("connection-failed",D("{label}\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002",{label:this.#e.label}))),this.#I.warn?.(`[dsh-im:${this.#e.key}] bot ${t.botId} failed to initialize:`,i)}finally{this.#f()}});return this.status()}async bindCredentials({token:t}={}){if(this.#p)throw new Error(`${this.#e.label} controller is closed`);let o=iE(t);if(!o)throw new TypeError(`${this.#e.label} Bot Token is required`);let i=await this.#r(o),e=iE(i?.platformId),a=iE(i?.name);if(!e||!a)throw new Error(`${this.#e.label} returned an invalid bot identity`);let A=this.#a(e);return await this.#B(A.botId,async()=>{if(this.#p)throw new Error(`${this.#e.label} controller is closed`);let r=this.#t.getByPlatformId(e),s=await this.#A.resolve(A.tokenRef).catch(()=>{}),g={botId:A.botId,platformId:e,tokenRef:A.tokenRef,name:a,username:iE(i.username),createdAt:r?.createdAt??new Date().toISOString(),connectedAt:new Date().toISOString()};await this.#A.set(A.tokenRef,o);try{await this.#t.save(g)}catch(c){throw await this.#u(A.tokenRef,s),c}try{await this.#d(g,o),this.#n.delete(A.botId)}catch(c){this.#n.set(A.botId,oE("connection-failed",D("{label}\u673A\u5668\u4EBA\u5DF2\u63A5\u5165\uFF0C\u6D88\u606F\u8FDE\u63A5\u6682\u672A\u5C31\u7EEA\u3002",{label:this.#e.label}))),this.#I.warn?.(`[dsh-im:${this.#e.key}] bot ${A.botId} credential connection failed:`,c)}this.#f()}),this.status()}async reconnectBot(t){let o=this.#t.get(t);if(!o)throw new Error(`Unknown ${this.#e.label} bot`);return await this.#B(t,async()=>{let i=await this.#E(o.tokenRef);if(!i)throw new Error(`${this.#e.label} bot token is missing`);try{await this.#d(o,i),this.#n.delete(t)}catch(e){throw this.#n.set(t,oE("connection-failed",D("{label}\u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",{label:this.#e.label}))),e}finally{this.#f()}}),this.status()}async updateBotConfig(t,o){if(this.#p)throw new Error(`${this.#e.label} controller is closed`);if(typeof o!="function")throw new TypeError("Bot config update must be a function");return await this.#B(t,async()=>{if(this.#p)throw new Error(`${this.#e.label} controller is closed`);let i=this.#t.get(t);if(!i)throw new Error(`Unknown ${this.#e.label} bot`);let e=await this.#E(i.tokenRef);if(!e)throw new Error(`${this.#e.label} bot token is missing`);if(this.#p)throw new Error(`${this.#e.label} controller is closed`);let a=o(i),A=await this.#t.save(a);try{await this.#d(A,e),this.#n.delete(t)}catch(r){throw this.#n.set(t,oE("connection-failed",D("{label}\u8FDE\u63A5\u4ECD\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",{label:this.#e.label}))),r}finally{this.#f()}}),this.status()}async sendConnectionTest(t){let o=this.#t.get(t);if(!o)throw new Error(`Unknown ${this.#e.label} bot`);return this.#B(t,async()=>{let i=this.#o.get(t);if(!i?.status?.ready||typeof i.sendConnectionTest!="function"){let a=new Error(D("{label}\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5",{label:this.#e.label}));throw a.code="test-target-unavailable",a}let e=D("{name}\uFF08{id}\uFF09",{name:o.name,id:this.#i(o.platformId)});return await i.sendConnectionTest(ma(e,D("{label}\u673A\u5668\u4EBA",{label:this.#e.label}))),{sent:!0}})}async deleteBot(t){let o=this.#t.get(t);if(!o)throw new Error(`Unknown ${this.#e.label} bot`);return await this.#B(t,async()=>{let i=await this.#A.resolve(o.tokenRef).catch(()=>{});await this.#h(t);try{await this.#A.unset(o.tokenRef),await this.#t.remove(t)}catch(e){throw i?.value&&(await this.#A.set(o.tokenRef,i.value).catch(()=>{}),await this.#d(o,i.value).catch(()=>{})),new Error(`Unable to remove the ${this.#e.label} bot safely.`,{cause:e})}await this.#s({botId:t,config:o}).catch(e=>{this.#I.warn?.(`[dsh-im:${this.#e.key}] bot ${t} state cleanup failed:`,e)}),this.#n.delete(t),this.#f()}),this.status()}status(){let t=this.#t.list().map(i=>{let e=this.#o.get(i.botId)?.status??null,a=e?.ready===!0&&e.connectionState==="connected"&&e.harnessReachable===!0,A=a?"connected":e?.connectionState==="connecting"?"connecting":this.#n.has(i.botId)||e?.connectionState==="failed"?"error":"offline";return{botId:i.botId,state:A,connected:a,configured:!0,bot:{name:i.name,username:i.username,idMasked:this.#i(i.platformId)},health:{status:a?"healthy":A==="error"?"error":"offline",summary:a?D("{label}{connectionLabel}\u8FD0\u884C\u6B63\u5E38",{label:this.#e.label,connectionLabel:D(this.#e.connectionLabel)}):A==="error"?D("{label}\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u91CD\u8BD5",{label:this.#e.label}):D("{label}\u8FDE\u63A5\u5F53\u524D\u79BB\u7EBF",{label:this.#e.label}),lastCheckedAt:e?.lastCheckedAt??null,lastConnectedAt:e?.lastConnectedAt??null},stats:{messagesReceived:e?.messagesReceived??0,messagesReplied:e?.messagesReplied??0},lastMessageError:qr(e?.lastMessageError),error:structuredClone(this.#n.get(i.botId)??null)}}),o=t.filter(i=>i.connected).length;return{schemaVersion:1,revision:this.#l,state:t.length===0?"disconnected":o===t.length?"connected":o>0?"degraded":"offline",bots:t,totals:{configured:t.length,connected:o}}}async close(){this.#p||(this.#p=!0,await Promise.allSettled([...this.#g.values()]),await Promise.allSettled([...this.#o.keys()].map(t=>this.#h(t))))}async#d(t,o){if(this.#p)throw new Error(`${this.#e.label} controller is closed`);if(await this.#h(t.botId),this.#p)throw new Error(`${this.#e.label} controller is closed`);let i=await this.#c({botId:t.botId,config:t,token:o});if(!i||typeof i.start!="function"||typeof i.stop!="function")throw new TypeError(`createRuntime returned an invalid ${this.#e.label} runtime`);this.#o.set(t.botId,i);try{await i.start()}catch(e){throw await i.stop().catch(()=>{}),this.#o.delete(t.botId),e}}async#h(t){let o=this.#o.get(t);this.#o.delete(t),await o?.stop().catch(i=>{this.#I.warn?.(`[dsh-im:${this.#e.key}] bot ${t} failed to stop cleanly:`,i)})}async#E(t){let o=await this.#A.resolve(t).catch(()=>{});return iE(o?.value)}async#u(t,o){o?.value?await this.#A.set(t,o.value).catch(()=>{}):await this.#A.unset(t).catch(()=>{})}#B(t,o){let a=(this.#g.get(t)??Promise.resolve()).catch(()=>{}).then(o).finally(()=>{this.#g.get(t)===a&&this.#g.delete(t)});return this.#g.set(t,a),a}#f(){this.#l+=1}};import{createHash as cde}from"node:crypto";var Ide="https://discord.com/api/v10/",lde=12e4,pde=new Set([50001,50013]),dde=new Set([40005]);function vn(n){return typeof n=="string"&&n.trim()?n.trim():null}function ux(n,t){let o=AbortSignal.timeout(t);return n?AbortSignal.any([n,o]):o}function BM(n){return n?.reason instanceof Error?n.reason:new DOMException("The operation was aborted","AbortError")}function hde(n,t){if(!Number.isInteger(n)||n<1)throw new TypeError(`${t} must be a positive integer`);return n}function fx(n,t){return t?.providerCode!==void 0&&(n.providerCode=t.providerCode),t?.retry_after!==void 0&&(n.retry_after=t.retry_after,n.retryAfter=t.retry_after),Number.isInteger(t?.status)&&(n.status=t.status),n}function Ede(n){let t=Number(n?.providerCode),o=Number(n?.status),i=vn(n?.message)??"",e="artifact-provider-rejected",a="Discord rejected the attachment.";o===401||o===403||pde.has(t)?(e="artifact-permission-required",a="Discord denied permission to send the attachment."):o===413||dde.has(t)||/(?:request|attachment|file).{0,24}too large/i.test(i)?(e="artifact-too-large",a="The attachment exceeds Discord's size limit."):o===429?(e="artifact-rate-limited",a="Discord rate-limited attachment delivery."):o>=500&&(e="artifact-delivery-uncertain",a="Discord attachment delivery result is uncertain.");let A=new Error(a,{cause:n});return A.code=e,fx(A,n)}function Cde(n){let t=new Error("Discord attachment delivery result is uncertain",{cause:n});return t.code="artifact-delivery-uncertain",fx(t,n)}function ude(n,t){return new Promise((o,i)=>{if(t?.aborted){i(t.reason??new DOMException("Aborted","AbortError"));return}let e=setTimeout(o,n);e?.unref?.(),t?.addEventListener("abort",()=>{clearTimeout(e),i(t.reason??new DOMException("Aborted","AbortError"))},{once:!0})})}function Ga(n,t){let o=vn(n);if(!o||!/^\d{5,30}$/.test(o))throw new TypeError(`Invalid Discord ${t}`);return o}function Bx(n){let t=vn(n);if(!t)throw new TypeError("A Discord reaction emoji is required");return t}function Bde(n){return typeof n=="string"&&/^[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{20,}$/.test(n.trim())}var nE=class{#e;#A;#t;#r;constructor({token:t,fetchImpl:o=fetch,baseUrl:i=Ide,fileUploadTimeoutMs:e=lde}){if(!Bde(t))throw new TypeError("Discord Bot Token is invalid");if(typeof o!="function")throw new TypeError("DiscordApi requires fetch");this.#e=t.trim(),this.#A=o,this.#t=new URL(i),this.#r=hde(e,"fileUploadTimeoutMs")}getCurrentUser(t={}){return this.#a("users/@me",{...t,method:"GET"})}getGatewayBot(t={}){return this.#a("gateway/bot",{...t,method:"GET"})}getChannel({channelId:t,signal:o}={}){return this.#a(`channels/${Ga(t,"channel id")}`,{method:"GET",signal:o})}startThreadFromMessage({channelId:t,messageId:o,name:i,signal:e}={}){let a=vn(i);if(!a||[...a].length>100)throw new TypeError("Discord thread name must contain 1-100 characters");if(e?.aborted)throw BM(e);return this.#a(`channels/${Ga(t,"channel id")}/messages/${Ga(o,"message id")}/threads`,{method:"POST",signal:e,body:{name:a}})}createMessage({channelId:t,content:o,replyToMessageId:i,signal:e}){return this.#a(`channels/${Ga(t,"channel id")}/messages`,{method:"POST",signal:e,body:{content:o,allowed_mentions:{parse:[],replied_user:!1},...i?{message_reference:{message_id:Ga(i,"message id"),channel_id:Ga(t,"channel id"),fail_if_not_exists:!1}}:{}}})}async createFileMessage({channelId:t,file:o,replyToMessageId:i,signal:e}){if(!o||typeof o!="object"||typeof o.fileName!="string"||!o.fileName||!Buffer.isBuffer(o.bytes))throw new TypeError("A Discord attachment is required");let a=vn(o.deliveryKey)??vn(o.artifactId),A=a?cde("sha256").update(a).digest("hex").slice(0,25):void 0,r=new FormData;r.append("payload_json",JSON.stringify({allowed_mentions:{parse:[],replied_user:!1},attachments:[{id:0,filename:o.fileName}],...A?{nonce:A,enforce_nonce:!0}:{},...i?{message_reference:{message_id:Ga(i,"message id"),channel_id:Ga(t,"channel id"),fail_if_not_exists:!1}}:{}})),r.append("files[0]",new Blob([o.bytes],{type:o.mediaType??"application/octet-stream"}),o.fileName);let s=Ga(t,"channel id");if(e?.aborted)throw BM(e);let g=ux(e,this.#r);try{return await this.#a(`channels/${s}/messages`,{method:"POST",signal:g,timeoutMs:this.#r,body:r,multipart:!0})}catch(c){throw e?.aborted?BM(e):c?.code?.startsWith?.("discord-")?Ede(c):Cde(c)}}editMessage({channelId:t,messageId:o,content:i,signal:e}){return this.#a(`channels/${Ga(t,"channel id")}/messages/${Ga(o,"message id")}`,{method:"PATCH",signal:e,body:{content:i,allowed_mentions:{parse:[],replied_user:!1}}})}sendTyping({channelId:t,signal:o}){return this.#a(`channels/${Ga(t,"channel id")}/typing`,{method:"POST",signal:o,expectBody:!1})}async addOwnReaction({channelId:t,messageId:o,emoji:i,signal:e}={}){let a=Bx(i);return await this.#a(`channels/${Ga(t,"channel id")}/messages/${Ga(o,"message id")}/reactions/${encodeURIComponent(a)}/@me`,{method:"PUT",signal:e,expectBody:!1,retry:!1}),a}removeOwnReaction({channelId:t,messageId:o,emoji:i,signal:e}={}){let a=Bx(i);return this.#a(`channels/${Ga(t,"channel id")}/messages/${Ga(o,"message id")}/reactions/${encodeURIComponent(a)}/@me`,{method:"DELETE",signal:e,expectBody:!1,retry:!1})}async#a(t,{method:o,body:i,signal:e,timeoutMs:a=15e3,expectBody:A=!0,retry:r=!0,multipart:s=!1}){let g;try{g=await this.#A(new URL(t,this.#t),{method:o,headers:{authorization:`Bot ${this.#e}`,...s?{}:{"content-type":"application/json"},"user-agent":"DeepSeek-Harness-dsh-im (https://github.com/xmanrui/dsh-im, 1.1.0)"},...i===void 0?{}:{body:s?i:JSON.stringify(i)},signal:ux(e,a),redirect:"error"})}catch(I){throw I?.name==="AbortError"||I?.name==="TimeoutError"?I:new Error(`Discord ${o} transport failed`)}let c=null;if(A||g.status===429||!g.ok)try{c=await g.json()}catch{if(A){let I=new Error(`Discord ${o} returned invalid JSON`);throw I.status=g?.status,I}}if(g.status===429&&r){let I=Math.min(1e4,Math.max(50,Number(c?.retry_after)*1e3||1e3));return await ude(I,e),this.#a(t,{method:o,body:i,signal:e,timeoutMs:a,expectBody:A,retry:!1,multipart:s})}if(!g.ok){let I=new Error(vn(c?.message)??`Discord API failed with HTTP ${g.status}`);I.code=`discord-${g.status}`,I.status=g.status,(Number.isInteger(c?.code)||typeof c?.code=="string")&&(I.providerCode=c.code);let d=Number(c?.retry_after);throw Number.isFinite(d)&&d>=0&&(I.retry_after=d,I.retryAfter=d),I}return A?c:null}};async function Qx(n,t={}){let i=await new nE({token:n,...t}).getCurrentUser();if(!i?.id||i?.bot!==!0)throw new Error("Discord token does not belong to a bot");return{platformId:String(i.id),name:vn(i.global_name)??vn(i.username)??D("Discord\u673A\u5668\u4EBA"),username:vn(i.username)}}var fde=Object.freeze({success(){},error(){},clear(){},settled:()=>Promise.resolve()});function yx(n,t){!n||typeof n!="object"||(n[t]=(n[t]??0)+1)}async function Qde(n,t){let o=AbortSignal.timeout(t),i,e=new Promise((a,A)=>{i=()=>A(o.reason??new DOMException("Timed out","TimeoutError")),o.addEventListener("abort",i,{once:!0})});try{return await Promise.race([n(o),e])}finally{o.removeEventListener("abort",i)}}function kf({adapter:n,target:t,reactions:o,status:i,logger:e=console,label:a="channel",timeoutMs:A=2e3}={}){if(!t||typeof n?.addReaction!="function"||typeof n?.removeReaction!="function"||typeof o?.processing!="string"||!o.processing||!Number.isSafeInteger(A)||A<=0)return fde;let r=null,s=!1,g=async(B,f)=>{try{let Q=await Qde(f,A);return yx(i,B==="add"?"reactionsAdded":"reactionsRemoved"),{ok:!0,value:Q}}catch(Q){return yx(i,"reactionErrors"),e.warn?.(`[dsh-im:${a}] status reaction ${B} failed:`,Q?.message??Q?.name??String(Q)),{ok:!1,value:null}}},c=async B=>{if(r!==null){let Q=r;r=null,await g("remove",y=>n.removeReaction(t,Q,{signal:y}))}if(typeof B!="string"||!B)return;let f=await g("add",Q=>n.addReaction(t,B,{signal:Q}));f.ok&&f.value!==void 0&&f.value!==null&&(r=f.value)},I=c(o.processing),d=B=>{s||(s=!0,I=I.then(()=>c(B),()=>c(B)),I.catch(()=>{}))};return Object.freeze({success:()=>d(o.success),error:()=>d(o.error),clear:()=>d(null),settled:()=>I})}var mx="\u8FD9\u4E2A\u95EE\u9898\u5DF2\u5728\u5176\u4ED6\u5BA2\u6237\u7AEF\u5904\u7406\uFF0C\u65E0\u9700\u518D\u6B21\u56DE\u7B54\u3002",yde="\u4EFB\u52A1\u5DF2\u5B8C\u6210\u3002";function Ci(n){return typeof n=="string"?n.trim():""}function mde(n,t,o){return t.actor===o&&(n.kind!=="group"||n.addressed===!0)&&!qt(n)&&!Gt(n)&&!!Ci(n.content)}function Sde(n,t,o){let i=String(n??D("\u7ED3\u679C\u6587\u4EF6")).replace(/[\r\n]+/g," ").trim().slice(0,255)||D("\u7ED3\u679C\u6587\u4EF6");switch(t?.code){case"artifact-delivery-uncertain":return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u7684\u53D1\u9001\u7ED3\u679C\u672A\u80FD\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u804A\u5929\u5185\u662F\u5426\u5DF2\u6536\u5230\uFF0C\u4E0D\u8981\u7ACB\u5373\u91CD\u8BD5\u3002",{name:i});case"artifact-permission-required":return o?.key==="slack"?D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46 Slack \u5E94\u7528\u7F3A\u5C11 files:write \u6743\u9650\u3002\u8BF7\u66F4\u65B0 Manifest\u3001\u91CD\u65B0\u5B89\u88C5\u5E94\u7528\u5E76\u91CD\u65B0\u8FDE\u63A5\u673A\u5668\u4EBA\u540E\u91CD\u8BD5\u3002",{name:i}):o?.key==="discord"?D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u673A\u5668\u4EBA\u7F3A\u5C11 Discord \u7684 Send Messages\u3001Attach Files \u6216 Read Message History \u6743\u9650\u3002",{name:i}):o?.key==="telegram"?D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46 Telegram \u4E0D\u5141\u8BB8\u673A\u5668\u4EBA\u5728\u5F53\u524D\u804A\u5929\u53D1\u9001\u6587\u6863\uFF0C\u8BF7\u68C0\u67E5\u804A\u5929\u6743\u9650\u3002",{name:i}):D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u5F53\u524D\u673A\u5668\u4EBA\u6CA1\u6709\u6587\u4EF6\u53D1\u9001\u6743\u9650\uFF0C\u8BF7\u68C0\u67E5\u6E20\u9053\u6743\u9650\u3002",{name:i});case"artifact-too-large":return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u8D85\u8FC7\u5F53\u524D\u6E20\u9053\u5927\u5C0F\u4E0A\u9650\uFF0C\u672A\u53D1\u9001\u3002",{name:i});case"artifact-empty":return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001\u3002",{name:i});case"artifact-invalid":case"artifact-changed":case"artifact-unavailable":return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u6216\u51C6\u5907\u53D1\u9001\uFF0C\u8BF7\u786E\u8BA4\u6587\u4EF6\u4ECD\u53EF\u8BBF\u95EE\u540E\u91CD\u8BD5\u3002",{name:i});case"artifact-rate-limited":return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u6682\u65F6\u88AB\u5F53\u524D\u6E20\u9053\u9650\u6D41\uFF0C\u672A\u80FD\u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",{name:i});case"artifact-provider-rejected":return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u5F53\u524D\u6E20\u9053\u62D2\u7EDD\u4E86\u8BE5\u6587\u4EF6\u6216\u6587\u4EF6\u6D88\u606F\u3002",{name:i});default:return D("\u7ED3\u679C\u6587\u4EF6\u300C{name}\u300D\u5DF2\u751F\u6210\uFF0C\u4F46\u5F53\u524D\u6E20\u9053\u6682\u65F6\u672A\u80FD\u53D1\u9001\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",{name:i})}}function Ui(){return{messagesReceived:0,messagesReplied:0,messagesRejected:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastError:null,lastMessageError:null,reactionsAdded:0,reactionsRemoved:0,reactionErrors:0}}var Pn=class{#e;#A;#t;#r;#a;#i;#c;#s;#I=new Map;#o=new Map;#n=new Map;#g=new Set;#l=new Set;#p=new Set;#d;#h=new Ii;constructor({descriptor:t,bot:o,harness:i,state:e,status:a=Ui(),logger:A=console,replyTimeoutMs:r=6e5,signal:s}){if(!t?.key||!t?.label)throw new TypeError("A channel descriptor is required");if(!o||typeof o.sendText!="function")throw new TypeError("A bot client is required");if(!i||!e)throw new TypeError("Harness client and state store are required");this.#e=t,this.#A=o,this.#t=i,this.#r=e,this.#a=a,this.#i=A,this.#c=r,this.#s=s,this.#d=new ii({label:t.key,logger:A})}get status(){return structuredClone(this.#a)}accept(t){if(this.#s?.aborted)return Promise.resolve();let o=Ci(t?.conversationId),i=t?.kind==="group"?"group":"direct",e={...t,kind:i,conversationId:o},a=Ci(e.messageId),A=Ci(e.senderId);if(!a||!A||!o||e.senderIsBot===!0||this.#r.hasSeen(a)||this.#g.has(a))return Promise.resolve();this.#g.add(a);let r=kf({adapter:this.#A,target:e.kind==="direct"||e.addressed===!0?e.reactionTarget:null,reactions:this.#e.reactions,status:this.#a,logger:this.#i,label:this.#e.key});e.statusReaction=r;let s=this.#E(e,a,A);return s.then(()=>r.success(),()=>r.error()),s}#E(t,o,i){t.kind==="direct"&&io(this.#r,t.connectionTestTarget??t.replyTarget);let e=`${t.kind}:${t.conversationId}`,a=this.#o.get(e),A=Ci(t.content),r=lo(A);if(r&&t.kind==="group"&&t.addressed===!0)return this.#u(t,o,Tn());if(r&&t.kind==="direct"){if(/^\/batch$/iu.test(A)&&(this.#I.has(e)||a||this.#d.hasPending(e)))return this.#u(t,o,po());let d=this.#h.handle(e,A,{plainText:!!A&&t.plainText!==!1&&!qt(t)&&!Gt(t)});if(d.handled)return d.kind==="submit"?this.#B({...t,content:d.prompt,batchSubmission:{token:d.token}},o,i,e):this.#u(t,o,d.message)}else if(t.kind==="direct"&&this.#h.status(e).phase==="collecting"){let I=this.#h.handle(e,A,{plainText:!!A&&t.plainText!==!1&&!qt(t)&&!Gt(t)});if(I.handled)return this.#u(t,o,I.message)}let g=t.kind==="direct"&&this.#h.status(e).phase==="collecting"||Gt(t)?null:Pi(A)?gi:Gi(A)?Fi:Li(A)?ci:null;if(g&&(t.kind!=="group"||t.addressed===!0)){let I;return I=this.#f(t,o,e,g).finally(()=>{this.#g.delete(o),this.#p.delete(I)}),this.#p.add(I),I}let c=this.#d.claimReply({key:e,actor:i,messageId:o,text:qt(t)||Gt(t)?"":t.content,addressed:t.kind!=="group"||t.addressed===!0,hasPendingQuestion:!!a,questionCompletion:a?.submitting||a?.claimedReplyMessageId?a.queue:null,isQuestionPending:()=>this.#o.has(e),send:I=>this.#A.sendText(t.replyTarget,I)});if(c){let I;return I=c.process(async()=>this.#r.hasSeen(o)?!1:(await this.#r.markSeen(o),this.#a.messagesReceived+=1,this.#a.lastMessageAt=new Date().toISOString(),!0)).finally(()=>{this.#g.delete(o),this.#l.delete(I)}),this.#l.add(I),I}if(a&&a.actor!==i)return this.#B(t,o,i,e);if(a?.submitting||a?.claimedReplyMessageId)return this.#B(t,o,i,e);if(a){mde(t,a,i)&&(a.claimedReplyMessageId=o);let d=(a.queue??Promise.resolve()).catch(()=>{}).then(()=>this.#Q(t,o,i,e,a)).finally(()=>{this.#g.delete(o),a.claimedReplyMessageId===o&&(a.claimedReplyMessageId=null),a.queue===d&&(a.queue=null)});return a.queue=d,d}return this.#B(t,o,i,e)}#u(t,o,i){let e;return e=(async()=>{this.#r.hasSeen(o)||(await this.#r.markSeen(o),this.#a.messagesReceived+=1,this.#a.lastMessageAt=new Date().toISOString(),i&&await this.#A.sendText(t.replyTarget,i),this.#a.lastError=null)})().catch(async a=>{if(this.#s?.aborted){t.statusReaction?.clear();return}t.statusReaction?.error(),this.#a.lastError=a?.message??String(a);let A=At(this.#a,a);this.#i.error?.(`[dsh-im:${this.#e.key}] failed to process a batch input message [${A.referenceId}]:`,a)}).finally(()=>{this.#g.delete(o),this.#p.delete(e)}),this.#p.add(e),e}#B(t,o,i,e,{releaseMessageId:a=!0,alreadyRecorded:A=!1}={}){let s=(this.#I.get(e)??Promise.resolve()).catch(()=>{}).then(()=>this.#y(t,o,i,e,{alreadyRecorded:A})).finally(()=>{a&&this.#g.delete(o),this.#I.get(e)===s&&this.#I.delete(e)});return this.#I.set(e,s),s}async waitForIdle(){await Promise.allSettled([...this.#I.values(),...[...this.#o.values()].flatMap(t=>t.queue?[t.queue]:[]),...this.#l,...this.#p])}async#f(t,o,i,e){if(this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#a.messagesReceived+=1,this.#a.lastMessageAt=new Date().toISOString();let a=t.replyTarget;try{let A=await e(Ci(t.content),this.#t,this.#r,i,{signal:this.#s,hasImages:qt(t),hasFiles:Gt(t),pendingInteraction:this.#o.has(i)||this.#d.hasPending(i),control:{owner:this,key:i}});A?.stopped&&await Promise.allSettled([this.#k(i),this.#d.closeRoute(i)]);for(let r of A?.messages??[A?.message])r&&await this.#A.sendText(a,r);this.#a.lastError=null}catch(A){if(A?.code==="turn-stopped"||this.#s?.aborted){t.statusReaction?.clear();return}t.statusReaction?.error(),this.#a.lastError=A?.message??String(A);let r=At(this.#a,A);this.#i.error?.(`[dsh-im:${this.#e.key}] failed to process a command [${r.referenceId}]:`,A),await this.#A.sendText(a,dt(r)).catch(()=>{})}}sendConnectionTest(t){return Tg({state:this.#r,text:t,channelLabel:D("{label}\u673A\u5668\u4EBA",{label:this.#e.label}),send:(o,i)=>this.#A.sendText(o,i)})}async#m(t,o,i=[],e){let a=await Co({artifacts:i,baseReceipt:e,deliveryId:o,channelKey:this.#e.key,signal:this.#s,sendImage:typeof this.#A.sendImage=="function"?A=>this.#A.sendImage(t,A):void 0,sendFile:typeof this.#A.sendFile=="function"?A=>this.#A.sendFile(t,A):void 0,onFailure:(A,r)=>At(this.#a,r,{userMessage:Sde(A?.fileName,r,this.#e),reason:r?.code}),sendFailureNotice:(A,r,s)=>this.#A.sendText(t,dt(s)),logger:this.#i});return this.#a.artifactsSent=(this.#a.artifactsSent??0)+a.artifactsSent,this.#a.artifactSendErrors=(this.#a.artifactSendErrors??0)+a.artifactSendErrors,{receipt:a.receipt,userVisible:a.userVisible,artifactSendErrors:a.artifactSendErrors}}async#y(t,o,i,e,{alreadyRecorded:a=!1}={}){if(!a){if(this.#r.hasSeen(o))return;await this.#r.markSeen(o),this.#a.messagesReceived+=1,this.#a.lastMessageAt=new Date().toISOString()}let A=t.replyTarget,r=Ci(t.content),s=t.batchSubmission,g=null,c=!1;try{if(this.#s?.throwIfAborted(),t.kind==="group"&&t.addressed!==!0){this.#a.messagesRejected+=1,this.#a.lastRejectedAt=new Date().toISOString();return}let I=qt(t),d=Gt(t);if(!r&&!I&&!d){await this.#A.sendText(A,D("\u76EE\u524D\u652F\u6301\u6587\u5B57\u3001\u56FE\u7247\u548C\u6587\u4EF6\u6D88\u606F\u3002"));return}let B=r.toLowerCase();if(!I&&!d&&B==="/help"){await this.#A.sendText(A,[D("{label}\u673A\u5668\u4EBA\u5DF2\u8FDE\u63A5 DeepSeek Harness\u3002",{label:this.#e.label}),"",D("\u76F4\u63A5\u53D1\u9001\u6587\u5B57\u3001\u56FE\u7247\u6216\u6587\u4EF6\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002"),D("/new \u5F00\u542F\u4E00\u4E2A\u5168\u65B0\u4F1A\u8BDD"),D("/compact \u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u7684\u8F83\u65E9\u4E0A\u4E0B\u6587"),D("/workspace \u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84 \u5207\u6362\u5DE5\u4F5C\u533A"),D("/workspacelist \u5217\u51FA\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84"),D("/sessionlist [\u5DE5\u4F5C\u533A\u5E8F\u53F7\u6216\u7EDD\u5BF9\u8DEF\u5F84] \u5217\u51FA\u4F1A\u8BDD ID \u548C\u6807\u9898"),D("/session Session ID \u6216\u5F53\u524D\u5DE5\u4F5C\u533A\u5E8F\u53F7 \u5C06\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u5230\u6307\u5B9A\u4F1A\u8BDD"),D("/models \u6309\u5E8F\u53F7\u5217\u51FA\u6240\u6709\u53EF\u7528\u6A21\u578B"),D("/reasoninglist \u6216 /reasonings \u6309\u5E8F\u53F7\u5217\u51FA\u5F53\u524D\u6A21\u578B\u53EF\u7528\u63A8\u7406\u7B49\u7EA7"),D("/reasoning [\u5E8F\u53F7\u3001\u7B49\u7EA7ID\u6216 --default] \u67E5\u770B\u6216\u5207\u6362\u5F53\u524D\u63A8\u7406\u7B49\u7EA7"),D("/model [\u5E8F\u53F7\u6216\u5B8C\u6574\u6A21\u578BID] [\u63A8\u7406\u7B49\u7EA7ID] \u67E5\u770B\u6216\u5207\u6362\u5F53\u524D\u4F1A\u8BDD\u6A21\u578B"),D("\u793A\u4F8B\uFF1A\u5148\u53D1 /models\uFF0C\u518D\u53D1 /model 2 [\u63A8\u7406\u7B49\u7EA7ID]"),D("/presetlist \u6309\u5E8F\u53F7\u5217\u51FA\u53EF\u7528 Agent Preset"),D("/preset [\u5E8F\u53F7\u6216\u5B8C\u6574ID] \u67E5\u770B\u6216\u8BBE\u7F6E\u5F53\u524D\u673A\u5668\u4EBA Agent Preset"),D("\u7EAF\u6570\u5B57 ID\uFF1A/preset id:"),D("/preset --default \u8DDF\u968F Host \u9ED8\u8BA4"),D("/stop \u505C\u6B62\u5F53\u524D\u4EFB\u52A1"),D("/steer \u8865\u5145\u6307\u4EE4 \u7EA0\u504F\u5F53\u524D\u4EFB\u52A1"),D("/batch \u5F00\u59CB\u6279\u91CF\u8F93\u5165\uFF08\u4EC5\u79C1\u804A\uFF0C\u6700\u591A 10 \u6761\u6587\u5B57\uFF09"),D("/send \u63D0\u4EA4\u5F53\u524D\u6279\u6B21"),D("/cancel \u53D6\u6D88\u5F53\u524D\u6279\u6B21"),D("/status \u68C0\u67E5\u8FDE\u63A5\u72B6\u6001"),D("/version \u67E5\u770B\u63D2\u4EF6\u7248\u672C"),D("/help \u663E\u793A\u672C\u5E2E\u52A9")].join(` `));return}if(!I&&!d&&B==="/status"){await this.#t.ensureRunning({signal:this.#s}),await this.#A.sendText(A,D("{label}\u673A\u5668\u4EBA\u4E0E DeepSeek Harness \u8FDE\u63A5\u6B63\u5E38\u3002",{label:this.#e.label}));return}let f=!I&&!d?await Io(r,this.#t,e):null;if(f){for(let R of f.messages??[f.message])await this.#A.sendText(A,R);return}if(!I&&!d&&B==="/new"){await this.#r.clearSession(e),await this.#A.sendText(A,D("\u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002\u8BF7\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002"));return}let Q=!I&&!d?await si(r,this.#t,this.#r,e,{signal:this.#s}):null;if(Q){await this.#A.sendText(A,Q.message);return}await this.#A.sendTyping?.(A).catch(R=>{this.#i.warn?.(`[dsh-im:${this.#e.key}] typing indicator failed:`,R)});let y=!1;if(typeof this.#A.openDeliveryStream=="function")try{g=await this.#A.openDeliveryStream(A),c=!0}catch(R){this.#i.warn?.(`[dsh-im:${this.#e.key}] unable to start a semantic reply stream; using final delivery:`,R)}else if(typeof this.#A.openStream=="function")try{g=await this.#A.openStream(A)}catch(R){this.#i.warn?.(`[dsh-im:${this.#e.key}] unable to start a streamed reply; using text:`,R)}let m=I?await so(t,{signal:this.#s}):void 0,{answer:_,artifacts:N=[]}=await ni({harness:this.#t,state:this.#r,key:e,text:r,content:m,createOptions:this.#s?{signal:this.#s}:void 0,existsOptions:this.#s?{signal:this.#s}:void 0,askOptions:{timeoutMs:this.#c,signal:this.#s,control:{owner:this,key:e},onUpdate:g?async R=>{let V=R.type==="text"?R.text:R.type==="tool"?D("\u6B63\u5728\u4F7F\u7528{name}\u2026",{name:R.name}):R.text;if(V){let L=R.type==="text"?"markdown":"plain";await g.update(c?Rn(V,L):V)}}:void 0,onInteraction:R=>this.#C(R,{key:e,actor:i,target:A,requiresMention:t.kind==="group"&&t.requiresMention!==!1}),onInteractionResolved:R=>this.#b(R),files:t.files}});s&&this.#h.complete(e,s.token);let G=!Ci(_)&&N.length>0,Y=G?D(yde):_,J=G?"plain":"markdown",H=null,j=null;if(g)try{let R=await g.finish(c?Rn(Y,J):Y);y=!0,j=zt({deliveryId:o,presentation:R?.presentation??g.presentation??`${this.#e.key}-stream`,providerMessageIds:[...li(g),...li(R)],deliveryOutcome:R?.deliveryOutcome,reason:R?.reason})}catch(R){g.cancel?.(),this.#i.warn?.(`[dsh-im:${this.#e.key}] streamed reply finalization failed; using text:`,R)}if(!y)try{let R=typeof this.#A.sendDelivery=="function"?await this.#A.sendDelivery(A,Rn(Y,J)):await this.#A.sendText(A,Y);j=zt({deliveryId:o,presentation:R?.presentation??`${this.#e.key}-text`,providerMessageIds:li(R),deliveryOutcome:R?.deliveryOutcome,reason:R?.reason})}catch(R){H=Sa(R)}let q=j?.deliveryOutcome==="unknown";j?.deliveryOutcome==="failed"?H=Sa(new Error(`Final text delivery failed (${j.reason??"unknown"})`),{uncertain:!1}):q&&(H=Sa(new Error(`Final text delivery outcome is unknown (${j.reason??"unknown"})`)));let U=await this.#m(A,o,N,j);if(H&&(!U.userVisible||q))throw H.deliveryReceipt=U.receipt,H;return H&&U.artifactSendErrors===0&&At(this.#a,H),U.userVisible&&(this.#a.messagesReplied+=1,this.#a.lastReplyAt=new Date().toISOString(),this.#a.lastError=null,!H&&U.artifactSendErrors===0&&oo(this.#a)),U.receipt}catch(I){let d=I?.code==="turn-stopped";s&&d&&this.#h.complete(e,s.token);let B=s&&!d?this.#h.fail(e,s.token):null;if(d){if(t.statusReaction?.clear(),g)try{await g.finish(D("\u5DF2\u505C\u6B62\u3002"))}catch{g.cancel?.()}return}if(this.#s?.aborted){t.statusReaction?.clear(),g?.cancel?.();return}t.statusReaction?.error(),this.#a.lastError=I?.message??String(I);let f=async N=>{let G=typeof g?.fail=="function"?"fail":typeof g?.finish=="function"?"finish":null;if(!G)return!1;try{let Y=await g[G](N);return G==="fail"?!!Y&&Y.deliveryOutcome!=="failed":Y!==!1&&Y?.deliveryOutcome!=="failed"}catch(Y){return this.#i.warn?.(`[dsh-im:${this.#e.key}] unable to finalize the failed stream:`,Y),!1}},Q=go(I),y=Eo(I),m=At(this.#a,I,{userMessage:y??Q,reason:vi(I)?.reason}),_=B?.retained?`${dt(m)} diff --git a/plugin-src/host/harness-command-executor.mjs b/plugin-src/host/harness-command-executor.mjs index 2f2d543..235d665 100644 --- a/plugin-src/host/harness-command-executor.mjs +++ b/plugin-src/host/harness-command-executor.mjs @@ -12,14 +12,30 @@ export function createHarnessCommandExecutor(ctx, provided) { if (typeof gateway.invoke !== 'function') { throw new TypeError('dsh-im requires a callable ctx.typertGateway'); } - return (sessionId, line, options = {}) => gateway.invoke({ - namespace: 'commands', - method: 'execute', - // The Harness commands execute descriptor declares agentId, line, and - // images as required JSON wire fields; omitting images makes the Typert - // gateway reject the call with arguments-invalid, so IM /compact always - // carried an empty image list. - args: { agentId: sessionId, line, images: [] }, - signal: options.signal, - }); + return async (sessionId, line, options = {}) => { + const request = { + namespace: 'commands', + method: 'execute', + args: { agentId: sessionId, line, images: [] }, + signal: options.signal, + }; + try { + return await gateway.invoke(request); + } catch (error) { + // Newer Hosts require images; older Hosts reject that field before + // invoking the command. Retry only that exact pre-dispatch failure so + // a business failure can never cause compaction to run twice. + if (error?.name !== 'TypertGatewayError' + || error.code !== 'arguments-invalid' + || error.endpoint !== 'commands/execute' + || error.message !== 'typert gateway: commands/execute: args fields do not match the descriptor: unexpected "images"') { + throw error; + } + options.signal?.throwIfAborted(); + return gateway.invoke({ + ...request, + args: { agentId: sessionId, line }, + }); + } + }; } diff --git a/test/compact-command.test.mjs b/test/compact-command.test.mjs index 861bdfd..559049e 100644 --- a/test/compact-command.test.mjs +++ b/test/compact-command.test.mjs @@ -24,6 +24,17 @@ function state(sessionId = 'session-one') { return { sessionFor: () => sessionId }; } +function legacyImagesArgumentError(overrides = {}) { + return Object.assign(new Error( + 'typert gateway: commands/execute: args fields do not match the descriptor: unexpected "images"', + ), { + name: 'TypertGatewayError', + code: 'arguments-invalid', + endpoint: 'commands/execute', + ...overrides, + }); +} + test('compact command validates syntax and requires an existing conversation Session', async () => { assert.equal(await runCompactCommand('hello', {}, state(), 'direct:one'), null); assert.match( @@ -145,9 +156,7 @@ test('Host command executor invokes the commands Typert endpoint with the Sessio assert.deepEqual(requests, [{ namespace: 'commands', method: 'execute', - // images must ride the wire as an empty array: the Harness commands - // execute descriptor declares it a required JSON field, and omitting it - // makes the Typert gateway reject the call with arguments-invalid. + // Newer Harness descriptors require images even for plain commands. args: { agentId: 'session-one', line: '/compact', images: [] }, signal, }]); @@ -155,6 +164,105 @@ test('Host command executor invokes the commands Typert endpoint with the Sessio assert.throws(() => createHarnessCommandExecutor({}, 'invalid'), /must be a function/); }); +test('compact executes once on older Harness after its gateway rejects the images field', async () => { + const requests = []; + let executions = 0; + const signal = new AbortController().signal; + const executor = createHarnessCommandExecutor({ + typertGateway: { invoke: async (request) => { + requests.push(request); + if (Object.hasOwn(request.args, 'images')) throw legacyImagesArgumentError(); + executions += 1; + return { + commandId: 'command-one', + result: { kind: 'success', text: 'Compacted 5 history items (~200 tokens).' }, + }; + } }, + }); + const client = new HarnessClient({ + baseUrl: 'http://127.0.0.1:1', workspace: '/tmp', commandExecutor: executor, + }); + + const result = await runCompactCommand('/compact', client, state(), 'direct:one', { signal }); + assert.equal(result.message, '已压缩 5 条历史记录(约 200 个 token)。'); + assert.equal(executions, 1); + assert.deepEqual(requests, [ + { + namespace: 'commands', method: 'execute', + args: { agentId: 'session-one', line: '/compact', images: [] }, signal, + }, + { + namespace: 'commands', method: 'execute', + args: { agentId: 'session-one', line: '/compact' }, signal, + }, + ]); +}); + +test('Host command executor never retries other gateway or business failures', async () => { + const message = legacyImagesArgumentError().message; + for (const failure of [ + new Error(message), + legacyImagesArgumentError({ name: 'CommandError' }), + legacyImagesArgumentError({ code: 'result-invalid' }), + legacyImagesArgumentError({ endpoint: 'other/execute' }), + legacyImagesArgumentError({ message: message.replace('unexpected "images"', 'missing "images"') }), + legacyImagesArgumentError({ message: `${message}, "other"` }), + Object.assign(new Error('busy'), { failure: { code: 'agent-busy' } }), + new Error('compaction failed after starting'), + ]) { + let attempts = 0; + const executor = createHarnessCommandExecutor({ + typertGateway: { invoke: async () => { attempts += 1; throw failure; } }, + }); + await assert.rejects(executor('session-one', '/compact'), (error) => error === failure); + assert.equal(attempts, 1); + } +}); + +test('Host command executor does not repeat a failed legacy invocation', async () => { + let attempts = 0; + const failure = new Error('compaction failed after starting'); + const executor = createHarnessCommandExecutor({ + typertGateway: { invoke: async () => { + attempts += 1; + if (attempts === 1) throw legacyImagesArgumentError(); + throw failure; + } }, + }); + await assert.rejects(executor('session-one', '/compact'), (error) => error === failure); + assert.equal(attempts, 2); +}); + +test('Host command executor preserves an unresolved command on the legacy endpoint', async () => { + let attempts = 0; + const executor = createHarnessCommandExecutor({ + typertGateway: { invoke: async () => { + attempts += 1; + if (attempts === 1) throw legacyImagesArgumentError(); + return undefined; + } }, + }); + assert.equal(await executor('session-one', '/compact'), undefined); + assert.equal(attempts, 2); +}); + +test('Host command executor honours cancellation before retrying the legacy endpoint', async () => { + let attempts = 0; + const controller = new AbortController(); + const executor = createHarnessCommandExecutor({ + typertGateway: { invoke: async () => { + attempts += 1; + controller.abort(); + throw legacyImagesArgumentError(); + } }, + }); + await assert.rejects( + executor('session-one', '/compact', { signal: controller.signal }), + (error) => error === controller.signal.reason, + ); + assert.equal(attempts, 1); +}); + test('all nine production channels receive the Host command executor', async () => { for (const path of PRODUCTION_FILES) { const source = await readFile(new URL(`../${path}`, import.meta.url), 'utf8');