adam-agent-server 1.15.0 → 1.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/approval-handler-ZWZZ3FKR.js +1 -0
- package/dist/audit-manager-3YOVBIFV.js +1 -0
- package/dist/bree-engine-Y6WEQCC4.js +1 -0
- package/dist/{channels-6BEGHNOK.js → channels-2DFKJ33W.js} +1 -1
- package/dist/{chunk-GXWB47NF.js → chunk-27C637GL.js} +4 -4
- package/dist/{chunk-UFWMUBFH.js → chunk-2Q6XLYCC.js} +2 -2
- package/dist/{chunk-FD4IKMXV.js → chunk-DMDZ3QW7.js} +1 -1
- package/dist/chunk-JUVQWLWM.js +14 -0
- package/dist/{chunk-EVUZ5LH2.js → chunk-JYJWNUGH.js} +1 -1
- package/dist/{chunk-XZEBYOFR.js → chunk-LBINDAPE.js} +10 -10
- package/dist/chunk-LZDO4PXK.js +34 -0
- package/dist/chunk-MFFJ5HFI.js +178 -0
- package/dist/{chunk-I7LJ4432.js → chunk-OW3HDZV5.js} +1 -1
- package/dist/{chunk-3KNR2F6H.js → chunk-QZ34KQ76.js} +1 -1
- package/dist/{chunk-42V6ZPCS.js → chunk-RX274IH7.js} +1 -1
- package/dist/{chunk-OQ3JOTPK.js → chunk-VLS3BPCG.js} +1 -1
- package/dist/{chunk-APAOIZN4.js → chunk-VVPRB2JU.js} +33 -33
- package/dist/chunk-XA3MZOWU.js +61 -0
- package/dist/engine-IZRMVJRH.js +1 -0
- package/dist/execution-tools-3UATAFUL.js +1 -0
- package/dist/index.js +19 -19
- package/dist/{memory-extractor-5PTMCSOX.js → memory-extractor-X2HTMKCV.js} +1 -1
- package/dist/{outbound-gateway-3INYZDOR.js → outbound-gateway-R6EVRWHP.js} +1 -1
- package/dist/presets-ZZVLCPB2.js +1 -0
- package/dist/{reflection-job-ST4ANCGB.js → reflection-job-BHX3BWAG.js} +3 -3
- package/dist/role-presets-JJI7532O.js +1 -0
- package/dist/{session-manager-JTQRJI7R.js → session-manager-6MUWHQYF.js} +1 -1
- package/dist/template-dispatch-NDQH6S2P.js +1 -0
- package/package.json +1 -1
- package/dist/approval-handler-YLO3V75T.js +0 -1
- package/dist/audit-manager-LYBXP7U4.js +0 -1
- package/dist/bree-engine-AA7EVKTG.js +0 -1
- package/dist/chunk-6NWIZ3BH.js +0 -220
- package/dist/chunk-LU3D53ZV.js +0 -34
- package/dist/chunk-SVUP3F4V.js +0 -14
- package/dist/chunk-TLP4ZMJB.js +0 -19
- package/dist/engine-XLH4VL6Y.js +0 -1
- package/dist/execution-tools-SYP3GR6T.js +0 -1
- package/dist/presets-DT3J2ON4.js +0 -1
- package/dist/role-presets-3IQKCSVQ.js +0 -1
- package/dist/template-dispatch-2K7KV7YS.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as a,d as b,e as c,f as d,g as e}from"./chunk-RX274IH7.js";import"./chunk-2Q6XLYCC.js";import"./chunk-NPGZRSGL.js";import"./chunk-QZ34KQ76.js";import"./chunk-CLNYHWZ6.js";import"./chunk-NWGRLNUM.js";import"./chunk-BKNXRSJU.js";import"./chunk-LZDO4PXK.js";import"./chunk-RBJPQYV3.js";import"./chunk-L7JP7DUO.js";import"./chunk-KJNAORKM.js";import"./chunk-IRUR4DVD.js";import"./chunk-ASPPM7TQ.js";import"./chunk-Z6LHGA27.js";import"./chunk-L47LZYVG.js";import"./chunk-BPXS4QEO.js";import"./chunk-WBAPIPST.js";import"./chunk-BLCNUT53.js";import"./chunk-245WE5AF.js";import"./chunk-FCV2DPZQ.js";export{b as formatPlanForChannel,e as getPendingApprovalRequestIds,d as handleInboundForApproval,a as parseApprovalReply,c as sendApprovalToChannel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{I as a,J as b,K as c,L as d,M as e,N as f,O as g}from"./chunk-MFFJ5HFI.js";import"./chunk-QMW7VEPC.js";import"./chunk-LBINDAPE.js";import"./chunk-XA3MZOWU.js";import"./chunk-J3VYLSJI.js";import"./chunk-XYZVMTNN.js";import"./chunk-ICAM2GUU.js";import"./chunk-TZCMK3UG.js";import"./chunk-XF7YHFVR.js";import"./chunk-NPGZRSGL.js";import"./chunk-JUVQWLWM.js";import"./chunk-DMDZ3QW7.js";import"./chunk-F6U5TMM3.js";import"./chunk-LZDO4PXK.js";import"./chunk-VNXTBIPI.js";import"./chunk-RBJPQYV3.js";import"./chunk-L7JP7DUO.js";import"./chunk-D3SPXZZY.js";import"./chunk-ISKCTUI7.js";import"./chunk-DRO3DG7X.js";import"./chunk-XIVFVKMB.js";import"./chunk-KJNAORKM.js";import"./chunk-N2OLEUAQ.js";import"./chunk-IRUR4DVD.js";import"./chunk-ASPPM7TQ.js";import"./chunk-Z6LHGA27.js";import"./chunk-L47LZYVG.js";import"./chunk-BPXS4QEO.js";import"./chunk-WBAPIPST.js";import"./chunk-BLCNUT53.js";import"./chunk-245WE5AF.js";import"./chunk-FCV2DPZQ.js";export{e as auditAssistantCommitment,f as auditDeliveryClaims,a as evaluateTaskCompletion,g as getSecurityPosture,d as reportViolation,b as startAuditManager,c as stopAuditManager};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b,c}from"./chunk-VLS3BPCG.js";import"./chunk-VVPRB2JU.js";import"./chunk-XA3MZOWU.js";import"./chunk-J3VYLSJI.js";import"./chunk-XYZVMTNN.js";import"./chunk-ICAM2GUU.js";import"./chunk-OW3HDZV5.js";import"./chunk-NUJSTEV4.js";import"./chunk-XF7YHFVR.js";import"./chunk-NNMQGISW.js";import"./chunk-2Q6XLYCC.js";import"./chunk-NPGZRSGL.js";import"./chunk-QZ34KQ76.js";import"./chunk-CLNYHWZ6.js";import"./chunk-NWGRLNUM.js";import"./chunk-BKNXRSJU.js";import"./chunk-DMDZ3QW7.js";import"./chunk-F6U5TMM3.js";import"./chunk-LZDO4PXK.js";import"./chunk-VNXTBIPI.js";import"./chunk-RBJPQYV3.js";import"./chunk-L7JP7DUO.js";import"./chunk-DRO3DG7X.js";import"./chunk-XIVFVKMB.js";import"./chunk-KJNAORKM.js";import"./chunk-IRUR4DVD.js";import"./chunk-VKKDSXMR.js";import"./chunk-ASPPM7TQ.js";import"./chunk-TLMG5W3L.js";import"./chunk-Z6LHGA27.js";import"./chunk-L47LZYVG.js";import"./chunk-BPXS4QEO.js";import"./chunk-WBAPIPST.js";import"./chunk-BLCNUT53.js";import"./chunk-245WE5AF.js";import"./chunk-FCV2DPZQ.js";export{a as BreeEngine,b as getBreeEngine,c as setBreeEngine};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i as a,j as b,k as c}from"./chunk-
|
|
1
|
+
import{i as a,j as b,k as c}from"./chunk-JYJWNUGH.js";import"./chunk-XF7YHFVR.js";import"./chunk-NNMQGISW.js";import"./chunk-QZ34KQ76.js";import"./chunk-CLNYHWZ6.js";import"./chunk-NWGRLNUM.js";import"./chunk-BKNXRSJU.js";import"./chunk-ASPPM7TQ.js";import"./chunk-Z6LHGA27.js";import"./chunk-BPXS4QEO.js";import"./chunk-WBAPIPST.js";import"./chunk-BLCNUT53.js";import"./chunk-245WE5AF.js";import"./chunk-FCV2DPZQ.js";export{c as channelRoutes,b as getChannelManager,a as setChannelManager};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{d as D}from"./chunk-
|
|
1
|
+
import{d as D}from"./chunk-RX274IH7.js";import{a as b}from"./chunk-NUJSTEV4.js";import{f as v}from"./chunk-XF7YHFVR.js";import{e as O}from"./chunk-2Q6XLYCC.js";import{a as S,b as P,c,d as I,e as w,f as C,g as M}from"./chunk-NPGZRSGL.js";import{b as x}from"./chunk-CLNYHWZ6.js";import{b as y}from"./chunk-NWGRLNUM.js";import{b as R}from"./chunk-LZDO4PXK.js";import{s as k}from"./chunk-RBJPQYV3.js";import{a as f}from"./chunk-L7JP7DUO.js";import{b as h,o as B}from"./chunk-KJNAORKM.js";import{l as d,n as j}from"./chunk-BPXS4QEO.js";import{c as E,h as N}from"./chunk-BLCNUT53.js";j();function L(i){return{id:i.id,eventType:i.event_type,matchCriteria:JSON.parse(i.match_criteria),target:JSON.parse(i.target),formatTemplate:i.format_template??void 0,maxPerMinute:i.max_per_minute,skipOriginChannel:i.skip_origin_channel===1,enabled:i.enabled===1,createdAt:i.created_at,createdBy:i.created_by??void 0}}function q(i){d().prepare(`
|
|
2
2
|
INSERT INTO delivery_rules (id, event_type, match_criteria, target, format_template,
|
|
3
3
|
max_per_minute, skip_origin_channel, enabled, created_at, created_by)
|
|
4
4
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5
|
-
`).run(i.id,i.eventType,JSON.stringify(i.matchCriteria),JSON.stringify(i.target),i.formatTemplate??null,i.maxPerMinute,i.skipOriginChannel?1:0,i.enabled?1:0,i.createdAt,i.createdBy??null)}function H(i){let n=d().prepare("SELECT * FROM delivery_rules WHERE id = ?").get(i);return n?L(n):void 0}function W(i){let e=d(),n="SELECT * FROM delivery_rules",r=[];return i!==void 0&&(n+=" WHERE enabled = ?",r.push(i?1:0)),n+=" ORDER BY created_at DESC",e.prepare(n).all(...r).map(L)}function U(i,e){let n=d(),r=[],t=[];e.eventType!==void 0&&(r.push("event_type = ?"),t.push(e.eventType)),e.matchCriteria!==void 0&&(r.push("match_criteria = ?"),t.push(JSON.stringify(e.matchCriteria))),e.target!==void 0&&(r.push("target = ?"),t.push(JSON.stringify(e.target))),e.formatTemplate!==void 0&&(r.push("format_template = ?"),t.push(e.formatTemplate)),e.maxPerMinute!==void 0&&(r.push("max_per_minute = ?"),t.push(e.maxPerMinute)),e.skipOriginChannel!==void 0&&(r.push("skip_origin_channel = ?"),t.push(e.skipOriginChannel?1:0)),e.enabled!==void 0&&(r.push("enabled = ?"),t.push(e.enabled?1:0)),r.length!==0&&(t.push(i),n.prepare(`UPDATE delivery_rules SET ${r.join(", ")} WHERE id = ?`).run(...t))}function G(i){let e=d();e.prepare("DELETE FROM delivery_log WHERE rule_id = ?").run(i),e.prepare("DELETE FROM delivery_rules WHERE id = ?").run(i)}function A(i,e){return W(!0).filter(r=>{if(r.eventType!=="*"&&r.eventType!==i)return!1;let t=r.matchCriteria;if(t.templateId&&t.templateId!==e.templateId||t.roleId&&t.roleId!==e.roleId||t.taskStatus&&t.taskStatus!==e.taskStatus)return!1;if(t.promptPattern)try{if(!new RegExp(t.promptPattern,"i").test(e.prompt??""))return!1}catch{return!1}if(t.excludePromptPatterns&&t.excludePromptPatterns.length>0){let a=e.prompt??"";for(let s of t.excludePromptPatterns)if(!(typeof s!="string"||s.length>200))try{if(new RegExp(s,"i").test(a))return!1}catch{continue}}return!0})}B();N();import{v4 as J}from"uuid";function F(i){return!!(i.templateId&&i.stepId&&i.parentId)}var l=E("admin"),_=new Map,m=null,g=null,u=null,T=class{constructor(){f.on("task_status_change",e=>{(e.newStatus==="completed"||e.newStatus==="failed")&&this.handleTaskStatusChange(e.taskId,e.newStatus).catch(n=>{l.error({taskId:e.taskId,error:n},"Delivery processing failed")})}),f.on("plan_approval_request",e=>{this.handlePlanApprovalRequest(e.taskId,e.planId,e.plan).catch(n=>{l.error({taskId:e.taskId,error:n},"Delivery processing failed (plan_approval)")})}),f.on("template_execution_status_change",e=>{e.status==="failed"&&this.handleTemplateExecutionFailure(e.executionId,e.templateId).catch(n=>{l.error({executionId:e.executionId,error:n},"Template failure delivery processing failed")})}),l.info("DeliveryEngine initialized")}async handlePlanApprovalRequest(e,n,r){let t=h(e),a=this.getSourceChannelForTask(e);if(a){let o=D(r),{sendApprovalToChannel:p}=await import("./approval-handler-
|
|
5
|
+
`).run(i.id,i.eventType,JSON.stringify(i.matchCriteria),JSON.stringify(i.target),i.formatTemplate??null,i.maxPerMinute,i.skipOriginChannel?1:0,i.enabled?1:0,i.createdAt,i.createdBy??null)}function H(i){let n=d().prepare("SELECT * FROM delivery_rules WHERE id = ?").get(i);return n?L(n):void 0}function W(i){let e=d(),n="SELECT * FROM delivery_rules",r=[];return i!==void 0&&(n+=" WHERE enabled = ?",r.push(i?1:0)),n+=" ORDER BY created_at DESC",e.prepare(n).all(...r).map(L)}function U(i,e){let n=d(),r=[],t=[];e.eventType!==void 0&&(r.push("event_type = ?"),t.push(e.eventType)),e.matchCriteria!==void 0&&(r.push("match_criteria = ?"),t.push(JSON.stringify(e.matchCriteria))),e.target!==void 0&&(r.push("target = ?"),t.push(JSON.stringify(e.target))),e.formatTemplate!==void 0&&(r.push("format_template = ?"),t.push(e.formatTemplate)),e.maxPerMinute!==void 0&&(r.push("max_per_minute = ?"),t.push(e.maxPerMinute)),e.skipOriginChannel!==void 0&&(r.push("skip_origin_channel = ?"),t.push(e.skipOriginChannel?1:0)),e.enabled!==void 0&&(r.push("enabled = ?"),t.push(e.enabled?1:0)),r.length!==0&&(t.push(i),n.prepare(`UPDATE delivery_rules SET ${r.join(", ")} WHERE id = ?`).run(...t))}function G(i){let e=d();e.prepare("DELETE FROM delivery_log WHERE rule_id = ?").run(i),e.prepare("DELETE FROM delivery_rules WHERE id = ?").run(i)}function A(i,e){return W(!0).filter(r=>{if(r.eventType!=="*"&&r.eventType!==i)return!1;let t=r.matchCriteria;if(t.templateId&&t.templateId!==e.templateId||t.roleId&&t.roleId!==e.roleId||t.taskStatus&&t.taskStatus!==e.taskStatus)return!1;if(t.promptPattern)try{if(!new RegExp(t.promptPattern,"i").test(e.prompt??""))return!1}catch{return!1}if(t.excludePromptPatterns&&t.excludePromptPatterns.length>0){let a=e.prompt??"";for(let s of t.excludePromptPatterns)if(!(typeof s!="string"||s.length>200))try{if(new RegExp(s,"i").test(a))return!1}catch{continue}}return!0})}B();N();import{v4 as J}from"uuid";function F(i){return!!(i.templateId&&i.stepId&&i.parentId)}var l=E("admin"),_=new Map,m=null,g=null,u=null,T=class{constructor(){f.on("task_status_change",e=>{(e.newStatus==="completed"||e.newStatus==="failed")&&this.handleTaskStatusChange(e.taskId,e.newStatus).catch(n=>{l.error({taskId:e.taskId,error:n},"Delivery processing failed")})}),f.on("plan_approval_request",e=>{this.handlePlanApprovalRequest(e.taskId,e.planId,e.plan).catch(n=>{l.error({taskId:e.taskId,error:n},"Delivery processing failed (plan_approval)")})}),f.on("template_execution_status_change",e=>{e.status==="failed"&&this.handleTemplateExecutionFailure(e.executionId,e.templateId).catch(n=>{l.error({executionId:e.executionId,error:n},"Template failure delivery processing failed")})}),l.info("DeliveryEngine initialized")}async handlePlanApprovalRequest(e,n,r){let t=h(e),a=this.getSourceChannelForTask(e);if(a){let o=D(r),{sendApprovalToChannel:p}=await import("./approval-handler-ZWZZ3FKR.js");await p(a.channelId,a.chatId,n,e,o)}let s=D(r)+`
|
|
6
6
|
|
|
7
|
-
Task: ${e}`;await this.matchAndDeliver("plan_approval_request",{templateId:t?.templateId,roleId:t?.roleId,prompt:t?.prompt,taskStatus:"pending"},s,e)}async handleTemplateExecutionFailure(e,n){let r=
|
|
7
|
+
Task: ${e}`;await this.matchAndDeliver("plan_approval_request",{templateId:t?.templateId,roleId:t?.roleId,prompt:t?.prompt,taskStatus:"pending"},s,e)}async handleTemplateExecutionFailure(e,n){let r=R(e),t=n?k(n):null,a=r?Object.entries(r.stepStatuses).filter(([,o])=>o.status==="failed"):[],s=["\u26A0\uFE0F TemplateExecution failed",`Template: ${t?.name??n}`,`Execution: ${e}`,`Failed steps: ${a.map(([o])=>o).join(", ")||"(unknown \u2014 no failed step recorded)"}`,a[0]?.[1]?.error?`
|
|
8
8
|
First error: ${a[0][1].error.slice(0,300)}`:""].filter(Boolean).join(`
|
|
9
|
-
`);await this.matchAndDeliver("template_execution_failed",{templateId:n,roleId:void 0,prompt:void 0,taskStatus:"failed"},s,void 0,e)}getSourceChannelForTask(e){try{let n=v(e);if(!n)return null;let r=
|
|
9
|
+
`);await this.matchAndDeliver("template_execution_failed",{templateId:n,roleId:void 0,prompt:void 0,taskStatus:"failed"},s,void 0,e)}getSourceChannelForTask(e){try{let n=v(e);if(!n)return null;let r=y(n.sessionId);return!r||r.source.type!=="channel"||!r.source.channelId||!r.source.chatId?null:{channelId:r.source.channelId,chatId:r.source.chatId}}catch{return null}}async handleTaskStatusChange(e,n){let r=h(e);if(!r)return;if(F(r)){l.debug({taskId:e,templateId:r.templateId,stepId:r.stepId},"Skipping delivery for TemplateExecution step task");return}if(r.config?.taskType==="contract-verifier"){l.debug({taskId:e},"Skipping delivery for contract-verifier task");return}let t={templateId:r.templateId,roleId:r.roleId,prompt:r.prompt,taskStatus:n},a=n==="completed"?"task_complete":"task_error",s=r.result??r.error??"";await this.matchAndDeliver(a,t,s,e)}async matchAndDeliver(e,n,r,t,a){let s=A(e,n);if(s.length!==0){l.debug({eventType:e,ruleCount:s.length,taskId:t},"Matched delivery rules");for(let o of s){if(!this.checkRateLimit(o)){l.warn({ruleId:o.id,maxPerMinute:o.maxPerMinute},"Delivery rate limit exceeded, skipping");continue}if(o.skipOriginChannel&&o.target.type==="channel"&&t&&this.isOriginChannel(t,o.target))continue;let p={id:J(),ruleId:o.id,taskId:t,executionId:a,status:"pending",target:o.target,content:r,attempts:0,createdAt:Date.now(),expiresAt:Date.now()+S,source:"rule"};P(p),await this.attemptDelivery(p,o)}}}async attemptDeliveryPublic(e,n){return this.attemptDelivery(e,n)}async attemptDelivery(e,n){let r=O();try{if(e.target.type==="channel"){let t=e.target.chatId;if(!t&&e.target.channelId){let s=x(e.target.channelId);t=s?b(s):void 0}let a=await r.send({taskId:e.taskId,channelId:e.target.channelId,chatId:t,content:e.content,messageType:"deliver"});a.success?(I(e.id),l.info({entryId:e.id,ruleId:n.id,targetType:"channel"},"Delivery successful")):c(e.id,"failed",a.error??"Gateway returned failure")}else if(e.target.type==="webhook"){let t=await r.send({taskId:e.taskId,webhookUrl:e.target.webhookUrl,content:e.content,messageType:"deliver"});t.success?(I(e.id),l.info({entryId:e.id,ruleId:n.id,targetType:"webhook"},"Webhook delivery successful")):c(e.id,"failed",t.error??"Gateway returned failure")}}catch(t){let a=t instanceof Error?t.message:String(t);c(e.id,"failed",a),l.warn({entryId:e.id,error:a},"Delivery attempt failed")}}checkRateLimit(e){let n=Date.now(),r=6e4,t=_.get(e.id);t||(t=[],_.set(e.id,t));let a=n-r;for(;t.length>0&&t[0]<a;)t.shift();return t.length>=e.maxPerMinute?!1:(t.push(n),!0)}isOriginChannel(e,n){try{if(n.type!=="channel"||!n.channelId)return!1;let r=v(e);if(!r)return!1;let t=y(r.sessionId);return t?t.source.type==="channel"&&t.source.channelId===n.channelId&&(!n.chatId||t.source.chatId===n.chatId):!1}catch{return!1}}async retryPending(){let e=w("rule",50),n=C("rule",50),r=[...e,...n];if(r.length!==0){l.debug({count:r.length},"Retrying pending/failed deliveries");for(let t of r){if(t.attempts>=3){c(t.id,"failed","Max retries (3) exceeded");continue}let a={id:t.ruleId??"retry-synthetic",eventType:"*",matchCriteria:{},target:t.target,maxPerMinute:5,skipOriginChannel:!0,enabled:!0,createdAt:0};await this.attemptDelivery(t,a)}}}};function ce(){return u}function ue(){u||(u=new T,m=setInterval(()=>{u?.retryPending().catch(i=>{l.error({error:i},"Delivery retry scan failed")})},6e4),g=setInterval(()=>{try{let i=M();i>0&&l.info({cleaned:i},"Expired delivery log entries cleaned up")}catch(i){l.error({error:i},"Delivery cleanup failed")}},36e5),l.info("DeliveryEngine started with retry (60s) and cleanup (1h) timers"))}function pe(){m&&(clearInterval(m),m=null),g&&(clearInterval(g),g=null),u=null,_.clear(),l.info("DeliveryEngine stopped")}export{q as a,H as b,W as c,U as d,G as e,F as f,T as g,ce as h,ue as i,pe as j};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{b as X,c as I,d as D}from"./chunk-NPGZRSGL.js";import{a as G,e as Y,g as Q}from"./chunk-QZ34KQ76.js";import{b as A}from"./chunk-CLNYHWZ6.js";import{a as C,d as ge}from"./chunk-BKNXRSJU.js";import{b as B,h as J,i as z}from"./chunk-LZDO4PXK.js";import{s as H}from"./chunk-RBJPQYV3.js";import{a as v}from"./chunk-L7JP7DUO.js";import{c as W,l as ue}from"./chunk-L47LZYVG.js";import{l as E,n as me}from"./chunk-BPXS4QEO.js";import{c as F,h as ce}from"./chunk-BLCNUT53.js";import{c as w,e as q}from"./chunk-245WE5AF.js";import{existsSync as _e}from"fs";import{createHash as Ie}from"crypto";import{isAbsolute as be}from"path";ge();me();q();import{v4 as pe}from"uuid";function re(e){return{id:e.id,eventKey:e.event_key,sourceType:e.source_type,sourceId:e.source_id,taskId:e.task_id??void 0,templateId:e.template_id??void 0,templateName:e.template_name??void 0,messageType:e.message_type,viewerKey:e.viewer_key,title:e.title??void 0,contentPreview:e.content_preview,attachments:k(e.attachments_json),targets:k(e.targets_json),firstDeliveredAt:e.first_delivered_at,lastDeliveredAt:e.last_delivered_at,createdAt:e.created_at,traceId:e.trace_id??void 0}}function k(e){try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function ne(e){if(!e.viewerKey||e.viewerKey.trim().length===0)throw new Error("recordUserVisibleDeliveryEvent requires viewerKey");if(!e.eventKey||e.eventKey.trim().length===0)throw new Error("recordUserVisibleDeliveryEvent requires eventKey");if(!e.sourceId||e.sourceId.trim().length===0)throw new Error("recordUserVisibleDeliveryEvent requires sourceId");let t=E(),r=Date.now(),n=e.deliveredAt??r,i=t.prepare("SELECT * FROM user_visible_events WHERE event_key = ?").get(e.eventKey);if(!i){let p=pe();return t.prepare(`
|
|
2
2
|
INSERT INTO user_visible_events (
|
|
3
3
|
id, event_key, source_type, source_id, task_id, template_id, template_name,
|
|
4
4
|
message_type, viewer_key, title, content_preview, attachments_json,
|
|
@@ -22,4 +22,4 @@ import{a as B,b as J,e as X}from"./chunk-LU3D53ZV.js";import{b as z,c as I,d as
|
|
|
22
22
|
WHERE viewer_key = ?
|
|
23
23
|
AND last_delivered_at >= ?
|
|
24
24
|
AND last_delivered_at <= ?
|
|
25
|
-
`;return r.length>0&&(i+=` AND source_id NOT IN (${r.map(()=>"?").join(",")})`,n.push(...r)),i+=" ORDER BY last_delivered_at ASC",e.limit!==void 0&&(i+=" LIMIT ?",n.push(e.limit)),t.prepare(i).all(...n).map(re)}function fe(e,t){let r=[...e];for(let n of t){let i=ee(n);r.some(s=>ee(s)===i)||r.push(n)}return r}function ee(e){return[e.type,e.channelId??"",e.webhookUrl??"",e.chatId??"",e.sessionId??""].join("|")}function ye(e,t){let r=[...e];for(let n of t){let i=te(n),s=r.findIndex(l=>te(l)===i);s>=0?r[s]={...r[s],...n}:r.push(n)}return r}function te(e){return e.artifactId?`artifact:${e.artifactId}`:["file",e.filename??"",e.sizeBytes??"",e.mimeType??""].join("|")}ce();import{v4 as oe}from"uuid";q();ue();import{basename as x,extname as se}from"path";function ie(e){return W(e).filter(t=>t.kind==="file"&&!!t.blobPath)}function he(e){let t=e.mime??"";return t.startsWith("image/")?"image":t.startsWith("audio/")?"audio":t.startsWith("video/")?"video":"file"}function ve(e){let t=x(e.key).replace(/[\\/]/g,"-");if(e.originalFilename){let r=x(e.originalFilename).replace(/[\\/]/g,"-");if(se(r))return r}if(se(t))return t;if(e.mime){let r=Q(e.mime);if(r&&r!==".bin"&&t)return`${t}${r}`}return e.originalFilename?x(e.originalFilename).replace(/[\\/]/g,"-"):t||(e.blobPath?x(e.blobPath):e.id)}function ae(e){return e.map(t=>({path:t.blobPath,mediaType:he(t),filename:ve(t),contentType:t.mime,mimeType:t.mime,artifactId:t.id,locator:t.locator,sizeBytes:t.sizeBytes,purpose:t.purpose,contentHash:t.contentHash}))}var b=F("adam"),K=class{_dedupCache=new Map;_rateLimitWindows=new Map;_recentlySentIds=new Set;_laneTails=new Map;async _acquireLane(t,r){let n=`${t}:${r}`,i=this._laneTails.get(n)??Promise.resolve(),s,l=new Promise(p=>{s=p});return this._laneTails.set(n,l),l.then(()=>{this._laneTails.get(n)===l&&this._laneTails.delete(n)}),await i,s}isRecentlySent(t){return this._recentlySentIds.has(t)}async send(t){let{taskId:r,channelId:n,chatId:i,content:s,messageType:l,platform:p,webhookUrl:o,replyMarkup:T,replyToMessageId:_,quoteExcerpt:L,quoteTitle:R,mediaUrl:U,mediaType:N,attachments:P,dedupDiscriminator:j}=t,g=Ve(l),le=g!=="reply"&&!!r,d;if(le){d=`${r}:${n??"none"}:${i??"none"}:${g}${j?`:${j}`:""}`;let m=this._dedupCache.get(d);if(m&&Date.now()-m.timestamp<300*1e3)return b.debug({dedupKey:d},"Dedup hit, returning cached log entry"),{success:!0,logEntryId:m.logEntryId}}if(n){let m=Date.now(),f=6e4,u=this._rateLimitWindows.get(n);u||(u=[],this._rateLimitWindows.set(n,u));let V=m-f;for(;u.length>0&&u[0]<V;)u.shift();if(u.length>=60){let O=oe();b.warn({channelId:n,count:u.length},"Rate limited, not sending");let y={type:"channel",channelId:n,chatId:i??""};return this._writeOutboundReceipt(t,y,s,"failure"),{success:!1,logEntryId:O,error:"rate_limited"}}u.push(m)}let de=p??(n?A(n)?.platform:void 0)??"unknown",$=o?s:G(s,de,r),a=oe(),c={id:a,ruleId:void 0,taskId:r??void 0,status:"pending",target:n&&i?{type:"channel",channelId:n,chatId:i}:o?{type:"webhook",webhookUrl:o}:{type:"channel",channelId:n??"",chatId:i??""},content:$,attempts:0,createdAt:Date.now(),expiresAt:Date.now()+1440*60*1e3,source:"direct",messageType:g};z(c),d&&this._dedupCache.set(d,{logEntryId:a,timestamp:Date.now()});try{let m=Ue(U);if(m)return I(a,"failed",m),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:m,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:m};if(o){let f=await fetch(o,{method:"POST",body:JSON.stringify({result:s,taskId:r,timestamp:new Date().toISOString()}),signal:AbortSignal.timeout(1e4)});if(f.ok)return D(a),this._recordDeliveryLedgerAfterSuccess(t,c.target,g,s),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"delivered",messageType:g}),{success:!0,logEntryId:a};{let u=`Webhook returned ${f.status}`;return I(a,"failed",u),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:u,messageType:g}),{success:!1,logEntryId:a,error:u}}}else if(n&&i){let{getChannelManager:f}=await Se(),u=f();if(!u){let h="ChannelManager not available";return I(a,"failed",h),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:h,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:h}}let V={content:$,messageType:g,...T?{replyMarkup:T}:{},..._?{replyToMessageId:_}:{},...L?{quoteExcerpt:L}:{},...R?{quoteTitle:R}:{},...U?{mediaUrl:U}:{},...N?{mediaType:N}:{},...P?{attachments:P}:{}},O=await this._acquireLane(n,i),y;try{y=await u.sendMessage(n,i,V)}finally{O()}if(y===null){let h="Channel adapter send failed (returned null)";return I(a,"failed",h),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:h,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:h}}if(y&&(this._recentlySentIds.add(y),setTimeout(()=>this._recentlySentIds.delete(y),300*1e3)),y?.startsWith("queued-")){let h="queued_not_delivered";return d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"pending",error:h,messageType:g}),{success:!1,messageId:y,logEntryId:a,error:h}}return D(a),this._recordDeliveryLedgerAfterSuccess(t,c.target,g,s),this._writeOutboundReceipt(t,c.target,s,"success"),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"delivered",messageType:g}),{success:!0,messageId:y??void 0,logEntryId:a}}else{let f="No channelId/chatId or webhookUrl provided";return I(a,"failed",f),d&&this._dedupCache.delete(d),{success:!1,logEntryId:a,error:f}}}catch(m){let f=m instanceof Error?m.message:String(m);return I(a,"failed",f),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:f,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:f}}}_writeOutboundReceipt(t,r,n,i){if(r.type!=="channel"||!r.channelId)return;let s=w();if(!s){b.debug({taskId:t.taskId,channelId:r.channelId,outcome:i},"Outbound receipt skipped: no active trace context");return}let l=(t.attachments??[]).map(o=>o.artifactId).filter(o=>typeof o=="string"&&o.length>0),p=t.actorToolName??"OutboundGateway.send";try{J({traceId:s,taskId:t.taskId,sessionId:t.sessionId,effectCategory:"outbound_message",verb:"send",entityType:"channel_message",target:{channelId:r.channelId,chatId:r.chatId,platform:t.platform},payload:{textChars:n.length,attachmentCount:t.attachments?.length??0,attachmentRefs:l.length>0?l:void 0},actor:{traceId:s,toolName:p,taskId:t.taskId},outcome:i})}catch(o){o instanceof B?b.warn({errors:o.errors,taskId:t.taskId,channelId:r.channelId},"Outbound receipt validation failed"):b.warn({error:o instanceof Error?o.message:String(o),taskId:t.taskId},"Outbound receipt write failed")}}async redeliverExecutionTo(t){let r=t.includeArtifacts??!0,n=t.messageType??"result_delivery",i=t.dedupDiscriminator??`redelivery:${Date.now()}`,s=r?t.fileArtifacts??ie(t.executionId):[],l=s.length>0?ae(s):void 0,p=[];for(let o of t.targets){let T=A(o.channelId);if(!T){p.push({target:{channelId:o.channelId,chatId:o.chatId},deliveryLogId:"",status:"failed",attachmentCount:0,error:`Channel not found: ${o.channelId}`});continue}let _=await this.send({taskId:t.executionId,sessionId:t.sessionId,channelId:o.channelId,chatId:o.chatId,content:t.content,messageType:n,platform:T.platform,attachments:l,dedupDiscriminator:i,actorToolName:t.actorToolName});p.push({target:{channelId:o.channelId,chatId:o.chatId},deliveryLogId:_.logEntryId,status:_.success?"delivered":"failed",attachmentCount:s.length,..._.error?{error:_.error}:{}})}return{deliveries:p}}_recordDeliveryLedgerAfterSuccess(t,r,n,i){if(Te(n,t.taskId))try{let s=we(t,r);if(!s){C({source:"delivery_ledger",severity:"warning",sourceId:t.taskId,message:`Skipped user-visible delivery ledger write for ${n}: viewer identity unresolved`});return}let l=Ee(t.taskId),p=xe(i);ne({eventKey:`${s}|${l.sourceId}|${n}|${p}`,sourceType:l.sourceType,sourceId:l.sourceId,taskId:t.taskId,templateId:l.templateId,templateName:l.templateName,messageType:n,viewerKey:s,title:l.templateName,contentPreview:i,attachments:(t.attachments??[]).map(Ae),targets:[ke(r)]})}catch(s){let l=s instanceof Error?s.message:String(s);b.warn({error:l,taskId:t.taskId,messageType:n},"User-visible delivery ledger write failed");try{C({source:"delivery_ledger",severity:"error",sourceId:t.taskId,message:l})}catch{}}}};function Te(e,t){return t?!["reply","assistant_text","user_message","approval","approval_prompt"].includes(e):!1}function we(e,t){if(e.viewerKey)return e.viewerKey;if(t.type==="channel"&&t.channelId)return Y({type:"channel",channelId:t.channelId,chatId:t.chatId})}function Ee(e){let t=X(e);if(!t)return{sourceType:"task",sourceId:e};let r=H(t.templateId);return{sourceType:"template_execution",sourceId:t.id,templateId:t.templateId,templateName:r?.name}}function Ae(e){return{artifactId:e.artifactId,locator:e.locator,filename:e.filename,mimeType:e.mimeType??e.contentType,sizeBytes:e.sizeBytes,purpose:e.purpose,contentHash:e.contentHash}}function ke(e){if(e.type==="webhook")return{type:"webhook",webhookUrl:e.webhookUrl};let t=e.channelId?A(e.channelId):void 0;return{type:"channel",channelId:e.channelId,chatId:e.chatId,label:t?.name}}function xe(e){return Ie("sha256").update(e).digest("hex")}var S=null;function Se(){return S||(S=import("./channels-6BEGHNOK.js")),S}function it(){S=null}function Ue(e){if(!e)return;if(e.includes("://")&&!e.startsWith("file://"))return"mediaUrl must be a local file path";let t=e.startsWith("file://")?new URL(e).pathname:e;if(!be(t))return"mediaUrl must be absolute";if(!_e(t))return"mediaUrl file does not exist"}function Ve(e){return e==="report"?"status_report":e==="deliver"?"result_delivery":e}var M=null;function Oe(){return M||(M=new K),M}function at(e){return Oe().isRecentlySent(e)}export{Le as a,ie as b,K as c,it as d,Oe as e,at as f};
|
|
25
|
+
`;return r.length>0&&(i+=` AND source_id NOT IN (${r.map(()=>"?").join(",")})`,n.push(...r)),i+=" ORDER BY last_delivered_at ASC",e.limit!==void 0&&(i+=" LIMIT ?",n.push(e.limit)),t.prepare(i).all(...n).map(re)}function fe(e,t){let r=[...e];for(let n of t){let i=ee(n);r.some(s=>ee(s)===i)||r.push(n)}return r}function ee(e){return[e.type,e.channelId??"",e.webhookUrl??"",e.chatId??"",e.sessionId??""].join("|")}function ye(e,t){let r=[...e];for(let n of t){let i=te(n),s=r.findIndex(l=>te(l)===i);s>=0?r[s]={...r[s],...n}:r.push(n)}return r}function te(e){return e.artifactId?`artifact:${e.artifactId}`:["file",e.filename??"",e.sizeBytes??"",e.mimeType??""].join("|")}ce();import{v4 as oe}from"uuid";q();ue();import{basename as x,extname as se}from"path";function ie(e){return W(e).filter(t=>t.kind==="file"&&!!t.blobPath)}function he(e){let t=e.mime??"";return t.startsWith("image/")?"image":t.startsWith("audio/")?"audio":t.startsWith("video/")?"video":"file"}function ve(e){let t=x(e.key).replace(/[\\/]/g,"-");if(e.originalFilename){let r=x(e.originalFilename).replace(/[\\/]/g,"-");if(se(r))return r}if(se(t))return t;if(e.mime){let r=Q(e.mime);if(r&&r!==".bin"&&t)return`${t}${r}`}return e.originalFilename?x(e.originalFilename).replace(/[\\/]/g,"-"):t||(e.blobPath?x(e.blobPath):e.id)}function ae(e){return e.map(t=>({path:t.blobPath,mediaType:he(t),filename:ve(t),contentType:t.mime,mimeType:t.mime,artifactId:t.id,locator:t.locator,sizeBytes:t.sizeBytes,purpose:t.purpose,contentHash:t.contentHash}))}var b=F("adam"),K=class{_dedupCache=new Map;_rateLimitWindows=new Map;_recentlySentIds=new Set;_laneTails=new Map;async _acquireLane(t,r){let n=`${t}:${r}`,i=this._laneTails.get(n)??Promise.resolve(),s,l=new Promise(p=>{s=p});return this._laneTails.set(n,l),l.then(()=>{this._laneTails.get(n)===l&&this._laneTails.delete(n)}),await i,s}isRecentlySent(t){return this._recentlySentIds.has(t)}async send(t){let{taskId:r,channelId:n,chatId:i,content:s,messageType:l,platform:p,webhookUrl:o,replyMarkup:T,replyToMessageId:_,quoteExcerpt:L,quoteTitle:R,mediaUrl:U,mediaType:N,attachments:P,dedupDiscriminator:j}=t,g=Ve(l),le=g!=="reply"&&!!r,d;if(le){d=`${r}:${n??"none"}:${i??"none"}:${g}${j?`:${j}`:""}`;let m=this._dedupCache.get(d);if(m&&Date.now()-m.timestamp<300*1e3)return b.debug({dedupKey:d},"Dedup hit, returning cached log entry"),{success:!0,logEntryId:m.logEntryId}}if(n){let m=Date.now(),f=6e4,u=this._rateLimitWindows.get(n);u||(u=[],this._rateLimitWindows.set(n,u));let V=m-f;for(;u.length>0&&u[0]<V;)u.shift();if(u.length>=60){let O=oe();b.warn({channelId:n,count:u.length},"Rate limited, not sending");let y={type:"channel",channelId:n,chatId:i??""};return this._writeOutboundReceipt(t,y,s,"failure"),{success:!1,logEntryId:O,error:"rate_limited"}}u.push(m)}let de=p??(n?A(n)?.platform:void 0)??"unknown",$=o?s:G(s,de,r),a=oe(),c={id:a,ruleId:void 0,taskId:r??void 0,status:"pending",target:n&&i?{type:"channel",channelId:n,chatId:i}:o?{type:"webhook",webhookUrl:o}:{type:"channel",channelId:n??"",chatId:i??""},content:$,attempts:0,createdAt:Date.now(),expiresAt:Date.now()+1440*60*1e3,source:"direct",messageType:g};X(c),d&&this._dedupCache.set(d,{logEntryId:a,timestamp:Date.now()});try{let m=Ue(U);if(m)return I(a,"failed",m),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:m,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:m};if(o){let f=await fetch(o,{method:"POST",body:JSON.stringify({result:s,taskId:r,timestamp:new Date().toISOString()}),signal:AbortSignal.timeout(1e4)});if(f.ok)return D(a),this._recordDeliveryLedgerAfterSuccess(t,c.target,g,s),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"delivered",messageType:g}),{success:!0,logEntryId:a};{let u=`Webhook returned ${f.status}`;return I(a,"failed",u),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:u,messageType:g}),{success:!1,logEntryId:a,error:u}}}else if(n&&i){let{getChannelManager:f}=await Se(),u=f();if(!u){let h="ChannelManager not available";return I(a,"failed",h),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:h,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:h}}let V={content:$,messageType:g,...T?{replyMarkup:T}:{},..._?{replyToMessageId:_}:{},...L?{quoteExcerpt:L}:{},...R?{quoteTitle:R}:{},...U?{mediaUrl:U}:{},...N?{mediaType:N}:{},...P?{attachments:P}:{}},O=await this._acquireLane(n,i),y;try{y=await u.sendMessage(n,i,V)}finally{O()}if(y===null){let h="Channel adapter send failed (returned null)";return I(a,"failed",h),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:h,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:h}}if(y&&(this._recentlySentIds.add(y),setTimeout(()=>this._recentlySentIds.delete(y),300*1e3)),y?.startsWith("queued-")){let h="queued_not_delivered";return d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"pending",error:h,messageType:g}),{success:!1,messageId:y,logEntryId:a,error:h}}return D(a),this._recordDeliveryLedgerAfterSuccess(t,c.target,g,s),this._writeOutboundReceipt(t,c.target,s,"success"),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"delivered",messageType:g}),{success:!0,messageId:y??void 0,logEntryId:a}}else{let f="No channelId/chatId or webhookUrl provided";return I(a,"failed",f),d&&this._dedupCache.delete(d),{success:!1,logEntryId:a,error:f}}}catch(m){let f=m instanceof Error?m.message:String(m);return I(a,"failed",f),d&&this._dedupCache.delete(d),v.emit({type:"delivery_status_change",logEntryId:a,taskId:r,target:c.target,status:"failed",error:f,messageType:g}),this._writeOutboundReceipt(t,c.target,s,"failure"),{success:!1,logEntryId:a,error:f}}}_writeOutboundReceipt(t,r,n,i){if(r.type!=="channel"||!r.channelId)return;let s=w();if(!s){b.debug({taskId:t.taskId,channelId:r.channelId,outcome:i},"Outbound receipt skipped: no active trace context");return}let l=(t.attachments??[]).map(o=>o.artifactId).filter(o=>typeof o=="string"&&o.length>0),p=t.actorToolName??"OutboundGateway.send";try{z({traceId:s,taskId:t.taskId,sessionId:t.sessionId,effectCategory:"outbound_message",verb:"send",entityType:"channel_message",target:{channelId:r.channelId,chatId:r.chatId,platform:t.platform},payload:{textChars:n.length,attachmentCount:t.attachments?.length??0,attachmentRefs:l.length>0?l:void 0},actor:{traceId:s,toolName:p,taskId:t.taskId},outcome:i})}catch(o){o instanceof J?b.warn({errors:o.errors,taskId:t.taskId,channelId:r.channelId},"Outbound receipt validation failed"):b.warn({error:o instanceof Error?o.message:String(o),taskId:t.taskId},"Outbound receipt write failed")}}async redeliverExecutionTo(t){let r=t.includeArtifacts??!0,n=t.messageType??"result_delivery",i=t.dedupDiscriminator??`redelivery:${Date.now()}`,s=r?t.fileArtifacts??ie(t.executionId):[],l=s.length>0?ae(s):void 0,p=[];for(let o of t.targets){let T=A(o.channelId);if(!T){p.push({target:{channelId:o.channelId,chatId:o.chatId},deliveryLogId:"",status:"failed",attachmentCount:0,error:`Channel not found: ${o.channelId}`});continue}let _=await this.send({taskId:t.executionId,sessionId:t.sessionId,channelId:o.channelId,chatId:o.chatId,content:t.content,messageType:n,platform:T.platform,attachments:l,dedupDiscriminator:i,actorToolName:t.actorToolName});p.push({target:{channelId:o.channelId,chatId:o.chatId},deliveryLogId:_.logEntryId,status:_.success?"delivered":"failed",attachmentCount:s.length,..._.error?{error:_.error}:{}})}return{deliveries:p}}_recordDeliveryLedgerAfterSuccess(t,r,n,i){if(Te(n,t.taskId))try{let s=we(t,r);if(!s){C({source:"delivery_ledger",severity:"warning",sourceId:t.taskId,message:`Skipped user-visible delivery ledger write for ${n}: viewer identity unresolved`});return}let l=Ee(t.taskId),p=xe(i);ne({eventKey:`${s}|${l.sourceId}|${n}|${p}`,sourceType:l.sourceType,sourceId:l.sourceId,taskId:t.taskId,templateId:l.templateId,templateName:l.templateName,messageType:n,viewerKey:s,title:l.templateName,contentPreview:i,attachments:(t.attachments??[]).map(Ae),targets:[ke(r)]})}catch(s){let l=s instanceof Error?s.message:String(s);b.warn({error:l,taskId:t.taskId,messageType:n},"User-visible delivery ledger write failed");try{C({source:"delivery_ledger",severity:"error",sourceId:t.taskId,message:l})}catch{}}}};function Te(e,t){return t?!["reply","assistant_text","user_message","approval","approval_prompt"].includes(e):!1}function we(e,t){if(e.viewerKey)return e.viewerKey;if(t.type==="channel"&&t.channelId)return Y({type:"channel",channelId:t.channelId,chatId:t.chatId})}function Ee(e){let t=B(e);if(!t)return{sourceType:"task",sourceId:e};let r=H(t.templateId);return{sourceType:"template_execution",sourceId:t.id,templateId:t.templateId,templateName:r?.name}}function Ae(e){return{artifactId:e.artifactId,locator:e.locator,filename:e.filename,mimeType:e.mimeType??e.contentType,sizeBytes:e.sizeBytes,purpose:e.purpose,contentHash:e.contentHash}}function ke(e){if(e.type==="webhook")return{type:"webhook",webhookUrl:e.webhookUrl};let t=e.channelId?A(e.channelId):void 0;return{type:"channel",channelId:e.channelId,chatId:e.chatId,label:t?.name}}function xe(e){return Ie("sha256").update(e).digest("hex")}var S=null;function Se(){return S||(S=import("./channels-2DFKJ33W.js")),S}function it(){S=null}function Ue(e){if(!e)return;if(e.includes("://")&&!e.startsWith("file://"))return"mediaUrl must be a local file path";let t=e.startsWith("file://")?new URL(e).pathname:e;if(!be(t))return"mediaUrl must be absolute";if(!_e(t))return"mediaUrl file does not exist"}function Ve(e){return e==="report"?"status_report":e==="deliver"?"result_delivery":e}var M=null;function Oe(){return M||(M=new K),M}function at(e){return Oe().isRecentlySent(e)}export{Le as a,ie as b,K as c,it as d,Oe as e,at as f};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{h as c,i as s}from"./chunk-LZDO4PXK.js";import{c as i,h as d}from"./chunk-BLCNUT53.js";import{c as a,e as f}from"./chunk-245WE5AF.js";f();d();var o=i("adam");function l(e){let r=e.traceIdOverride??a();if(!r){o.debug({toolName:e.toolName,entityType:e.entityType,verb:e.verb},"Mutation receipt skipped: no active trace context");return}let n={traceId:r,toolName:e.toolName,taskId:e.taskId,roleId:e.roleId};try{s({traceId:r,taskId:e.taskId,sessionId:e.sessionId,effectCategory:"entity_mutation",verb:e.verb,entityType:e.entityType,entityId:e.entityId,entityIds:e.entityIds,fieldChanges:e.fieldChanges,scope:e.scope,actor:n,outcome:"success"})}catch(t){t instanceof c?o.warn({errors:t.errors,toolName:e.toolName,entityType:e.entityType},"Mutation receipt validation failed"):o.warn({error:t instanceof Error?t.message:String(t),toolName:e.toolName},"Mutation receipt write failed")}}export{l as a};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{a as R}from"./chunk-DMDZ3QW7.js";import{a as ge}from"./chunk-F6U5TMM3.js";import{b as X}from"./chunk-LZDO4PXK.js";import{e as be,i as Ge}from"./chunk-VNXTBIPI.js";import{b as re,k as oe,m as W,s as V}from"./chunk-RBJPQYV3.js";import{a as ke}from"./chunk-L7JP7DUO.js";import{a as Ae}from"./chunk-D3SPXZZY.js";import{a as Ee}from"./chunk-DRO3DG7X.js";import{a as xe,b as ie,c as we,k as ve}from"./chunk-XIVFVKMB.js";import{C as te,I as Ye,b as J,c as _e,o as Xe}from"./chunk-KJNAORKM.js";import{a as H,b as U,c as ce,f as de,g as le,i as ue,j as me,l as Je}from"./chunk-L47LZYVG.js";import{b as Z,c as pe,d as fe,e as he,f as ye,j as We,l as $,n as ee}from"./chunk-BPXS4QEO.js";import{c as j,h as ae}from"./chunk-BLCNUT53.js";import{c as Ie,e as Ve}from"./chunk-245WE5AF.js";Ye();Ge();Xe();import{createSdkMcpServer as Ot,tool as C}from"@anthropic-ai/claude-agent-sdk";import{z as c}from"zod";import{v4 as Ke}from"uuid";Je();ae();ee();var Qe=j("audit");function _(r){try{$().prepare(`
|
|
2
|
+
INSERT INTO artifact_access_log (
|
|
3
|
+
timestamp, task_id, role_id, execution_id, step_id, tool, artifact_key, artifact_id,
|
|
4
|
+
size_bytes, outcome, error_reason
|
|
5
|
+
)
|
|
6
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
7
|
+
`).run(r.timestamp,r.taskId??null,r.roleId??null,r.executionId,r.stepId??null,r.tool,r.artifactKey??null,r.artifactId??null,r.sizeBytes??null,r.outcome,r.errorReason??null)}catch(e){Qe.error({err:e,entry:r},"Failed to write artifact access log")}}We();import{tool as B}from"@anthropic-ai/claude-agent-sdk";import{z as k}from"zod";import{v4 as Ze}from"uuid";function O(r){return{content:[{type:"text",text:JSON.stringify(r)}]}}var et={query:k.string().describe("Search query for memory retrieval"),roleId:re.optional().describe("Role ID to scope search (omit for cross-role)"),topK:k.number().optional().describe("Max results to return (default 5)")},tt={query:k.string().describe("Search query for memory retrieval"),topK:k.number().optional().describe("Max results to return (default 5)")},rt={id:k.string().optional().describe("Memory ID to update. Omit to create new."),roleId:re.describe("Role ID to save memory under"),content:k.string().describe("Memory content text"),type:k.enum(["event","thought","reflection"]).optional().describe("Memory type (default: thought)"),keywords:k.array(k.string()).optional().describe("Keywords for BM25 search"),importance:k.number().min(1).max(5).optional().describe("Importance 1-5 (default: 3)"),tier:k.enum(["working","episodic","semantic"]).optional().describe("Memory tier (default: episodic)")},ot={id:k.string().optional().describe("Memory ID to update. Omit to create new."),content:k.string().describe("Memory content text"),type:k.enum(["event","thought","reflection"]).optional().describe("Memory type (default: thought)"),keywords:k.array(k.string()).optional().describe("Keywords for BM25 search"),importance:k.number().min(1).max(5).optional().describe("Importance 1-5 (default: 3)"),tier:k.enum(["working","episodic","semantic"]).optional().describe("Memory tier (default: episodic)")},Se={id:k.string().describe("Memory ID to delete")};async function Ce(r,e){let o=r??e.roleId,n=e.topK??5,s=await Ae(o,e.query,{topK:n});return O({results:s.map(a=>({id:a.id,type:a.type,content:a.content,keywords:a.keywords,importance:a.importance,score:a.score}))})}async function Te(r,e){let o=r??e.roleId;if(!o)return O({error:"roleId is required"});let n,s=!0;try{n=await Ee(e.content)}catch{s=!1}if(e.id){let I=ie(e.id);if(!I)return O({error:`Memory ${e.id} not found`});let i=we(e.id,{content:e.content,embedding:n,keywords:e.keywords,importance:e.importance,type:e.type});return R({toolName:"save_memory",entityType:"memory",verb:"update",entityId:e.id,fieldChanges:[{path:"content",op:"set",before:I.content,after:e.content}],roleId:o}),O({id:e.id,action:"updated",success:i,embeddingUpdated:s})}let a=`mem-${Ze().slice(0,8)}`,u=Date.now();return xe({id:a,roleId:o,type:e.type??"thought",content:e.content,embedding:n,keywords:e.keywords??[],importance:e.importance??3,sourceType:"manual",createdAt:u,lastAccessed:u,retrievedCount:0,tier:e.tier??"episodic"}),R({toolName:"save_memory",entityType:"memory",verb:"create",entityId:a,fieldChanges:[{path:"_entity",op:"set",before:null,after:{id:a,roleId:o,type:e.type??"thought",content:e.content.length>200?`${e.content.slice(0,200)}\u2026`:e.content,tier:e.tier??"episodic"}}],roleId:o}),O({id:a,action:"created",success:!0,embeddingUpdated:s})}async function Re(r,e){let o=ie(e.id);if(r){if(!o)return O({error:`Memory ${e.id} not found`});if(o.roleId!==r)return O({error:`Memory ${e.id} does not belong to this role`})}return ve(e.id),R({toolName:"delete_memory",entityType:"memory",verb:"delete",entityId:e.id,fieldChanges:[{path:"_entity",op:"set",before:o?{id:o.id,roleId:o.roleId,content:o.content.length>200?`${o.content.slice(0,200)}\u2026`:o.content}:null,after:null}],roleId:r??o?.roleId}),O({id:e.id,deleted:!0})}function Oe(r){return r?[B("search_memories","Search agent memory using hybrid vector + keyword search. Returns scored memories ranked by relevance, recency, and importance.",tt,async e=>Ce(r,e)),B("save_memory","Create a new memory or update an existing one. Provide 'id' to update, omit to create. Embedding is auto-generated from content.",ot,async e=>Te(r,e)),B("delete_memory","Delete a memory by ID.",Se,async e=>Re(r,e))]:[B("search_memories","Search agent memory using hybrid vector + keyword search. Returns scored memories ranked by relevance, recency, and importance.",et,async e=>Ce(void 0,e)),B("save_memory","Create a new memory or update an existing one. Provide 'id' to update, omit to create. Embedding is auto-generated from content.",rt,async e=>Te(void 0,e)),B("delete_memory","Delete a memory by ID.",Se,async e=>Re(void 0,e))]}ae();import{basename as se}from"path";ee();import{v4 as it}from"uuid";function Ne(r){let e=[];if(r.verb||e.push("verb is required"),r.entityType||e.push("entityType is required"),!r.expected)return e.push("expected is required"),{valid:!1,errors:e};let o=r.expected;if(o.kind==="outbound")o.target?.channelId||e.push("expected.target.channelId is required for outbound"),o.attachmentCount!==void 0&&(typeof o.attachmentCount!="number"||o.attachmentCount<0)&&e.push("expected.attachmentCount must be a non-negative number");else if(o.kind==="field_change")o.entityId||e.push("expected.entityId is required for field_change"),o.fieldPath||e.push("expected.fieldPath is required for field_change"),o.op!=="set"&&o.op!=="list_add"&&o.op!=="list_remove"&&e.push("expected.op must be 'set', 'list_add', or 'list_remove'"),o.op==="set"&&(o.after===void 0&&e.push("expected.after is required when op='set'"),(o.added!==void 0||o.removed!==void 0)&&e.push("expected.added/removed must be absent when op='set'")),o.op==="list_add"&&((!Array.isArray(o.added)||o.added.length===0)&&e.push("expected.added (non-empty array) is required when op='list_add'"),(o.after!==void 0||o.removed!==void 0)&&e.push("expected.after/removed must be absent when op='list_add'")),o.op==="list_remove"&&((!Array.isArray(o.removed)||o.removed.length===0)&&e.push("expected.removed (non-empty array) is required when op='list_remove'"),(o.after!==void 0||o.added!==void 0)&&e.push("expected.after/added must be absent when op='list_remove'"));else if(o.kind==="batch"){o.entityType||e.push("expected.entityType is required for batch");let n=Array.isArray(o.entityIds)&&o.entityIds.length>0,s=!!o.scope&&typeof o.scope.expectedCount=="number"&&o.scope.expectedCount>=0&&!!o.scope.filter;!n&&!s&&e.push("batch claims require entityIds (non-empty) or scope (with filter + non-negative expectedCount)")}else e.push(`expected.kind must be 'outbound', 'field_change', or 'batch'; got '${o.kind}'`);return{valid:e.length===0,errors:e}}var F=class extends Error{constructor(o){super(`Invalid claim spec: ${o.join("; ")}`);this.errors=o;this.name="InvalidClaimError"}errors};function De(r){if(!r.traceId)throw new F(["traceId is required"]);if(!Array.isArray(r.claims)||r.claims.length===0)throw new F(["claims must be a non-empty array"]);for(let[o,n]of r.claims.entries()){let s=Ne(n);if(!s.valid)throw new F([`claims[${o}]: ${s.errors.join("; ")}`])}let e={id:r.id??it(),traceId:r.traceId,sessionId:r.sessionId,taskId:r.taskId,sourceMessageId:r.sourceMessageId,claims:r.claims,declaredAt:r.declaredAt??Date.now()};return $().prepare(`
|
|
8
|
+
INSERT INTO assistant_claims (
|
|
9
|
+
id, trace_id, session_id, task_id, source_message_id, claims_json, declared_at
|
|
10
|
+
)
|
|
11
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
12
|
+
`).run(e.id,e.traceId,e.sessionId??null,e.taskId??null,e.sourceMessageId??null,JSON.stringify(e.claims),e.declaredAt),e}function er(r){return $().prepare(`
|
|
13
|
+
SELECT * FROM assistant_claims WHERE trace_id = ? ORDER BY declared_at ASC
|
|
14
|
+
`).all(r).map(nt)}function nt(r){return{id:r.id,traceId:r.trace_id,sessionId:r.session_id??void 0,taskId:r.task_id??void 0,sourceMessageId:r.source_message_id??void 0,claims:JSON.parse(r.claims_json),declaredAt:r.declared_at}}Ve();import{execFile as wt}from"child_process";import{promisify as vt}from"util";import{isAbsolute as Et,basename as At}from"path";import Fe from"vm";import{isAbsolute as st}from"path";var S=class extends Error{constructor(e,o){super(`DSL parse error in "${e}": ${o}`),this.name="DslParseError"}},at=/^[a-z][a-z0-9_.]*$/i,ct=/\.\./;function L(r){if(!at.test(r))throw new S(r,`invalid handler key format "${r}" \u2014 must match [a-z][a-z0-9_.]*`);if(ct.test(r))throw new S(r,'handler key must not contain ".."')}function Me(r){let e=r.trim();try{let n=JSON.parse(e);if(typeof n=="number"||typeof n=="string"||typeof n=="boolean")return n}catch{}let o=parseFloat(e);return Number.isNaN(o)?e:o}var dt=/^([a-z][a-z0-9_.]*)\s+matches\s+\/(.+)\/([gimsuy]*)$/i,lt=/^([a-z][a-z0-9_.]*)\s*(<=|>=|==|!=)\s*(.+)$/i,ut=/^([a-z][a-z0-9_.]*)\s*(<|>)\s*(.+)$/i,mt=/^([a-z][a-z0-9_.]*)\s+between\s+(-?\d+(?:\.\d+)?)\s+and\s+(-?\d+(?:\.\d+)?)$/i,pt=/^([a-z][a-z0-9_.]*)\s+in\s+\[([^\]]+)\]$/i;function $e(r){if(typeof r=="object"&&r!==null&&"script"in r){let o=String(r.script);if(!st(o))throw new S(`{script: "${o}"}`,"script path must be absolute");return{kind:"script",scriptPath:o}}if(typeof r!="string")throw new S(String(r),"assertion must be a string or {script: string} object");let e=r.trim();if(!e)throw new S(e,"empty assertion string");{let o=dt.exec(e);if(o){let n=o[1];return L(n),{kind:"matches",key:n,regexSource:o[2],regexFlags:o[3]??""}}}{let o=mt.exec(e);if(o){let n=o[1];return L(n),{kind:"between",key:n,min:parseFloat(o[2]),max:parseFloat(o[3])}}}{let o=pt.exec(e);if(o){let n=o[1];L(n);let s=o[2],a=[];for(let u of s.split(",")){let I=u.trim();if(I)try{let i=JSON.parse(I);typeof i=="number"||typeof i=="string"||typeof i=="boolean"?a.push(i):a.push(I)}catch{a.push(I)}}return{kind:"in",key:n,values:a}}}{let o=lt.exec(e);if(o){let n=o[1];return L(n),{kind:"comparison",key:n,op:o[2],value:Me(o[3])}}}{let o=ut.exec(e);if(o){let n=o[1];return L(n),{kind:"comparison",key:n,op:o[2],value:Me(o[3])}}}throw new S(e,"unrecognized assertion syntax \u2014 expected key <op> value, between, in [...], matches /.../, or {script: ...}")}import{execFile as ht,spawn as yt}from"child_process";import{promisify as It}from"util";import{readFile as K}from"fs/promises";import{existsSync as _t}from"fs";import{createHash as gt}from"crypto";function ft(r){return typeof r=="number"?Number.isInteger(r)?r.toString():r.toFixed(4):JSON.stringify(r)}var P=class extends Error{constructor(o){super(`NO_HANDLER: ${o}, install relevant capability or remove assertion`);this.handlerKey=o;this.name="NoHandlerError"}handlerKey},v=class extends Error{constructor(o,n,s){super(`ASSERTION_FAILED: ${o}=${ft(n)}, expected ${s}`);this.handlerKey=o;this.measured=n;this.expected=s;this.name="AssertionFailedError"}handlerKey;measured;expected},b=class extends Error{constructor(o,n){super(`HANDLER_RUNTIME_ERROR: ${o}: ${n}`);this.handlerKey=o;this.detail=n;this.name="HandlerRuntimeError"}handlerKey;detail};var bt=It(ht);function N(r,e){if(!_t(e))throw new b(r,`file not found: ${e}`)}async function kt(r){try{return await bt("ffprobe",r,{maxBuffer:10*1024*1024})}catch(e){throw e.code==="ENOENT"?new b("audio.*","ffprobe not found on PATH \u2014 install ffmpeg/ffprobe"):new b("audio.*",`ffprobe failed: ${e.message}`)}}async function Pe(r,e){return new Promise((o,n)=>{let s=[],a=yt("ffmpeg",["-v","error","-i",r,"-f","s16le","-ar",String(e),"-ac","1","-"]);a.stdout.on("data",I=>s.push(I));let u="";a.stderr.on("data",I=>{u+=I.toString()}),a.on("error",I=>{I.code==="ENOENT"?n(new b("audio.*","ffmpeg not found on PATH \u2014 install ffmpeg/ffprobe")):n(new b("audio.*",`ffmpeg failed: ${I.message}`))}),a.on("close",I=>{I!==0?n(new b("audio.*",`ffmpeg exit ${I}: ${u.trim()}`)):o(Buffer.concat(s))})})}var ze=new Map;async function xt(r){let e=JSON.stringify(r);if(/"\$ref"\s*:\s*"https?:\/\//.test(e))throw new b("json.schema_valid","remote $ref not supported in schema");let o=gt("sha256").update(e).digest("hex"),n=ze.get(o);if(n)return n;let s=(await import("ajv")).default,u=new s({strict:!1,allErrors:!1}).compile(r);return ze.set(o,u),u}var Be={"audio.duration_s":async r=>{N("audio.duration_s",r);let{stdout:e}=await kt(["-v","error","-show_entries","format=duration","-of","default=noprint_wrappers=1:nokey=1",r]),o=parseFloat(e.trim());if(!Number.isFinite(o))throw new b("audio.duration_s",`ffprobe returned non-numeric duration: ${e.trim()}`);return o},"audio.zc_rate_per_s":async r=>{N("audio.zc_rate_per_s",r);let e=24e3,o=await Pe(r,e),n=new Int16Array(o.buffer,o.byteOffset,o.byteLength/2),s=0;for(let u=1;u<n.length;u++)n[u-1]>=0!=n[u]>=0&&s++;let a=n.length/e;return a>0?s/a:0},"audio.rms":async r=>{N("audio.rms",r);let o=await Pe(r,24e3),n=new Int16Array(o.buffer,o.byteOffset,o.byteLength/2),s=0;for(let a=0;a<n.length;a++){let u=n[a]/32768;s+=u*u}return n.length>0?Math.sqrt(s/n.length):0},"markdown.word_count":async r=>{N("markdown.word_count",r);let e=await K(r,"utf-8");return e.trim().length===0?0:e.trim().split(/\s+/).length},"image.width_px":async r=>{N("image.width_px",r);let{imageSize:e}=await import("image-size"),o=await K(r),n=e(o);if(typeof n.width!="number")throw new b("image.width_px","could not determine image width");return n.width},"image.height_px":async r=>{N("image.height_px",r);let{imageSize:e}=await import("image-size"),o=await K(r),n=e(o);if(typeof n.height!="number")throw new b("image.height_px","could not determine image height");return n.height},"pdf.page_count":async r=>{N("pdf.page_count",r);let{PDFDocument:e}=await import("pdf-lib"),o=await K(r);return(await e.load(o,{ignoreEncryption:!0})).getPageCount()},"json.schema_valid":async(r,e)=>{if(N("json.schema_valid",r),!e||typeof e!="object"||!("schema"in e))throw new b("json.schema_valid","missing schema arg");let o=await xt(e.schema),n=await K(r,"utf-8"),s;try{s=JSON.parse(n)}catch(a){throw new b("json.schema_valid",`file is not valid JSON: ${a.message}`)}return o(s)===!0}};var St=vt(wt);async function Le(r,e,o={}){let n=o.handlerRegistry??Be;for(let s=0;s<e.length;s++){let a=e[s],u=$e(a);if(u.kind==="script"){await Tt(u.scriptPath,r);continue}let I=n[u.key];if(!I)throw new P(u.key);let i=o.handlerArgsByIndex?.[s],t=await I(r,i);Ct(u,t)}}function Ct(r,e){switch(r.kind){case"comparison":{let{key:o,op:n,value:s}=r,a=!1;if(n==="<"?a=e<s:n===">"?a=e>s:n==="<="?a=e<=s:n===">="?a=e>=s:n==="=="?a=e==s:n==="!="&&(a=e!=s),!a)throw new v(o,e,`${n} ${s}`);break}case"between":{let{key:o,min:n,max:s}=r;if(e<n||e>s)throw new v(o,e,`between ${n} and ${s}`);break}case"in":{let{key:o,values:n}=r;if(!n.includes(e))throw new v(o,e,`in [${n.join(", ")}]`);break}case"matches":{let{key:o,regexSource:n,regexFlags:s}=r;if(!Rt(String(e),n,s,100))throw new v(o,e,`matches /${n}/${s}`);break}}}async function Tt(r,e){if(!Et(r))throw new b("script",`script path must be absolute: ${r}`);try{await St(r,[e],{timeout:6e4,maxBuffer:1024*1024})}catch(o){let n=o;if(n.code==="ENOENT")throw new b("script",`script not found: ${r}`);let s=n.exitCode;throw new v("script:"+At(r),s??"error",n.stderr?.trim()??n.message)}}function Rt(r,e,o,n){let s={value:r,regex:new RegExp(e,o),result:!1};Fe.createContext(s);try{return Fe.runInContext("result = regex.test(value)",s,{timeout:n}),s.result}catch(a){throw new b("matches",`regex evaluation timeout or error: ${a.message}`)}}ee();var Nt="execution-tools",Er="mcp__execution-tools__",Ar=["mcp__execution-tools__write_artifact","mcp__execution-tools__publish_artifact_file","mcp__execution-tools__send_to_channel","mcp__execution-tools__report_blocked","mcp__execution-tools__commit_claim","mcp__execution-tools__save_memory","mcp__execution-tools__delete_memory"],Sr=["mcp__execution-tools__list_channels","mcp__execution-tools__read_artifact","mcp__execution-tools__fetch_artifact_file","mcp__execution-tools__list_artifacts","mcp__execution-tools__search_memories"],Cr=["mcp__execution-tools__write_artifact","mcp__execution-tools__publish_artifact_file","mcp__execution-tools__send_to_channel","mcp__execution-tools__report_blocked","mcp__execution-tools__commit_claim","mcp__execution-tools__save_memory","mcp__execution-tools__delete_memory","mcp__execution-tools__list_channels","mcp__execution-tools__read_artifact","mcp__execution-tools__fetch_artifact_file","mcp__execution-tools__list_artifacts","mcp__execution-tools__search_memories"],Y=j("execution"),Dt=/^[\p{L}0-9._-]{1,256}$/u,Mt=/^[\p{L}0-9._-]{1,128}$/u,qe=256*1024,$t=/^[a-z]+\/[a-z0-9.+-]+$/;async function Pt(r){let{listChannels:e}=await import("./channels-2IL6USWL.js"),o=e(),{listSessions:n}=await import("./session-manager-6MUWHQYF.js"),s=[...n("active"),...n("archived")],{getDefaultChatIdForChannel:a}=await import("./target-resolution-PSSBM4LX.js"),u=o.find(i=>i.name.toLowerCase().includes(r.toLowerCase()));if(!u)return null;let I=a(u,s)??"";return{channelId:u.id,chatId:I}}function d(r){return{content:[{type:"text",text:JSON.stringify(r)}]}}function G(r){return Dt.test(r)?null:"Invalid artifact key. Use only letters, numbers, dot, underscore, or dash (1-256 chars)."}function ne(r){return Mt.test(r)?null:"Invalid stepId format. Use only letters, numbers, dot, underscore, or dash (1-128 chars)."}function je(r,e,o){return r!==e?r:se(o)}function He(r,e){let o=X(r);if(!o)return null;let n=V(o.templateId);return n?n.steps.find(u=>u.id===e)?.outputAs??null:null}var zt=r=>{if(!r)return!1;let e=J(r);return!!(e?.parentId&&e.templateId&&e.stepId)};function Yr(r,e,o){let n=r?te(r):void 0,s=o??(()=>{}),a=async()=>{if(!e)return{error:"artifact tools require a task context"};let i=J(e);if(!i)return{error:`task not found: ${e}`};if(!i.parentId)return{error:"this task is not a TemplateExecution step (no execution context)"};if(!i.stepId)return{error:"this task is not a TemplateExecution step (no step_id)"};let t=i.roleId??r;if(!t)return{error:"this template execution task has no role context"};let l=te(t);return l?{executionId:i.parentId,stepId:i.stepId,roleId:t,roleWorkspacePath:be(l.name),taskId:e}:{error:`role not found: ${t}`}},u=[...Oe(r),C("list_channels","List all available channels. Use this to discover what channels can be used with send_to_channel.",{},async()=>{let{listChannels:i}=await import("./channels-2IL6USWL.js"),t=i();return d({channels:t.map(l=>({id:l.id,name:l.name,enabled:l.enabled,type:l.config?.type??"unknown"}))})}),C("send_to_channel","Send a message to a connected channel by name. This role can only send to channels in its allowedChannels list (if configured).",{channelName:c.string().describe("The channel name, e.g., 'WeChat on iPad' or 'Client Mail'"),message:c.string().describe("The message content to send")},async i=>{if(n?.allowedChannels!==void 0){if(n.allowedChannels.length===0)return d({error:"This role is not allowed to send to any channels"});if(!n.allowedChannels.some(f=>f.toLowerCase()===i.channelName.toLowerCase()))return d({error:`Channel "${i.channelName}" is not in the allowed channels list for this role`})}let t=await Pt(i.channelName);if(!t)return d({error:`Channel "${i.channelName}" not found or has no chatId available`});let{getOutboundGateway:l}=await import("./outbound-gateway-R6EVRWHP.js"),h=await l().send({channelId:t.channelId,chatId:t.chatId,content:i.message,messageType:"reply"});return d({success:h.success,channelName:i.channelName})}),C("write_artifact","Persist a small structured value (JSON <= 256KB) for downstream TemplateExecution steps to read. USE THIS for: extracted fields, status flags, URL lists, summaries, structured key-value data. Do NOT use for: files (audio, video, reports). For files use publish_artifact_file instead.",{key:c.string().describe("Artifact key \u2014 a unique identifier for this value within the template execution."),value:c.unknown().describe("The JSON value to persist (must be <= 256KB serialized).")},async i=>{let t=await a();if("error"in t)return d({error:t.error});let l=G(i.key);if(l)return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"write_artifact",artifactKey:i.key,outcome:"denied",errorReason:l}),d({error:l});let m=He(t.executionId,t.stepId),h=X(t.executionId),p=h?V(h.templateId):null,f=p?p.steps.some(g=>g.id===t.stepId):!1,x=i.key,D,q=p!=null&&p.steps.some(g=>!!g.outputAs);if(m===null&&f&&q){let g=`Step "${t.stepId}" in template "${h.templateId}" has no outputAs declared. This template must be migrated before its steps can publish artifacts. Operator action required: run \`pnpm tsx scripts/migrate-all-templates-outputAs.ts --apply\` from the project root, or have the operator ask ChatManager in chat to upgrade the template.`;return Y.warn({taskId:t.taskId,stepId:t.stepId,templateId:h.templateId},"write_artifact: step has no outputAs in migrated template"),_({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"write_artifact",artifactKey:i.key,outcome:"denied",errorReason:g}),d({error:g})}m&&i.key!==m&&(x=m,D=`key '${i.key}' replaced with step.outputAs '${m}'`,Y.warn({taskId:t.taskId,llmKey:i.key,outputAs:m},"write_artifact: server key override"));try{let g=JSON.stringify(i.value),w=Buffer.byteLength(g,"utf8");if(w>qe){let A=`Artifact JSON exceeds ${qe} bytes`;return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"write_artifact",artifactKey:i.key,sizeBytes:w,outcome:"denied",errorReason:A}),d({error:A})}let E=Ke();return H({id:E,executionId:t.executionId,stepId:t.stepId,key:x,kind:"json",value:i.value,sizeBytes:w,createdAt:Date.now()}),R({toolName:"write_artifact",entityType:"artifact",verb:"create",entityId:E,fieldChanges:[{path:"_entity",op:"set",before:null,after:{artifactId:E,key:x,kind:"json",taskId:t.taskId}}],taskId:t.taskId,roleId:t.roleId}),_({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"write_artifact",artifactKey:x,artifactId:E,sizeBytes:w,outcome:"success"}),d({success:!0,artifactId:E,sizeBytes:w,...D?{note:D}:{}})}catch(g){let w=g instanceof Error?g.message:String(g);return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"write_artifact",artifactKey:i.key,outcome:"error",errorReason:w}),d({error:w})}}),C("read_artifact","Read a structured value previously written by an upstream step's write_artifact. Returns the JSON value. For files, use fetch_artifact_file instead.",{stepId:W.describe("TemplateExecution step ID of the artifact's source step."),key:c.string().describe("Artifact key \u2014 a unique identifier for this value within the template execution.")},async i=>{let t=await a();if("error"in t)return d({error:t.error});let l=ne(i.stepId),m=G(i.key),h=l??m;if(h)return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"read_artifact",artifactKey:i.key,outcome:"denied",errorReason:h}),d({error:h});let p=U(t.executionId,i.stepId,i.key);if(!p){let f=`no artifact at ${i.stepId}/${i.key}`;return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"read_artifact",artifactKey:i.key,outcome:"error",errorReason:f}),d({error:f})}if(p.kind!=="json"){let f="artifact is a file; use fetch_artifact_file";return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"read_artifact",artifactKey:i.key,artifactId:p.id,sizeBytes:p.sizeBytes,outcome:"denied",errorReason:f}),d({error:f})}return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"read_artifact",artifactKey:i.key,artifactId:p.id,sizeBytes:p.sizeBytes,outcome:"success"}),d({value:p.value,sizeBytes:p.sizeBytes})}),C("publish_artifact_file","Publish a file from your workspace as a TemplateExecution artifact. The file is COPIED to the template execution's shared storage. USE THIS for: generated audio, video, reports, images, or large outputs. Do NOT use for: small structured values; use write_artifact instead. If you publish with cleanup=true, this step will not be retryable through publish; only choose cleanup=true when you do not need the source file again.",{key:c.string().describe("Artifact key \u2014 a unique identifier for this value within the template execution."),sourcePath:oe.describe("Source file path in the Role workspace to publish as a TemplateExecution artifact."),mime:c.string().optional().describe("MIME type of the file (e.g., 'image/png', 'audio/mp3'). Auto-detected if omitted."),cleanup:c.boolean().optional().describe("If true, delete the source file after publishing. Only use when the source file is no longer needed.")},async i=>{let t=await a();if("error"in t)return d({error:t.error});let l=G(i.key);if(l)return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"publish_artifact_file",artifactKey:i.key,outcome:"denied",errorReason:l}),d({error:l});if(i.mime&&!$t.test(i.mime)){let y=`Invalid MIME type: ${i.mime}`;return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"publish_artifact_file",artifactKey:i.key,outcome:"denied",errorReason:y}),d({error:y})}let m=He(t.executionId,t.stepId),h=X(t.executionId),p=h?V(h.templateId):null,f=p?p.steps.some(y=>y.id===t.stepId):!1,x=i.key,D,q=p!=null&&p.steps.some(y=>!!y.outputAs);if(m===null&&f&&q){let y=`Step "${t.stepId}" in template "${h.templateId}" has no outputAs declared. This template must be migrated before its steps can publish artifacts. Operator action required: run \`pnpm tsx scripts/migrate-all-templates-outputAs.ts --apply\` from the project root, or have the operator ask ChatManager in chat to upgrade the template.`;return Y.warn({taskId:t.taskId,stepId:t.stepId,templateId:h.templateId},"publish_artifact_file: step has no outputAs in migrated template"),_({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"publish_artifact_file",artifactKey:i.key,outcome:"denied",errorReason:y}),d({error:y})}m&&i.key!==m&&(x=m,D=`key '${i.key}' replaced with step.outputAs '${m}'`,Y.warn({taskId:t.taskId,llmKey:i.key,outputAs:m},"publish_artifact_file: server key override"));try{Z(i.sourcePath,t.roleWorkspacePath,!0)}catch(y){let z=y instanceof Error?y.message:String(y);return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"publish_artifact_file",artifactKey:x,outcome:"denied",errorReason:z}),d({error:z})}let g=Ke(),w=null,E=!1,A=null;try{let y=pe({executionId:t.executionId,artifactId:g,sourcePath:i.sourcePath});w=y.blobPath;let Q=(p?.steps?.find?.(M=>M.id===t.stepId)??null)?.assertions??[];Q.length>0&&await Le(w,Q);let T={id:g,executionId:t.executionId,stepId:t.stepId,key:x,kind:"file",blobPath:w,mime:i.mime,originalFilename:se(i.sourcePath),sizeBytes:y.sizeBytes,createdAt:Date.now()};if(m&&q){let M=U(t.executionId,t.stepId,m);if(!M)H(T),E=!0,A=T;else if(M.kind==="file")A=me(t.executionId,t.stepId,m,M,{...T,key:je(i.key,m,i.sourcePath)}).childArtifact;else if(M.kind==="json"&&le(M.value))A=ue(t.executionId,t.stepId,m,{...T,key:je(i.key,m,i.sourcePath)}).childArtifact;else throw new Error(`Artifact key "${m}" already contains a non-collection JSON artifact`)}else H(T),E=!0,A=T;return i.cleanup===!0&&fe(i.sourcePath),R({toolName:"publish_artifact_file",entityType:"artifact",verb:"create",entityId:g,fieldChanges:[{path:"_entity",op:"set",before:null,after:{artifactId:g,key:A?.key??x,kind:"file",filename:se(i.sourcePath),taskId:t.taskId}}],taskId:t.taskId,roleId:t.roleId}),_({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"publish_artifact_file",artifactKey:A?.key??x,artifactId:g,sizeBytes:y.sizeBytes,outcome:"success"}),d({success:!0,artifactId:g,sizeBytes:y.sizeBytes,...D?{note:D}:{}})}catch(y){if(E)try{de(g)}catch{}if(w&&(!A||E))try{ye(w)}catch{}let z=y instanceof Error?y.message:String(y);if(_({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"publish_artifact_file",artifactKey:x,artifactId:g,outcome:"error",errorReason:z}),y instanceof v||y instanceof P)try{let T=($().prepare("SELECT COUNT(*) as n FROM step_logs WHERE task_id = ?").get(t.taskId)?.n??0)+1;ge({id:`step-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,taskId:t.taskId,index:T,type:"validator_error",content:y.message,toolName:"publish_artifact_file",timestamp:Date.now()})}catch{}return d({error:z})}}),C("fetch_artifact_file","Copy an upstream step's published file into your current Role workspace. Use this when an earlier step published audio, video, reports, or other files you need to process.",{stepId:W.describe("TemplateExecution step ID of the artifact's source step."),key:c.string().describe("Artifact key \u2014 a unique identifier for this value within the template execution."),destPath:oe.describe("Destination path in the Role workspace where the file will be copied.")},async i=>{let t=await a();if("error"in t)return d({error:t.error});let l=ne(i.stepId),m=G(i.key),h=l??m;if(h)return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"fetch_artifact_file",artifactKey:i.key,outcome:"denied",errorReason:h}),d({error:h});try{Z(i.destPath,t.roleWorkspacePath,!1)}catch(f){let x=f instanceof Error?f.message:String(f);return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"fetch_artifact_file",artifactKey:i.key,outcome:"denied",errorReason:x}),d({error:x})}let p=U(t.executionId,i.stepId,i.key);if(!p){let f=`no artifact at ${i.stepId}/${i.key}`;return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"fetch_artifact_file",artifactKey:i.key,outcome:"error",errorReason:f}),d({error:f})}if(p.kind!=="file"||!p.blobPath){let f="artifact is not a file";return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"fetch_artifact_file",artifactKey:i.key,artifactId:p.id,outcome:"denied",errorReason:f}),d({error:f})}try{let f=he({blobPath:p.blobPath,destPath:i.destPath});return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"fetch_artifact_file",artifactKey:i.key,artifactId:p.id,sizeBytes:f.sizeBytes,outcome:"success"}),d({success:!0,sizeBytes:f.sizeBytes,mime:p.mime,destPath:i.destPath})}catch(f){let x=f instanceof Error?f.message:String(f);return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"fetch_artifact_file",artifactKey:i.key,artifactId:p.id,outcome:"error",errorReason:x}),d({error:x})}}),C("list_artifacts","Discover artifacts published by upstream steps in this template execution. Returns step_id, key, kind ('json' or 'file'), size, mime. Use this to learn what is available before calling read_artifact or fetch_artifact_file.",{stepId:W.optional().describe("Filter to a specific TemplateExecution step (omit to list all artifacts in the execution).")},async i=>{let t=await a();if("error"in t)return d({error:t.error});let l=i.stepId?ne(i.stepId):null;if(l)return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"list_artifacts",outcome:"denied",errorReason:l}),d({error:l});let m=ce(t.executionId,i.stepId);return _({timestamp:Date.now(),taskId:t.taskId,roleId:t.roleId,executionId:t.executionId,stepId:t.stepId,tool:"list_artifacts",sizeBytes:m.length,outcome:"success"}),d({artifacts:m.map(h=>({id:h.id,stepId:h.stepId,key:h.key,kind:h.kind,sizeBytes:h.sizeBytes,mime:h.mime,createdAt:h.createdAt}))})}),C("report_blocked","Report that the task cannot proceed due to a missing prerequisite (e.g., missing credential, missing input, missing target). This sets the task status to 'blocked', stores the reason for the UI to display, and aborts the execution loop.",{reason:c.string().describe("Short reason, e.g. 'missing_credential', 'missing_target', 'missing_input'"),missingPrereqs:c.array(c.string()).optional().describe("Specific keys/IDs that are missing, e.g. ['MINIMAX_API_KEY']"),resumeHint:c.string().optional().describe("How the user can unblock, e.g. 'set MINIMAX_API_KEY in role env'")},async i=>{if(!e)return d({error:"report_blocked requires a task context (taskId not available)"});let t=J(e);if(!t)return d({error:`task not found: ${e}`});let l={reason:i.reason,missingPrereqs:i.missingPrereqs,resumeHint:i.resumeHint};return _e(e,{status:"blocked",blockReason:l,completedAt:Date.now()}),ke.emit({type:"task_status_change",taskId:e,oldStatus:t.status,newStatus:"blocked"}),R({toolName:"report_blocked",entityType:"task",verb:"update",entityId:e,fieldChanges:[{path:"status",op:"set",before:t.status,after:"blocked"},{path:"blockReason",op:"set",before:void 0,after:i.reason},{path:"completedAt",op:"set",before:void 0,after:Date.now()}],taskId:e,roleId:t.roleId}),s(),d({success:!0,blocked:!0,reason:i.reason})}),C("commit_claim","Declare structured claims about what this worker task just did so the audit engine can verify against effect receipts. Call this in the SAME task turn before reporting completion text. Mirror of the ChatManager tool \u2014 workers may also need to declare claims for actions taken inside template execution steps.",{claims:c.array(c.object({verb:c.string().min(1).describe("What was done: 'send', 'update', 'create', 'delete', 'cancel', 'enable', 'disable', 'bind', 'unbind', etc."),entityType:c.string().min(1).describe("What kind of thing was affected: 'channel_message', 'task_template', 'task', 'goal', 'role', 'delivery_rule', 'plugin', 'mcp_binding', 'config_field', etc."),expected:c.discriminatedUnion("kind",[c.object({kind:c.literal("outbound").describe("Used when verb='send' \u2014 declares a channel message was sent."),target:c.object({channelId:c.string().min(1).describe("Channel that received the message."),chatId:c.string().min(1).optional().describe("Specific chat within the channel; omit for any chat.")}).describe("Where the message went."),attachmentCount:c.number().int().min(0).optional().describe("How many attachments were sent. Verifier requires receipt.attachmentCount >= this."),textPresent:c.boolean().optional().describe("Whether the message body had non-empty text. Verifier requires receipt.textChars > 0 when true.")}),c.object({kind:c.literal("field_change").describe("Used for single-entity updates \u2014 declares a specific field on a specific entity changed."),entityId:c.string().min(1).describe("Identifier of the entity that was changed."),fieldPath:c.string().min(1).describe("Dotted path to the field that changed, e.g. 'deliverTo', 'cron', 'config.timeout'."),op:c.enum(["set","list_add","list_remove"]).describe("How the field changed: scalar set, list append, or list removal."),added:c.array(c.unknown()).min(1).optional().describe("Items appended when op='list_add'. Verifier accepts a superset (receipt may have appended more items)."),removed:c.array(c.unknown()).min(1).optional().describe("Items removed when op='list_remove'. Verifier accepts a superset."),after:c.unknown().optional().describe("New value when op='set'. Verifier requires deep-equal match.")}),c.object({kind:c.literal("batch").describe("Used for batch operations like cancel-many or delete-many."),entityType:c.string().min(1).describe("Restrict matching to this entity type."),entityIds:c.array(c.string()).min(1).optional().describe("Specific entity IDs affected. Verifier checks receipt.entityIds is a superset."),scope:c.object({filter:c.string().min(1).describe("Free-text description of the filter applied (e.g., 'status=running AND role_id=role-x'). Verifier ignores this; human-readable only."),expectedCount:c.number().int().min(0).describe("Minimum number of entities expected to have been affected. Verifier requires receipt.scope.matchedCount >= this.")}).optional().describe("Filter+count for scope-based batches when individual IDs aren't enumerated.")})]).describe("Structured expectation matched against effect_receipts. Pick the kind that fits the action."),note:c.string().optional().describe("Free-text human note kept in the audit log only. Verifier ignores this.")})).min(1).max(20).describe("One or more claims declaring exactly what just happened. Each claim is verified independently against receipts.")},async i=>{let t=Ie();if(!t)return d({error:"commit_claim requires an active trace context"});try{let l=De({traceId:t,taskId:e,claims:i.claims});return d({claimRowId:l.id,claimsCount:l.claims.length,declaredAt:l.declaredAt})}catch(l){let m=l instanceof Error?l.message:String(l);return d({error:m})}})],I=zt(e)?u.filter(i=>i.name!=="list_channels"&&i.name!=="send_to_channel"):u;return Ot({name:Nt,version:"1.0.0",tools:I})}export{Oe as a,De as b,er as c,Nt as d,Er as e,Ar as f,Sr as g,Cr as h,Dt as i,Yr as j};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as We}from"./chunk-XF7YHFVR.js";import{a as ze,b as k,c as Ee,d as L,e as He}from"./chunk-NNMQGISW.js";import{b as Ve,c as Qe,f as se,g as re}from"./chunk-3KNR2F6H.js";import{a as je,b as T,c as te,d as ne,e as Te,f as V}from"./chunk-CLNYHWZ6.js";import{d as j}from"./chunk-Z6LHGA27.js";import{c as y,h as C}from"./chunk-BLCNUT53.js";import{z as p}from"zod/v4";import{v4 as os}from"uuid";import{randomUUID as et}from"crypto";import Ht from"crypto";var Ke="2.1.7",ie="bot";function Kt(t){let e=t.split(".").map(i=>parseInt(i,10)),n=e[0]??0,r=e[1]??0,s=e[2]??0;return(n&255)<<16|(r&255)<<8|s&255}var xe=Kt(Ke),Jt=35e3,Je=15e3,Xt=1e4;function ae(){return{channel_version:Ke}}function Yt(t){return t.endsWith("/")?t:`${t}/`}function Zt(){let t=Ht.randomBytes(4).readUInt32BE(0);return Buffer.from(String(t),"utf-8").toString("base64")}function en(t){let e={"Content-Type":"application/json",AuthorizationType:"ilink_bot_token","Content-Length":String(Buffer.byteLength(t.body,"utf-8")),"X-WECHAT-UIN":Zt(),"iLink-App-Id":ie,"iLink-App-ClientVersion":String(xe)};return t.token?.trim()&&(e.Authorization=`Bearer ${t.token.trim()}`),t.routeTag&&(e.SKRouteTag=t.routeTag),e}async function oe(t){let e=Yt(t.baseUrl),n=new URL(t.endpoint,e),r=en({token:t.token,routeTag:t.routeTag,body:t.body}),s=new AbortController,i=setTimeout(()=>s.abort(),t.timeoutMs);try{let a=await fetch(n.toString(),{method:"POST",headers:r,body:t.body,signal:s.signal});clearTimeout(i);let o=await a.text();if(!a.ok)throw new Error(`${t.label} ${a.status}: ${o}`);return o}catch(a){throw clearTimeout(i),a}}async function Xe(t){let e=t.timeoutMs??Jt;try{let n=await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/getupdates",body:JSON.stringify({get_updates_buf:t.get_updates_buf??"",base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:e,label:"getUpdates"});return JSON.parse(n)}catch(n){if(n instanceof Error&&n.name==="AbortError")return{ret:0,msgs:[],get_updates_buf:t.get_updates_buf};throw n}}var tn={[-2]:2,[-3]:3},nn=1e3;async function Q(t){let e=(await import("./logger-PAMNFWI3.js")).getLogger("channels"),n=new Map;for(;;){let r=await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/sendmessage",body:JSON.stringify({...t.body,base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:t.timeoutMs??Je,label:"sendMessage"});e.info({status:200,responseBody:r.slice(0,300)},"apiFetch sendMessage response");try{let s=JSON.parse(r);if(s.ret&&s.ret!==0){let i=tn[s.ret],a=(n.get(s.ret)??0)+1;if(n.set(s.ret,a),i!==void 0&&a<i){e.warn({ret:s.ret,attempt:a,maxRetries:i},"sendMessage: retriable iLink error, retrying"),await new Promise(o=>setTimeout(o,nn*a));continue}throw e.error({ret:s.ret,errmsg:s.errmsg,attempt:a},"sendMessage: iLink API error, no more retries"),new Error(`sendMessage failed: iLink ret=${s.ret}${s.errmsg?` errmsg=${s.errmsg}`:""}`)}}catch(s){if(s instanceof SyntaxError)e.warn({rawText:r.slice(0,200)},"sendMessage: non-JSON response, treating as success");else throw s}return}}async function Ye(t){await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/sendtyping",body:JSON.stringify({...t.body,base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:t.timeoutMs??Xt,label:"sendTyping"})}async function Ze(t){let e=await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/getuploadurl",body:JSON.stringify({filekey:t.filekey,media_type:t.media_type,to_user_id:t.to_user_id,rawsize:t.rawsize,rawfilemd5:t.rawfilemd5,filesize:t.filesize,thumb_rawsize:t.thumb_rawsize,thumb_rawfilemd5:t.thumb_rawfilemd5,thumb_filesize:t.thumb_filesize,no_need_thumb:t.no_need_thumb,aeskey:t.aeskey,base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:t.timeoutMs??Je,label:"getUploadUrl"});return JSON.parse(e)}var sn=5*6e4,rn=35e3,tt="3",E=new Map;function Me(t){return Date.now()-t.startedAt<sn}function an(){for(let[t,e]of E)Me(e)||E.delete(t)}async function nt(t,e,n){let r=t.endsWith("/")?t:`${t}/`,s=new URL(`ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(e)}`,r),i={"iLink-App-Id":ie};n&&(i.SKRouteTag=n);let a=await fetch(s.toString(),{headers:i});if(!a.ok){let o=await a.text().catch(()=>"(unreadable)");throw new Error(`Failed to fetch QR code: ${a.status} ${a.statusText} body=${o}`)}return await a.json()}async function on(t,e,n){let r=t.endsWith("/")?t:`${t}/`,s=new URL(`ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(e)}`,r),i={"iLink-App-Id":ie,"iLink-App-ClientVersion":String(xe)};n&&(i.SKRouteTag=n);let a=new AbortController,o=setTimeout(()=>a.abort(),rn);try{let d=await fetch(s.toString(),{headers:i,signal:a.signal});clearTimeout(o);let c=await d.text();if(!d.ok)throw new Error(`Failed to poll QR status: ${d.status} ${d.statusText}`);return JSON.parse(c)}catch(d){if(clearTimeout(o),d instanceof Error&&d.name==="AbortError")return{status:"wait"};throw d}}async function st(t){let e=t.accountId||et();an();let n=E.get(e);if(!t.force&&n&&Me(n)&&n.qrcodeUrl)return{qrcodeUrl:n.qrcodeUrl,message:"QR code ready. Scan with WeChat.",sessionKey:e};if(!t.apiBaseUrl)return{message:"No baseUrl configured for this WeChat channel.",sessionKey:e};try{let r=t.botType||tt,s=await nt(t.apiBaseUrl,r,t.routeTag),i={sessionKey:e,id:et(),qrcode:s.qrcode,qrcodeUrl:s.qrcode_img_content,startedAt:Date.now()};return E.set(e,i),{qrcodeUrl:s.qrcode_img_content,message:"Scan the QR code with WeChat to connect.",sessionKey:e}}catch(r){return{message:`Failed to start login: ${String(r)}`,sessionKey:e}}}var dn=3;async function rt(t){let e=E.get(t.sessionKey);if(!e)return{connected:!1,message:"No active login session. Start QR login first."};if(!Me(e))return E.delete(t.sessionKey),{connected:!1,message:"QR code expired. Please start again."};let n=Math.max(t.timeoutMs??48e4,1e3),r=Date.now()+n,s=1;for(;Date.now()<r;){try{let i=await on(t.apiBaseUrl,e.qrcode,t.routeTag);switch(e.status=i.status,i.status){case"wait":break;case"scaned":break;case"expired":{if(s++,s>dn)return E.delete(t.sessionKey),{connected:!1,message:"Login timeout: QR expired multiple times."};try{let a=t.botType||tt,o=await nt(t.apiBaseUrl,a,t.routeTag);e.qrcode=o.qrcode,e.qrcodeUrl=o.qrcode_img_content,e.startedAt=Date.now()}catch(a){return E.delete(t.sessionKey),{connected:!1,message:`QR refresh failed: ${String(a)}`}}break}case"confirmed":return i.ilink_bot_id?(E.delete(t.sessionKey),{connected:!0,botToken:i.bot_token,accountId:i.ilink_bot_id,baseUrl:i.baseurl,userId:i.ilink_user_id,message:"Connected to WeChat successfully!"}):(E.delete(t.sessionKey),{connected:!1,message:"Login failed: server did not return bot ID."})}}catch(i){return E.delete(t.sessionKey),{connected:!1,message:`Login failed: ${String(i)}`}}await new Promise(i=>setTimeout(i,1e3))}return E.delete(t.sessionKey),{connected:!1,message:"Login timeout. Please try again."}}import A from"fs";import*as M from"fs/promises";import x from"path";import{homedir as pe}from"os";var de={IMAGE:1,VIDEO:2,FILE:3,VOICE:4},z={NONE:0,USER:1,BOT:2},_={NONE:0,TEXT:1,IMAGE:2,VOICE:3,FILE:4,VIDEO:5},H={NEW:0,GENERATING:1,FINISH:2},it={TYPING:1,CANCEL:2};C();var un=y("channels"),Se=-14,ue=3600*1e3,q=new Map;function at(t){let e=Date.now()+ue;q.set(t,e),un.info({channelId:t},`Session paused until ${new Date(e).toISOString()} (${ue/1e3}s)`)}function ce(t){let e=q.get(t);return e===void 0?!1:Date.now()>=e?(q.delete(t),!1):!0}function ot(t){let e=q.get(t);if(e===void 0)return 0;let n=e-Date.now();return n<=0?(q.delete(t),0):n}function dt(t){q.delete(t)}C();import*as me from"fs/promises";import yt from"path";import{homedir as pn}from"os";import{createCipheriv as cn,createDecipheriv as ln}from"crypto";function ut(t,e){let n=cn("aes-128-ecb",e,null);return Buffer.concat([n.update(t),n.final()])}function ct(t,e){let n=ln("aes-128-ecb",e,null);return Buffer.concat([n.update(t),n.final()])}function lt(t){return Math.ceil((t+1)/16)*16}function Ce(t,e){return`${e}/download?encrypted_query_param=${encodeURIComponent(t)}`}function mt(t){return`${t.cdnBaseUrl}/upload?encrypted_query_param=${encodeURIComponent(t.uploadParam)}&filekey=${encodeURIComponent(t.filekey)}`}C();var Ms=y("channels");function mn(t){let e=Buffer.from(t,"base64");if(e.length===16)return e;if(e.length===32&&/^[0-9a-fA-F]{32}$/.test(e.toString("ascii")))return Buffer.from(e.toString("ascii"),"hex");throw new Error(`aes_key must decode to 16 raw bytes or 32-char hex, got ${e.length} bytes`)}async function gt(t){let e=await fetch(t);if(!e.ok)throw new Error(`CDN download ${e.status} ${e.statusText}`);return Buffer.from(await e.arrayBuffer())}async function K(t){let{encryptQueryParam:e,aesKeyBase64:n,cdnBaseUrl:r,fullUrl:s}=t,i=mn(n),a=s?.trim()||(e?Ce(e,r):null);if(!a)throw new Error("CDN download: need full_url or encrypt_query_param");let o=await gt(a);return ct(o,i)}async function pt(t){let{encryptQueryParam:e,cdnBaseUrl:n,fullUrl:r}=t,s=r?.trim()||(e?Ce(e,n):null);if(!s)throw new Error("CDN download: need full_url or encrypt_query_param");return gt(s)}C();var le=y("channels"),ft=24e3;function gn(t,e){let n=t.byteLength,r=44+n,s=Buffer.allocUnsafe(r),i=0;return s.write("RIFF",i),i+=4,s.writeUInt32LE(r-8,i),i+=4,s.write("WAVE",i),i+=4,s.write("fmt ",i),i+=4,s.writeUInt32LE(16,i),i+=4,s.writeUInt16LE(1,i),i+=2,s.writeUInt16LE(1,i),i+=2,s.writeUInt32LE(e,i),i+=4,s.writeUInt32LE(e*2,i),i+=4,s.writeUInt16LE(2,i),i+=2,s.writeUInt16LE(16,i),i+=2,s.write("data",i),i+=4,s.writeUInt32LE(n,i),i+=4,Buffer.from(t.buffer,t.byteOffset,t.byteLength).copy(s,i),s}async function ht(t){try{let{decode:e}=await import("silk-wasm");le.debug(`silkToWav: decoding ${t.length} bytes of SILK`);let n=await e(t,ft);le.debug(`silkToWav: decoded duration=${n.duration}ms pcmBytes=${n.data.byteLength}`);let r=gn(n.data,ft);return le.debug(`silkToWav: WAV size=${r.length}`),r}catch(e){return le.warn(`silkToWav: transcode failed, will use raw silk err=${String(e)}`),null}}var N=y("channels"),wt=100*1024*1024;function fn(t){return re(t)??".bin"}async function J(t,e,n,r,s=wt,i){if(t.length>s)throw new Error(`Media too large: ${t.length} bytes exceeds ${s} bytes`);let a=yt.join(pn(),".adam","wechat","media",r,n);await me.mkdir(a,{recursive:!0});let o;if(i&&/^[a-zA-Z0-9._-]+$/.test(i))o=i;else{let c=e?fn(e):".bin",u=Date.now(),g=Math.random().toString(36).slice(2,7);o=`${u}-${g}${c}`}let d=yt.join(a,o);return await me.writeFile(d,t),N.debug(`saveMedia: saved ${t.length} bytes to ${d}`),d}async function bt(t,e){let{cdnBaseUrl:n,channelId:r}=e;if(t.type===_.IMAGE){let s=t.image_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url)return null;let i=s.aeskey?Buffer.from(s.aeskey,"hex").toString("base64"):s.media?.aes_key;try{let a=i?await K({encryptQueryParam:s.media?.encrypt_query_param,aesKeyBase64:i,cdnBaseUrl:n,fullUrl:s.media?.full_url}):await pt({encryptQueryParam:s.media?.encrypt_query_param,cdnBaseUrl:n,fullUrl:s.media?.full_url});return{path:await J(a,"image/png","inbound",r),mimeType:"image/png",type:"image"}}catch(a){return N.error({channelId:r},`Image download/decrypt failed: ${String(a)}`),null}}if(t.type===_.VOICE){let s=t.voice_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url||!s?.media?.aes_key)return null;try{let i=await K({encryptQueryParam:s.media.encrypt_query_param,aesKeyBase64:s.media.aes_key,cdnBaseUrl:n,fullUrl:s.media.full_url}),a=await ht(i);if(a){let o=await J(a,"audio/wav","inbound",r);return N.debug(`Voice: saved WAV to ${o}`),{path:o,mimeType:"audio/wav",type:"audio"}}else{let o=await J(i,"audio/silk","inbound",r);return N.debug(`Voice: silk transcode unavailable, saved raw SILK to ${o}`),{path:o,mimeType:"audio/silk",type:"audio"}}}catch(i){return N.error({channelId:r},`Voice download/transcode failed: ${String(i)}`),null}}if(t.type===_.FILE){let s=t.file_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url||!s?.media?.aes_key)return null;try{let i=await K({encryptQueryParam:s.media.encrypt_query_param,aesKeyBase64:s.media.aes_key,cdnBaseUrl:n,fullUrl:s.media.full_url}),a=se(s.file_name??"file.bin");return{path:await J(i,a,"inbound",r,wt,s.file_name),mimeType:a,type:"file"}}catch(i){return N.error({channelId:r},`File download failed: ${String(i)}`),null}}if(t.type===_.VIDEO){let s=t.video_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url||!s?.media?.aes_key)return null;try{let i=await K({encryptQueryParam:s.media.encrypt_query_param,aesKeyBase64:s.media.aes_key,cdnBaseUrl:n,fullUrl:s.media.full_url});return{path:await J(i,"video/mp4","inbound",r),mimeType:"video/mp4",type:"video"}}catch(i){return N.error({channelId:r},`Video download failed: ${String(i)}`),null}}return null}import Tt from"path";import Ae from"crypto";import hn from"fs/promises";C();var O=y("channels"),ge=3;async function yn(t){let{buf:e,uploadFullUrl:n,uploadParam:r,filekey:s,cdnBaseUrl:i,label:a,aeskey:o}=t,d=ut(e,o),c=n?.trim(),u;if(c)u=c;else if(r)u=mt({cdnBaseUrl:i,uploadParam:r,filekey:s});else throw new Error(`${a}: CDN upload URL missing (need upload_full_url or upload_param)`);O.debug(`${a}: CDN POST url=${u} ciphertextSize=${d.length}`);let g,f;for(let m=1;m<=ge;m++)try{let l=await fetch(u,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:new Uint8Array(d)});if(l.status>=400&&l.status<500){let w=l.headers.get("x-error-message")??await l.text();throw O.error(`${a}: CDN client error attempt=${m} status=${l.status} errMsg=${w}`),new Error(`CDN upload client error ${l.status}: ${w}`)}if(l.status!==200){let w=l.headers.get("x-error-message")??`status ${l.status}`;throw O.error(`${a}: CDN server error attempt=${m} status=${l.status} errMsg=${w}`),new Error(`CDN upload server error: ${w}`)}if(g=l.headers.get("x-encrypted-param")??void 0,!g)throw O.error(`${a}: CDN response missing x-encrypted-param header attempt=${m}`),new Error("CDN upload response missing x-encrypted-param header");O.debug(`${a}: CDN upload success attempt=${m}`);break}catch(l){if(f=l,l instanceof Error&&l.message.includes("client error"))throw l;m<ge?O.warn(`${a}: attempt ${m} failed, retrying... err=${String(l)}`):O.error(`${a}: all ${ge} attempts failed err=${String(l)}`)}if(!g)throw f instanceof Error?f:new Error(`CDN upload failed after ${ge} attempts`);return{downloadParam:g}}async function Re(t){let{filePath:e,toUserId:n,opts:r,cdnBaseUrl:s,mediaType:i,label:a}=t,o=await hn.readFile(e),d=o.length,c=Ae.createHash("md5").update(o).digest("hex"),u=lt(d),g=Ae.randomBytes(16).toString("hex"),f=Ae.randomBytes(16);O.debug(`${a}: file=${e} rawsize=${d} filesize=${u} md5=${c} filekey=${g}`);let m=await Ze({...r,filekey:g,media_type:i,to_user_id:n,rawsize:d,rawfilemd5:c,filesize:u,no_need_thumb:!0,aeskey:f.toString("hex")}),l=m.upload_full_url?.trim(),w=m.upload_param;if(!l&&!w)throw new Error(`${a}: getUploadUrl returned no upload URL (need upload_full_url or upload_param)`);let{downloadParam:F}=await yn({buf:o,uploadFullUrl:l||void 0,uploadParam:w??void 0,filekey:g,cdnBaseUrl:s,aeskey:f,label:`${a}[orig filekey=${g}]`});return{filekey:g,downloadEncryptedQueryParam:F,aeskey:f.toString("hex"),fileSize:d,fileSizeCiphertext:u}}async function _t(t){return Re({...t,mediaType:de.IMAGE,label:"uploadImageToWeixin"})}async function It(t){return Re({...t,mediaType:de.VIDEO,label:"uploadVideoToWeixin"})}async function ke(t){return Re({...t,mediaType:de.FILE,label:"uploadFileAttachmentToWeixin"})}C();var X=y("channels");function wn(){return`adam-wechat-${Date.now()}-${Math.random().toString(36).slice(2,7)}`}function bn(t){let e=t;return e=e.replace(/```[^\n]*\n?([\s\S]*?)```/g,(n,r)=>r.trim()),e=e.replace(/!\[[^\]]*\]\([^)]*\)/g,""),e=e.replace(/\[([^\]]+)\]\([^)]*\)/g,"$1"),e=e.replace(/^\|[\s:|-]+\|$/gm,""),e=e.replace(/^\|(.+)\|$/gm,(n,r)=>r.split("|").map(s=>s.trim()).join(" ")),e}async function Ue(t){let{to:e,text:n,mediaItem:r,opts:s,label:i}=t,a=[],o=bn(n);o&&a.push({type:_.TEXT,text_item:{text:o}}),a.push(r);let d="";for(let c of a){d=wn();let u={msg:{from_user_id:"",to_user_id:e,client_id:d,message_type:z.BOT,message_state:H.FINISH,item_list:[c],context_token:s.contextToken}};await Q({baseUrl:s.baseUrl,token:s.token,routeTag:s.routeTag,body:u})}return X.debug(`${i}: sent to=${e} messageId=${d}`),{messageId:d}}async function _n(t){let{to:e,text:n,uploaded:r,opts:s}=t,i={type:_.IMAGE,image_item:{media:{encrypt_query_param:r.downloadEncryptedQueryParam,aes_key:Buffer.from(r.aeskey).toString("base64"),encrypt_type:1},mid_size:r.fileSizeCiphertext}};return Ue({to:e,text:n,mediaItem:i,opts:s,label:"sendImageMessage"})}async function In(t){let{to:e,text:n,uploaded:r,opts:s}=t,i={type:_.VIDEO,video_item:{media:{encrypt_query_param:r.downloadEncryptedQueryParam,aes_key:Buffer.from(r.aeskey).toString("base64"),encrypt_type:1},video_size:r.fileSizeCiphertext}};return Ue({to:e,text:n,mediaItem:i,opts:s,label:"sendVideoMessage"})}async function Et(t){let{to:e,text:n,fileName:r,uploaded:s,opts:i}=t,a={type:_.FILE,file_item:{media:{encrypt_query_param:s.downloadEncryptedQueryParam,aes_key:Buffer.from(s.aeskey).toString("base64"),encrypt_type:1},file_name:r,len:String(s.fileSize)}};return Ue({to:e,text:n,mediaItem:a,opts:i,label:"sendFileMessage"})}async function xt(t){let{filePath:e,to:n,text:r,opts:s,cdnBaseUrl:i}=t,a=se(e),o={baseUrl:s.baseUrl,token:s.token,routeTag:s.routeTag};if(a.startsWith("video/")){X.debug(`sendWeixinMediaFile: uploading video filePath=${e} to=${n}`);let u=await It({filePath:e,toUserId:n,opts:o,cdnBaseUrl:i});return In({to:n,text:r,uploaded:u,opts:s})}if(a.startsWith("image/")){X.debug(`sendWeixinMediaFile: uploading image filePath=${e} to=${n}`);let u=await _t({filePath:e,toUserId:n,opts:o,cdnBaseUrl:i});return _n({to:n,text:r,uploaded:u,opts:s})}if(a.startsWith("audio/")){let u=Tt.basename(e);X.debug(`sendWeixinMediaFile: uploading audio as file filePath=${e} name=${u} to=${n}`);let g=await ke({filePath:e,fileName:u,toUserId:n,opts:o,cdnBaseUrl:i});return Et({to:n,text:r,fileName:u,uploaded:g,opts:s})}let d=Tt.basename(e);X.debug(`sendWeixinMediaFile: uploading file attachment filePath=${e} name=${d} to=${n}`);let c=await ke({filePath:e,fileName:d,toUserId:n,opts:o,cdnBaseUrl:i});return Et({to:n,text:r,fileName:d,uploaded:c,opts:s})}C();var h=y("channels"),Mt="https://novac2c.cdn.weixin.qq.com/c2c",Oe=new Map;function At(t){return x.join(pe(),".adam","wechat",`${t}.context-tokens.json`)}function Tn(t){let e=At(t);try{let n=A.readFileSync(e,"utf-8"),r=JSON.parse(n);for(let[s,i]of Object.entries(r))typeof i=="string"&&i&&Oe.set(`${t}:${s}`,i);h.debug({channelId:t,count:Object.keys(r).length},"Restored context tokens from disk")}catch{}}function En(t,e,n){let r=At(t);try{let s={};try{let a=A.readFileSync(r,"utf-8");s=JSON.parse(a)}catch{}s[e]=n;let i=x.dirname(r);A.mkdirSync(i,{recursive:!0}),A.writeFileSync(r,JSON.stringify(s),"utf-8")}catch(s){h.warn({channelId:t,userId:e},`Failed to persist context token: ${String(s)}`)}}function xn(t,e,n){Oe.set(`${t}:${e}`,n),En(t,e,n)}function Pe(t,e){return Oe.get(`${t}:${e}`)}function Rt(t){return x.join(pe(),".adam","wechat",`${t}.sync`)}function Mn(t){try{return A.readFileSync(Rt(t),"utf-8")}catch{return""}}function Sn(t,e){let n=Rt(t);A.mkdirSync(x.dirname(n),{recursive:!0}),A.writeFileSync(n,e,"utf-8")}var ve=1440*60*1e3,St=10,Cn=20,Ct=1440*60*1e3,An=1320*60*1e3,Rn=1,kn=7200*1e3;function kt(t){return x.join(pe(),".adam","wechat",`${t}.session.json`)}function Un(t){let e=new Map,n=kt(t);try{let r=A.readFileSync(n,"utf-8"),s=JSON.parse(r);for(let[i,a]of Object.entries(s))a&&typeof a.lastUserMessageAt=="number"&&e.set(i,a);h.debug({channelId:t,count:e.size},"Restored sessions from disk")}catch{}return e}function Y(t,e){let n=kt(t);try{let r={};for(let[i,a]of e)r[i]=a;let s=x.dirname(n);A.mkdirSync(s,{recursive:!0}),A.writeFileSync(n,JSON.stringify(r),"utf-8")}catch(r){h.warn({channelId:t},`Failed to persist sessions: ${String(r)}`)}}var Pn=0;function Z(){return`adam-wechat-${Date.now()}-${++Pn}`}var $=class{platform="wechat";id;config;status="disconnected";messageHandler=null;pollAbort=null;getUpdatesBuf="";sessions=new Map;pendingQueue=new Map;lastReminderAt=new Map;constructor(e,n){if(this.id=e,!n.baseUrl)throw new Error("WeChat adapter requires baseUrl");this.config=n}async connect(){if(!this.config.botToken)throw new Error("WeChat adapter requires botToken. Complete QR login first.");this.status="connecting",this.getUpdatesBuf=Mn(this.id),Tn(this.id),this.sessions=Un(this.id),this.pollAbort=new AbortController,this.status="connected",h.info({channelId:this.id},"WeChat adapter connected, starting long-poll"),this.startLongPoll()}async disconnect(){this.pollAbort&&(this.pollAbort.abort(),this.pollAbort=null),this.status="disconnected",h.info({channelId:this.id},"WeChat adapter disconnected")}getStatus(){if(this.status==="connected"&&ce(this.id))return"error";if(this.status==="connected"){for(let[,e]of this.sessions)if(this.isSessionActive(e)&&e.quotaRemaining<=0)return"degraded"}return this.status}getCapabilities(){return{canEdit:!1,canQuote:!0,canParseQuote:!0,canInlineButtons:!1,maxTextLength:4e3,supportsAttachments:!0,maxAttachmentsPerMessage:1}}async sendMessage(e,n){if(ce(this.id)){let c=Math.ceil(ot(this.id)/6e4);throw new Error(`WeChat session paused, ${c} min remaining. Re-scan QR to reconnect.`)}let r=this.getOrCreateSession(e),i=this.getSessionRemainingMs(r)/36e5;if(!this.isSessionActive(r))return h.warn({channelId:this.id,chatId:e.slice(0,12),lastUserMessageAt:r.lastUserMessageAt,sessionExpired:!0},"iLink session expired (>24h), message queued"),this.enqueueMessage(e,n),`queued-${Z()}`;if(r.quotaRemaining<=0)return h.warn({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:0,remainingHours:i.toFixed(1)},"iLink quota exhausted, message queued"),this.enqueueMessage(e,n),`queued-${Z()}`;let a=Z(),o=Pe(this.id,e),d=this.config.cdnBaseUrl??Mt;try{let c=n.attachments?.[0],u=c?.path??n.mediaUrl,g=c?.contentType,f=c?.filename,m=c?.mediaType??n.mediaType;if(u){let l=!u.includes("://")||u.startsWith("file://"),w=x.join(pe(),".adam","wechat","media","outbound-tmp");await M.mkdir(w,{recursive:!0});let F=this.getExtensionFromMediaType(m,g),R;if(l){let I=u.startsWith("file://")?new URL(u).pathname:x.isAbsolute(u)?u:x.resolve(u),v=await M.readFile(I);R=x.join(w,`${Date.now()}-${Math.random().toString(36).slice(2,7)}${F}`),await M.writeFile(R,v)}else{let I=await fetch(u);if(!I.ok)throw new Error(`Failed to fetch media: ${I.status}`);let v=Buffer.from(await I.arrayBuffer());R=x.join(w,`${Date.now()}-${Math.random().toString(36).slice(2,7)}${F}`),await M.writeFile(R,v)}let b=R;if(f){let I=f.replace(/[\\/]/g,"-").replace(/\.\./g,"-").replace(/[\x00-\x1f]/g,"");if(I.length>0&&I.length<200){let v=x.join(w,`${Date.now()}-${I}`);await M.copyFile(R,v),await M.unlink(R).catch(()=>{}),b=v}}let P=await xt({filePath:b,to:e,text:n.content??"",opts:{baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,contextToken:o},cdnBaseUrl:d});return await M.unlink(b).catch(()=>{}),r.quotaRemaining--,Y(this.id,this.sessions),h.info({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:r.quotaRemaining,sessionRemainingHours:(this.getSessionRemainingMs(r)/36e5).toFixed(1)},"iLink send success: quota decremented"),this.checkAndSendReminder(e,r).catch(I=>{h.warn({channelId:this.id,chatId:e.slice(0,12)},`Reminder send failed: ${String(I)}`)}),P.messageId}return await Q({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{msg:{from_user_id:"",to_user_id:e,client_id:a,message_type:z.BOT,message_state:H.FINISH,item_list:this.buildItemList(n),context_token:o}}}),r.quotaRemaining--,Y(this.id,this.sessions),h.info({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:r.quotaRemaining,sessionRemainingHours:(this.getSessionRemainingMs(r)/36e5).toFixed(1)},"iLink send success: quota decremented"),this.checkAndSendReminder(e,r).catch(l=>{h.warn({channelId:this.id,chatId:e.slice(0,12)},`Reminder send failed: ${String(l)}`)}),a}catch(c){if(c instanceof Error&&c.message.includes("ret=-2"))return r.quotaRemaining=0,Y(this.id,this.sessions),h.warn({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:0},"iLink quota exhausted (ret=-2 confirmed), message queued"),this.enqueueMessage(e,n),`queued-${Z()}`;throw c}}onMessage(e){this.messageHandler=e}async sendTypingIndicator(e){if(ce(this.id))return;let n=Pe(this.id,e);try{await Ye({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{ilink_user_id:e,status:it.TYPING}})}catch{}}updateConfig(e){Object.assign(this.config,e)}buildItemList(e){if(!e.content)return;let n={type:_.TEXT,text_item:{text:e.content}};if(e.replyToMessageId){let r=(e.quoteExcerpt??"").slice(0,80);n.ref_msg={message_item:{msg_id:e.replyToMessageId,text_item:{text:r}},title:e.quoteTitle}}return[n]}getOrCreateSession(e){let n=this.sessions.get(e);return n||(n={lastUserMessageAt:0,quotaRemaining:0},this.sessions.set(e,n)),n}isSessionActive(e){return e.lastUserMessageAt>0&&Date.now()-e.lastUserMessageAt<=ve}getSessionRemainingMs(e){return e.lastUserMessageAt===0?0:Math.max(0,ve-(Date.now()-e.lastUserMessageAt))}enqueueMessage(e,n){let r=this.pendingQueue.get(e);r||(r=[],this.pendingQueue.set(e,r));let s=Date.now();r=r.filter(i=>s-i.queuedAt<Ct),r.length>=Cn&&(r.shift(),h.warn({channelId:this.id,chatId:e.slice(0,12)},"Queue full, dropping oldest message")),r.push({message:n,queuedAt:s}),this.pendingQueue.set(e,r),h.info({channelId:this.id,chatId:e.slice(0,12),queueDepth:r.length},"Message enqueued")}async flushQueue(e){let n=this.pendingQueue.get(e);if(!n||n.length===0)return;let r=this.getOrCreateSession(e),s=Math.min(n.length,Math.max(0,r.quotaRemaining-2));if(s<=0){h.info({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:r.quotaRemaining},"Queue flush skipped: insufficient quota (reserving 2 for conversation)");return}h.info({channelId:this.id,chatId:e.slice(0,12),queueDepth:n.length,sending:s,quotaRemaining:r.quotaRemaining},"Flushing queued messages");let i=0;for(;i<s&&n.length>0;){let a=n[0];if(Date.now()-a.queuedAt>Ct){n.shift();continue}try{if(await this.sendMessage(e,a.message),n.shift(),i++,r.quotaRemaining<=0)break}catch{h.warn({channelId:this.id,chatId:e.slice(0,12)},"Queue flush: send failed, stopping");break}}n.length===0&&this.pendingQueue.delete(e),h.info({channelId:this.id,chatId:e.slice(0,12),sent:i,remaining:n.length},"Queue flush complete")}async checkAndSendReminder(e,n){let r=Date.now(),s=this.lastReminderAt.get(e)??0;if(r-s<kn)return;let i=this.getSessionRemainingMs(n),o=r-n.lastUserMessageAt>=An,d=n.quotaRemaining<=Rn;if(!o&&!d)return;let c=(i/36e5).toFixed(1),u;o&&d?u=`[\u7CFB\u7EDF\u63D0\u9192] \u6D88\u606F\u7A97\u53E3\u5373\u5C06\u5173\u95ED\uFF08\u5269\u4F59${c}\u5C0F\u65F6/${n.quotaRemaining}\u6761\u914D\u989D\uFF09\u3002\u8BF7\u56DE\u590D\u4EFB\u610F\u6D88\u606F\u4EE5\u4FDD\u6301\u8FDE\u63A5\u3002`:o?u=`[\u7CFB\u7EDF\u63D0\u9192] \u6D88\u606F\u7A97\u53E3\u5373\u5C06\u5173\u95ED\uFF08\u5269\u4F59${c}\u5C0F\u65F6\uFF09\u3002\u8BF7\u56DE\u590D\u4EFB\u610F\u6D88\u606F\u4EE5\u4FDD\u6301\u8FDE\u63A5\u3002`:u=`[\u7CFB\u7EDF\u63D0\u9192] \u6D88\u606F\u914D\u989D\u5373\u5C06\u7528\u5B8C\uFF08\u5269\u4F59${n.quotaRemaining}\u6761\uFF09\u3002\u8BF7\u56DE\u590D\u4EFB\u610F\u6D88\u606F\u4EE5\u91CD\u7F6E\u914D\u989D\u3002`;let g=Pe(this.id,e);try{await Q({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{msg:{from_user_id:"",to_user_id:e,client_id:Z(),message_type:z.BOT,message_state:H.FINISH,item_list:[{type:_.TEXT,text_item:{text:u}}],context_token:g}}}),n.quotaRemaining--,this.lastReminderAt.set(e,r),Y(this.id,this.sessions),h.info({channelId:this.id,chatId:e.slice(0,12),remainingHours:c,quotaRemaining:n.quotaRemaining,trigger:o?"time":"quota"},"iLink session reminder sent")}catch(f){h.warn({channelId:this.id,chatId:e.slice(0,12)},`Reminder send failed: ${String(f)}`)}}async startLongPoll(){let e=this.pollAbort?.signal,n=0,r=3,s=3e4,i=2e3;for(;!e?.aborted;)try{let a=await Xe({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,get_updates_buf:this.getUpdatesBuf});if(a.ret===Se||a.errcode===Se){at(this.id),this.status="error",h.error({channelId:this.id},"Session expired (errcode=-14), pausing for 1 hour"),await this.sleep(ue,e),dt(this.id),this.status="connected";continue}if(a.ret!==void 0&&a.ret!==0||a.errcode!==void 0&&a.errcode!==0){n++,h.error({channelId:this.id,ret:a.ret,errcode:a.errcode},"getUpdates API error"),n>=r?(n=0,await this.sleep(s,e)):await this.sleep(i,e);continue}n=0,a.get_updates_buf&&(this.getUpdatesBuf=a.get_updates_buf,Sn(this.id,a.get_updates_buf));for(let d of a.msgs??[])await this.processInbound(d)}catch(a){if(e?.aborted)return;n++,h.error({channelId:this.id,error:a},"getUpdates error"),n>=r?(n=0,await this.sleep(s,e)):await this.sleep(i,e)}}async processInbound(e){if(!this.messageHandler)return;let n=!!e.group_id,r=n?e.group_id:e.from_user_id??"",s=e.from_user_id??"";e.context_token&&r&&xn(this.id,r,e.context_token);let i=this.getOrCreateSession(r),a=i.quotaRemaining;i.lastUserMessageAt=Date.now(),i.quotaRemaining=St,Y(this.id,this.sessions),h.info({channelId:this.id,chatId:r.slice(0,12),quotaReset:!0,prevQuota:a,newQuota:St,sessionWindowMs:ve},"iLink session reset: user message received, quota restored"),this.flushQueue(r);let o="",d,c=[],u;for(let m of e.item_list??[]){let l=m.ref_msg?.message_item?.msg_id;if(l){u=l;break}}for(let m of e.item_list??[])m.type===_.TEXT&&m.text_item?.text&&(o+=m.text_item.text),m.type===_.IMAGE&&(d="image",c.push(m)),m.type===_.VOICE&&(d="audio",c.push(m),m.voice_item?.text&&!o&&(o=m.voice_item.text)),m.type===_.FILE&&(d="file",c.push(m)),m.type===_.VIDEO&&(d="video",c.push(m));if(!o&&!d)return;let g;if(c.length>0){let m=this.config.cdnBaseUrl??Mt;try{let l=await bt(c[0],{cdnBaseUrl:m,channelId:this.id});l&&(g=l.path,d=l.type)}catch(l){h.error({channelId:this.id},`Media download failed: ${String(l)}`)}}let f={channelId:this.id,platform:"wechat",chatId:r,senderId:s,content:o,mediaType:d,mediaPath:g,isGroup:n,timestamp:e.create_time_ms??Date.now(),raw:e,...u?{quotedPlatformMessageId:u}:{}};this.messageHandler(f)}getExtensionFromMediaType(e,n){if(n){let r=re(n);if(r&&r!==".bin")return r}switch(e){case"image":return".png";case"video":return".mp4";case"audio":return".mp3";default:return".bin"}}sleep(e,n){return new Promise((r,s)=>{let i=setTimeout(r,e);n?.addEventListener("abort",()=>{clearTimeout(i),s(new Error("aborted"))},{once:!0})})}};C();C();var vn=y("channels"),fe=class{platform="discord";id;config;status="disconnected";messageHandler=null;client=null;constructor(e,n){if(this.id=e,!n.botToken)throw new Error("Discord adapter requires botToken");this.config=n}async connect(){this.status="connecting";try{let{Client:e,GatewayIntentBits:n}=await import("discord.js");this.client=new e({intents:[n.Guilds,n.GuildMessages,n.MessageContent,n.DirectMessages]});let r=this.client;r.on("messageCreate",s=>{if(!this.messageHandler||s.author.bot||this.config.allowedGuildIds?.length&&s.guildId&&!this.config.allowedGuildIds.includes(s.guildId))return;let i={channelId:this.id,platform:"discord",chatId:s.channelId,senderId:s.author.id,senderName:s.author.displayName??s.author.username,content:s.content,isGroup:!!s.guildId,timestamp:s.createdTimestamp,raw:s};this.messageHandler(i)}),await r.login(this.config.botToken),this.status="connected",vn.info({channelId:this.id},"Discord bot connected")}catch(e){throw this.status="error",e}}async disconnect(){this.client&&await this.client.destroy(),this.client=null,this.status="disconnected"}getStatus(){return this.status}getCapabilities(){return{canEdit:!0,canQuote:!0,canParseQuote:!0,canInlineButtons:!0,maxTextLength:2e3,supportsAttachments:!0}}async sendMessage(e,n){if(!this.client)throw new Error("Discord client not connected");let s=await this.client.channels.fetch(e);if(!s||!("send"in s))throw new Error(`Channel ${e} not found or not text channel`);return(await s.send({content:n.content,reply:n.replyToMessageId?{messageReference:n.replyToMessageId}:void 0})).id}onMessage(e){this.messageHandler=e}async sendTypingIndicator(e){if(!this.client)return;let r=await this.client.channels.fetch(e);r&&"sendTyping"in r&&await r.sendTyping()}};import{ImapFlow as zn}from"imapflow";import Hn from"nodemailer";import{existsSync as On,mkdirSync as Nn,readFileSync as Dn,writeFileSync as Fn}from"fs";import{dirname as Ln,join as Ut}from"path";import{homedir as qn}from"os";var $n={lastUid:0,seenMessageIds:[],sentMessageIds:[],updatedAt:0};function Ne(t=process.env.ADAM_TEST_DIR??Ut(qn(),".adam")){return Ut(t,"email-gateway","state.json")}function he(t=Ne()){if(!On(t))return{...$n};let e=JSON.parse(Dn(t,"utf-8"));return{uidValidity:e.uidValidity,lastUid:Number.isInteger(e.lastUid)?e.lastUid:0,seenMessageIds:Array.isArray(e.seenMessageIds)?e.seenMessageIds.filter(Pt):[],sentMessageIds:Array.isArray(e.sentMessageIds)?e.sentMessageIds.filter(Pt):[],updatedAt:typeof e.updatedAt=="number"?e.updatedAt:0}}function ee(t,e=Ne()){Nn(Ln(e),{recursive:!0}),Fn(e,JSON.stringify({...t,updatedAt:Date.now()},null,2),"utf-8")}function vt(t,e){let n=B(e);return n?{...t,seenMessageIds:t.seenMessageIds.includes(n)?t.seenMessageIds:[...t.seenMessageIds,n]}:t}function Bn(t,e){let n=B(e);return n?{...t,sentMessageIds:t.sentMessageIds.includes(n)?t.sentMessageIds:[...t.sentMessageIds,n]}:t}function Ot(t,e=Ne()){let n=Bn(he(e),t);return ee(n,e),n}function B(t){return typeof t=="string"?t.trim():""}function Pt(t){return typeof t=="string"}import{Readable as Gn}from"stream";import{MailParser as Wn}from"mailparser";import{convert as jn}from"html-to-text";async function Dt(t){let e=new Wn({skipImageLinks:!0,skipTextToHtml:!0}),n={},r,s,i,a=[],o,d="",c="",u="",g,f=0,m;if(await new Promise((F,R)=>{e.on("headers",b=>{try{for(let[I,v]of b.entries())n[I.toLowerCase()]=Qn(v);r=Nt(b.get("message-id")),o=Nt(b.get("subject")),u=qt(b.get("content-type"))??"";let P=b.get("date");P instanceof Date&&(g=P.getTime()),s=Ft(b.get("from"),"from"),i=Vn(b.get("reply-to"),"reply-to"),a=Lt(b.get("to"))}catch(P){m=P instanceof Error?P:new Error(String(P))}}),e.on("data",b=>{if(b.type==="attachment"){f+=1,b.release?.(),b.content?.resume?.();return}d=b.text??"",c=typeof b.html=="string"?b.html:""}),e.on("error",R),e.on("end",F),Gn.from([t]).pipe(e)}),m)throw m;if(!s)throw new Error("Inbound email must contain exactly one valid From address");let l=u.toLowerCase()==="text/html",w=d.trim();return(l||!w)&&c.trim()&&(w=jn(c,{wordwrap:!1,selectors:[{selector:"h1",format:"heading",options:{uppercase:!1}},{selector:"h2",format:"heading",options:{uppercase:!1}},{selector:"h3",format:"heading",options:{uppercase:!1}},{selector:"h4",format:"heading",options:{uppercase:!1}},{selector:"h5",format:"heading",options:{uppercase:!1}},{selector:"h6",format:"heading",options:{uppercase:!1}}]}).trim()),!w&&o&&(w=o.trim()),{messageId:r,from:s,replyTo:i,to:a,subject:o,text:w,date:g,rawHeaders:n,attachmentCount:f}}function Ft(t,e){let n=Lt(t);if(n.length!==1){if(n.length===0)return;throw new Error(`Inbound email ${e} must contain exactly one mailbox address`)}return n[0]}function Vn(t,e){if(t)return Ft(t,e)}function Lt(t){return t?typeof t=="string"?[k(t)]:(t.value??[]).map(r=>r.address).filter(r=>typeof r=="string"&&r.trim().length>0).map(r=>k(r)):[]}function Nt(t){if(typeof t=="string")return t;if(Array.isArray(t))return t.map(String).join(", ")}function Qn(t){if(t instanceof Date)return t.toISOString();if(typeof t=="string")return t;if(Array.isArray(t))return t.map(String).join(", ");let e=qt(t);return e||(t&&typeof t=="object"&&"text"in t?String(t.text??""):String(t??""))}function qt(t){if(typeof t=="string")return t;if(t&&typeof t=="object"&&"value"in t){let e=t.value;if(typeof e=="string")return e}}var Kn=1e4,Jn=3e4,Fe=class{imapClient;smtpTransporter;pollTimer;handlers=[];status={status:"stopped"};state=he();async start(e){if(await this.stop(),!e.enabled){this.status={status:"stopped",details:{reason:"disabled"}};return}this.status={status:"starting",lastStartedAt:Date.now()};try{this.imapClient=new zn({host:e.imap.host,port:e.imap.port,secure:e.imap.secure,auth:{user:e.imap.auth.user,pass:e.imap.auth.pass}}),await this.imapClient.connect();let n=await this.imapClient.mailboxOpen(e.imap.mailbox),r=n?.uidValidity?Number(n.uidValidity):void 0;r&&this.state.uidValidity&&r!==this.state.uidValidity?(this.state={...this.state,uidValidity:r,lastUid:0,seenMessageIds:[]},ee(this.state)):r&&(this.state={...this.state,uidValidity:r},ee(this.state)),this.smtpTransporter=Hn.createTransport({host:e.smtp.host,port:e.smtp.port,secure:e.smtp.secure,auth:{user:e.smtp.auth.user,pass:e.smtp.auth.pass}}),await this.smtpTransporter.verify(),this.status={status:"connected",lastStartedAt:Date.now(),lastCheckedAt:Date.now()},this.schedulePoll(e)}catch(n){throw await this.cleanupResources(),this.status={status:"error",lastError:Le(n),details:{stage:this.smtpTransporter?"smtp":"imap"}},n}}async stop(){await this.cleanupResources(),this.status={status:"stopped"}}getStatus(){return{...this.status}}onInbound(e){this.handlers.push(e)}async send(e){if(!this.smtpTransporter)throw new Error("EmailGateway SMTP transporter is not started");let n=await Xn(this.smtpTransporter.sendMail({from:e.from,to:e.to,subject:e.subject,text:e.text,html:e.html,attachments:e.attachments}),Kn,"SMTP send timed out"),r=B(n.messageId);if(!r)throw new Error("SMTP send returned no Message-ID");return this.state=Ot(r),r}isSentByAdam(e){let n=B(e);return n.length>0&&this.state.sentMessageIds.includes(n)}schedulePoll(e){this.pollTimer=setInterval(()=>{this.poll(e)},Jn)}async poll(e){if(this.imapClient)try{this.state=he();let n=`${this.state.lastUid+1}:*`,r=this.imapClient.fetch?.(n,{uid:!0,source:!0,envelope:!0},{uid:!0});if(!r||!r[Symbol.asyncIterator])return;let s=!1;for await(let i of r){let a=Number(i.uid);if(!Number.isInteger(a)||a<=this.state.lastUid)continue;if(!i.source){this.markDegraded(new Error(`IMAP fetch item ${a} is missing source`)),s=!0;break}let o;try{o=await Dt(i.source)}catch(u){this.markDegraded(u),s=!0;break}let d=o.rawHeaders["x-adam-probe-id"],c=B(o.messageId);if(d?.startsWith("adam-probe-")){this.advanceCursor(a);continue}if(c&&this.state.sentMessageIds.includes(c)){this.advanceCursor(a);continue}if(c&&this.state.seenMessageIds.includes(c)){this.advanceCursor(a);continue}try{await Promise.all(this.handlers.map(u=>u(o)))}catch(u){this.markDegraded(u),s=!0;break}this.state=vt(this.state,c),this.advanceCursor(a)}s||(this.status={...this.status,status:"connected",lastCheckedAt:Date.now(),lastError:void 0})}catch(n){this.markDegraded(n)}}advanceCursor(e){this.state={...this.state,lastUid:e},ee(this.state)}markDegraded(e){this.status={...this.status,status:"degraded",lastError:Le(e),lastCheckedAt:Date.now()}}async cleanupResources(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0);let e=this.imapClient,n=this.smtpTransporter;this.imapClient=void 0,this.smtpTransporter=void 0,e&&(await De(e.logout?.()),await De(e.close?.())),await De(n?.close?.())}},$t;function S(){return $t??=new Fe,$t}async function ye(t){await S().start(t)}async function Mr(t,e){await S().stop(),await S().start(t)}async function Sr(t){await S().stop()}async function Xn(t,e,n){let r;try{return await Promise.race([t,new Promise((s,i)=>{r=setTimeout(()=>i(new Error(n)),e)})])}catch(s){throw new Error(Le(s))}finally{r&&clearTimeout(r)}}function Le(t){return t instanceof Error?t.message.replace(/pass(word)?=[^\s]+/gi,"password=****"):"Email gateway operation failed"}async function De(t){t&&typeof t.then=="function"&&await t.catch(()=>{})}C();var we=y("channels"),qe=class{constructor(e){this.gateway=e}gateway;adaptersByAddress=new Map;channelAddressById=new Map;registerAdapter(e,n){if(!ze(e)||!e.enabled)return;let r=L(e);this.unregisterAdapter(e.id),this.adaptersByAddress.set(r,n),this.channelAddressById.set(e.id,r)}unregisterAdapter(e){let n=this.channelAddressById.get(e);n&&(this.adaptersByAddress.delete(n),this.channelAddressById.delete(e))}refreshFromChannels(e,n){this.adaptersByAddress.clear(),this.channelAddressById.clear();for(let r of e){let s=n.get(r.id);if(s)try{this.registerAdapter(r,s)}catch(i){we.warn({channelId:r.id,error:i},"Invalid email channel skipped during router refresh")}}}async handle(e){if(e.messageId&&this.gateway.isSentByAdam(e.messageId)){we.debug({messageId:e.messageId},"Skipping Adam-sent email");return}let n;try{n=k(e.from)}catch(s){we.warn({from:e.from,error:s},"Skipping email with invalid sender address");return}let r=this.adaptersByAddress.get(n);if(!r){we.info({from:n},"Skipping unmatched inbound email");return}await r.acceptInbound(e)}hasAddress(e){return this.adaptersByAddress.has(k(e))}},be,Bt;function $e(t){return(!be||Bt!==t)&&(be=new qe(t),Bt=t,t.onInbound(e=>be?.handle(e)??Promise.resolve())),be}import{existsSync as Yn}from"fs";import{basename as Zn,isAbsolute as es}from"path";function Gt(t){let e=[];return t.mediaUrl&&e.push({path:t.mediaUrl,mediaType:t.mediaType}),t.attachments&&e.push(...t.attachments),e.map(ts)}function ts(t){let e=t.path.startsWith("file://")?new URL(t.path).pathname:t.path;if(!es(e)||e.includes("://"))throw new Error("Email attachment path must be an absolute local file path");if(!Yn(e))throw new Error(`Email attachment file not found: ${e}`);return{filename:t.filename??Zn(e),path:e,...t.contentType?{contentType:t.contentType}:t.mediaType?{contentType:ns(t.mediaType)}:{}}}function ns(t){return"application/octet-stream"}import ss from"markdown-it";var rs=new ss({html:!1,linkify:!0});function Wt(t){return{text:Ve(t),html:rs.render(t)}}function jt(t){let e=t.prefix.trim()||"Adam";return t.messageType==="report"||t.messageType==="status_report"?`[${e} Report]`:t.messageType==="deliver"||t.messageType==="result_delivery"?`[${e} Deliver]`:`[${e}]`}var _e=class{platform="email";id;channel;gateway;handler;inboundDispatchHandler;status="disconnected";identity;constructor(e,n,r={}){this.channel=e,this.gateway=n,this.id=e.id,this.identity=r}async connect(){let e=this.gateway.getStatus();this.status=Ie(e.status)}async disconnect(){this.status="disconnected"}getStatus(){return this.status}getCapabilities(){return{canEdit:!1,canQuote:!1,canParseQuote:!1,canInlineButtons:!1,maxTextLength:Number.POSITIVE_INFINITY,supportsAttachments:!0}}async sendMessage(e,n){let r=k(e),s=L(this.channel);if(r!==s)throw new Error("Email channel recipient does not match configured address");let i=Wt(n.content);return this.gateway.send({from:this.identity.from?He(this.identity.from,this.identity.displayName):void 0,to:r,subject:jt({prefix:this.identity.subjectPrefix??"Adam",messageType:n.messageType??"reply"}),text:i.text,html:i.html,attachments:Gt(n)})}onMessage(e){this.handler=e}onInboundDispatch(e){this.inboundDispatchHandler=e}syncGatewayStatus(){this.status=Ie(this.gateway.getStatus().status)}async acceptInbound(e){let n=k(e.from),r={channelId:this.channel.id,platform:"email",chatId:n,senderId:n,senderName:e.from,content:e.text,replyToMessageId:e.messageId,isGroup:!1,timestamp:e.date??Date.now(),raw:{messageId:e.messageId,subject:e.subject,attachmentCount:e.attachmentCount,headers:e.rawHeaders}};this.handler?.(r),this.inboundDispatchHandler&&await this.inboundDispatchHandler(r)}};function Ie(t){switch(t){case"connected":return"connected";case"starting":return"connecting";case"degraded":case"error":return"degraded";case"stopped":return"disconnected";default:return"disconnected"}}var Vt=y("channels"),Be=new Map;async function G(t,e){if(t.hasAdapter(e.id))return!0;if(e.platform==="wechat"){let n=e.config;return n.botToken?(await t.addChannel(e,new $(e.id,n)),!0):!1}if(e.platform==="discord"){let n=e.config;return n.botToken?(await t.addChannel(e,new fe(e.id,{botToken:n.botToken})),!0):!1}if(e.platform==="email"){L(e);let n=S(),r=j().emailGateway,s=new _e(e,n,{from:r?.smtp?.from||r?.address,displayName:r?.displayName,subjectPrefix:r?.subjectPrefix??"Adam"});Be.set(e.id,s),$e(n).registerAdapter(e,s);try{await is(),await t.addChannel(e,s)}catch(i){throw await W(t,e),i}return!0}return!1}async function Jr(t){for(let e of ne(!0))try{await G(t,e)}catch(n){V(e.id,"error"),Vt.warn({channelId:e.id,platform:e.platform,error:n},"Failed to register built-in channel adapter")}}async function Qt(t,e){e.platform==="email"&&(await W(t,e),e.enabled&&await G(t,e))}async function zt(t,e){await W(t,e)}async function W(t,e){e.platform==="email"&&($e(S()).unregisterAdapter(e.id),Be.delete(e.id),t?.hasAdapter(e.id)&&await t.removeChannel(e.id))}function Xr(t){for(let[e,n]of Be.entries())n.syncGatewayStatus(),V(e,n.getStatus())}async function is(){let t=j().emailGateway;if(!t?.enabled)return;let e=S().getStatus().status;if(!(e!=="stopped"&&e!=="error"))try{await ye(t)}catch(n){Vt.warn({error:as(n)},"EmailGateway start failed during built-in adapter registration")}}function as(t){return t instanceof Error?t.message.replace(/pass(word)?=[^\s]+/gi,"password=****"):"Email gateway operation failed"}var U=p.object({id:p.string().uuid()}),ds=p.object({name:p.string().min(1,"name is required"),platform:p.string().min(1,"platform is required"),config:p.record(p.string(),p.unknown()),enabled:p.boolean().optional().default(!0),linkedRoleId:p.string().optional(),allowedChatIds:p.array(p.string()).optional()}),us=p.object({name:p.string().min(1).optional(),enabled:p.boolean().optional(),config:p.record(p.string(),p.unknown()).optional(),linkedRoleId:p.string().optional(),allowedChatIds:p.array(p.string()).optional(),viewerKey:p.string().min(1).max(100).regex(/^[a-zA-Z0-9_.@:-]+$/,"viewerKey must be alphanumeric or one of _ . @ : -").optional()}),Ge;function li(t){Ge=t}function mi(){return Ge}async function gi(t){let e=Ge;async function n(r){je(r);try{return e&&r.enabled&&await G(e,r),r}catch(s){throw await W(e,r),Te(r.id),s}}t.get("/channels",{schema:{tags:["Channels"],summary:"List channels",querystring:{type:"object",properties:{enabled:{type:"boolean"}}}}},async(r,s)=>({channels:ne(r.query.enabled)})),t.post("/channels",{schema:{tags:["Channels"],summary:"Create a channel",body:{type:"object",required:["name","platform","config"],properties:{name:{type:"string",minLength:1},platform:{type:"string",minLength:1},config:{type:"object"},enabled:{type:"boolean"},linkedRoleId:{type:"string"},allowedChatIds:{type:"array",items:{type:"string"}}}}}},async(r,s)=>{let i=ds.safeParse(r.body);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let{name:a,platform:o,config:d,enabled:c,linkedRoleId:u,allowedChatIds:g}=i.data,f=d;if(o==="email")try{f={...Ee(d)}}catch(l){return s.status(400).send({code:"VALIDATION_ERROR",message:l instanceof Error?l.message:String(l)})}let m={id:os(),name:a,platform:o,enabled:c,status:"disconnected",config:f,linkedRoleId:u,allowedChatIds:g,viewerKey:Qe(),createdAt:Date.now(),messageCount:0};try{await n(m)}catch(l){return s.status(400).send({code:"VALIDATION_ERROR",message:D(l)})}return s.status(201).send({channel:m})}),t.get("/channels/:id",{schema:{tags:["Channels"],summary:"Get channel by ID",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);return a?{channel:a}:s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),t.patch("/channels/:id",{schema:{tags:["Channels"],summary:"Update channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}},body:{type:"object",properties:{name:{type:"string"},enabled:{type:"boolean"},config:{type:"object"},linkedRoleId:{type:"string"},allowedChatIds:{type:"array",items:{type:"string"}},viewerKey:{type:"string",minLength:1,maxLength:100}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});let o=us.safeParse(r.body);if(!o.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(o.error)});let d={...o.data};if((a.platform==="email"||d.config)&&(d.config||a.config)){let g=d.config??a.config;if(a.platform==="email")try{d.config={...Ee(g)}}catch(f){return s.status(400).send({code:"VALIDATION_ERROR",message:f instanceof Error?f.message:String(f)})}}let c=a.platform==="email"&&(d.enabled!==void 0||d.config!==void 0);te(a.id,d);let u=T(a.id);if(e&&u&&c)try{await Qt(e,u)}catch(g){if(te(a.id,{name:a.name,enabled:a.enabled,status:a.status,config:a.config,linkedRoleId:a.linkedRoleId,allowedChatIds:a.allowedChatIds,lastMessageAt:a.lastMessageAt,messageCount:a.messageCount}),await W(e,u),a.enabled)try{await G(e,a)}catch(f){return s.status(500).send({code:"RESTORE_FAILED",message:D(f)})}return s.status(400).send({code:"VALIDATION_ERROR",message:D(g)})}return{channel:u}}),t.delete("/channels/:id",{schema:{tags:["Channels"],summary:"Delete channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(Te(a.id),e)try{await zt(e,a)}catch(o){t.log.warn({channelId:a.id,error:D(o)},"Failed to clean up built-in channel runtime")}return s.status(204).send()}),t.post("/channels/:id/connect",{schema:{tags:["Channels"],summary:"Connect channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});if(!e)return s.status(501).send({code:"NOT_IMPLEMENTED",message:"Channel manager not initialized"});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(a.platform==="email")try{await cs()}catch(o){let d=S().getStatus();return V(a.id,Ie(d.status)),s.status(409).send({code:"EMAIL_GATEWAY_NOT_READY",message:D(o),gatewayStatus:d})}if(!e.hasAdapter(a.id))try{await G(e,a)}catch(o){return s.status(400).send({code:"VALIDATION_ERROR",message:D(o)})}if(!e.hasAdapter(a.id))return s.status(400).send({code:"NO_ADAPTER",message:"No adapter registered for this channel. Install the appropriate adapter first."});try{await e.connectChannel(a.id);let o=T(a.id)?.status??e.getChannelStatus(a.id);return o!=="connected"?s.status(409).send({code:"CONNECT_INCOMPLETE",message:`Channel connect finished with status "${o}"`,status:o}):{channelId:a.id,status:o}}catch(o){return s.status(500).send({code:"CONNECT_FAILED",message:D(o)})}}),t.post("/channels/:id/disconnect",{schema:{tags:["Channels"],summary:"Disconnect channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});if(!e)return s.status(501).send({code:"NOT_IMPLEMENTED",message:"Channel manager not initialized"});let a=T(i.data.id);return a?(await e.disconnectChannel(a.id),{channelId:a.id,status:"disconnected"}):s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),t.get("/channels/:id/capabilities",{schema:{tags:["Channels"],summary:"Get channel adapter capabilities",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});if(!T(i.data.id))return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(!e)return s.status(503).send({code:"MANAGER_UNAVAILABLE",message:"ChannelManager not initialized"});let o=e.getCapabilities(i.data.id);return o?{capabilities:o}:s.status(404).send({code:"ADAPTER_NOT_REGISTERED",message:"Channel adapter not active"})}),t.get("/channels/:id/messages",{schema:{tags:["Channels"],summary:"Get channel message history",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}},querystring:{type:"object",properties:{limit:{type:"integer",minimum:1,maximum:200,default:50},offset:{type:"integer",minimum:0,default:0}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});let{limit:o=50,offset:d=0}=r.query;return{messages:We(a.id,o,d)}}),t.post("/channels/:id/wechat/qr-start",{schema:{tags:["WeChat"],summary:"Start WeChat QR login",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(a.platform!=="wechat")return s.status(400).send({code:"INVALID_PLATFORM",message:"Channel is not a WeChat channel"});let o=a.config;return await st({apiBaseUrl:o.baseUrl,routeTag:o.routeTag})}),t.post("/channels/:id/wechat/qr-wait",{schema:{tags:["WeChat"],summary:"Wait for WeChat QR scan",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}},body:{type:"object",properties:{sessionKey:{type:"string"},timeoutMs:{type:"number"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(a.platform!=="wechat")return s.status(400).send({code:"INVALID_PLATFORM",message:"Channel is not a WeChat channel"});let o=a.config,{sessionKey:d,timeoutMs:c}=r.body??{},u=await rt({sessionKey:d??"",apiBaseUrl:o.baseUrl,timeoutMs:c??12e4,routeTag:o.routeTag});if(u.connected&&u.botToken){let g={...o,botToken:u.botToken,accountId:u.accountId,baseUrl:u.baseUrl??o.baseUrl,userId:u.userId};if(te(a.id,{config:g}),e){let f=new $(a.id,g),m=T(a.id);m&&await e.addChannel(m,f)}}return{connected:u.connected,accountId:u.accountId,message:u.message}})}function D(t){return t instanceof Error?t.message.replace(/pass(word)?=[^\s]+/gi,"password=****"):String(t)}async function cs(){let t=j().emailGateway;if(!t?.enabled)throw new Error("Email Gateway is disabled. Enable Email Gateway in Settings before connecting Mail channels.");let e=S();e.getStatus().status!=="connected"&&await ye(t);let n=e.getStatus();if(n.status!=="connected"){let r=n.lastError?`: ${n.lastError}`:"";throw new Error(`Email Gateway status is ${n.status}${r}`)}}export{Ot as a,B as b,Dt as c,S as d,Mr as e,Sr as f,Jr as g,Xr as h,li as i,mi as j,gi as k};
|
|
1
|
+
import{g as je}from"./chunk-XF7YHFVR.js";import{a as Ve,b as k,c as Ee,d as L,e as Qe}from"./chunk-NNMQGISW.js";import{b as ze,c as He,f as se,g as re}from"./chunk-QZ34KQ76.js";import{a as We,b as T,c as te,d as ne,e as Te,f as V}from"./chunk-CLNYHWZ6.js";import{d as j}from"./chunk-Z6LHGA27.js";import{c as y,h as C}from"./chunk-BLCNUT53.js";import{z as p}from"zod/v4";import{v4 as os}from"uuid";import{randomUUID as et}from"crypto";import Ht from"crypto";var Ke="2.1.7",ie="bot";function Kt(t){let e=t.split(".").map(i=>parseInt(i,10)),n=e[0]??0,r=e[1]??0,s=e[2]??0;return(n&255)<<16|(r&255)<<8|s&255}var xe=Kt(Ke),Jt=35e3,Je=15e3,Xt=1e4;function ae(){return{channel_version:Ke}}function Yt(t){return t.endsWith("/")?t:`${t}/`}function Zt(){let t=Ht.randomBytes(4).readUInt32BE(0);return Buffer.from(String(t),"utf-8").toString("base64")}function en(t){let e={"Content-Type":"application/json",AuthorizationType:"ilink_bot_token","Content-Length":String(Buffer.byteLength(t.body,"utf-8")),"X-WECHAT-UIN":Zt(),"iLink-App-Id":ie,"iLink-App-ClientVersion":String(xe)};return t.token?.trim()&&(e.Authorization=`Bearer ${t.token.trim()}`),t.routeTag&&(e.SKRouteTag=t.routeTag),e}async function oe(t){let e=Yt(t.baseUrl),n=new URL(t.endpoint,e),r=en({token:t.token,routeTag:t.routeTag,body:t.body}),s=new AbortController,i=setTimeout(()=>s.abort(),t.timeoutMs);try{let a=await fetch(n.toString(),{method:"POST",headers:r,body:t.body,signal:s.signal});clearTimeout(i);let o=await a.text();if(!a.ok)throw new Error(`${t.label} ${a.status}: ${o}`);return o}catch(a){throw clearTimeout(i),a}}async function Xe(t){let e=t.timeoutMs??Jt;try{let n=await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/getupdates",body:JSON.stringify({get_updates_buf:t.get_updates_buf??"",base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:e,label:"getUpdates"});return JSON.parse(n)}catch(n){if(n instanceof Error&&n.name==="AbortError")return{ret:0,msgs:[],get_updates_buf:t.get_updates_buf};throw n}}var tn={[-2]:2,[-3]:3},nn=1e3;async function Q(t){let e=(await import("./logger-PAMNFWI3.js")).getLogger("channels"),n=new Map;for(;;){let r=await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/sendmessage",body:JSON.stringify({...t.body,base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:t.timeoutMs??Je,label:"sendMessage"});e.info({status:200,responseBody:r.slice(0,300)},"apiFetch sendMessage response");try{let s=JSON.parse(r);if(s.ret&&s.ret!==0){let i=tn[s.ret],a=(n.get(s.ret)??0)+1;if(n.set(s.ret,a),i!==void 0&&a<i){e.warn({ret:s.ret,attempt:a,maxRetries:i},"sendMessage: retriable iLink error, retrying"),await new Promise(o=>setTimeout(o,nn*a));continue}throw e.error({ret:s.ret,errmsg:s.errmsg,attempt:a},"sendMessage: iLink API error, no more retries"),new Error(`sendMessage failed: iLink ret=${s.ret}${s.errmsg?` errmsg=${s.errmsg}`:""}`)}}catch(s){if(s instanceof SyntaxError)e.warn({rawText:r.slice(0,200)},"sendMessage: non-JSON response, treating as success");else throw s}return}}async function Ye(t){await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/sendtyping",body:JSON.stringify({...t.body,base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:t.timeoutMs??Xt,label:"sendTyping"})}async function Ze(t){let e=await oe({baseUrl:t.baseUrl,endpoint:"ilink/bot/getuploadurl",body:JSON.stringify({filekey:t.filekey,media_type:t.media_type,to_user_id:t.to_user_id,rawsize:t.rawsize,rawfilemd5:t.rawfilemd5,filesize:t.filesize,thumb_rawsize:t.thumb_rawsize,thumb_rawfilemd5:t.thumb_rawfilemd5,thumb_filesize:t.thumb_filesize,no_need_thumb:t.no_need_thumb,aeskey:t.aeskey,base_info:ae()}),token:t.token,routeTag:t.routeTag,timeoutMs:t.timeoutMs??Je,label:"getUploadUrl"});return JSON.parse(e)}var sn=5*6e4,rn=35e3,tt="3",E=new Map;function Me(t){return Date.now()-t.startedAt<sn}function an(){for(let[t,e]of E)Me(e)||E.delete(t)}async function nt(t,e,n){let r=t.endsWith("/")?t:`${t}/`,s=new URL(`ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(e)}`,r),i={"iLink-App-Id":ie};n&&(i.SKRouteTag=n);let a=await fetch(s.toString(),{headers:i});if(!a.ok){let o=await a.text().catch(()=>"(unreadable)");throw new Error(`Failed to fetch QR code: ${a.status} ${a.statusText} body=${o}`)}return await a.json()}async function on(t,e,n){let r=t.endsWith("/")?t:`${t}/`,s=new URL(`ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(e)}`,r),i={"iLink-App-Id":ie,"iLink-App-ClientVersion":String(xe)};n&&(i.SKRouteTag=n);let a=new AbortController,o=setTimeout(()=>a.abort(),rn);try{let d=await fetch(s.toString(),{headers:i,signal:a.signal});clearTimeout(o);let c=await d.text();if(!d.ok)throw new Error(`Failed to poll QR status: ${d.status} ${d.statusText}`);return JSON.parse(c)}catch(d){if(clearTimeout(o),d instanceof Error&&d.name==="AbortError")return{status:"wait"};throw d}}async function st(t){let e=t.accountId||et();an();let n=E.get(e);if(!t.force&&n&&Me(n)&&n.qrcodeUrl)return{qrcodeUrl:n.qrcodeUrl,message:"QR code ready. Scan with WeChat.",sessionKey:e};if(!t.apiBaseUrl)return{message:"No baseUrl configured for this WeChat channel.",sessionKey:e};try{let r=t.botType||tt,s=await nt(t.apiBaseUrl,r,t.routeTag),i={sessionKey:e,id:et(),qrcode:s.qrcode,qrcodeUrl:s.qrcode_img_content,startedAt:Date.now()};return E.set(e,i),{qrcodeUrl:s.qrcode_img_content,message:"Scan the QR code with WeChat to connect.",sessionKey:e}}catch(r){return{message:`Failed to start login: ${String(r)}`,sessionKey:e}}}var dn=3;async function rt(t){let e=E.get(t.sessionKey);if(!e)return{connected:!1,message:"No active login session. Start QR login first."};if(!Me(e))return E.delete(t.sessionKey),{connected:!1,message:"QR code expired. Please start again."};let n=Math.max(t.timeoutMs??48e4,1e3),r=Date.now()+n,s=1;for(;Date.now()<r;){try{let i=await on(t.apiBaseUrl,e.qrcode,t.routeTag);switch(e.status=i.status,i.status){case"wait":break;case"scaned":break;case"expired":{if(s++,s>dn)return E.delete(t.sessionKey),{connected:!1,message:"Login timeout: QR expired multiple times."};try{let a=t.botType||tt,o=await nt(t.apiBaseUrl,a,t.routeTag);e.qrcode=o.qrcode,e.qrcodeUrl=o.qrcode_img_content,e.startedAt=Date.now()}catch(a){return E.delete(t.sessionKey),{connected:!1,message:`QR refresh failed: ${String(a)}`}}break}case"confirmed":return i.ilink_bot_id?(E.delete(t.sessionKey),{connected:!0,botToken:i.bot_token,accountId:i.ilink_bot_id,baseUrl:i.baseurl,userId:i.ilink_user_id,message:"Connected to WeChat successfully!"}):(E.delete(t.sessionKey),{connected:!1,message:"Login failed: server did not return bot ID."})}}catch(i){return E.delete(t.sessionKey),{connected:!1,message:`Login failed: ${String(i)}`}}await new Promise(i=>setTimeout(i,1e3))}return E.delete(t.sessionKey),{connected:!1,message:"Login timeout. Please try again."}}import A from"fs";import*as M from"fs/promises";import x from"path";import{homedir as pe}from"os";var de={IMAGE:1,VIDEO:2,FILE:3,VOICE:4},z={NONE:0,USER:1,BOT:2},_={NONE:0,TEXT:1,IMAGE:2,VOICE:3,FILE:4,VIDEO:5},H={NEW:0,GENERATING:1,FINISH:2},it={TYPING:1,CANCEL:2};C();var un=y("channels"),Se=-14,ue=3600*1e3,q=new Map;function at(t){let e=Date.now()+ue;q.set(t,e),un.info({channelId:t},`Session paused until ${new Date(e).toISOString()} (${ue/1e3}s)`)}function ce(t){let e=q.get(t);return e===void 0?!1:Date.now()>=e?(q.delete(t),!1):!0}function ot(t){let e=q.get(t);if(e===void 0)return 0;let n=e-Date.now();return n<=0?(q.delete(t),0):n}function dt(t){q.delete(t)}C();import*as me from"fs/promises";import yt from"path";import{homedir as pn}from"os";import{createCipheriv as cn,createDecipheriv as ln}from"crypto";function ut(t,e){let n=cn("aes-128-ecb",e,null);return Buffer.concat([n.update(t),n.final()])}function ct(t,e){let n=ln("aes-128-ecb",e,null);return Buffer.concat([n.update(t),n.final()])}function lt(t){return Math.ceil((t+1)/16)*16}function Ce(t,e){return`${e}/download?encrypted_query_param=${encodeURIComponent(t)}`}function mt(t){return`${t.cdnBaseUrl}/upload?encrypted_query_param=${encodeURIComponent(t.uploadParam)}&filekey=${encodeURIComponent(t.filekey)}`}C();var Ms=y("channels");function mn(t){let e=Buffer.from(t,"base64");if(e.length===16)return e;if(e.length===32&&/^[0-9a-fA-F]{32}$/.test(e.toString("ascii")))return Buffer.from(e.toString("ascii"),"hex");throw new Error(`aes_key must decode to 16 raw bytes or 32-char hex, got ${e.length} bytes`)}async function gt(t){let e=await fetch(t);if(!e.ok)throw new Error(`CDN download ${e.status} ${e.statusText}`);return Buffer.from(await e.arrayBuffer())}async function K(t){let{encryptQueryParam:e,aesKeyBase64:n,cdnBaseUrl:r,fullUrl:s}=t,i=mn(n),a=s?.trim()||(e?Ce(e,r):null);if(!a)throw new Error("CDN download: need full_url or encrypt_query_param");let o=await gt(a);return ct(o,i)}async function pt(t){let{encryptQueryParam:e,cdnBaseUrl:n,fullUrl:r}=t,s=r?.trim()||(e?Ce(e,n):null);if(!s)throw new Error("CDN download: need full_url or encrypt_query_param");return gt(s)}C();var le=y("channels"),ft=24e3;function gn(t,e){let n=t.byteLength,r=44+n,s=Buffer.allocUnsafe(r),i=0;return s.write("RIFF",i),i+=4,s.writeUInt32LE(r-8,i),i+=4,s.write("WAVE",i),i+=4,s.write("fmt ",i),i+=4,s.writeUInt32LE(16,i),i+=4,s.writeUInt16LE(1,i),i+=2,s.writeUInt16LE(1,i),i+=2,s.writeUInt32LE(e,i),i+=4,s.writeUInt32LE(e*2,i),i+=4,s.writeUInt16LE(2,i),i+=2,s.writeUInt16LE(16,i),i+=2,s.write("data",i),i+=4,s.writeUInt32LE(n,i),i+=4,Buffer.from(t.buffer,t.byteOffset,t.byteLength).copy(s,i),s}async function ht(t){try{let{decode:e}=await import("silk-wasm");le.debug(`silkToWav: decoding ${t.length} bytes of SILK`);let n=await e(t,ft);le.debug(`silkToWav: decoded duration=${n.duration}ms pcmBytes=${n.data.byteLength}`);let r=gn(n.data,ft);return le.debug(`silkToWav: WAV size=${r.length}`),r}catch(e){return le.warn(`silkToWav: transcode failed, will use raw silk err=${String(e)}`),null}}var N=y("channels"),wt=100*1024*1024;function fn(t){return re(t)??".bin"}async function J(t,e,n,r,s=wt,i){if(t.length>s)throw new Error(`Media too large: ${t.length} bytes exceeds ${s} bytes`);let a=yt.join(pn(),".adam","wechat","media",r,n);await me.mkdir(a,{recursive:!0});let o;if(i&&/^[a-zA-Z0-9._-]+$/.test(i))o=i;else{let c=e?fn(e):".bin",u=Date.now(),g=Math.random().toString(36).slice(2,7);o=`${u}-${g}${c}`}let d=yt.join(a,o);return await me.writeFile(d,t),N.debug(`saveMedia: saved ${t.length} bytes to ${d}`),d}async function bt(t,e){let{cdnBaseUrl:n,channelId:r}=e;if(t.type===_.IMAGE){let s=t.image_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url)return null;let i=s.aeskey?Buffer.from(s.aeskey,"hex").toString("base64"):s.media?.aes_key;try{let a=i?await K({encryptQueryParam:s.media?.encrypt_query_param,aesKeyBase64:i,cdnBaseUrl:n,fullUrl:s.media?.full_url}):await pt({encryptQueryParam:s.media?.encrypt_query_param,cdnBaseUrl:n,fullUrl:s.media?.full_url});return{path:await J(a,"image/png","inbound",r),mimeType:"image/png",type:"image"}}catch(a){return N.error({channelId:r},`Image download/decrypt failed: ${String(a)}`),null}}if(t.type===_.VOICE){let s=t.voice_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url||!s?.media?.aes_key)return null;try{let i=await K({encryptQueryParam:s.media.encrypt_query_param,aesKeyBase64:s.media.aes_key,cdnBaseUrl:n,fullUrl:s.media.full_url}),a=await ht(i);if(a){let o=await J(a,"audio/wav","inbound",r);return N.debug(`Voice: saved WAV to ${o}`),{path:o,mimeType:"audio/wav",type:"audio"}}else{let o=await J(i,"audio/silk","inbound",r);return N.debug(`Voice: silk transcode unavailable, saved raw SILK to ${o}`),{path:o,mimeType:"audio/silk",type:"audio"}}}catch(i){return N.error({channelId:r},`Voice download/transcode failed: ${String(i)}`),null}}if(t.type===_.FILE){let s=t.file_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url||!s?.media?.aes_key)return null;try{let i=await K({encryptQueryParam:s.media.encrypt_query_param,aesKeyBase64:s.media.aes_key,cdnBaseUrl:n,fullUrl:s.media.full_url}),a=se(s.file_name??"file.bin");return{path:await J(i,a,"inbound",r,wt,s.file_name),mimeType:a,type:"file"}}catch(i){return N.error({channelId:r},`File download failed: ${String(i)}`),null}}if(t.type===_.VIDEO){let s=t.video_item;if(!s?.media?.encrypt_query_param&&!s?.media?.full_url||!s?.media?.aes_key)return null;try{let i=await K({encryptQueryParam:s.media.encrypt_query_param,aesKeyBase64:s.media.aes_key,cdnBaseUrl:n,fullUrl:s.media.full_url});return{path:await J(i,"video/mp4","inbound",r),mimeType:"video/mp4",type:"video"}}catch(i){return N.error({channelId:r},`Video download failed: ${String(i)}`),null}}return null}import Tt from"path";import Ae from"crypto";import hn from"fs/promises";C();var O=y("channels"),ge=3;async function yn(t){let{buf:e,uploadFullUrl:n,uploadParam:r,filekey:s,cdnBaseUrl:i,label:a,aeskey:o}=t,d=ut(e,o),c=n?.trim(),u;if(c)u=c;else if(r)u=mt({cdnBaseUrl:i,uploadParam:r,filekey:s});else throw new Error(`${a}: CDN upload URL missing (need upload_full_url or upload_param)`);O.debug(`${a}: CDN POST url=${u} ciphertextSize=${d.length}`);let g,f;for(let m=1;m<=ge;m++)try{let l=await fetch(u,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:new Uint8Array(d)});if(l.status>=400&&l.status<500){let w=l.headers.get("x-error-message")??await l.text();throw O.error(`${a}: CDN client error attempt=${m} status=${l.status} errMsg=${w}`),new Error(`CDN upload client error ${l.status}: ${w}`)}if(l.status!==200){let w=l.headers.get("x-error-message")??`status ${l.status}`;throw O.error(`${a}: CDN server error attempt=${m} status=${l.status} errMsg=${w}`),new Error(`CDN upload server error: ${w}`)}if(g=l.headers.get("x-encrypted-param")??void 0,!g)throw O.error(`${a}: CDN response missing x-encrypted-param header attempt=${m}`),new Error("CDN upload response missing x-encrypted-param header");O.debug(`${a}: CDN upload success attempt=${m}`);break}catch(l){if(f=l,l instanceof Error&&l.message.includes("client error"))throw l;m<ge?O.warn(`${a}: attempt ${m} failed, retrying... err=${String(l)}`):O.error(`${a}: all ${ge} attempts failed err=${String(l)}`)}if(!g)throw f instanceof Error?f:new Error(`CDN upload failed after ${ge} attempts`);return{downloadParam:g}}async function Re(t){let{filePath:e,toUserId:n,opts:r,cdnBaseUrl:s,mediaType:i,label:a}=t,o=await hn.readFile(e),d=o.length,c=Ae.createHash("md5").update(o).digest("hex"),u=lt(d),g=Ae.randomBytes(16).toString("hex"),f=Ae.randomBytes(16);O.debug(`${a}: file=${e} rawsize=${d} filesize=${u} md5=${c} filekey=${g}`);let m=await Ze({...r,filekey:g,media_type:i,to_user_id:n,rawsize:d,rawfilemd5:c,filesize:u,no_need_thumb:!0,aeskey:f.toString("hex")}),l=m.upload_full_url?.trim(),w=m.upload_param;if(!l&&!w)throw new Error(`${a}: getUploadUrl returned no upload URL (need upload_full_url or upload_param)`);let{downloadParam:F}=await yn({buf:o,uploadFullUrl:l||void 0,uploadParam:w??void 0,filekey:g,cdnBaseUrl:s,aeskey:f,label:`${a}[orig filekey=${g}]`});return{filekey:g,downloadEncryptedQueryParam:F,aeskey:f.toString("hex"),fileSize:d,fileSizeCiphertext:u}}async function _t(t){return Re({...t,mediaType:de.IMAGE,label:"uploadImageToWeixin"})}async function It(t){return Re({...t,mediaType:de.VIDEO,label:"uploadVideoToWeixin"})}async function ke(t){return Re({...t,mediaType:de.FILE,label:"uploadFileAttachmentToWeixin"})}C();var X=y("channels");function wn(){return`adam-wechat-${Date.now()}-${Math.random().toString(36).slice(2,7)}`}function bn(t){let e=t;return e=e.replace(/```[^\n]*\n?([\s\S]*?)```/g,(n,r)=>r.trim()),e=e.replace(/!\[[^\]]*\]\([^)]*\)/g,""),e=e.replace(/\[([^\]]+)\]\([^)]*\)/g,"$1"),e=e.replace(/^\|[\s:|-]+\|$/gm,""),e=e.replace(/^\|(.+)\|$/gm,(n,r)=>r.split("|").map(s=>s.trim()).join(" ")),e}async function Ue(t){let{to:e,text:n,mediaItem:r,opts:s,label:i}=t,a=[],o=bn(n);o&&a.push({type:_.TEXT,text_item:{text:o}}),a.push(r);let d="";for(let c of a){d=wn();let u={msg:{from_user_id:"",to_user_id:e,client_id:d,message_type:z.BOT,message_state:H.FINISH,item_list:[c],context_token:s.contextToken}};await Q({baseUrl:s.baseUrl,token:s.token,routeTag:s.routeTag,body:u})}return X.debug(`${i}: sent to=${e} messageId=${d}`),{messageId:d}}async function _n(t){let{to:e,text:n,uploaded:r,opts:s}=t,i={type:_.IMAGE,image_item:{media:{encrypt_query_param:r.downloadEncryptedQueryParam,aes_key:Buffer.from(r.aeskey).toString("base64"),encrypt_type:1},mid_size:r.fileSizeCiphertext}};return Ue({to:e,text:n,mediaItem:i,opts:s,label:"sendImageMessage"})}async function In(t){let{to:e,text:n,uploaded:r,opts:s}=t,i={type:_.VIDEO,video_item:{media:{encrypt_query_param:r.downloadEncryptedQueryParam,aes_key:Buffer.from(r.aeskey).toString("base64"),encrypt_type:1},video_size:r.fileSizeCiphertext}};return Ue({to:e,text:n,mediaItem:i,opts:s,label:"sendVideoMessage"})}async function Et(t){let{to:e,text:n,fileName:r,uploaded:s,opts:i}=t,a={type:_.FILE,file_item:{media:{encrypt_query_param:s.downloadEncryptedQueryParam,aes_key:Buffer.from(s.aeskey).toString("base64"),encrypt_type:1},file_name:r,len:String(s.fileSize)}};return Ue({to:e,text:n,mediaItem:a,opts:i,label:"sendFileMessage"})}async function xt(t){let{filePath:e,to:n,text:r,opts:s,cdnBaseUrl:i}=t,a=se(e),o={baseUrl:s.baseUrl,token:s.token,routeTag:s.routeTag};if(a.startsWith("video/")){X.debug(`sendWeixinMediaFile: uploading video filePath=${e} to=${n}`);let u=await It({filePath:e,toUserId:n,opts:o,cdnBaseUrl:i});return In({to:n,text:r,uploaded:u,opts:s})}if(a.startsWith("image/")){X.debug(`sendWeixinMediaFile: uploading image filePath=${e} to=${n}`);let u=await _t({filePath:e,toUserId:n,opts:o,cdnBaseUrl:i});return _n({to:n,text:r,uploaded:u,opts:s})}if(a.startsWith("audio/")){let u=Tt.basename(e);X.debug(`sendWeixinMediaFile: uploading audio as file filePath=${e} name=${u} to=${n}`);let g=await ke({filePath:e,fileName:u,toUserId:n,opts:o,cdnBaseUrl:i});return Et({to:n,text:r,fileName:u,uploaded:g,opts:s})}let d=Tt.basename(e);X.debug(`sendWeixinMediaFile: uploading file attachment filePath=${e} name=${d} to=${n}`);let c=await ke({filePath:e,fileName:d,toUserId:n,opts:o,cdnBaseUrl:i});return Et({to:n,text:r,fileName:d,uploaded:c,opts:s})}C();var h=y("channels"),Mt="https://novac2c.cdn.weixin.qq.com/c2c",Oe=new Map;function At(t){return x.join(pe(),".adam","wechat",`${t}.context-tokens.json`)}function Tn(t){let e=At(t);try{let n=A.readFileSync(e,"utf-8"),r=JSON.parse(n);for(let[s,i]of Object.entries(r))typeof i=="string"&&i&&Oe.set(`${t}:${s}`,i);h.debug({channelId:t,count:Object.keys(r).length},"Restored context tokens from disk")}catch{}}function En(t,e,n){let r=At(t);try{let s={};try{let a=A.readFileSync(r,"utf-8");s=JSON.parse(a)}catch{}s[e]=n;let i=x.dirname(r);A.mkdirSync(i,{recursive:!0}),A.writeFileSync(r,JSON.stringify(s),"utf-8")}catch(s){h.warn({channelId:t,userId:e},`Failed to persist context token: ${String(s)}`)}}function xn(t,e,n){Oe.set(`${t}:${e}`,n),En(t,e,n)}function Pe(t,e){return Oe.get(`${t}:${e}`)}function Rt(t){return x.join(pe(),".adam","wechat",`${t}.sync`)}function Mn(t){try{return A.readFileSync(Rt(t),"utf-8")}catch{return""}}function Sn(t,e){let n=Rt(t);A.mkdirSync(x.dirname(n),{recursive:!0}),A.writeFileSync(n,e,"utf-8")}var ve=1440*60*1e3,St=10,Cn=20,Ct=1440*60*1e3,An=1320*60*1e3,Rn=1,kn=7200*1e3;function kt(t){return x.join(pe(),".adam","wechat",`${t}.session.json`)}function Un(t){let e=new Map,n=kt(t);try{let r=A.readFileSync(n,"utf-8"),s=JSON.parse(r);for(let[i,a]of Object.entries(s))a&&typeof a.lastUserMessageAt=="number"&&e.set(i,a);h.debug({channelId:t,count:e.size},"Restored sessions from disk")}catch{}return e}function Y(t,e){let n=kt(t);try{let r={};for(let[i,a]of e)r[i]=a;let s=x.dirname(n);A.mkdirSync(s,{recursive:!0}),A.writeFileSync(n,JSON.stringify(r),"utf-8")}catch(r){h.warn({channelId:t},`Failed to persist sessions: ${String(r)}`)}}var Pn=0;function Z(){return`adam-wechat-${Date.now()}-${++Pn}`}var $=class{platform="wechat";id;config;status="disconnected";messageHandler=null;pollAbort=null;getUpdatesBuf="";sessions=new Map;pendingQueue=new Map;lastReminderAt=new Map;constructor(e,n){if(this.id=e,!n.baseUrl)throw new Error("WeChat adapter requires baseUrl");this.config=n}async connect(){if(!this.config.botToken)throw new Error("WeChat adapter requires botToken. Complete QR login first.");this.status="connecting",this.getUpdatesBuf=Mn(this.id),Tn(this.id),this.sessions=Un(this.id),this.pollAbort=new AbortController,this.status="connected",h.info({channelId:this.id},"WeChat adapter connected, starting long-poll"),this.startLongPoll()}async disconnect(){this.pollAbort&&(this.pollAbort.abort(),this.pollAbort=null),this.status="disconnected",h.info({channelId:this.id},"WeChat adapter disconnected")}getStatus(){if(this.status==="connected"&&ce(this.id))return"error";if(this.status==="connected"){for(let[,e]of this.sessions)if(this.isSessionActive(e)&&e.quotaRemaining<=0)return"degraded"}return this.status}getCapabilities(){return{canEdit:!1,canQuote:!0,canParseQuote:!0,canInlineButtons:!1,maxTextLength:4e3,supportsAttachments:!0,maxAttachmentsPerMessage:1}}async sendMessage(e,n){if(ce(this.id)){let c=Math.ceil(ot(this.id)/6e4);throw new Error(`WeChat session paused, ${c} min remaining. Re-scan QR to reconnect.`)}let r=this.getOrCreateSession(e),i=this.getSessionRemainingMs(r)/36e5;if(!this.isSessionActive(r))return h.warn({channelId:this.id,chatId:e.slice(0,12),lastUserMessageAt:r.lastUserMessageAt,sessionExpired:!0},"iLink session expired (>24h), message queued"),this.enqueueMessage(e,n),`queued-${Z()}`;if(r.quotaRemaining<=0)return h.warn({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:0,remainingHours:i.toFixed(1)},"iLink quota exhausted, message queued"),this.enqueueMessage(e,n),`queued-${Z()}`;let a=Z(),o=Pe(this.id,e),d=this.config.cdnBaseUrl??Mt;try{let c=n.attachments?.[0],u=c?.path??n.mediaUrl,g=c?.contentType,f=c?.filename,m=c?.mediaType??n.mediaType;if(u){let l=!u.includes("://")||u.startsWith("file://"),w=x.join(pe(),".adam","wechat","media","outbound-tmp");await M.mkdir(w,{recursive:!0});let F=this.getExtensionFromMediaType(m,g),R;if(l){let I=u.startsWith("file://")?new URL(u).pathname:x.isAbsolute(u)?u:x.resolve(u),v=await M.readFile(I);R=x.join(w,`${Date.now()}-${Math.random().toString(36).slice(2,7)}${F}`),await M.writeFile(R,v)}else{let I=await fetch(u);if(!I.ok)throw new Error(`Failed to fetch media: ${I.status}`);let v=Buffer.from(await I.arrayBuffer());R=x.join(w,`${Date.now()}-${Math.random().toString(36).slice(2,7)}${F}`),await M.writeFile(R,v)}let b=R;if(f){let I=f.replace(/[\\/]/g,"-").replace(/\.\./g,"-").replace(/[\x00-\x1f]/g,"");if(I.length>0&&I.length<200){let v=x.join(w,`${Date.now()}-${I}`);await M.copyFile(R,v),await M.unlink(R).catch(()=>{}),b=v}}let P=await xt({filePath:b,to:e,text:n.content??"",opts:{baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,contextToken:o},cdnBaseUrl:d});return await M.unlink(b).catch(()=>{}),r.quotaRemaining--,Y(this.id,this.sessions),h.info({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:r.quotaRemaining,sessionRemainingHours:(this.getSessionRemainingMs(r)/36e5).toFixed(1)},"iLink send success: quota decremented"),this.checkAndSendReminder(e,r).catch(I=>{h.warn({channelId:this.id,chatId:e.slice(0,12)},`Reminder send failed: ${String(I)}`)}),P.messageId}return await Q({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{msg:{from_user_id:"",to_user_id:e,client_id:a,message_type:z.BOT,message_state:H.FINISH,item_list:this.buildItemList(n),context_token:o}}}),r.quotaRemaining--,Y(this.id,this.sessions),h.info({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:r.quotaRemaining,sessionRemainingHours:(this.getSessionRemainingMs(r)/36e5).toFixed(1)},"iLink send success: quota decremented"),this.checkAndSendReminder(e,r).catch(l=>{h.warn({channelId:this.id,chatId:e.slice(0,12)},`Reminder send failed: ${String(l)}`)}),a}catch(c){if(c instanceof Error&&c.message.includes("ret=-2"))return r.quotaRemaining=0,Y(this.id,this.sessions),h.warn({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:0},"iLink quota exhausted (ret=-2 confirmed), message queued"),this.enqueueMessage(e,n),`queued-${Z()}`;throw c}}onMessage(e){this.messageHandler=e}async sendTypingIndicator(e){if(ce(this.id))return;let n=Pe(this.id,e);try{await Ye({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{ilink_user_id:e,status:it.TYPING}})}catch{}}updateConfig(e){Object.assign(this.config,e)}buildItemList(e){if(!e.content)return;let n={type:_.TEXT,text_item:{text:e.content}};if(e.replyToMessageId){let r=(e.quoteExcerpt??"").slice(0,80);n.ref_msg={message_item:{msg_id:e.replyToMessageId,text_item:{text:r}},title:e.quoteTitle}}return[n]}getOrCreateSession(e){let n=this.sessions.get(e);return n||(n={lastUserMessageAt:0,quotaRemaining:0},this.sessions.set(e,n)),n}isSessionActive(e){return e.lastUserMessageAt>0&&Date.now()-e.lastUserMessageAt<=ve}getSessionRemainingMs(e){return e.lastUserMessageAt===0?0:Math.max(0,ve-(Date.now()-e.lastUserMessageAt))}enqueueMessage(e,n){let r=this.pendingQueue.get(e);r||(r=[],this.pendingQueue.set(e,r));let s=Date.now();r=r.filter(i=>s-i.queuedAt<Ct),r.length>=Cn&&(r.shift(),h.warn({channelId:this.id,chatId:e.slice(0,12)},"Queue full, dropping oldest message")),r.push({message:n,queuedAt:s}),this.pendingQueue.set(e,r),h.info({channelId:this.id,chatId:e.slice(0,12),queueDepth:r.length},"Message enqueued")}async flushQueue(e){let n=this.pendingQueue.get(e);if(!n||n.length===0)return;let r=this.getOrCreateSession(e),s=Math.min(n.length,Math.max(0,r.quotaRemaining-2));if(s<=0){h.info({channelId:this.id,chatId:e.slice(0,12),quotaRemaining:r.quotaRemaining},"Queue flush skipped: insufficient quota (reserving 2 for conversation)");return}h.info({channelId:this.id,chatId:e.slice(0,12),queueDepth:n.length,sending:s,quotaRemaining:r.quotaRemaining},"Flushing queued messages");let i=0;for(;i<s&&n.length>0;){let a=n[0];if(Date.now()-a.queuedAt>Ct){n.shift();continue}try{if(await this.sendMessage(e,a.message),n.shift(),i++,r.quotaRemaining<=0)break}catch{h.warn({channelId:this.id,chatId:e.slice(0,12)},"Queue flush: send failed, stopping");break}}n.length===0&&this.pendingQueue.delete(e),h.info({channelId:this.id,chatId:e.slice(0,12),sent:i,remaining:n.length},"Queue flush complete")}async checkAndSendReminder(e,n){let r=Date.now(),s=this.lastReminderAt.get(e)??0;if(r-s<kn)return;let i=this.getSessionRemainingMs(n),o=r-n.lastUserMessageAt>=An,d=n.quotaRemaining<=Rn;if(!o&&!d)return;let c=(i/36e5).toFixed(1),u;o&&d?u=`[\u7CFB\u7EDF\u63D0\u9192] \u6D88\u606F\u7A97\u53E3\u5373\u5C06\u5173\u95ED\uFF08\u5269\u4F59${c}\u5C0F\u65F6/${n.quotaRemaining}\u6761\u914D\u989D\uFF09\u3002\u8BF7\u56DE\u590D\u4EFB\u610F\u6D88\u606F\u4EE5\u4FDD\u6301\u8FDE\u63A5\u3002`:o?u=`[\u7CFB\u7EDF\u63D0\u9192] \u6D88\u606F\u7A97\u53E3\u5373\u5C06\u5173\u95ED\uFF08\u5269\u4F59${c}\u5C0F\u65F6\uFF09\u3002\u8BF7\u56DE\u590D\u4EFB\u610F\u6D88\u606F\u4EE5\u4FDD\u6301\u8FDE\u63A5\u3002`:u=`[\u7CFB\u7EDF\u63D0\u9192] \u6D88\u606F\u914D\u989D\u5373\u5C06\u7528\u5B8C\uFF08\u5269\u4F59${n.quotaRemaining}\u6761\uFF09\u3002\u8BF7\u56DE\u590D\u4EFB\u610F\u6D88\u606F\u4EE5\u91CD\u7F6E\u914D\u989D\u3002`;let g=Pe(this.id,e);try{await Q({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{msg:{from_user_id:"",to_user_id:e,client_id:Z(),message_type:z.BOT,message_state:H.FINISH,item_list:[{type:_.TEXT,text_item:{text:u}}],context_token:g}}}),n.quotaRemaining--,this.lastReminderAt.set(e,r),Y(this.id,this.sessions),h.info({channelId:this.id,chatId:e.slice(0,12),remainingHours:c,quotaRemaining:n.quotaRemaining,trigger:o?"time":"quota"},"iLink session reminder sent")}catch(f){h.warn({channelId:this.id,chatId:e.slice(0,12)},`Reminder send failed: ${String(f)}`)}}async startLongPoll(){let e=this.pollAbort?.signal,n=0,r=3,s=3e4,i=2e3;for(;!e?.aborted;)try{let a=await Xe({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,get_updates_buf:this.getUpdatesBuf});if(a.ret===Se||a.errcode===Se){at(this.id),this.status="error",h.error({channelId:this.id},"Session expired (errcode=-14), pausing for 1 hour"),await this.sleep(ue,e),dt(this.id),this.status="connected";continue}if(a.ret!==void 0&&a.ret!==0||a.errcode!==void 0&&a.errcode!==0){n++,h.error({channelId:this.id,ret:a.ret,errcode:a.errcode},"getUpdates API error"),n>=r?(n=0,await this.sleep(s,e)):await this.sleep(i,e);continue}n=0,a.get_updates_buf&&(this.getUpdatesBuf=a.get_updates_buf,Sn(this.id,a.get_updates_buf));for(let d of a.msgs??[])await this.processInbound(d)}catch(a){if(e?.aborted)return;n++,h.error({channelId:this.id,error:a},"getUpdates error"),n>=r?(n=0,await this.sleep(s,e)):await this.sleep(i,e)}}async processInbound(e){if(!this.messageHandler)return;let n=!!e.group_id,r=n?e.group_id:e.from_user_id??"",s=e.from_user_id??"";e.context_token&&r&&xn(this.id,r,e.context_token);let i=this.getOrCreateSession(r),a=i.quotaRemaining;i.lastUserMessageAt=Date.now(),i.quotaRemaining=St,Y(this.id,this.sessions),h.info({channelId:this.id,chatId:r.slice(0,12),quotaReset:!0,prevQuota:a,newQuota:St,sessionWindowMs:ve},"iLink session reset: user message received, quota restored"),this.flushQueue(r);let o="",d,c=[],u;for(let m of e.item_list??[]){let l=m.ref_msg?.message_item?.msg_id;if(l){u=l;break}}for(let m of e.item_list??[])m.type===_.TEXT&&m.text_item?.text&&(o+=m.text_item.text),m.type===_.IMAGE&&(d="image",c.push(m)),m.type===_.VOICE&&(d="audio",c.push(m),m.voice_item?.text&&!o&&(o=m.voice_item.text)),m.type===_.FILE&&(d="file",c.push(m)),m.type===_.VIDEO&&(d="video",c.push(m));if(!o&&!d)return;let g;if(c.length>0){let m=this.config.cdnBaseUrl??Mt;try{let l=await bt(c[0],{cdnBaseUrl:m,channelId:this.id});l&&(g=l.path,d=l.type)}catch(l){h.error({channelId:this.id},`Media download failed: ${String(l)}`)}}let f={channelId:this.id,platform:"wechat",chatId:r,senderId:s,content:o,mediaType:d,mediaPath:g,isGroup:n,timestamp:e.create_time_ms??Date.now(),raw:e,...u?{quotedPlatformMessageId:u}:{}};this.messageHandler(f)}getExtensionFromMediaType(e,n){if(n){let r=re(n);if(r&&r!==".bin")return r}switch(e){case"image":return".png";case"video":return".mp4";case"audio":return".mp3";default:return".bin"}}sleep(e,n){return new Promise((r,s)=>{let i=setTimeout(r,e);n?.addEventListener("abort",()=>{clearTimeout(i),s(new Error("aborted"))},{once:!0})})}};C();C();var vn=y("channels"),fe=class{platform="discord";id;config;status="disconnected";messageHandler=null;client=null;constructor(e,n){if(this.id=e,!n.botToken)throw new Error("Discord adapter requires botToken");this.config=n}async connect(){this.status="connecting";try{let{Client:e,GatewayIntentBits:n}=await import("discord.js");this.client=new e({intents:[n.Guilds,n.GuildMessages,n.MessageContent,n.DirectMessages]});let r=this.client;r.on("messageCreate",s=>{if(!this.messageHandler||s.author.bot||this.config.allowedGuildIds?.length&&s.guildId&&!this.config.allowedGuildIds.includes(s.guildId))return;let i={channelId:this.id,platform:"discord",chatId:s.channelId,senderId:s.author.id,senderName:s.author.displayName??s.author.username,content:s.content,isGroup:!!s.guildId,timestamp:s.createdTimestamp,raw:s};this.messageHandler(i)}),await r.login(this.config.botToken),this.status="connected",vn.info({channelId:this.id},"Discord bot connected")}catch(e){throw this.status="error",e}}async disconnect(){this.client&&await this.client.destroy(),this.client=null,this.status="disconnected"}getStatus(){return this.status}getCapabilities(){return{canEdit:!0,canQuote:!0,canParseQuote:!0,canInlineButtons:!0,maxTextLength:2e3,supportsAttachments:!0}}async sendMessage(e,n){if(!this.client)throw new Error("Discord client not connected");let s=await this.client.channels.fetch(e);if(!s||!("send"in s))throw new Error(`Channel ${e} not found or not text channel`);return(await s.send({content:n.content,reply:n.replyToMessageId?{messageReference:n.replyToMessageId}:void 0})).id}onMessage(e){this.messageHandler=e}async sendTypingIndicator(e){if(!this.client)return;let r=await this.client.channels.fetch(e);r&&"sendTyping"in r&&await r.sendTyping()}};import{ImapFlow as zn}from"imapflow";import Hn from"nodemailer";import{existsSync as On,mkdirSync as Nn,readFileSync as Dn,writeFileSync as Fn}from"fs";import{dirname as Ln,join as Ut}from"path";import{homedir as qn}from"os";var $n={lastUid:0,seenMessageIds:[],sentMessageIds:[],updatedAt:0};function Ne(t=process.env.ADAM_TEST_DIR??Ut(qn(),".adam")){return Ut(t,"email-gateway","state.json")}function he(t=Ne()){if(!On(t))return{...$n};let e=JSON.parse(Dn(t,"utf-8"));return{uidValidity:e.uidValidity,lastUid:Number.isInteger(e.lastUid)?e.lastUid:0,seenMessageIds:Array.isArray(e.seenMessageIds)?e.seenMessageIds.filter(Pt):[],sentMessageIds:Array.isArray(e.sentMessageIds)?e.sentMessageIds.filter(Pt):[],updatedAt:typeof e.updatedAt=="number"?e.updatedAt:0}}function ee(t,e=Ne()){Nn(Ln(e),{recursive:!0}),Fn(e,JSON.stringify({...t,updatedAt:Date.now()},null,2),"utf-8")}function vt(t,e){let n=B(e);return n?{...t,seenMessageIds:t.seenMessageIds.includes(n)?t.seenMessageIds:[...t.seenMessageIds,n]}:t}function Bn(t,e){let n=B(e);return n?{...t,sentMessageIds:t.sentMessageIds.includes(n)?t.sentMessageIds:[...t.sentMessageIds,n]}:t}function Ot(t,e=Ne()){let n=Bn(he(e),t);return ee(n,e),n}function B(t){return typeof t=="string"?t.trim():""}function Pt(t){return typeof t=="string"}import{Readable as Gn}from"stream";import{MailParser as Wn}from"mailparser";import{convert as jn}from"html-to-text";async function Dt(t){let e=new Wn({skipImageLinks:!0,skipTextToHtml:!0}),n={},r,s,i,a=[],o,d="",c="",u="",g,f=0,m;if(await new Promise((F,R)=>{e.on("headers",b=>{try{for(let[I,v]of b.entries())n[I.toLowerCase()]=Qn(v);r=Nt(b.get("message-id")),o=Nt(b.get("subject")),u=qt(b.get("content-type"))??"";let P=b.get("date");P instanceof Date&&(g=P.getTime()),s=Ft(b.get("from"),"from"),i=Vn(b.get("reply-to"),"reply-to"),a=Lt(b.get("to"))}catch(P){m=P instanceof Error?P:new Error(String(P))}}),e.on("data",b=>{if(b.type==="attachment"){f+=1,b.release?.(),b.content?.resume?.();return}d=b.text??"",c=typeof b.html=="string"?b.html:""}),e.on("error",R),e.on("end",F),Gn.from([t]).pipe(e)}),m)throw m;if(!s)throw new Error("Inbound email must contain exactly one valid From address");let l=u.toLowerCase()==="text/html",w=d.trim();return(l||!w)&&c.trim()&&(w=jn(c,{wordwrap:!1,selectors:[{selector:"h1",format:"heading",options:{uppercase:!1}},{selector:"h2",format:"heading",options:{uppercase:!1}},{selector:"h3",format:"heading",options:{uppercase:!1}},{selector:"h4",format:"heading",options:{uppercase:!1}},{selector:"h5",format:"heading",options:{uppercase:!1}},{selector:"h6",format:"heading",options:{uppercase:!1}}]}).trim()),!w&&o&&(w=o.trim()),{messageId:r,from:s,replyTo:i,to:a,subject:o,text:w,date:g,rawHeaders:n,attachmentCount:f}}function Ft(t,e){let n=Lt(t);if(n.length!==1){if(n.length===0)return;throw new Error(`Inbound email ${e} must contain exactly one mailbox address`)}return n[0]}function Vn(t,e){if(t)return Ft(t,e)}function Lt(t){return t?typeof t=="string"?[k(t)]:(t.value??[]).map(r=>r.address).filter(r=>typeof r=="string"&&r.trim().length>0).map(r=>k(r)):[]}function Nt(t){if(typeof t=="string")return t;if(Array.isArray(t))return t.map(String).join(", ")}function Qn(t){if(t instanceof Date)return t.toISOString();if(typeof t=="string")return t;if(Array.isArray(t))return t.map(String).join(", ");let e=qt(t);return e||(t&&typeof t=="object"&&"text"in t?String(t.text??""):String(t??""))}function qt(t){if(typeof t=="string")return t;if(t&&typeof t=="object"&&"value"in t){let e=t.value;if(typeof e=="string")return e}}var Kn=1e4,Jn=3e4,Fe=class{imapClient;smtpTransporter;pollTimer;handlers=[];status={status:"stopped"};state=he();async start(e){if(await this.stop(),!e.enabled){this.status={status:"stopped",details:{reason:"disabled"}};return}this.status={status:"starting",lastStartedAt:Date.now()};try{this.imapClient=new zn({host:e.imap.host,port:e.imap.port,secure:e.imap.secure,auth:{user:e.imap.auth.user,pass:e.imap.auth.pass}}),await this.imapClient.connect();let n=await this.imapClient.mailboxOpen(e.imap.mailbox),r=n?.uidValidity?Number(n.uidValidity):void 0;r&&this.state.uidValidity&&r!==this.state.uidValidity?(this.state={...this.state,uidValidity:r,lastUid:0,seenMessageIds:[]},ee(this.state)):r&&(this.state={...this.state,uidValidity:r},ee(this.state)),this.smtpTransporter=Hn.createTransport({host:e.smtp.host,port:e.smtp.port,secure:e.smtp.secure,auth:{user:e.smtp.auth.user,pass:e.smtp.auth.pass}}),await this.smtpTransporter.verify(),this.status={status:"connected",lastStartedAt:Date.now(),lastCheckedAt:Date.now()},this.schedulePoll(e)}catch(n){throw await this.cleanupResources(),this.status={status:"error",lastError:Le(n),details:{stage:this.smtpTransporter?"smtp":"imap"}},n}}async stop(){await this.cleanupResources(),this.status={status:"stopped"}}getStatus(){return{...this.status}}onInbound(e){this.handlers.push(e)}async send(e){if(!this.smtpTransporter)throw new Error("EmailGateway SMTP transporter is not started");let n=await Xn(this.smtpTransporter.sendMail({from:e.from,to:e.to,subject:e.subject,text:e.text,html:e.html,attachments:e.attachments}),Kn,"SMTP send timed out"),r=B(n.messageId);if(!r)throw new Error("SMTP send returned no Message-ID");return this.state=Ot(r),r}isSentByAdam(e){let n=B(e);return n.length>0&&this.state.sentMessageIds.includes(n)}schedulePoll(e){this.pollTimer=setInterval(()=>{this.poll(e)},Jn)}async poll(e){if(this.imapClient)try{this.state=he();let n=`${this.state.lastUid+1}:*`,r=this.imapClient.fetch?.(n,{uid:!0,source:!0,envelope:!0},{uid:!0});if(!r||!r[Symbol.asyncIterator])return;let s=!1;for await(let i of r){let a=Number(i.uid);if(!Number.isInteger(a)||a<=this.state.lastUid)continue;if(!i.source){this.markDegraded(new Error(`IMAP fetch item ${a} is missing source`)),s=!0;break}let o;try{o=await Dt(i.source)}catch(u){this.markDegraded(u),s=!0;break}let d=o.rawHeaders["x-adam-probe-id"],c=B(o.messageId);if(d?.startsWith("adam-probe-")){this.advanceCursor(a);continue}if(c&&this.state.sentMessageIds.includes(c)){this.advanceCursor(a);continue}if(c&&this.state.seenMessageIds.includes(c)){this.advanceCursor(a);continue}try{await Promise.all(this.handlers.map(u=>u(o)))}catch(u){this.markDegraded(u),s=!0;break}this.state=vt(this.state,c),this.advanceCursor(a)}s||(this.status={...this.status,status:"connected",lastCheckedAt:Date.now(),lastError:void 0})}catch(n){this.markDegraded(n)}}advanceCursor(e){this.state={...this.state,lastUid:e},ee(this.state)}markDegraded(e){this.status={...this.status,status:"degraded",lastError:Le(e),lastCheckedAt:Date.now()}}async cleanupResources(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0);let e=this.imapClient,n=this.smtpTransporter;this.imapClient=void 0,this.smtpTransporter=void 0,e&&(await De(e.logout?.()),await De(e.close?.())),await De(n?.close?.())}},$t;function S(){return $t??=new Fe,$t}async function ye(t){await S().start(t)}async function Mr(t,e){await S().stop(),await S().start(t)}async function Sr(t){await S().stop()}async function Xn(t,e,n){let r;try{return await Promise.race([t,new Promise((s,i)=>{r=setTimeout(()=>i(new Error(n)),e)})])}catch(s){throw new Error(Le(s))}finally{r&&clearTimeout(r)}}function Le(t){return t instanceof Error?t.message.replace(/pass(word)?=[^\s]+/gi,"password=****"):"Email gateway operation failed"}async function De(t){t&&typeof t.then=="function"&&await t.catch(()=>{})}C();var we=y("channels"),qe=class{constructor(e){this.gateway=e}gateway;adaptersByAddress=new Map;channelAddressById=new Map;registerAdapter(e,n){if(!Ve(e)||!e.enabled)return;let r=L(e);this.unregisterAdapter(e.id),this.adaptersByAddress.set(r,n),this.channelAddressById.set(e.id,r)}unregisterAdapter(e){let n=this.channelAddressById.get(e);n&&(this.adaptersByAddress.delete(n),this.channelAddressById.delete(e))}refreshFromChannels(e,n){this.adaptersByAddress.clear(),this.channelAddressById.clear();for(let r of e){let s=n.get(r.id);if(s)try{this.registerAdapter(r,s)}catch(i){we.warn({channelId:r.id,error:i},"Invalid email channel skipped during router refresh")}}}async handle(e){if(e.messageId&&this.gateway.isSentByAdam(e.messageId)){we.debug({messageId:e.messageId},"Skipping Adam-sent email");return}let n;try{n=k(e.from)}catch(s){we.warn({from:e.from,error:s},"Skipping email with invalid sender address");return}let r=this.adaptersByAddress.get(n);if(!r){we.info({from:n},"Skipping unmatched inbound email");return}await r.acceptInbound(e)}hasAddress(e){return this.adaptersByAddress.has(k(e))}},be,Bt;function $e(t){return(!be||Bt!==t)&&(be=new qe(t),Bt=t,t.onInbound(e=>be?.handle(e)??Promise.resolve())),be}import{existsSync as Yn}from"fs";import{basename as Zn,isAbsolute as es}from"path";function Gt(t){let e=[];return t.mediaUrl&&e.push({path:t.mediaUrl,mediaType:t.mediaType}),t.attachments&&e.push(...t.attachments),e.map(ts)}function ts(t){let e=t.path.startsWith("file://")?new URL(t.path).pathname:t.path;if(!es(e)||e.includes("://"))throw new Error("Email attachment path must be an absolute local file path");if(!Yn(e))throw new Error(`Email attachment file not found: ${e}`);return{filename:t.filename??Zn(e),path:e,...t.contentType?{contentType:t.contentType}:t.mediaType?{contentType:ns(t.mediaType)}:{}}}function ns(t){return"application/octet-stream"}import ss from"markdown-it";var rs=new ss({html:!1,linkify:!0});function Wt(t){return{text:ze(t),html:rs.render(t)}}function jt(t){let e=t.prefix.trim()||"Adam";return t.messageType==="report"||t.messageType==="status_report"?`[${e} Report]`:t.messageType==="deliver"||t.messageType==="result_delivery"?`[${e} Deliver]`:`[${e}]`}var _e=class{platform="email";id;channel;gateway;handler;inboundDispatchHandler;status="disconnected";identity;constructor(e,n,r={}){this.channel=e,this.gateway=n,this.id=e.id,this.identity=r}async connect(){let e=this.gateway.getStatus();this.status=Ie(e.status)}async disconnect(){this.status="disconnected"}getStatus(){return this.status}getCapabilities(){return{canEdit:!1,canQuote:!1,canParseQuote:!1,canInlineButtons:!1,maxTextLength:Number.POSITIVE_INFINITY,supportsAttachments:!0}}async sendMessage(e,n){let r=k(e),s=L(this.channel);if(r!==s)throw new Error("Email channel recipient does not match configured address");let i=Wt(n.content);return this.gateway.send({from:this.identity.from?Qe(this.identity.from,this.identity.displayName):void 0,to:r,subject:jt({prefix:this.identity.subjectPrefix??"Adam",messageType:n.messageType??"reply"}),text:i.text,html:i.html,attachments:Gt(n)})}onMessage(e){this.handler=e}onInboundDispatch(e){this.inboundDispatchHandler=e}syncGatewayStatus(){this.status=Ie(this.gateway.getStatus().status)}async acceptInbound(e){let n=k(e.from),r={channelId:this.channel.id,platform:"email",chatId:n,senderId:n,senderName:e.from,content:e.text,replyToMessageId:e.messageId,isGroup:!1,timestamp:e.date??Date.now(),raw:{messageId:e.messageId,subject:e.subject,attachmentCount:e.attachmentCount,headers:e.rawHeaders}};this.handler?.(r),this.inboundDispatchHandler&&await this.inboundDispatchHandler(r)}};function Ie(t){switch(t){case"connected":return"connected";case"starting":return"connecting";case"degraded":case"error":return"degraded";case"stopped":return"disconnected";default:return"disconnected"}}var Vt=y("channels"),Be=new Map;async function G(t,e){if(t.hasAdapter(e.id))return!0;if(e.platform==="wechat"){let n=e.config;return n.botToken?(await t.addChannel(e,new $(e.id,n)),!0):!1}if(e.platform==="discord"){let n=e.config;return n.botToken?(await t.addChannel(e,new fe(e.id,{botToken:n.botToken})),!0):!1}if(e.platform==="email"){L(e);let n=S(),r=j().emailGateway,s=new _e(e,n,{from:r?.smtp?.from||r?.address,displayName:r?.displayName,subjectPrefix:r?.subjectPrefix??"Adam"});Be.set(e.id,s),$e(n).registerAdapter(e,s);try{await is(),await t.addChannel(e,s)}catch(i){throw await W(t,e),i}return!0}return!1}async function Jr(t){for(let e of ne(!0))try{await G(t,e)}catch(n){V(e.id,"error"),Vt.warn({channelId:e.id,platform:e.platform,error:n},"Failed to register built-in channel adapter")}}async function Qt(t,e){e.platform==="email"&&(await W(t,e),e.enabled&&await G(t,e))}async function zt(t,e){await W(t,e)}async function W(t,e){e.platform==="email"&&($e(S()).unregisterAdapter(e.id),Be.delete(e.id),t?.hasAdapter(e.id)&&await t.removeChannel(e.id))}function Xr(t){for(let[e,n]of Be.entries())n.syncGatewayStatus(),V(e,n.getStatus())}async function is(){let t=j().emailGateway;if(!t?.enabled)return;let e=S().getStatus().status;if(!(e!=="stopped"&&e!=="error"))try{await ye(t)}catch(n){Vt.warn({error:as(n)},"EmailGateway start failed during built-in adapter registration")}}function as(t){return t instanceof Error?t.message.replace(/pass(word)?=[^\s]+/gi,"password=****"):"Email gateway operation failed"}var U=p.object({id:p.string().uuid()}),ds=p.object({name:p.string().min(1,"name is required"),platform:p.string().min(1,"platform is required"),config:p.record(p.string(),p.unknown()),enabled:p.boolean().optional().default(!0),linkedRoleId:p.string().optional(),allowedChatIds:p.array(p.string()).optional()}),us=p.object({name:p.string().min(1).optional(),enabled:p.boolean().optional(),config:p.record(p.string(),p.unknown()).optional(),linkedRoleId:p.string().optional(),allowedChatIds:p.array(p.string()).optional(),viewerKey:p.string().min(1).max(100).regex(/^[a-zA-Z0-9_.@:-]+$/,"viewerKey must be alphanumeric or one of _ . @ : -").optional()}),Ge;function li(t){Ge=t}function mi(){return Ge}async function gi(t){let e=Ge;async function n(r){We(r);try{return e&&r.enabled&&await G(e,r),r}catch(s){throw await W(e,r),Te(r.id),s}}t.get("/channels",{schema:{tags:["Channels"],summary:"List channels",querystring:{type:"object",properties:{enabled:{type:"boolean"}}}}},async(r,s)=>({channels:ne(r.query.enabled)})),t.post("/channels",{schema:{tags:["Channels"],summary:"Create a channel",body:{type:"object",required:["name","platform","config"],properties:{name:{type:"string",minLength:1},platform:{type:"string",minLength:1},config:{type:"object"},enabled:{type:"boolean"},linkedRoleId:{type:"string"},allowedChatIds:{type:"array",items:{type:"string"}}}}}},async(r,s)=>{let i=ds.safeParse(r.body);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let{name:a,platform:o,config:d,enabled:c,linkedRoleId:u,allowedChatIds:g}=i.data,f=d;if(o==="email")try{f={...Ee(d)}}catch(l){return s.status(400).send({code:"VALIDATION_ERROR",message:l instanceof Error?l.message:String(l)})}let m={id:os(),name:a,platform:o,enabled:c,status:"disconnected",config:f,linkedRoleId:u,allowedChatIds:g,viewerKey:He(),createdAt:Date.now(),messageCount:0};try{await n(m)}catch(l){return s.status(400).send({code:"VALIDATION_ERROR",message:D(l)})}return s.status(201).send({channel:m})}),t.get("/channels/:id",{schema:{tags:["Channels"],summary:"Get channel by ID",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);return a?{channel:a}:s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),t.patch("/channels/:id",{schema:{tags:["Channels"],summary:"Update channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}},body:{type:"object",properties:{name:{type:"string"},enabled:{type:"boolean"},config:{type:"object"},linkedRoleId:{type:"string"},allowedChatIds:{type:"array",items:{type:"string"}},viewerKey:{type:"string",minLength:1,maxLength:100}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});let o=us.safeParse(r.body);if(!o.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(o.error)});let d={...o.data};if((a.platform==="email"||d.config)&&(d.config||a.config)){let g=d.config??a.config;if(a.platform==="email")try{d.config={...Ee(g)}}catch(f){return s.status(400).send({code:"VALIDATION_ERROR",message:f instanceof Error?f.message:String(f)})}}let c=a.platform==="email"&&(d.enabled!==void 0||d.config!==void 0);te(a.id,d);let u=T(a.id);if(e&&u&&c)try{await Qt(e,u)}catch(g){if(te(a.id,{name:a.name,enabled:a.enabled,status:a.status,config:a.config,linkedRoleId:a.linkedRoleId,allowedChatIds:a.allowedChatIds,lastMessageAt:a.lastMessageAt,messageCount:a.messageCount}),await W(e,u),a.enabled)try{await G(e,a)}catch(f){return s.status(500).send({code:"RESTORE_FAILED",message:D(f)})}return s.status(400).send({code:"VALIDATION_ERROR",message:D(g)})}return{channel:u}}),t.delete("/channels/:id",{schema:{tags:["Channels"],summary:"Delete channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(Te(a.id),e)try{await zt(e,a)}catch(o){t.log.warn({channelId:a.id,error:D(o)},"Failed to clean up built-in channel runtime")}return s.status(204).send()}),t.post("/channels/:id/connect",{schema:{tags:["Channels"],summary:"Connect channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});if(!e)return s.status(501).send({code:"NOT_IMPLEMENTED",message:"Channel manager not initialized"});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(a.platform==="email")try{await cs()}catch(o){let d=S().getStatus();return V(a.id,Ie(d.status)),s.status(409).send({code:"EMAIL_GATEWAY_NOT_READY",message:D(o),gatewayStatus:d})}if(!e.hasAdapter(a.id))try{await G(e,a)}catch(o){return s.status(400).send({code:"VALIDATION_ERROR",message:D(o)})}if(!e.hasAdapter(a.id))return s.status(400).send({code:"NO_ADAPTER",message:"No adapter registered for this channel. Install the appropriate adapter first."});try{await e.connectChannel(a.id);let o=T(a.id)?.status??e.getChannelStatus(a.id);return o!=="connected"?s.status(409).send({code:"CONNECT_INCOMPLETE",message:`Channel connect finished with status "${o}"`,status:o}):{channelId:a.id,status:o}}catch(o){return s.status(500).send({code:"CONNECT_FAILED",message:D(o)})}}),t.post("/channels/:id/disconnect",{schema:{tags:["Channels"],summary:"Disconnect channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});if(!e)return s.status(501).send({code:"NOT_IMPLEMENTED",message:"Channel manager not initialized"});let a=T(i.data.id);return a?(await e.disconnectChannel(a.id),{channelId:a.id,status:"disconnected"}):s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),t.get("/channels/:id/capabilities",{schema:{tags:["Channels"],summary:"Get channel adapter capabilities",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});if(!T(i.data.id))return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(!e)return s.status(503).send({code:"MANAGER_UNAVAILABLE",message:"ChannelManager not initialized"});let o=e.getCapabilities(i.data.id);return o?{capabilities:o}:s.status(404).send({code:"ADAPTER_NOT_REGISTERED",message:"Channel adapter not active"})}),t.get("/channels/:id/messages",{schema:{tags:["Channels"],summary:"Get channel message history",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}},querystring:{type:"object",properties:{limit:{type:"integer",minimum:1,maximum:200,default:50},offset:{type:"integer",minimum:0,default:0}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});let{limit:o=50,offset:d=0}=r.query;return{messages:je(a.id,o,d)}}),t.post("/channels/:id/wechat/qr-start",{schema:{tags:["WeChat"],summary:"Start WeChat QR login",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(a.platform!=="wechat")return s.status(400).send({code:"INVALID_PLATFORM",message:"Channel is not a WeChat channel"});let o=a.config;return await st({apiBaseUrl:o.baseUrl,routeTag:o.routeTag})}),t.post("/channels/:id/wechat/qr-wait",{schema:{tags:["WeChat"],summary:"Wait for WeChat QR scan",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}},body:{type:"object",properties:{sessionKey:{type:"string"},timeoutMs:{type:"number"}}}}},async(r,s)=>{let i=U.safeParse(r.params);if(!i.success)return s.status(400).send({code:"VALIDATION_ERROR",message:p.prettifyError(i.error)});let a=T(i.data.id);if(!a)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(a.platform!=="wechat")return s.status(400).send({code:"INVALID_PLATFORM",message:"Channel is not a WeChat channel"});let o=a.config,{sessionKey:d,timeoutMs:c}=r.body??{},u=await rt({sessionKey:d??"",apiBaseUrl:o.baseUrl,timeoutMs:c??12e4,routeTag:o.routeTag});if(u.connected&&u.botToken){let g={...o,botToken:u.botToken,accountId:u.accountId,baseUrl:u.baseUrl??o.baseUrl,userId:u.userId};if(te(a.id,{config:g}),e){let f=new $(a.id,g),m=T(a.id);m&&await e.addChannel(m,f)}}return{connected:u.connected,accountId:u.accountId,message:u.message}})}function D(t){return t instanceof Error?t.message.replace(/pass(word)?=[^\s]+/gi,"password=****"):String(t)}async function cs(){let t=j().emailGateway;if(!t?.enabled)throw new Error("Email Gateway is disabled. Enable Email Gateway in Settings before connecting Mail channels.");let e=S();e.getStatus().status!=="connected"&&await ye(t);let n=e.getStatus();if(n.status!=="connected"){let r=n.lastError?`: ${n.lastError}`:"";throw new Error(`Email Gateway status is ${n.status}${r}`)}}export{Ot as a,B as b,Dt as c,S as d,Mr as e,Sr as f,Jr as g,Xr as h,li as i,mi as j,gi as k};
|