adam-agent-server 0.3.0 → 0.4.0

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.
@@ -1 +1 @@
1
- import{a,b,c}from"./chunk-LBLERTM4.js";import"./chunk-PQ7KPALO.js";import"./chunk-FDWW245P.js";import"./chunk-L7JP7DUO.js";import"./chunk-PCSZW2PE.js";import"./chunk-SFUS33SO.js";import"./chunk-3DAK2XWP.js";import"./chunk-FCV2DPZQ.js";export{a as OutboundGateway,b as getOutboundGateway,c as isRecentlySent};
1
+ import{a,b,c}from"./chunk-NXTTKAQX.js";import"./chunk-PQ7KPALO.js";import"./chunk-FDWW245P.js";import"./chunk-L7JP7DUO.js";import"./chunk-PCSZW2PE.js";import"./chunk-SFUS33SO.js";import"./chunk-3DAK2XWP.js";import"./chunk-FCV2DPZQ.js";export{a as OutboundGateway,b as getOutboundGateway,c as isRecentlySent};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adam-agent-server",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Goal-driven AI agent orchestration server with Role+Skill model, real-time streaming, and multi-channel delivery",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -26,6 +26,7 @@
26
26
  "@fastify/websocket": "^11.0.0",
27
27
  "better-sqlite3": "^11.0.0",
28
28
  "bree": "^9.2.9",
29
+ "discord.js": "^14.16.0",
29
30
  "chalk": "^5.0.0",
30
31
  "commander": "^13.0.0",
31
32
  "cron-parser": "^5.5.0",
@@ -1 +0,0 @@
1
- import{f as ne}from"./chunk-742NWPTQ.js";import{a as re,b,c as z,d as ie,e as se}from"./chunk-PQ7KPALO.js";import{c as f}from"./chunk-3DAK2XWP.js";import{z as c}from"zod/v4";import{v4 as Ut}from"uuid";import{randomUUID as ue}from"crypto";import We from"crypto";var oe="1.0.0",S="";function qe(e){let t=e.split(".").map(r=>parseInt(r,10)),i=t[0]??0,s=t[1]??0,n=t[2]??0;return(i&255)<<16|(s&255)<<8|n&255}var V=qe(oe),je=35e3,ae=15e3,ze=1e4;function P(){return{channel_version:oe}}function Ve(e){return e.endsWith("/")?e:`${e}/`}function Qe(){let e=We.randomBytes(4).readUInt32BE(0);return Buffer.from(String(e),"utf-8").toString("base64")}function Ge(e){let t={"Content-Type":"application/json",AuthorizationType:"ilink_bot_token","Content-Length":String(Buffer.byteLength(e.body,"utf-8")),"X-WECHAT-UIN":Qe(),"iLink-App-Id":S,"iLink-App-ClientVersion":String(V)};return e.token?.trim()&&(t.Authorization=`Bearer ${e.token.trim()}`),e.routeTag&&(t.SKRouteTag=e.routeTag),t}async function A(e){let t=Ve(e.baseUrl),i=new URL(e.endpoint,t),s=Ge({token:e.token,routeTag:e.routeTag,body:e.body}),n=new AbortController,r=setTimeout(()=>n.abort(),e.timeoutMs);try{let o=await fetch(i.toString(),{method:"POST",headers:s,body:e.body,signal:n.signal});clearTimeout(r);let a=await o.text();if(!o.ok)throw new Error(`${e.label} ${o.status}: ${a}`);return a}catch(o){throw clearTimeout(r),o}}async function de(e){let t=e.timeoutMs??je;try{let i=await A({baseUrl:e.baseUrl,endpoint:"ilink/bot/getupdates",body:JSON.stringify({get_updates_buf:e.get_updates_buf??"",base_info:P()}),token:e.token,routeTag:e.routeTag,timeoutMs:t,label:"getUpdates"});return JSON.parse(i)}catch(i){if(i instanceof Error&&i.name==="AbortError")return{ret:0,msgs:[],get_updates_buf:e.get_updates_buf};throw i}}async function v(e){await A({baseUrl:e.baseUrl,endpoint:"ilink/bot/sendmessage",body:JSON.stringify({...e.body,base_info:P()}),token:e.token,routeTag:e.routeTag,timeoutMs:e.timeoutMs??ae,label:"sendMessage"})}async function ce(e){await A({baseUrl:e.baseUrl,endpoint:"ilink/bot/sendtyping",body:JSON.stringify({...e.body,base_info:P()}),token:e.token,routeTag:e.routeTag,timeoutMs:e.timeoutMs??ze,label:"sendTyping"})}async function le(e){let t=await A({baseUrl:e.baseUrl,endpoint:"ilink/bot/getuploadurl",body:JSON.stringify({filekey:e.filekey,media_type:e.media_type,to_user_id:e.to_user_id,rawsize:e.rawsize,rawfilemd5:e.rawfilemd5,filesize:e.filesize,thumb_rawsize:e.thumb_rawsize,thumb_rawfilemd5:e.thumb_rawfilemd5,thumb_filesize:e.thumb_filesize,no_need_thumb:e.no_need_thumb,aeskey:e.aeskey,base_info:P()}),token:e.token,routeTag:e.routeTag,timeoutMs:e.timeoutMs??ae,label:"getUploadUrl"});return JSON.parse(t)}var Ke=5*6e4,He=35e3,ge="3",y=new Map;function Q(e){return Date.now()-e.startedAt<Ke}function Xe(){for(let[e,t]of y)Q(t)||y.delete(e)}async function pe(e,t,i){let s=e.endsWith("/")?e:`${e}/`,n=new URL(`ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(t)}`,s),r={"iLink-App-Id":S};i&&(r.SKRouteTag=i);let o=await fetch(n.toString(),{headers:r});if(!o.ok){let a=await o.text().catch(()=>"(unreadable)");throw new Error(`Failed to fetch QR code: ${o.status} ${o.statusText} body=${a}`)}return await o.json()}async function Je(e,t,i){let s=e.endsWith("/")?e:`${e}/`,n=new URL(`ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(t)}`,s),r={"iLink-App-Id":S,"iLink-App-ClientVersion":String(V)};i&&(r.SKRouteTag=i);let o=new AbortController,a=setTimeout(()=>o.abort(),He);try{let d=await fetch(n.toString(),{headers:r,signal:o.signal});clearTimeout(a);let l=await d.text();if(!d.ok)throw new Error(`Failed to poll QR status: ${d.status} ${d.statusText}`);return JSON.parse(l)}catch(d){if(clearTimeout(a),d instanceof Error&&d.name==="AbortError")return{status:"wait"};throw d}}async function me(e){let t=e.accountId||ue();Xe();let i=y.get(t);if(!e.force&&i&&Q(i)&&i.qrcodeUrl)return{qrcodeUrl:i.qrcodeUrl,message:"QR code ready. Scan with WeChat.",sessionKey:t};if(!e.apiBaseUrl)return{message:"No baseUrl configured for this WeChat channel.",sessionKey:t};try{let s=e.botType||ge,n=await pe(e.apiBaseUrl,s,e.routeTag),r={sessionKey:t,id:ue(),qrcode:n.qrcode,qrcodeUrl:n.qrcode_img_content,startedAt:Date.now()};return y.set(t,r),{qrcodeUrl:n.qrcode_img_content,message:"Scan the QR code with WeChat to connect.",sessionKey:t}}catch(s){return{message:`Failed to start login: ${String(s)}`,sessionKey:t}}}var Ye=3;async function fe(e){let t=y.get(e.sessionKey);if(!t)return{connected:!1,message:"No active login session. Start QR login first."};if(!Q(t))return y.delete(e.sessionKey),{connected:!1,message:"QR code expired. Please start again."};let i=Math.max(e.timeoutMs??48e4,1e3),s=Date.now()+i,n=1;for(;Date.now()<s;){try{let r=await Je(e.apiBaseUrl,t.qrcode,e.routeTag);switch(t.status=r.status,r.status){case"wait":break;case"scaned":break;case"expired":{if(n++,n>Ye)return y.delete(e.sessionKey),{connected:!1,message:"Login timeout: QR expired multiple times."};try{let o=e.botType||ge,a=await pe(e.apiBaseUrl,o,e.routeTag);t.qrcode=a.qrcode,t.qrcodeUrl=a.qrcode_img_content,t.startedAt=Date.now()}catch(o){return y.delete(e.sessionKey),{connected:!1,message:`QR refresh failed: ${String(o)}`}}break}case"confirmed":return r.ilink_bot_id?(y.delete(e.sessionKey),{connected:!0,botToken:r.bot_token,accountId:r.ilink_bot_id,baseUrl:r.baseurl,userId:r.ilink_user_id,message:"Connected to WeChat successfully!"}):(y.delete(e.sessionKey),{connected:!1,message:"Login failed: server did not return bot ID."})}}catch(r){return y.delete(e.sessionKey),{connected:!1,message:`Login failed: ${String(r)}`}}await new Promise(r=>setTimeout(r,1e3))}return y.delete(e.sessionKey),{connected:!1,message:"Login timeout. Please try again."}}import k,{promises as Y}from"fs";import C from"path";import{homedir as Z}from"os";var O={IMAGE:1,VIDEO:2,FILE:3,VOICE:4},F={NONE:0,USER:1,BOT:2},m={NONE:0,TEXT:1,IMAGE:2,VOICE:3,FILE:4,VIDEO:5},N={NEW:0,GENERATING:1,FINISH:2},ye={TYPING:1,CANCEL:2};var Ze=f("channels"),G=-14,$=3600*1e3,R=new Map;function he(e){let t=Date.now()+$;R.set(e,t),Ze.info({channelId:e},`Session paused until ${new Date(t).toISOString()} (${$/1e3}s)`)}function L(e){let t=R.get(e);return t===void 0?!1:Date.now()>=t?(R.delete(e),!1):!0}function be(e){let t=R.get(e);if(t===void 0)return 0;let i=t-Date.now();return i<=0?(R.delete(e),0):i}function _e(e){R.delete(e)}import Ee from"fs";import Se from"path";import{homedir as at}from"os";import{createCipheriv as et,createDecipheriv as tt}from"crypto";function we(e,t){let i=et("aes-128-ecb",t,null);return Buffer.concat([i.update(e),i.final()])}function xe(e,t){let i=tt("aes-128-ecb",t,null);return Buffer.concat([i.update(e),i.final()])}function Ie(e){return Math.ceil((e+1)/16)*16}function K(e,t){return`${t}/download?encrypted_query_param=${encodeURIComponent(e)}`}function Te(e){return`${e.cdnBaseUrl}/upload?encrypted_query_param=${encodeURIComponent(e.uploadParam)}&filekey=${encodeURIComponent(e.filekey)}`}var Wt=f("channels");function nt(e){let t=Buffer.from(e,"base64");if(t.length===16)return t;if(t.length===32&&/^[0-9a-fA-F]{32}$/.test(t.toString("ascii")))return Buffer.from(t.toString("ascii"),"hex");throw new Error(`aes_key must decode to 16 raw bytes or 32-char hex, got ${t.length} bytes`)}async function Ue(e){let t=await fetch(e);if(!t.ok)throw new Error(`CDN download ${t.status} ${t.statusText}`);return Buffer.from(await t.arrayBuffer())}async function M(e){let{encryptQueryParam:t,aesKeyBase64:i,cdnBaseUrl:s,fullUrl:n}=e,r=nt(i),o=n?.trim()||(t?K(t,s):null);if(!o)throw new Error("CDN download: need full_url or encrypt_query_param");let a=await Ue(o);return xe(a,r)}async function ke(e){let{encryptQueryParam:t,cdnBaseUrl:i,fullUrl:s}=e,n=s?.trim()||(t?K(t,i):null);if(!n)throw new Error("CDN download: need full_url or encrypt_query_param");return Ue(n)}var B=f("channels"),Re=24e3;function rt(e,t){let i=e.byteLength,s=44+i,n=Buffer.allocUnsafe(s),r=0;return n.write("RIFF",r),r+=4,n.writeUInt32LE(s-8,r),r+=4,n.write("WAVE",r),r+=4,n.write("fmt ",r),r+=4,n.writeUInt32LE(16,r),r+=4,n.writeUInt16LE(1,r),r+=2,n.writeUInt16LE(1,r),r+=2,n.writeUInt32LE(t,r),r+=4,n.writeUInt32LE(t*2,r),r+=4,n.writeUInt16LE(2,r),r+=2,n.writeUInt16LE(16,r),r+=2,n.write("data",r),r+=4,n.writeUInt32LE(i,r),r+=4,Buffer.from(e.buffer,e.byteOffset,e.byteLength).copy(n,r),n}async function Ce(e){try{let{decode:t}=await import("silk-wasm");B.debug(`silkToWav: decoding ${e.length} bytes of SILK`);let i=await t(e,Re);B.debug(`silkToWav: decoded duration=${i.duration}ms pcmBytes=${i.data.byteLength}`);let s=rt(i.data,Re);return B.debug(`silkToWav: WAV size=${s.length}`),s}catch(t){return B.warn(`silkToWav: transcode failed, will use raw silk err=${String(t)}`),null}}import it from"path";var st={".pdf":"application/pdf",".doc":"application/msword",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xls":"application/vnd.ms-excel",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".ppt":"application/vnd.ms-powerpoint",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".txt":"text/plain",".csv":"text/csv",".zip":"application/zip",".tar":"application/x-tar",".gz":"application/gzip",".mp3":"audio/mpeg",".ogg":"audio/ogg",".wav":"audio/wav",".mp4":"video/mp4",".mov":"video/quicktime",".webm":"video/webm",".mkv":"video/x-matroska",".avi":"video/x-msvideo",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".bmp":"image/bmp"},ot={"image/jpeg":".jpg","image/jpg":".jpg","image/png":".png","image/gif":".gif","image/webp":".webp","image/bmp":".bmp","video/mp4":".mp4","video/quicktime":".mov","video/webm":".webm","video/x-matroska":".mkv","video/x-msvideo":".avi","audio/mpeg":".mp3","audio/ogg":".ogg","audio/wav":".wav","application/pdf":".pdf","application/zip":".zip","application/x-tar":".tar","application/gzip":".gz","text/plain":".txt","text/csv":".csv"};function D(e){let t=it.extname(e).toLowerCase();return st[t]??"application/octet-stream"}function Me(e){let t=e.split(";")[0].trim().toLowerCase();return ot[t]??".bin"}var U=f("channels"),Pe=100*1024*1024;function dt(e){return Me(e)??".bin"}async function E(e,t,i,s,n=Pe,r){if(e.length>n)throw new Error(`Media too large: ${e.length} bytes exceeds ${n} bytes`);let o=Se.join(at(),".adam","wechat","media",s,i);await Ee.promises.mkdir(o,{recursive:!0});let a;if(r&&/^[a-zA-Z0-9._-]+$/.test(r))a=r;else{let l=t?dt(t):".bin",u=Date.now(),p=Math.random().toString(36).slice(2,7);a=`${u}-${p}${l}`}let d=Se.join(o,a);return await Ee.promises.writeFile(d,e),U.debug(`saveMedia: saved ${e.length} bytes to ${d}`),d}async function Ae(e,t){let{cdnBaseUrl:i,channelId:s}=t;if(e.type===m.IMAGE){let n=e.image_item;if(!n?.media?.encrypt_query_param&&!n?.media?.full_url)return null;let r=n.aeskey?Buffer.from(n.aeskey,"hex").toString("base64"):n.media?.aes_key;try{let o=r?await M({encryptQueryParam:n.media?.encrypt_query_param,aesKeyBase64:r,cdnBaseUrl:i,fullUrl:n.media?.full_url}):await ke({encryptQueryParam:n.media?.encrypt_query_param,cdnBaseUrl:i,fullUrl:n.media?.full_url});return{path:await E(o,"image/png","inbound",s),mimeType:"image/png",type:"image"}}catch(o){return U.error({channelId:s},`Image download/decrypt failed: ${String(o)}`),null}}if(e.type===m.VOICE){let n=e.voice_item;if(!n?.media?.encrypt_query_param&&!n?.media?.full_url||!n?.media?.aes_key)return null;try{let r=await M({encryptQueryParam:n.media.encrypt_query_param,aesKeyBase64:n.media.aes_key,cdnBaseUrl:i,fullUrl:n.media.full_url}),o=await Ce(r);if(o){let a=await E(o,"audio/wav","inbound",s);return U.debug(`Voice: saved WAV to ${a}`),{path:a,mimeType:"audio/wav",type:"audio"}}else{let a=await E(r,"audio/silk","inbound",s);return U.debug(`Voice: silk transcode unavailable, saved raw SILK to ${a}`),{path:a,mimeType:"audio/silk",type:"audio"}}}catch(r){return U.error({channelId:s},`Voice download/transcode failed: ${String(r)}`),null}}if(e.type===m.FILE){let n=e.file_item;if(!n?.media?.encrypt_query_param&&!n?.media?.full_url||!n?.media?.aes_key)return null;try{let r=await M({encryptQueryParam:n.media.encrypt_query_param,aesKeyBase64:n.media.aes_key,cdnBaseUrl:i,fullUrl:n.media.full_url}),o=D(n.file_name??"file.bin");return{path:await E(r,o,"inbound",s,Pe,n.file_name),mimeType:o,type:"file"}}catch(r){return U.error({channelId:s},`File download failed: ${String(r)}`),null}}if(e.type===m.VIDEO){let n=e.video_item;if(!n?.media?.encrypt_query_param&&!n?.media?.full_url||!n?.media?.aes_key)return null;try{let r=await M({encryptQueryParam:n.media.encrypt_query_param,aesKeyBase64:n.media.aes_key,cdnBaseUrl:i,fullUrl:n.media.full_url});return{path:await E(r,"video/mp4","inbound",s),mimeType:"video/mp4",type:"video"}}catch(r){return U.error({channelId:s},`Video download failed: ${String(r)}`),null}}return null}import ut from"path";import H from"crypto";import ct from"fs/promises";var I=f("channels"),W=3;async function lt(e){let{buf:t,uploadFullUrl:i,uploadParam:s,filekey:n,cdnBaseUrl:r,label:o,aeskey:a}=e,d=we(t,a),l=i?.trim(),u;if(l)u=l;else if(s)u=Te({cdnBaseUrl:r,uploadParam:s,filekey:n});else throw new Error(`${o}: CDN upload URL missing (need upload_full_url or upload_param)`);I.debug(`${o}: CDN POST url=${u} ciphertextSize=${d.length}`);let p,_;for(let h=1;h<=W;h++)try{let g=await fetch(u,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:new Uint8Array(d)});if(g.status>=400&&g.status<500){let x=g.headers.get("x-error-message")??await g.text();throw I.error(`${o}: CDN client error attempt=${h} status=${g.status} errMsg=${x}`),new Error(`CDN upload client error ${g.status}: ${x}`)}if(g.status!==200){let x=g.headers.get("x-error-message")??`status ${g.status}`;throw I.error(`${o}: CDN server error attempt=${h} status=${g.status} errMsg=${x}`),new Error(`CDN upload server error: ${x}`)}if(p=g.headers.get("x-encrypted-param")??void 0,!p)throw I.error(`${o}: CDN response missing x-encrypted-param header attempt=${h}`),new Error("CDN upload response missing x-encrypted-param header");I.debug(`${o}: CDN upload success attempt=${h}`);break}catch(g){if(_=g,g instanceof Error&&g.message.includes("client error"))throw g;h<W?I.warn(`${o}: attempt ${h} failed, retrying... err=${String(g)}`):I.error(`${o}: all ${W} attempts failed err=${String(g)}`)}if(!p)throw _ instanceof Error?_:new Error(`CDN upload failed after ${W} attempts`);return{downloadParam:p}}async function X(e){let{filePath:t,toUserId:i,opts:s,cdnBaseUrl:n,mediaType:r,label:o}=e,a=await ct.readFile(t),d=a.length,l=H.createHash("md5").update(a).digest("hex"),u=Ie(d),p=H.randomBytes(16).toString("hex"),_=H.randomBytes(16);I.debug(`${o}: file=${t} rawsize=${d} filesize=${u} md5=${l} filekey=${p}`);let h=await le({...s,filekey:p,media_type:r,to_user_id:i,rawsize:d,rawfilemd5:l,filesize:u,no_need_thumb:!0,aeskey:_.toString("hex")}),g=h.upload_full_url?.trim(),x=h.upload_param;if(!g&&!x)throw new Error(`${o}: getUploadUrl returned no upload URL (need upload_full_url or upload_param)`);let{downloadParam:De}=await lt({buf:a,uploadFullUrl:g||void 0,uploadParam:x??void 0,filekey:p,cdnBaseUrl:n,aeskey:_,label:`${o}[orig filekey=${p}]`});return{filekey:p,downloadEncryptedQueryParam:De,aeskey:_.toString("hex"),fileSize:d,fileSizeCiphertext:u}}async function ve(e){return X({...e,mediaType:O.IMAGE,label:"uploadImageToWeixin"})}async function Oe(e){return X({...e,mediaType:O.VIDEO,label:"uploadVideoToWeixin"})}async function Fe(e){return X({...e,mediaType:O.FILE,label:"uploadFileAttachmentToWeixin"})}var q=f("channels");function gt(){return`adam-wechat-${Date.now()}-${Math.random().toString(36).slice(2,7)}`}function pt(e){let t=e;return t=t.replace(/```[^\n]*\n?([\s\S]*?)```/g,(i,s)=>s.trim()),t=t.replace(/!\[[^\]]*\]\([^)]*\)/g,""),t=t.replace(/\[([^\]]+)\]\([^)]*\)/g,"$1"),t=t.replace(/^\|[\s:|-]+\|$/gm,""),t=t.replace(/^\|(.+)\|$/gm,(i,s)=>s.split("|").map(n=>n.trim()).join(" ")),t}async function J(e){let{to:t,text:i,mediaItem:s,opts:n,label:r}=e,o=[],a=pt(i);a&&o.push({type:m.TEXT,text_item:{text:a}}),o.push(s);let d="";for(let l of o){d=gt();let u={msg:{from_user_id:"",to_user_id:t,client_id:d,message_type:F.BOT,message_state:N.FINISH,item_list:[l],context_token:n.contextToken}};await v({baseUrl:n.baseUrl,token:n.token,routeTag:n.routeTag,body:u})}return q.debug(`${r}: sent to=${t} messageId=${d}`),{messageId:d}}async function mt(e){let{to:t,text:i,uploaded:s,opts:n}=e,r={type:m.IMAGE,image_item:{media:{encrypt_query_param:s.downloadEncryptedQueryParam,aes_key:Buffer.from(s.aeskey).toString("base64"),encrypt_type:1},mid_size:s.fileSizeCiphertext}};return J({to:t,text:i,mediaItem:r,opts:n,label:"sendImageMessage"})}async function ft(e){let{to:t,text:i,uploaded:s,opts:n}=e,r={type:m.VIDEO,video_item:{media:{encrypt_query_param:s.downloadEncryptedQueryParam,aes_key:Buffer.from(s.aeskey).toString("base64"),encrypt_type:1},video_size:s.fileSizeCiphertext}};return J({to:t,text:i,mediaItem:r,opts:n,label:"sendVideoMessage"})}async function yt(e){let{to:t,text:i,fileName:s,uploaded:n,opts:r}=e,o={type:m.FILE,file_item:{media:{encrypt_query_param:n.downloadEncryptedQueryParam,aes_key:Buffer.from(n.aeskey).toString("base64"),encrypt_type:1},file_name:s,len:String(n.fileSize)}};return J({to:t,text:i,mediaItem:o,opts:r,label:"sendFileMessage"})}async function Ne(e){let{filePath:t,to:i,text:s,opts:n,cdnBaseUrl:r}=e,o=D(t),a={baseUrl:n.baseUrl,token:n.token,routeTag:n.routeTag};if(o.startsWith("video/")){q.debug(`sendWeixinMediaFile: uploading video filePath=${t} to=${i}`);let u=await Oe({filePath:t,toUserId:i,opts:a,cdnBaseUrl:r});return ft({to:i,text:s,uploaded:u,opts:n})}if(o.startsWith("image/")){q.debug(`sendWeixinMediaFile: uploading image filePath=${t} to=${i}`);let u=await ve({filePath:t,toUserId:i,opts:a,cdnBaseUrl:r});return mt({to:i,text:s,uploaded:u,opts:n})}let d=ut.basename(t);q.debug(`sendWeixinMediaFile: uploading file attachment filePath=${t} name=${d} to=${i}`);let l=await Fe({filePath:t,fileName:d,toUserId:i,opts:a,cdnBaseUrl:r});return yt({to:i,text:s,fileName:d,uploaded:l,opts:n})}var w=f("channels"),ee=new Map;function Le(e){return C.join(Z(),".adam","wechat",`${e}.context-tokens.json`)}function ht(e){let t=Le(e);try{let i=k.readFileSync(t,"utf-8"),s=JSON.parse(i);for(let[n,r]of Object.entries(s))typeof r=="string"&&r&&ee.set(`${e}:${n}`,r);w.debug({channelId:e,count:Object.keys(s).length},"Restored context tokens from disk")}catch{}}function bt(e,t,i){let s=Le(e);try{let n={};try{let o=k.readFileSync(s,"utf-8");n=JSON.parse(o)}catch{}n[t]=i;let r=C.dirname(s);k.mkdirSync(r,{recursive:!0}),k.writeFileSync(s,JSON.stringify(n),"utf-8")}catch(n){w.warn({channelId:e,userId:t},`Failed to persist context token: ${String(n)}`)}}function _t(e,t,i){ee.set(`${e}:${t}`,i),bt(e,t,i)}function $e(e,t){return ee.get(`${e}:${t}`)}function Be(e){return C.join(Z(),".adam","wechat",`${e}.sync`)}function wt(e){try{return k.readFileSync(Be(e),"utf-8")}catch{return""}}function xt(e,t){let i=Be(e);k.mkdirSync(C.dirname(i),{recursive:!0}),k.writeFileSync(i,t,"utf-8")}var It=0;function Tt(){return`adam-wechat-${Date.now()}-${++It}`}var j=class{platform="wechat";id;config;status="disconnected";messageHandler=null;pollAbort=null;getUpdatesBuf="";constructor(t,i){if(this.id=t,!i.baseUrl)throw new Error("WeChat adapter requires baseUrl");this.config=i}async connect(){if(!this.config.botToken)throw new Error("WeChat adapter requires botToken. Complete QR login first.");this.status="connecting",this.getUpdatesBuf=wt(this.id),ht(this.id),this.pollAbort=new AbortController,this.status="connected",w.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",w.info({channelId:this.id},"WeChat adapter disconnected")}getStatus(){return this.status==="connected"&&L(this.id)?"error":this.status}async sendMessage(t,i){if(L(this.id)){let o=Math.ceil(be(this.id)/6e4);throw new Error(`WeChat session paused, ${o} min remaining. Re-scan QR to reconnect.`)}let s=Tt(),n=$e(this.id,t),r=this.config.cdnBaseUrl??this.config.baseUrl;if(i.mediaUrl)try{let o=await fetch(i.mediaUrl);if(!o.ok)throw new Error(`Failed to fetch media: ${o.status}`);let a=Buffer.from(await o.arrayBuffer()),d=C.join(Z(),".adam","wechat","media","outbound-tmp");await Y.mkdir(d,{recursive:!0});let l=this.getExtensionFromMediaType(i.mediaType),u=C.join(d,`${Date.now()}-${Math.random().toString(36).slice(2,7)}${l}`);await Y.writeFile(u,a);let p=await Ne({filePath:u,to:t,text:i.content??"",opts:{baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,contextToken:n},cdnBaseUrl:r});return await Y.unlink(u).catch(()=>{}),p.messageId}catch(o){throw w.error({channelId:this.id},`sendMessage media handling failed: ${String(o)}`),o}return await v({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{msg:{from_user_id:"",to_user_id:t,client_id:s,message_type:F.BOT,message_state:N.FINISH,item_list:i.content?[{type:m.TEXT,text_item:{text:i.content}}]:void 0,context_token:n}}}),s}onMessage(t){this.messageHandler=t}async sendTypingIndicator(t){if(L(this.id))return;let i=$e(this.id,t);try{await ce({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,body:{ilink_user_id:t,status:ye.TYPING}})}catch{}}updateConfig(t){Object.assign(this.config,t)}async startLongPoll(){let t=this.pollAbort?.signal,i=0,s=3,n=3e4,r=2e3;for(;!t?.aborted;)try{let o=await de({baseUrl:this.config.baseUrl,token:this.config.botToken,routeTag:this.config.routeTag,get_updates_buf:this.getUpdatesBuf});if(o.ret===G||o.errcode===G){he(this.id),this.status="error",w.error({channelId:this.id},"Session expired (errcode=-14), pausing for 1 hour"),await this.sleep($,t),_e(this.id),this.status="connected";continue}if(o.ret!==void 0&&o.ret!==0||o.errcode!==void 0&&o.errcode!==0){i++,w.error({channelId:this.id,ret:o.ret,errcode:o.errcode},"getUpdates API error"),i>=s?(i=0,await this.sleep(n,t)):await this.sleep(r,t);continue}i=0,o.get_updates_buf&&(this.getUpdatesBuf=o.get_updates_buf,xt(this.id,o.get_updates_buf));for(let d of o.msgs??[])await this.processInbound(d)}catch(o){if(t?.aborted)return;i++,w.error({channelId:this.id,error:o},"getUpdates error"),i>=s?(i=0,await this.sleep(n,t)):await this.sleep(r,t)}}async processInbound(t){if(!this.messageHandler)return;t.context_token&&t.from_user_id&&_t(this.id,t.from_user_id??"",t.context_token);let i="",s,n=[];for(let a of t.item_list??[])a.type===m.TEXT&&a.text_item?.text&&(i+=a.text_item.text),a.type===m.IMAGE&&(s="image",n.push(a)),a.type===m.VOICE&&(s="audio",n.push(a),a.voice_item?.text&&!i&&(i=a.voice_item.text)),a.type===m.FILE&&(s="file",n.push(a)),a.type===m.VIDEO&&(s="video",n.push(a));if(!i&&!s)return;let r;if(n.length>0){let a=this.config.cdnBaseUrl??this.config.baseUrl;try{let d=await Ae(n[0],{cdnBaseUrl:a,channelId:this.id});d&&(r=d.path,s=d.type)}catch(d){w.error({channelId:this.id},`Media download failed: ${String(d)}`)}}let o={channelId:this.id,platform:"wechat",chatId:t.from_user_id??"",senderId:t.from_user_id??"",content:i,mediaType:s,mediaPath:r,isGroup:!1,timestamp:t.create_time_ms??Date.now(),raw:t};this.messageHandler(o)}getExtensionFromMediaType(t){switch(t){case"image":return".png";case"video":return".mp4";case"audio":return".mp3";default:return".bin"}}sleep(t,i){return new Promise((s,n)=>{let r=setTimeout(s,t);i?.addEventListener("abort",()=>{clearTimeout(r),n(new Error("aborted"))},{once:!0})})}};var T=c.object({id:c.string().uuid()}),kt=c.object({name:c.string().min(1,"name is required"),platform:c.string().min(1,"platform is required"),config:c.record(c.string(),c.unknown()),enabled:c.boolean().optional().default(!0),linkedRoleId:c.string().optional(),allowedChatIds:c.array(c.string()).optional()}),Rt=c.object({name:c.string().min(1).optional(),enabled:c.boolean().optional(),config:c.record(c.string(),c.unknown()).optional(),linkedRoleId:c.string().optional(),allowedChatIds:c.array(c.string()).optional()}),te;function On(e){te=e}function Fn(){return te}async function Nn(e){let t=te;e.get("/channels",{schema:{tags:["Channels"],summary:"List channels",querystring:{type:"object",properties:{enabled:{type:"boolean"}}}}},async(i,s)=>({channels:ie(i.query.enabled)})),e.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(i,s)=>{let n=kt.safeParse(i.body);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let{name:r,platform:o,config:a,enabled:d,linkedRoleId:l,allowedChatIds:u}=n.data,p={id:Ut(),name:r,platform:o,enabled:d,status:"disconnected",config:a,linkedRoleId:l,allowedChatIds:u,createdAt:Date.now(),messageCount:0};return re(p),s.status(201).send({channel:p})}),e.get("/channels/:id",{schema:{tags:["Channels"],summary:"Get channel by ID",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let r=b(n.data.id);return r?{channel:r}:s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),e.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"}}}}}},async(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let r=b(n.data.id);if(!r)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});let o=Rt.safeParse(i.body);return o.success?(z(r.id,o.data),{channel:b(r.id)}):s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(o.error)})}),e.delete("/channels/:id",{schema:{tags:["Channels"],summary:"Delete channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let r=b(n.data.id);return r?(se(r.id),s.status(204).send()):s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),e.post("/channels/:id/connect",{schema:{tags:["Channels"],summary:"Connect channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});if(!t)return s.status(501).send({code:"NOT_IMPLEMENTED",message:"Channel manager not initialized"});let r=b(n.data.id);if(!r)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(!t.hasAdapter(r.id))return s.status(400).send({code:"NO_ADAPTER",message:"No adapter registered for this channel. Install the appropriate adapter first."});try{return await t.connectChannel(r.id),{channelId:r.id,status:"connected"}}catch(o){return s.status(500).send({code:"CONNECT_FAILED",message:String(o)})}}),e.post("/channels/:id/disconnect",{schema:{tags:["Channels"],summary:"Disconnect channel",params:{type:"object",required:["id"],properties:{id:{type:"string",format:"uuid"}}}}},async(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});if(!t)return s.status(501).send({code:"NOT_IMPLEMENTED",message:"Channel manager not initialized"});let r=b(n.data.id);return r?(await t.disconnectChannel(r.id),{channelId:r.id,status:"disconnected"}):s.status(404).send({code:"NOT_FOUND",message:"Channel not found"})}),e.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(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let r=b(n.data.id);if(!r)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});let{limit:o=50,offset:a=0}=i.query;return{messages:ne(r.id,o,a)}}),e.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(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let r=b(n.data.id);if(!r)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(r.platform!=="wechat")return s.status(400).send({code:"INVALID_PLATFORM",message:"Channel is not a WeChat channel"});let o=r.config;return await me({apiBaseUrl:o.baseUrl,routeTag:o.routeTag})}),e.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(i,s)=>{let n=T.safeParse(i.params);if(!n.success)return s.status(400).send({code:"VALIDATION_ERROR",message:c.prettifyError(n.error)});let r=b(n.data.id);if(!r)return s.status(404).send({code:"NOT_FOUND",message:"Channel not found"});if(r.platform!=="wechat")return s.status(400).send({code:"INVALID_PLATFORM",message:"Channel is not a WeChat channel"});let o=r.config,{sessionKey:a,timeoutMs:d}=i.body??{},l=await fe({sessionKey:a??"",apiBaseUrl:o.baseUrl,timeoutMs:d??12e4,routeTag:o.routeTag});if(l.connected&&l.botToken){let u={...o,botToken:l.botToken,accountId:l.accountId,baseUrl:l.baseUrl??o.baseUrl,userId:l.userId};if(z(r.id,{config:u}),t){let p=new j(r.id,u),_=b(r.id);_&&await t.addChannel(_,p)}}return{connected:l.connected,accountId:l.accountId,message:l.message}})}export{j as a,On as b,Fn as c,Nn as d};
@@ -1,49 +0,0 @@
1
- import{a as A,b as P}from"./chunk-WXN3PSVX.js";import{a as T,b as p}from"./chunk-L7426WNY.js";import{a as u}from"./chunk-L7JP7DUO.js";import{p as x}from"./chunk-HAWA62R2.js";import{a as I,b as l,d as y,f as C}from"./chunk-VF6GJGD6.js";import{d as h}from"./chunk-T25NLVMY.js";import{i as b,l as J}from"./chunk-XNWZZYAV.js";import{c as k}from"./chunk-3DAK2XWP.js";J();import{v4 as d}from"uuid";import{CronExpressionParser as D}from"cron-parser";import{v4 as M}from"uuid";var m=k("scheduler"),w=class{maxRetries=3;baseDelayMs=1e3;async execute(e,t){let s=h(),r=e.config?.fileAccess,i={timeout:e.config?.timeout??s.timeout,approvalRequired:s.approvalRequired,approvalTimeout:s.approvalTimeout,fileAccess:{allowedPaths:[...s.fileAccess.allowedPaths,...r?.allowedPaths??[]],deniedPaths:[...s.fileAccess.deniedPaths,...r?.deniedPaths??[]]},plugins:e.config?.plugins,mcpServers:e.config?.mcpServers,model:e.config?.model??s.model,maxTurns:e.config?.maxTurns??s.maxTurns,maxBudgetUsd:e.config?.maxBudgetUsd??s.maxBudgetUsd,env:{...s.env,...e.config?.env},claudeCodePath:s.claudeCodePath},o={templateId:e.id,executionId:t,stepResults:new Map,config:i},a=this.sortSteps(e.steps);for(let c of a){try{await this.executeStep(c,o)}catch(_){m.error({stepId:c.id,error:_},"Workflow step failed");break}if(o.stepResults.get(c.id)?.status==="failed"){m.warn({stepId:c.id},"Workflow step failed, workflow aborted");break}}m.info({executionId:t,completedSteps:o.stepResults.size,totalSteps:a.length},"Workflow completed")}sortSteps(e){let t=new Set,s=[],r=new Map(e.map(o=>[o.id,o])),i=o=>{if(!t.has(o.id)){if(t.add(o.id),o.dependsOn)for(let a of o.dependsOn){let c=r.get(a);c&&i(c)}s.push(o)}};for(let o of e)i(o);return s}async executeStep(e,t){let s=this.resolveVariables(e.prompt,t.stepResults),r=M();T({id:r,status:"pending",prompt:s,config:t.config,createdAt:Date.now(),parentId:t.executionId,templateId:t.templateId}),m.debug({stepId:e.id,taskId:r},"Created workflow step as task"),u.emit({type:"task_created",taskId:r});let i=await this.executeWithRetry(r,e.id),o=p(r);t.stepResults.set(e.id,{stepId:e.id,taskId:r,status:i==="completed"?"completed":"failed",result:o?.result,error:o?.error})}resolveVariables(e,t){return e.replace(/\{\{([^}]+)\.result\}\}/g,(s,r)=>t.get(r)?.result??`[no result from ${r}]`)}async executeWithRetry(e,t){let s=0;for(;s<this.maxRetries;){if(s++,await this.waitForTaskCompletion(e)==="completed")return"completed";if(s<this.maxRetries){let i=this.baseDelayMs*Math.pow(2,s-1);m.info({stepId:t,attempt:s,maxRetries:this.maxRetries,delayMs:i},"Workflow step failed, retrying"),await this.sleep(i)}}return"failed"}waitForTaskCompletion(e,t=6e5){return new Promise(s=>{let r=Date.now(),i=()=>{if(Date.now()-r>t){s("failed");return}let o=p(e);if(!o){s("failed");return}if(o.status==="completed"){s("completed");return}if(o.status==="failed"||o.status==="cancelled"){s("failed");return}setTimeout(i,500)};i()})}sleep(e){return new Promise(t=>setTimeout(t,e))}};var n=k("scheduler"),v="ai-hourly-digest";function O(){if(l(v)){n.debug({templateId:v},"Built-in template already exists");return}let e={id:v,name:"AI Hourly Digest",description:"\u6BCF\u5C0F\u65F6\u641C\u7D22 AI \u524D\u6CBF\u6587\u7AE0\uFF0C\u603B\u7ED3\u540E\u4FDD\u5B58\u5230 Omnifocus",trigger:{type:"cron",cron:"0 * * * *"},enabled:!0,steps:[{id:"search_ai_news",prompt:`\u641C\u7D22\u8FC7\u53BB 24 \u5C0F\u65F6\u5185\u5173\u4E8E AI/\u4EBA\u5DE5\u667A\u80FD\u7684\u6700\u65B0\u524D\u6CBF\u6587\u7AE0\u3002
2
-
3
- \u641C\u7D22\u6765\u6E90:
4
- 1. Hacker News AI \u677F\u5757 (https://news.ycombinator.com/front?day=1)
5
- 2. ArXiv cs.AI \u6700\u65B0\u8BBA\u6587 (https://arxiv.org/list/cs.AI/recent)
6
- 3. Reddit r/MachineLearning \u70ED\u95E8\u5E16\u5B50
7
-
8
- \u627E\u51FA\u4E00\u7BC7\u6700\u6709\u4EF7\u503C\u3001\u6700\u6709\u6280\u672F\u6DF1\u5EA6\u7684\u6587\u7AE0\u3002
9
-
10
- \u8F93\u51FA\u683C\u5F0F:
11
- - \u6807\u9898\uFF1A[\u6587\u7AE0\u6807\u9898]
12
- - \u6765\u6E90\uFF1A[\u7F51\u7AD9/\u5E73\u53F0\u540D\u79F0]
13
- - \u94FE\u63A5\uFF1A[\u5B8C\u6574 URL]
14
- - \u6838\u5FC3\u4EF7\u503C\uFF1A[1-2 \u53E5\u8BDD\u8BF4\u660E\u4E3A\u4EC0\u4E48\u8FD9\u7BC7\u6587\u7AE0\u503C\u5F97\u770B]`},{id:"summarize_article",dependsOn:["search_ai_news"],prompt:`\u9605\u8BFB\u5E76\u603B\u7ED3\u8FD9\u7BC7\u6587\u7AE0\u3002
15
-
16
- \u6587\u7AE0\u4FE1\u606F:
17
- {{search_ai_news.result}}
18
-
19
- \u8BF7:
20
- 1. \u7528 WebFetch \u83B7\u53D6\u6587\u7AE0\u5B8C\u6574\u5185\u5BB9
21
- 2. \u63D0\u53D6\u6838\u5FC3\u89C2\u70B9\u548C\u6280\u672F\u7EC6\u8282
22
- 3. \u7528\u4E2D\u6587\u5199\u51FA 300-500 \u5B57\u7684\u603B\u7ED3
23
-
24
- \u603B\u7ED3\u7ED3\u6784:
25
- ## \u6838\u5FC3\u53D1\u73B0
26
- [\u6587\u7AE0\u6700\u91CD\u8981\u7684\u53D1\u73B0/\u521B\u65B0\u70B9]
27
-
28
- ## \u6280\u672F\u7EC6\u8282
29
- [\u5173\u952E\u7684\u6280\u672F\u65B9\u6CD5/\u5B9E\u73B0\u7EC6\u8282]
30
-
31
- ## \u5F71\u54CD/\u610F\u4E49
32
- [\u8FD9\u9879\u5DE5\u4F5C\u7684\u610F\u4E49\u6216\u5BF9\u884C\u4E1A\u7684\u5F71\u54CD]
33
-
34
- ## \u539F\u6587\u94FE\u63A5
35
- [\u6587\u7AE0 URL]`},{id:"save_to_omnifocus",dependsOn:["summarize_article"],prompt:`\u5C06\u6587\u7AE0\u603B\u7ED3\u4FDD\u5B58\u5230 Omnifocus\u3002
36
-
37
- \u603B\u7ED3\u5185\u5BB9:
38
- {{summarize_article.result}}
39
-
40
- \u63D0\u53D6\u6587\u7AE0\u6807\u9898\u548C\u5B8C\u6574\u603B\u7ED3\uFF0C\u7136\u540E\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u6DFB\u52A0\u5230 Omnifocus Inbox\uFF1A
41
-
42
- osascript /Users/norvyn/Code/Projects/Adam/scripts/add-to-omnifocus.applescript "[\u6587\u7AE0\u6807\u9898] AI \u524D\u6CBF\u901F\u9012" "[\u5B8C\u6574\u603B\u7ED3\u5185\u5BB9]"
43
-
44
- \u6CE8\u610F\uFF1A
45
- - \u5C06 [\u6587\u7AE0\u6807\u9898] \u66FF\u6362\u4E3A\u5B9E\u9645\u6807\u9898
46
- - \u5C06 [\u5B8C\u6574\u603B\u7ED3\u5185\u5BB9] \u66FF\u6362\u4E3A\u5B8C\u6574\u7684\u603B\u7ED3\u6587\u672C\uFF08\u5305\u542B\u6838\u5FC3\u53D1\u73B0\u3001\u6280\u672F\u7EC6\u8282\u3001\u5F71\u54CD/\u610F\u4E49\u548C\u539F\u6587\u94FE\u63A5\uFF09
47
- - \u603B\u7ED3\u5185\u5BB9\u4F7F\u7528\u6362\u884C\u7B26\u5206\u9694\u5404\u90E8\u5206
48
-
49
- \u5B8C\u6210\u540E\u8F93\u51FA\uFF1A\u5DF2\u4FDD\u5B58\u5230 Omnifocus\uFF1A[\u4EFB\u52A1\u6807\u9898]`}],config:{timeout:300,fileAccess:{allowedPaths:["~/.adam/","/Users/norvyn/Code/Projects/Adam/scripts/"],deniedPaths:[]}},tags:["ai","digest","hourly","automation"],createdAt:Date.now()};I(e),n.info({templateId:v,cron:"0 * * * *"},"Registered built-in AI Hourly Digest template")}var R=class{cronJobs=new Map;workflowExecutor=new w;started=!1;taskCompletionHandler=null;async start(){if(this.started)return;this.started=!0,O();let e=y(!0),t=0;for(let r of e)r.trigger.type==="cron"&&r.trigger.cron&&(this.scheduleCronJob(r),t++);let s=0;for(let r of e)r.trigger.type==="once"&&r.trigger.runAt&&(this.scheduleOnceJob(r.id),s++);this.taskCompletionHandler=r=>{r.newStatus==="completed"&&this.checkEventTriggers(r.taskId).catch(i=>{n.error({taskId:r.taskId,error:i},"Event trigger check failed")})},u.on("task_status_change",this.taskCompletionHandler),this.cronJobs.set("memory-cleanup",setInterval(()=>{this.runMemoryCleanup()},36e5)),n.info({cronCount:t,onceCount:s},"Bree engine started with cron jobs + memory cleanup")}runMemoryCleanup(){try{let e=b(void 0,1e3,0),t=0;for(let s of e)t+=x(s.id);t>0&&n.info({totalCleaned:t},"Memory cleanup completed")}catch(e){n.warn({error:e},"Memory cleanup failed")}}async stop(){for(let[,e]of this.cronJobs)clearTimeout(e),clearInterval(e);this.cronJobs.clear(),this.taskCompletionHandler&&(u.off("task_status_change",this.taskCompletionHandler),this.taskCompletionHandler=null),this.started=!1,n.info("Bree engine stopped")}scheduleCronJob(e){let t=`template-${e.id}`;this.cronJobs.has(t)&&(clearTimeout(this.cronJobs.get(t)),this.cronJobs.delete(t));let s;try{s=D.parse(e.trigger.cron)}catch{n.warn({templateId:e.id,cron:e.trigger.cron},"Invalid cron expression");return}let r=()=>{let f=s.next().getTime()-Date.now();return Math.max(f,1e3)},i=()=>{this.executeCronTrigger(e.id).catch(f=>{n.error({templateId:e.id,error:f},"Cron trigger failed")});let c=setTimeout(i,r());this.cronJobs.set(t,c)},o=r(),a=setTimeout(i,o);this.cronJobs.set(t,a),n.debug({jobName:t,nextRun:new Date(Date.now()+o).toISOString()},"Scheduled cron job")}async executeCronTrigger(e){let t=l(e);!t||!t.enabled||(n.info({templateName:t.name},"Cron triggered"),await this.executeWorkflow(t,d()))}async scheduleJob(e){let t=l(e);t&&t.trigger.type==="cron"&&t.trigger.cron&&this.scheduleCronJob(t)}async unscheduleJob(e){let t=`template-${e}`,s=this.cronJobs.get(t);s&&(clearTimeout(s),this.cronJobs.delete(t))}async runNow(e){let t=l(e);if(!t)throw new Error(`Template ${e} not found`);let s=d();return this.executeWorkflow(t,s).catch(r=>{n.error({templateId:e,error:r},"Workflow execution failed")}),s}async checkEventTriggers(e){let t=p(e);if(!t)return;let s=y(!0),r=s.filter(i=>i.trigger.type==="event"&&i.trigger.event==="task_complete");for(let i of r)n.debug({templateName:i.name},"Event trigger matched"),await this.executeWorkflow(i,d());if(t.templateId){let i=s.filter(o=>o.trigger.type!=="event"||!o.trigger.event?!1:o.trigger.event===`template_complete:${t.templateId}`);for(let o of i)n.info({templateName:o.name,sourceTemplateId:t.templateId},"Template complete trigger matched"),await this.executeWorkflow(o,d())}}async executeWorkflow(e,t){if(n.info({templateName:e.name,executionId:t},"Executing workflow"),e.goalIds&&e.goalIds.length>0){for(let s of e.goalIds){let r=P(s);if(!r){n.warn({goalId:s,templateId:e.id},"Goal reference not found, skipping");continue}let i=d();A({id:i,name:r.name,description:r.description,roleId:r.roleId,metricType:r.metricType,targetValue:r.targetValue,currentValue:0,deadline:r.deadline,budgetUsd:r.budgetUsd,status:"active",createdAt:Date.now(),sourceSessionId:e.sourceSessionId,deliverTo:e.deliverTo,reportTo:e.reportTo});let o=d();T({id:o,status:"pending",prompt:`Decompose and execute goal: ${r.name}. ${r.description??""}`,parentId:i,config:h(),createdAt:Date.now(),templateId:e.id}),u.emit({type:"task_created",taskId:o}),n.info({templateId:e.id,sourceGoalId:s,newGoalId:i,taskId:o},"Goal reference triggered, dispatched decomposition task")}return}await this.workflowExecutor.execute(e,t)}scheduleOnceJob(e){let t=l(e);if(!t||!t.enabled||t.trigger.type!=="once")return;let r=(t.trigger.runAt?new Date(t.trigger.runAt).getTime():0)-Date.now();if(r<=0){n.info({templateId:e,runAt:t.trigger.runAt},"Once-shot template past due, executing immediately"),this.executeOnceTrigger(e).catch(a=>{n.error({templateId:e,error:a},"Once trigger execution failed")});return}let i=`template-${e}`;this.cronJobs.has(i)&&clearTimeout(this.cronJobs.get(i));let o=setTimeout(()=>{this.cronJobs.delete(i),this.executeOnceTrigger(e).catch(a=>{n.error({templateId:e,error:a},"Once trigger execution failed")})},r);this.cronJobs.set(i,o),n.info({templateId:e,runAt:t.trigger.runAt,delayMs:r},"Scheduled once-shot job")}async executeOnceTrigger(e){let t=l(e);!t||!t.enabled||(n.info({templateName:t.name},"Once-shot triggered"),await this.executeWorkflow(t,d()),C(e),n.info({templateId:e},"Once-shot template auto-disabled after execution"))}},S=null;function Y(){return S}function Z(g){S=g}export{R as a,Y as b,Z as c};
@@ -1,3 +0,0 @@
1
- import{b as M}from"./chunk-PQ7KPALO.js";import{b as k,c as h,d as w}from"./chunk-FDWW245P.js";import{a as p}from"./chunk-L7JP7DUO.js";import{c as b}from"./chunk-3DAK2XWP.js";function $(n,c,s){switch(c){case"wechat":return D(n);case"telegram":return n;case"slack":return R(n);case"webhook":return JSON.stringify({result:n,taskId:s,timestamp:new Date().toISOString()});default:return D(n)}}function D(n){return n.replace(/^#{1,6}\s+/gm,"").replace(/\*\*(.+?)\*\*/g,"$1").replace(/\*(.+?)\*/g,"$1").replace(/__(.+?)__/g,"$1").replace(/_(.+?)_/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/```[\s\S]*?```/g,c=>c.replace(/```\w*\n?/g,"").trim()).replace(/\[([^\]]+)\]\([^)]+\)/g,"$1").replace(/!\[([^\]]*)\]\([^)]+\)/g,"$1").replace(/\n{3,}/g,`
2
-
3
- `).trim()}function R(n){return n.replace(/\*\*(.+?)\*\*/g,"*$1*").replace(/\[([^\]]+)\]\(([^)]+)\)/g,"<$2|$1>")}import{v4 as O}from"uuid";var C=b("adam"),I=class{_dedupCache=new Map;_rateLimitWindows=new Map;_recentlySentIds=new Set;isRecentlySent(c){return this._recentlySentIds.has(c)}async send(c){let{taskId:s,channelId:a,chatId:l,content:y,messageType:d,platform:x,webhookUrl:m,replyMarkup:S}=c,T=d!=="reply"&&!!s,r;if(T){r=`${s}:${a??"none"}:${l??"none"}:${d}`;let t=this._dedupCache.get(r);if(t&&Date.now()-t.timestamp<300*1e3)return C.debug({dedupKey:r},"Dedup hit, returning cached log entry"),{success:!0,logEntryId:t.logEntryId}}if(a){let t=Date.now(),i=6e4,o=this._rateLimitWindows.get(a);o||(o=[],this._rateLimitWindows.set(a,o));let u=t-i;for(;o.length>0&&o[0]<u;)o.shift();if(o.length>=60){let f=O();return C.warn({channelId:a,count:o.length},"Rate limited, not sending"),{success:!1,logEntryId:f,error:"rate_limited"}}o.push(t)}let E=x??(a?M(a)?.platform:void 0)??"unknown",v=m?y:$(y,E,s),e=O(),g={id:e,ruleId:void 0,taskId:s??void 0,status:"pending",target:a&&l?{type:"channel",channelId:a,chatId:l}:m?{type:"webhook",webhookUrl:m}:{type:"channel",channelId:a??"",chatId:l??""},content:v,attempts:0,createdAt:Date.now(),expiresAt:Date.now()+1440*60*1e3,source:"direct",messageType:d};k(g),r&&this._dedupCache.set(r,{logEntryId:e,timestamp:Date.now()});try{if(m){let t=await fetch(m,{method:"POST",body:JSON.stringify({result:y,taskId:s,timestamp:new Date().toISOString()}),signal:AbortSignal.timeout(1e4)});if(t.ok)return w(e),p.emit({type:"delivery_status_change",logEntryId:e,taskId:s,target:g.target,status:"delivered",messageType:d}),{success:!0,logEntryId:e};{let i=`Webhook returned ${t.status}`;return h(e,"failed",i),r&&this._dedupCache.delete(r),p.emit({type:"delivery_status_change",logEntryId:e,taskId:s,target:g.target,status:"failed",error:i,messageType:d}),{success:!1,logEntryId:e,error:i}}}else if(a&&l){let{getChannelManager:t}=await import("./channels-WFZAONF3.js"),i=t();if(!i){let f="ChannelManager not available";return h(e,"failed",f),r&&this._dedupCache.delete(r),p.emit({type:"delivery_status_change",logEntryId:e,taskId:s,target:g.target,status:"failed",error:f,messageType:d}),{success:!1,logEntryId:e,error:f}}let o={content:v,...S?{replyMarkup:S}:{}},u=await i.sendMessage(a,l,o);return u&&(this._recentlySentIds.add(u),setTimeout(()=>this._recentlySentIds.delete(u),300*1e3)),w(e),p.emit({type:"delivery_status_change",logEntryId:e,taskId:s,target:g.target,status:"delivered",messageType:d}),{success:!0,messageId:u??void 0,logEntryId:e}}else{let t="No channelId/chatId or webhookUrl provided";return h(e,"failed",t),r&&this._dedupCache.delete(r),{success:!1,logEntryId:e,error:t}}}catch(t){let i=t instanceof Error?t.message:String(t);return h(e,"failed",i),r&&this._dedupCache.delete(r),p.emit({type:"delivery_status_change",logEntryId:e,taskId:s,target:g.target,status:"failed",error:i,messageType:d}),{success:!1,logEntryId:e,error:i}}}},_=null;function L(){return _||(_=new I),_}function J(n){return L().isRecentlySent(n)}export{I as a,L as b,J as c};