@superclawd-ai/fda 0.1.63 → 0.1.64

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.
@@ -578,7 +578,7 @@ ${i.join(`
578
578
  ${n}`:""}`;if(!r)return this.postMarkdown(e,i,`Question: ${t}`,{live:this.endLive(e),final:1}),this.status(e);let o=Zi(this.clean(i),e.id,{...r,options:r.options.map(a=>this.clean(a))});this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:this.clean(`Question: ${t}`),blocks:o.blocks,overflow:o.overflow,choicesId:r.id,live:this.endLive(e),final:1}),this.status(e)}plan(e,t,n){let r=Yi(this.clean(t.markdown),t.version,e.id,n?this.clean(n):null);this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:r.text,blocks:r.blocks,overflow:r.overflow,planVersion:t.version,live:this.endLive(e),final:1}),this.status(e)}handoff(e,t,n){let r=o=>o.replace(/[^A-Z0-9]/gi,""),i=`<@${r(t.to)}> ${this.clean(t.task)}
579
579
 
580
580
  _Hand-off for <@${r(t.requester)}>: react with \u2705 to approve it (only <@${r(t.requester)}> can)._`;this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:i.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:i.slice(0,2900)}}],overflow:null,metadata:n})}failed(e,t){this.postMarkdown(e,t,t,{live:this.endLive(e),final:1}),this.status(e)}cancelled(e,t){let n=t?`Stopped by <@${t}>.`:"Stopped.";this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:n,blocks:[],overflow:null,live:this.endLive(e)}),this.status(e)}conversationPost(e,t,n,r={}){let i=new Set(pe(t).map(a=>a.id)),o=qo(this.redactor.redact(n).text,i);this.add(t.channel_id,e.id,{op:"post",requestId:e.id,threadTs:null,text:o.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:o.slice(0,3e3)}}],overflow:null,...r.opening?{conversationOpen:t.id}:{}})}conversationNote(e,t){let n=this.redactor.redact(t).text.replace(/<!(channel|here|everyone|subteam)[^>]{0,200}>/gi,"").slice(0,2900);this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:n,blocks:[{type:"section",text:{type:"mrkdwn",text:n}}],overflow:null})}conversationReply(e,t,n){let r=this.store.getConversation(t);if(!r){let o=n.trim()||"Done.";return this.postMarkdown(e,o,o,{live:this.endLive(e),final:1}),this.status(e)}let i=this.endLive(e);n.trim()&&this.conversationPost(e,r,n),i&&this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:"Replied in the conversation.",blocks:[],overflow:null,live:i}),this.status(e)}info(e,t,n={}){this.postMarkdown(e,t,t,n.final?{live:this.endLive(e)}:{})}dropProgress(e){this.store.outboxDropPendingUpdates(e.id)}progress(e,t){this.postMarkdown(e,t,t,{progress:1})}scheduleCard(e,t){let n=to({...t,title:this.clean(t.title),prompt:this.clean(t.prompt)});this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:n.text,blocks:n.blocks,overflow:null,scheduleId:t.id})}prAnnounce(e,t,n){let i=[`:eyes: *${this.clean(n.title).replace(/[*\n]/g," ").trim().slice(0,200)||"Pull request"}*`,`${n.prLink}${n.ticketLink?` \xB7 Ticket ${n.ticketLink}`:""}`,...n.reviewers.length?[`Review: ${n.reviewers.join(", ")}`]:[]].join(`
581
- `);this.add(e,null,{op:"post",requestId:null,threadTs:null,text:i.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:i.slice(0,2900)}}],overflow:null,prFollowId:t})}reactTo(e,t,n){n.length&&this.add(e,null,{op:"react",requestId:"",reaction:n[0],ts:t,fallbacks:n.slice(1)})}dm(e,t){this.add(e,null,{op:"dm",user:e,text:this.clean(t)})}ephemeral(e,t,n,r){this.add(e,null,{op:"ephemeral",user:t,threadTs:n,text:r})}upload(e,t,n,r){this.add(e.channel_id,e.id,{op:"upload",requestId:e.id,threadTs:e.thread_ts,path:t,filename:n,title:this.clean(r)})}update(e,t,n,r,i){this.add(e,t,{op:"update",ts:n,text:r,blocks:i})}};import rd from"node:fs";var K=class extends Error{constructor(t,n=null){super(t);this.code=t;this.retryAfterSec=n}};function id(s){return s.status==="awaiting_input"||s.status==="awaiting_approval"||s.plan_status==="proposed"?"suspended":s.status==="queued"||s.status==="running"?"processing":"active"}var od=new Set(["feature_disabled","unknown_method","missing_scope","not_allowed_token_type","no_permission","access_denied"]),ad=6*36e5,ld=new Set(["invalid_auth","account_inactive","token_revoked","not_authed","missing_scope","token_expired"]),la=new Set(["channel_not_found","is_archived","not_in_channel","thread_not_found","message_not_found","cant_update_message","msg_too_long","no_text","user_not_in_channel","file_not_found"]),ud=5,cd=new Set(["user_not_found","user_disabled","cannot_dm_bot","user_not_visible","not_allowed_token_type"]),on=class{constructor(e){this.d=e;this.now=e.now??Date.now}timer=null;busy=!1;stopped=!1;halted=!1;now;lastLive=new Map;dmScopeLogged=!1;sessionsOffUntil=0;lastSession=new Map;start(){this.stopped=!1,this.halted=!1,this.wake()}resume(){this.halted&&(this.halted=!1,this.d.store.outboxRetryNow(this.now()),this.wake())}stop(){this.stopped=!0,this.timer&&clearTimeout(this.timer)}wake(){this.stopped||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),0))}inflight=null;idle(){return this.inflight??Promise.resolve()}drain(){return this.busy||this.stopped||this.halted?this.idle():(this.inflight=this.drainOnce().finally(()=>{this.inflight=null}),this.inflight)}async drainOnce(){let e=this.d.lane==="tickets"?null:this.d.slack();if(!e&&this.d.lane!=="tickets")return;this.busy=!0;try{for(;;){let n=this.d.store.outboxDue(this.now(),20,this.d.lane);if(!n.length)break;for(let r of n){if(this.halted||this.stopped)break;await this.send(e,r)}if(this.halted||this.stopped)return}}finally{this.busy=!1}let t=this.d.store.outboxNextWakeAt(this.d.lane);t!==null&&!this.stopped&&(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),Math.max(50,t-this.now())),this.timer.unref?.())}async send(e,t){let{store:n}=this.d,r;try{r=JSON.parse(t.payload)}catch{n.outboxFinal(t.id,"dropped","bad payload");return}try{let i=await this.execute(e,t.channel,r);n.outboxSent(t.id,i)}catch(i){let o=i instanceof K?i.code:String(i?.message??i);i instanceof K&&o==="ratelimited"?n.outboxRetry(t.id,this.now()+Math.max(1,i.retryAfterSec??30)*1e3,o):ld.has(o)?(n.outboxHold(t.id,this.now()+36e5,o),this.halted=!0,this.d.onFatal(o)):la.has(o)||t.attempts+1>=ud?(n.outboxFinal(t.id,"dropped",o),this.d.onDropped?.(o,t.channel)):o==="invalid_blocks"&&r.op==="post"?(n.outboxFinal(t.id,"dropped",o),n.outboxAdd({requestId:r.requestId,channel:t.channel,kind:"post",payload:{...r,blocks:[]}})):n.outboxRetry(t.id,this.now()+2**t.attempts*1e3,o)}}metadataFor(e){if(e.metadata)return e.metadata;if(e.requestId){if(e.final)try{let t=this.d.threadBlock?.(e.requestId,e.text);if(t)return t}catch{}return{event_type:"fda_message",event_payload:{request:e.requestId}}}}async finishLive(e,t,n,r){let{store:i}=this.d,o=i.getRequest(n.requestId),a=o?.status_ts??null,l=()=>{o&&i.updateRequest(o.id,{status_ts:null},o.updated_at),o&&this.lastLive.delete(o.id)};if(a&&!r.handoff)try{return await e.updateMessage({channel:t,ts:a,text:n.text,blocks:n.blocks,metadata:n.final?this.metadataFor(n):void 0}),n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,a),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,a),l(),a}catch(c){if(!(c instanceof K)||la.has(c.code)===!1)throw c}let u=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});if(n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,u.ts),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,u.ts),a){let c=Vi(this.now()-r.since);await e.updateMessage({channel:t,ts:a,text:c.text,blocks:c.blocks}).catch(()=>{})}return l(),u.ts}async execute(e,t,n){let{store:r}=this.d;if(t.startsWith("tk:"))return this.d.tickets?this.d.tickets(t,n):null;switch(n.op){case"post":{if(n.live&&n.requestId)return this.finishLive(e,t,n,n.live);let i=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});return n.planVersion&&n.requestId&&r.setPlanMessageTs(n.requestId,n.planVersion,i.ts),n.choicesId&&n.requestId&&r.setChoicesMessageTs(n.requestId,n.choicesId,i.ts),n.scheduleId&&r.updateSchedule(n.scheduleId,{card_ts:i.ts}),n.prFollowId&&r.updatePrFollow(n.prFollowId,{announce_ts:i.ts}),n.conversationOpen&&r.setConversationOpenedTs(n.conversationOpen,i.ts),i.ts}case"dm":{let i;try{if(!e.openDm)throw new K("missing_scope");i=await e.openDm(n.user)}catch(a){let l=a instanceof K?a.code:"";if(l==="missing_scope")return this.dmScopeLogged||this.d.log?.("slack: a direct message was skipped: the Slack app needs the im:write scope (add it under OAuth & Permissions and reinstall the app)"),this.dmScopeLogged=!0,null;if(cd.has(l))return null;throw a}return(await e.postMessage({channel:i,text:n.text})).ts}case"status":{if(!n.live)return null;let i=r.getRequest(n.requestId);if(!i||i.live_since!==n.live.since)return i&&this.lastLive.delete(i.id),null;let o=Nn({step:n.live.step,handoff:i.live_handoff===1,queued:i.status==="queued"&&this.now()-n.live.since>1500,icons:n.live.icons,stopFor:this.d.stopButton?.()?i.id:null}),a=JSON.stringify(o.blocks);if(i.status_ts)return this.lastLive.get(i.id)===a||(await e.updateMessage({channel:t,ts:i.status_ts,text:o.text,blocks:o.blocks}),this.lastLive.set(i.id,a)),i.status_ts;let l=null;try{l=this.d.presenceBlock?.(i.id)??null}catch{}let u=await e.postMessage({channel:t,threadTs:i.thread_ts,text:o.text,blocks:o.blocks,...l?{metadata:l}:{}});return r.updateRequest(i.id,{status_ts:u.ts},i.updated_at),this.lastLive.set(i.id,a),u.ts}case"session":{if(!e.setAgentSession||this.now()<this.sessionsOffUntil)return null;let i=r.getRequest(n.requestId);if(!i?.thread_ts)return null;let o=id(i),a=i.title.trim(),l=this.lastSession.get(i.id);if(l?.status===o&&l.title===a)return null;try{await e.setAgentSession({channel:t,threadTs:i.thread_ts,status:o,title:a||void 0}),a&&l&&l.title!==a&&await e.renameAgentSession?.({channel:t,threadTs:i.thread_ts,title:a}),this.lastSession.set(i.id,{status:o,title:a})}catch(u){let c=u instanceof K?u.code:"";od.has(c)&&(this.sessionsOffUntil||this.d.log?.(`slack: agent sessions are off for this app (${c}); turn on the Agent experience in the Slack app settings to show progress and a stop button`),this.sessionsOffUntil=this.now()+ad)}return o==="active"&&this.lastSession.delete(i.id),null}case"react":{if(n.ts){for(let l of[n.reaction,...n.fallbacks??[]])try{return await e.addReaction(t,n.ts,l),null}catch(u){if(!(u instanceof K)||u.code!=="invalid_name")throw u}return null}let i=r.getRequest(n.requestId);if(!i)return null;let o=i.status_reaction;if(o===n.reaction)return null;let a=o?[o]:aa.filter(l=>l!==n.reaction);for(let l of a)await e.removeReaction(t,i.origin_ts,l);return await e.addReaction(t,i.origin_ts,n.reaction),r.updateRequest(i.id,{status_reaction:n.reaction},i.updated_at),null}case"ephemeral":return await e.postEphemeral({channel:t,user:n.user,text:n.text,threadTs:n.threadTs}),null;case"upload":{let i=rd.readFileSync(n.path);return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:i}),null}case"text_file":return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:Buffer.from(n.content,"utf8")}),null;case"update":return await e.updateMessage({channel:t,ts:n.ts,text:n.text,blocks:n.blocks}),n.ts}}};import{SocketModeClient as dd}from"@slack/socket-mode";var Zn=class{constructor(e){this.d=e}client=null;async start(){let e=new dd({appToken:this.d.appToken,logLevel:void 0});this.client=e,e.on("slack_event",async t=>{try{this.d.receive({type:t.type,envelope_id:t.envelope_id,body:t.body})}catch(n){this.d.log(`inbox insert failed: ${String(n)}`);return}try{await t.ack()}catch{}this.d.onReceived()}),e.on("connected",()=>this.d.onConnected()),e.on("disconnected",()=>this.d.onDisconnected()),await e.start()}async stop(){let e=this.client;if(this.client=null,e)try{await e.disconnect()}catch{}}};import{WebClient as br}from"@slack/web-api";var pd="files.slack.com";function hd(s){let e=s;throw e?.code==="slack_webapi_rate_limited_error"?new K("ratelimited",e.retryAfter??30):e?.data?.error?new K(e.data.error):e?.code==="slack_webapi_request_error"?new K("network_error"):new K(e?.message??"unknown_error")}async function J(s){try{return await s}catch(e){hd(e)}}var an=class{constructor(e){this.token=e;this.post=new br(e,{retryConfig:{retries:0},rejectRateLimitedCalls:!0,timeout:15e3}),this.read=new br(e,{retryConfig:{retries:3},timeout:15e3}),this.background=new br(e,{retryConfig:{retries:2},timeout:15e3})}post;read;background;async authTest(){let e=await J(this.read.auth.test());return{userId:String(e.user_id),botId:e.bot_id??null,teamId:String(e.team_id),team:String(e.team),user:String(e.user)}}async postMessage(e){let t=await J(this.post.chat.postMessage({channel:e.channel,thread_ts:e.threadTs??void 0,text:e.text,blocks:e.blocks,metadata:e.metadata,unfurl_links:!1,unfurl_media:!1}));return{ts:String(t.ts)}}async updateMessage(e){await J(this.post.chat.update({channel:e.channel,ts:e.ts,text:e.text,blocks:e.blocks,...e.metadata?{metadata:e.metadata}:{}}))}async postEphemeral(e){await J(this.post.chat.postEphemeral({channel:e.channel,user:e.user,text:e.text,thread_ts:e.threadTs??void 0}))}async addReaction(e,t,n){try{await J(this.post.reactions.add({channel:e,timestamp:t,name:n}))}catch(r){if(r.code!=="already_reacted")throw r}}async setAgentSession(e){await J(this.post.apiCall("agents.sessions.setStatus",{channel_id:e.channel,thread_ts:e.threadTs,status:e.status,...e.title?{title:e.title.slice(0,200)}:{}}))}async renameAgentSession(e){await J(this.post.apiCall("agents.sessions.rename",{channel_id:e.channel,thread_ts:e.threadTs,title:e.title.slice(0,200)}))}async openDm(e){let n=(await J(this.post.conversations.open({users:e}))).channel?.id;if(!n)throw new K("channel_not_found");return n}async openConversation(e){let n=(await J(this.post.conversations.open({users:e.join(",")}))).channel?.id;if(!n)throw new K("channel_not_found");return n}async removeReaction(e,t,n){try{await J(this.post.reactions.remove({channel:e,timestamp:t,name:n}))}catch(r){if(r.code!=="no_reaction")throw r}}async uploadFile(e){await J(this.post.filesUploadV2({channel_id:e.channel,thread_ts:e.threadTs,filename:e.filename,title:e.title,file:e.content}))}async permalink(e,t){try{return(await J(this.read.chat.getPermalink({channel:e,message_ts:t}))).permalink??null}catch{return null}}async replies(e,t,n,r=200,i=!1,o=!1){let a=i?this.background:this.read,l=[],u;do{let c=await J(a.conversations.replies({channel:e,ts:t,oldest:n,limit:Math.min(r,200),cursor:u,inclusive:!1,...o?{include_all_metadata:!0}:{}}));for(let p of c.messages??[])l.push({ts:String(p.ts),user:p.user??null,botId:p.bot_id??null,text:p.text??"",subtype:p.subtype??null,threadTs:p.thread_ts??null,files:Array.isArray(p.files)?p.files:[],botName:p.bot_profile?.name??p.username??null,metadata:p.metadata??null});u=c.response_metadata?.next_cursor||void 0}while(u&&l.length<r);return l}async userInfo(e){try{let n=(await J(this.read.users.info({user:e}))).user,r=n.profile??{};return{id:e,name:String(r.display_name||r.real_name||n.real_name||n.name||e),isBot:!!n.is_bot,teamId:n.team_id??null,tz:typeof n.tz=="string"?n.tz:null,isGuest:!!n.is_restricted||!!n.is_ultra_restricted,deleted:!!n.deleted,email:typeof r.email=="string"?r.email:null,realName:typeof r.real_name=="string"?r.real_name:null}}catch{return null}}async channelInfo(e){try{let t=await J(this.read.conversations.info({channel:e}));return ua(t.channel)}catch{return null}}async listChannels(){let e=[],t;do{let n=await J(this.read.conversations.list({types:"public_channel,private_channel",exclude_archived:!0,limit:200,cursor:t}));for(let r of n.channels??[])e.push(ua(r));t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<5e3);return e}async listUsers(){let e=[],t;do{let n=await J(this.read.users.list({limit:200,cursor:t}));for(let r of n.members??[]){if(r.deleted)continue;let i=r.profile??{};e.push({id:String(r.id),name:String(i.display_name||i.real_name||r.name),isBot:!!r.is_bot||r.id==="USLACKBOT",teamId:r.team_id??null,isGuest:!!r.is_restricted||!!r.is_ultra_restricted,email:typeof i.email=="string"?i.email:null,realName:typeof i.real_name=="string"?i.real_name:null})}t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<2e4);return e}async listUsergroups(){try{return((await J(this.read.usergroups.list({include_disabled:!1}))).usergroups??[]).map(t=>({id:String(t.id),handle:String(t.handle??""),name:String(t.name??"")}))}catch{return[]}}async isChannelMember(e,t){let n;for(let r=0;r<50;r++){let i=await J(this.read.conversations.members({channel:e,limit:1e3,cursor:n}));if((i.members??[]).includes(t))return!0;if(n=i.response_metadata?.next_cursor||void 0,!n)break}return!1}async usergroupMembers(e){return(await J(this.read.usergroups.users.list({usergroup:e}))).users??[]}async openModal(e,t){await J(this.post.views.open({trigger_id:e,view:t}))}async publishHome(e,t){await J(this.post.views.publish({user_id:e,view:t}))}async download(e,t){let n=new URL(e);if(n.protocol!=="https:"||n.hostname!==pd)throw new K("untrusted_file_host");let r=await fetch(n,{headers:{Authorization:`Bearer ${this.token}`},redirect:"error",signal:AbortSignal.timeout(12e4)});if(!r.ok||!r.body)throw new K(`download_http_${r.status}`);if(Number(r.headers.get("content-length")||0)>t)throw new K("file_too_large");let o=[],a=0;for await(let l of r.body){if(a+=l.byteLength,a>t)throw new K("file_too_large");o.push(Buffer.from(l))}return Buffer.concat(o)}};function ua(s){return{id:String(s.id),name:s.name??null,isPrivate:!!s.is_private,isExtShared:!!s.is_ext_shared||!!s.is_pending_ext_shared,isMember:!!s.is_member}}import gd from"node:os";var md=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Ut=class{constructor(e){this.d=e;this.base=(e.baseUrl??ui).replace(/\/$/,""),this.fetch=e.fetch??fetch}base;fetch;async call(e,t,n,r={}){let i=this.d.credential(),o=r.userLevel?null:this.d.workspaceSlug();if(!i||!o&&!r.userLevel)return{ok:!1,kind:"auth",status:0};let a;try{a=await this.fetch(`${this.base}${t}`,{method:e,headers:{"content-type":"application/json","x-mcp-key-id":i.keyId,"x-mcp-secret":i.secret,...o?{"x-workspace-slug":o}:{},"user-agent":`superclawd-fda/${Pe}`},body:n===void 0?void 0:JSON.stringify(n),redirect:"error",signal:AbortSignal.timeout(r.timeoutMs??this.d.timeoutMs??1e4)})}catch{return{ok:!1,kind:"unavailable",status:0}}if(a.ok)try{let c=await a.json();return{ok:!0,data:c.data??c}}catch{return{ok:!1,kind:"unavailable",status:a.status}}return await a.body?.cancel().catch(()=>{}),{ok:!1,kind:{400:"bad_request",401:"auth",403:"forbidden",404:"not_found",409:"limit",410:"revoked",429:"rate_limited"}[a.status]??"unavailable",status:a.status}}async workspaces(){let e=await this.call("GET","/api/prompt/workspaces",void 0,{userLevel:!0});return e.ok?{ok:!0,data:(Array.isArray(e.data?.workspaces)?e.data.workspaces:[]).filter(n=>typeof n?.slug=="string").map(n=>({slug:n.slug,name:String(n.name??n.slug),role:n.role??null}))}:e}agents(){return this.call("GET","/api/prompt/fda/agents")}register(e,t=gd.hostname()){return this.call("POST","/api/prompt/fda/machines",{machineId:e,label:t.slice(0,120)||"fda",daemonVersion:Pe.slice(0,40)})}bridgeRegister(e,t,n){return this.call("POST","/api/prompt/fda/bridge",{machineId:e,tracker:t,secret:n})}bridgeWait(e){return this.call("GET",`/api/prompt/fda/bridge/wait?token=${encodeURIComponent(e)}`,void 0,{timeoutMs:35e3})}heartbeat(e,t){return this.call("POST",`/api/prompt/fda/machines/${encodeURIComponent(e)}/heartbeat`,{state:t.state,queueDepth:Math.max(0,Math.min(1e4,Math.trunc(t.queueDepth))),agentId:t.agentId&&md.test(t.agentId)?t.agentId:null,slackBotName:t.slackBotName?.slice(0,80)??null,daemonVersion:Pe.slice(0,40),currentTitle:t.currentTitle?.slice(0,120)??null})}};function Ee(s){return s.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"skill"}var Qn=class{constructor(e){this.d=e}timer=null;registered=!1;agentChecked=!1;running=!1;start(){this.tick(),this.timer=setInterval(()=>void this.tick(),this.d.intervalMs??6e4),this.timer.unref()}stop(){this.timer&&clearInterval(this.timer),this.timer=null}reset(){this.registered=!1,this.agentChecked=!1}async tick(){if(!this.running){this.running=!0;try{let e=this.d.machineId();if(!e)return;if(!this.registered){let n=await this.d.client.register(e);if(!n.ok)return this.fail(n.kind);this.registered=!0,this.d.clearCondition("machine_revoked"),this.agentChecked=!1}this.agentChecked||(this.agentChecked=!0,await this.resolveAgent());let t=await this.d.client.heartbeat(e,this.d.heartbeat());if(!t.ok)return t.kind==="not_found"&&(this.registered=!1),t.kind==="rate_limited"?void 0:this.fail(t.kind);this.d.clearCondition("cloud"),t.data.agentRejected&&(this.agentChecked=!1),this.adoptAssignedAgent(t.data.assignedAgent)}catch(e){this.d.log?.(`cloud: ${e.message}`)}finally{this.running=!1}}}fail(e){e==="revoked"?(this.registered=!1,this.d.setCondition("machine_revoked","blocked","This machine was revoked in the SuperClawd App. If it should run again, a maintainer can register it anew with `superclawd fda setup --workspace <slug> --reset-id`.")):e==="auth"?this.d.setCondition("cloud","warn","SuperClawd rejected this machine's login. Run `superclawd login`."):e==="forbidden"?this.d.setCondition("cloud","warn","This machine was registered by another SuperClawd user. Log in as them, or ask a workspace maintainer."):e==="limit"?this.d.setCondition("cloud","warn","This workspace has reached its FDA machine limit. Remove an unused machine in the SuperClawd App."):e==="bad_request"?this.d.setCondition("cloud","warn","SuperClawd refused this machine's report. Updating SuperClawd FDA may help."):e!=="not_found"&&this.d.setCondition("cloud","warn","Can't reach SuperClawd right now; retrying.")}adoptAssignedAgent(e){if(!e||!this.d.setAgentName)return;let t=Ee(e.name);t===this.d.agentName()&&e.id===this.d.agentId()||(this.d.setAgentName(t),this.d.setAgentId(e.id),this.d.clearCondition("agent_cloud"),this.d.log?.(`cloud: agent switched to "${t}" (picked in the SuperClawd App)`))}async resolveAgent(){let e=this.d.agentName();if(!e)return;let t=await this.d.client.agents();if(!t.ok)return;let n=t.data.find(r=>Ee(r.name)===e||r.id===this.d.agentId());if(!n){this.d.agentId()&&this.d.setAgentId(null),this.d.setCondition("agent_cloud","blocked",`The selected agent "${e}" isn't an enabled Primary agent in this workspace. Pick another one.`);return}this.d.clearCondition("agent_cloud"),n.id!==this.d.agentId()&&this.d.setAgentId(n.id)}};function ca(s){switch(s){case"revoked":return"This machine was revoked in the SuperClawd App. Register it anew with --reset-id if it should run again.";case"auth":return"SuperClawd rejected this machine's login. Run `superclawd login`.";case"forbidden":return"This machine was registered by another SuperClawd user. Log in as them, or ask a workspace maintainer.";case"limit":return"This workspace has reached its FDA machine limit. Remove an unused machine in the SuperClawd App.";case"not_found":return"This SuperClawd server doesn't support FDA machines yet; the daemon will register when it does.";case"bad_request":return"SuperClawd refused this machine's report. Updating SuperClawd FDA may help.";default:return"Can't reach SuperClawd right now; the daemon will retry."}}import pt from"node:crypto";import es from"node:fs";var Ge={N:2**15,r:8,p:1,maxmem:64*1024*1024},ha=32,da=12*36e5,fd=7*24*36e5,wd=6e4,_d=6e4,kd=12,yd=30,bd=8,Sd=180*24*36e5,Td=/^[a-zA-Z0-9._-]{3,40}$/,Sr=0,Rr=[];async function Ed(s){Sr>=2&&await new Promise(e=>Rr.push(e)),Sr++;try{return await s()}finally{Sr--,Rr.shift()?.()}}function ga(s,e){return Ed(()=>new Promise((t,n)=>pt.scrypt(s,e,ha,Ge,(r,i)=>r?n(r):t(i))))}async function Tr(s){let e=pt.randomBytes(16),t=await ga(s,e);return`scrypt$${Ge.N}$${Ge.r}$${Ge.p}$${e.toString("base64")}$${t.toString("base64")}`}async function Er(s,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,n,r,i,o,a]=t;if(Number(n)!==Ge.N||Number(r)!==Ge.r||Number(i)!==Ge.p)return!1;let l=Buffer.from(a,"base64"),u=await ga(s,Buffer.from(o,"base64"));return u.length===l.length&&pt.timingSafeEqual(u,l)}function pa(s=20){let e="abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789",t=pt.randomBytes(s),n="";for(let r=0;r<s;r++)n+=e[t[r]%e.length];return n}function vr(s){return pt.createHash("sha256").update(s).digest("hex")}var Et=class{constructor(e,t=Date.now){this.db=e;this.now=t}failWindowStart=0;failsInWindow=0;toUser(e){return{id:e.id,username:e.username,mustChange:e.must_change===1}}async ensureAdmin(){if(this.db.get("SELECT id FROM admin_users LIMIT 1"))return{created:!1};let e=pa(),t=await Tr(e);return this.db.get("SELECT id FROM admin_users LIMIT 1")?{created:!1}:(this.db.run("INSERT INTO admin_users (id, username, password_hash, must_change, updated_at) VALUES (?, 'admin', ?, 1, ?)",pt.randomUUID(),t,this.now()),es.writeFileSync($.initialPassword,`${e}
581
+ `);this.add(e,null,{op:"post",requestId:null,threadTs:null,text:i.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:i.slice(0,2900)}}],overflow:null,prFollowId:t})}reactTo(e,t,n){n.length&&this.add(e,null,{op:"react",requestId:"",reaction:n[0],ts:t,fallbacks:n.slice(1)})}dm(e,t){this.add(e,null,{op:"dm",user:e,text:this.clean(t)})}ephemeral(e,t,n,r){this.add(e,null,{op:"ephemeral",user:t,threadTs:n,text:r})}upload(e,t,n,r){this.add(e.channel_id,e.id,{op:"upload",requestId:e.id,threadTs:e.thread_ts,path:t,filename:n,title:this.clean(r)})}update(e,t,n,r,i){this.add(e,t,{op:"update",ts:n,text:r,blocks:i})}};import rd from"node:fs";var K=class extends Error{constructor(t,n=null){super(t);this.code=t;this.retryAfterSec=n}};function id(s){return s.status==="awaiting_input"||s.status==="awaiting_approval"||s.plan_status==="proposed"?"suspended":s.status==="queued"||s.status==="running"?"processing":"active"}var od=new Set(["not_authorized","feature_disabled","unknown_method","missing_scope","not_allowed_token_type","no_permission","access_denied"]),ad=6*36e5,ld=new Set(["invalid_auth","account_inactive","token_revoked","not_authed","missing_scope","token_expired"]),la=new Set(["channel_not_found","is_archived","not_in_channel","thread_not_found","message_not_found","cant_update_message","msg_too_long","no_text","user_not_in_channel","file_not_found"]),ud=5,cd=new Set(["user_not_found","user_disabled","cannot_dm_bot","user_not_visible","not_allowed_token_type"]),on=class{constructor(e){this.d=e;this.now=e.now??Date.now}timer=null;busy=!1;stopped=!1;halted=!1;now;lastLive=new Map;dmScopeLogged=!1;sessionsOffUntil=0;lastSession=new Map;sessionErrorsLogged=new Set;start(){this.stopped=!1,this.halted=!1,this.wake()}resume(){this.halted&&(this.halted=!1,this.d.store.outboxRetryNow(this.now()),this.wake())}stop(){this.stopped=!0,this.timer&&clearTimeout(this.timer)}wake(){this.stopped||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),0))}inflight=null;idle(){return this.inflight??Promise.resolve()}drain(){return this.busy||this.stopped||this.halted?this.idle():(this.inflight=this.drainOnce().finally(()=>{this.inflight=null}),this.inflight)}async drainOnce(){let e=this.d.lane==="tickets"?null:this.d.slack();if(!e&&this.d.lane!=="tickets")return;this.busy=!0;try{for(;;){let n=this.d.store.outboxDue(this.now(),20,this.d.lane);if(!n.length)break;for(let r of n){if(this.halted||this.stopped)break;await this.send(e,r)}if(this.halted||this.stopped)return}}finally{this.busy=!1}let t=this.d.store.outboxNextWakeAt(this.d.lane);t!==null&&!this.stopped&&(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),Math.max(50,t-this.now())),this.timer.unref?.())}async send(e,t){let{store:n}=this.d,r;try{r=JSON.parse(t.payload)}catch{n.outboxFinal(t.id,"dropped","bad payload");return}try{let i=await this.execute(e,t.channel,r);n.outboxSent(t.id,i)}catch(i){let o=i instanceof K?i.code:String(i?.message??i);i instanceof K&&o==="ratelimited"?n.outboxRetry(t.id,this.now()+Math.max(1,i.retryAfterSec??30)*1e3,o):ld.has(o)?(n.outboxHold(t.id,this.now()+36e5,o),this.halted=!0,this.d.onFatal(o)):la.has(o)||t.attempts+1>=ud?(n.outboxFinal(t.id,"dropped",o),this.d.onDropped?.(o,t.channel)):o==="invalid_blocks"&&r.op==="post"?(n.outboxFinal(t.id,"dropped",o),n.outboxAdd({requestId:r.requestId,channel:t.channel,kind:"post",payload:{...r,blocks:[]}})):n.outboxRetry(t.id,this.now()+2**t.attempts*1e3,o)}}metadataFor(e){if(e.metadata)return e.metadata;if(e.requestId){if(e.final)try{let t=this.d.threadBlock?.(e.requestId,e.text);if(t)return t}catch{}return{event_type:"fda_message",event_payload:{request:e.requestId}}}}async finishLive(e,t,n,r){let{store:i}=this.d,o=i.getRequest(n.requestId),a=o?.status_ts??null,l=()=>{o&&i.updateRequest(o.id,{status_ts:null},o.updated_at),o&&this.lastLive.delete(o.id)};if(a&&!r.handoff)try{return await e.updateMessage({channel:t,ts:a,text:n.text,blocks:n.blocks,metadata:n.final?this.metadataFor(n):void 0}),n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,a),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,a),l(),a}catch(c){if(!(c instanceof K)||la.has(c.code)===!1)throw c}let u=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});if(n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,u.ts),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,u.ts),a){let c=Vi(this.now()-r.since);await e.updateMessage({channel:t,ts:a,text:c.text,blocks:c.blocks}).catch(()=>{})}return l(),u.ts}async execute(e,t,n){let{store:r}=this.d;if(t.startsWith("tk:"))return this.d.tickets?this.d.tickets(t,n):null;switch(n.op){case"post":{if(n.live&&n.requestId)return this.finishLive(e,t,n,n.live);let i=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});return n.planVersion&&n.requestId&&r.setPlanMessageTs(n.requestId,n.planVersion,i.ts),n.choicesId&&n.requestId&&r.setChoicesMessageTs(n.requestId,n.choicesId,i.ts),n.scheduleId&&r.updateSchedule(n.scheduleId,{card_ts:i.ts}),n.prFollowId&&r.updatePrFollow(n.prFollowId,{announce_ts:i.ts}),n.conversationOpen&&r.setConversationOpenedTs(n.conversationOpen,i.ts),i.ts}case"dm":{let i;try{if(!e.openDm)throw new K("missing_scope");i=await e.openDm(n.user)}catch(a){let l=a instanceof K?a.code:"";if(l==="missing_scope")return this.dmScopeLogged||this.d.log?.("slack: a direct message was skipped: the Slack app needs the im:write scope (add it under OAuth & Permissions and reinstall the app)"),this.dmScopeLogged=!0,null;if(cd.has(l))return null;throw a}return(await e.postMessage({channel:i,text:n.text})).ts}case"status":{if(!n.live)return null;let i=r.getRequest(n.requestId);if(!i||i.live_since!==n.live.since)return i&&this.lastLive.delete(i.id),null;let o=Nn({step:n.live.step,handoff:i.live_handoff===1,queued:i.status==="queued"&&this.now()-n.live.since>1500,icons:n.live.icons,stopFor:this.d.stopButton?.()?i.id:null}),a=JSON.stringify(o.blocks);if(i.status_ts)return this.lastLive.get(i.id)===a||(await e.updateMessage({channel:t,ts:i.status_ts,text:o.text,blocks:o.blocks}),this.lastLive.set(i.id,a)),i.status_ts;let l=null;try{l=this.d.presenceBlock?.(i.id)??null}catch{}let u=await e.postMessage({channel:t,threadTs:i.thread_ts,text:o.text,blocks:o.blocks,...l?{metadata:l}:{}});return r.updateRequest(i.id,{status_ts:u.ts},i.updated_at),this.lastLive.set(i.id,a),u.ts}case"session":{if(!e.setAgentSession||this.now()<this.sessionsOffUntil)return null;let i=r.getRequest(n.requestId);if(!i?.thread_ts)return null;let o=id(i),a=i.title.trim(),l=this.lastSession.get(i.id);if(l?.status===o&&l.title===a)return null;try{await e.setAgentSession({channel:t,threadTs:i.thread_ts,status:o,title:a||void 0}),a&&l&&l.title!==a&&await e.renameAgentSession?.({channel:t,threadTs:i.thread_ts,title:a}),this.lastSession.set(i.id,{status:o,title:a})}catch(u){let c=u instanceof K?u.code:"";od.has(c)?(this.sessionsOffUntil||this.d.log?.(`slack: agent sessions are off for this app (${c}); turn on the Agent experience in the Slack app settings to show progress and a stop button`),this.sessionsOffUntil=this.now()+ad):this.sessionErrorsLogged.has(c)||(this.sessionErrorsLogged.add(c),this.d.log?.(`slack: an agent session update was skipped (${c||String(u)})`))}return o==="active"&&this.lastSession.delete(i.id),null}case"react":{if(n.ts){for(let l of[n.reaction,...n.fallbacks??[]])try{return await e.addReaction(t,n.ts,l),null}catch(u){if(!(u instanceof K)||u.code!=="invalid_name")throw u}return null}let i=r.getRequest(n.requestId);if(!i)return null;let o=i.status_reaction;if(o===n.reaction)return null;let a=o?[o]:aa.filter(l=>l!==n.reaction);for(let l of a)await e.removeReaction(t,i.origin_ts,l);return await e.addReaction(t,i.origin_ts,n.reaction),r.updateRequest(i.id,{status_reaction:n.reaction},i.updated_at),null}case"ephemeral":return await e.postEphemeral({channel:t,user:n.user,text:n.text,threadTs:n.threadTs}),null;case"upload":{let i=rd.readFileSync(n.path);return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:i}),null}case"text_file":return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:Buffer.from(n.content,"utf8")}),null;case"update":return await e.updateMessage({channel:t,ts:n.ts,text:n.text,blocks:n.blocks}),n.ts}}};import{SocketModeClient as dd}from"@slack/socket-mode";var Zn=class{constructor(e){this.d=e}client=null;async start(){let e=new dd({appToken:this.d.appToken,logLevel:void 0});this.client=e,e.on("slack_event",async t=>{try{this.d.receive({type:t.type,envelope_id:t.envelope_id,body:t.body})}catch(n){this.d.log(`inbox insert failed: ${String(n)}`);return}try{await t.ack()}catch{}this.d.onReceived()}),e.on("connected",()=>this.d.onConnected()),e.on("disconnected",()=>this.d.onDisconnected()),await e.start()}async stop(){let e=this.client;if(this.client=null,e)try{await e.disconnect()}catch{}}};import{WebClient as br}from"@slack/web-api";var pd="files.slack.com";function hd(s){let e=s;throw e?.code==="slack_webapi_rate_limited_error"?new K("ratelimited",e.retryAfter??30):e?.data?.error?new K(e.data.error):e?.code==="slack_webapi_request_error"?new K("network_error"):new K(e?.message??"unknown_error")}async function J(s){try{return await s}catch(e){hd(e)}}var an=class{constructor(e){this.token=e;this.post=new br(e,{retryConfig:{retries:0},rejectRateLimitedCalls:!0,timeout:15e3}),this.read=new br(e,{retryConfig:{retries:3},timeout:15e3}),this.background=new br(e,{retryConfig:{retries:2},timeout:15e3})}post;read;background;async authTest(){let e=await J(this.read.auth.test());return{userId:String(e.user_id),botId:e.bot_id??null,teamId:String(e.team_id),team:String(e.team),user:String(e.user)}}async postMessage(e){let t=await J(this.post.chat.postMessage({channel:e.channel,thread_ts:e.threadTs??void 0,text:e.text,blocks:e.blocks,metadata:e.metadata,unfurl_links:!1,unfurl_media:!1}));return{ts:String(t.ts)}}async updateMessage(e){await J(this.post.chat.update({channel:e.channel,ts:e.ts,text:e.text,blocks:e.blocks,...e.metadata?{metadata:e.metadata}:{}}))}async postEphemeral(e){await J(this.post.chat.postEphemeral({channel:e.channel,user:e.user,text:e.text,thread_ts:e.threadTs??void 0}))}async addReaction(e,t,n){try{await J(this.post.reactions.add({channel:e,timestamp:t,name:n}))}catch(r){if(r.code!=="already_reacted")throw r}}async setAgentSession(e){await J(this.post.apiCall("agents.sessions.setStatus",{channel_id:e.channel,thread_ts:e.threadTs,status:e.status,...e.title?{title:e.title.slice(0,200)}:{}}))}async renameAgentSession(e){await J(this.post.apiCall("agents.sessions.rename",{channel_id:e.channel,thread_ts:e.threadTs,title:e.title.slice(0,200)}))}async openDm(e){let n=(await J(this.post.conversations.open({users:e}))).channel?.id;if(!n)throw new K("channel_not_found");return n}async openConversation(e){let n=(await J(this.post.conversations.open({users:e.join(",")}))).channel?.id;if(!n)throw new K("channel_not_found");return n}async removeReaction(e,t,n){try{await J(this.post.reactions.remove({channel:e,timestamp:t,name:n}))}catch(r){if(r.code!=="no_reaction")throw r}}async uploadFile(e){await J(this.post.filesUploadV2({channel_id:e.channel,thread_ts:e.threadTs,filename:e.filename,title:e.title,file:e.content}))}async permalink(e,t){try{return(await J(this.read.chat.getPermalink({channel:e,message_ts:t}))).permalink??null}catch{return null}}async replies(e,t,n,r=200,i=!1,o=!1){let a=i?this.background:this.read,l=[],u;do{let c=await J(a.conversations.replies({channel:e,ts:t,oldest:n,limit:Math.min(r,200),cursor:u,inclusive:!1,...o?{include_all_metadata:!0}:{}}));for(let p of c.messages??[])l.push({ts:String(p.ts),user:p.user??null,botId:p.bot_id??null,text:p.text??"",subtype:p.subtype??null,threadTs:p.thread_ts??null,files:Array.isArray(p.files)?p.files:[],botName:p.bot_profile?.name??p.username??null,metadata:p.metadata??null});u=c.response_metadata?.next_cursor||void 0}while(u&&l.length<r);return l}async userInfo(e){try{let n=(await J(this.read.users.info({user:e}))).user,r=n.profile??{};return{id:e,name:String(r.display_name||r.real_name||n.real_name||n.name||e),isBot:!!n.is_bot,teamId:n.team_id??null,tz:typeof n.tz=="string"?n.tz:null,isGuest:!!n.is_restricted||!!n.is_ultra_restricted,deleted:!!n.deleted,email:typeof r.email=="string"?r.email:null,realName:typeof r.real_name=="string"?r.real_name:null}}catch{return null}}async channelInfo(e){try{let t=await J(this.read.conversations.info({channel:e}));return ua(t.channel)}catch{return null}}async listChannels(){let e=[],t;do{let n=await J(this.read.conversations.list({types:"public_channel,private_channel",exclude_archived:!0,limit:200,cursor:t}));for(let r of n.channels??[])e.push(ua(r));t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<5e3);return e}async listUsers(){let e=[],t;do{let n=await J(this.read.users.list({limit:200,cursor:t}));for(let r of n.members??[]){if(r.deleted)continue;let i=r.profile??{};e.push({id:String(r.id),name:String(i.display_name||i.real_name||r.name),isBot:!!r.is_bot||r.id==="USLACKBOT",teamId:r.team_id??null,isGuest:!!r.is_restricted||!!r.is_ultra_restricted,email:typeof i.email=="string"?i.email:null,realName:typeof i.real_name=="string"?i.real_name:null})}t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<2e4);return e}async listUsergroups(){try{return((await J(this.read.usergroups.list({include_disabled:!1}))).usergroups??[]).map(t=>({id:String(t.id),handle:String(t.handle??""),name:String(t.name??"")}))}catch{return[]}}async isChannelMember(e,t){let n;for(let r=0;r<50;r++){let i=await J(this.read.conversations.members({channel:e,limit:1e3,cursor:n}));if((i.members??[]).includes(t))return!0;if(n=i.response_metadata?.next_cursor||void 0,!n)break}return!1}async usergroupMembers(e){return(await J(this.read.usergroups.users.list({usergroup:e}))).users??[]}async openModal(e,t){await J(this.post.views.open({trigger_id:e,view:t}))}async publishHome(e,t){await J(this.post.views.publish({user_id:e,view:t}))}async download(e,t){let n=new URL(e);if(n.protocol!=="https:"||n.hostname!==pd)throw new K("untrusted_file_host");let r=await fetch(n,{headers:{Authorization:`Bearer ${this.token}`},redirect:"error",signal:AbortSignal.timeout(12e4)});if(!r.ok||!r.body)throw new K(`download_http_${r.status}`);if(Number(r.headers.get("content-length")||0)>t)throw new K("file_too_large");let o=[],a=0;for await(let l of r.body){if(a+=l.byteLength,a>t)throw new K("file_too_large");o.push(Buffer.from(l))}return Buffer.concat(o)}};function ua(s){return{id:String(s.id),name:s.name??null,isPrivate:!!s.is_private,isExtShared:!!s.is_ext_shared||!!s.is_pending_ext_shared,isMember:!!s.is_member}}import gd from"node:os";var md=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Ut=class{constructor(e){this.d=e;this.base=(e.baseUrl??ui).replace(/\/$/,""),this.fetch=e.fetch??fetch}base;fetch;async call(e,t,n,r={}){let i=this.d.credential(),o=r.userLevel?null:this.d.workspaceSlug();if(!i||!o&&!r.userLevel)return{ok:!1,kind:"auth",status:0};let a;try{a=await this.fetch(`${this.base}${t}`,{method:e,headers:{"content-type":"application/json","x-mcp-key-id":i.keyId,"x-mcp-secret":i.secret,...o?{"x-workspace-slug":o}:{},"user-agent":`superclawd-fda/${Pe}`},body:n===void 0?void 0:JSON.stringify(n),redirect:"error",signal:AbortSignal.timeout(r.timeoutMs??this.d.timeoutMs??1e4)})}catch{return{ok:!1,kind:"unavailable",status:0}}if(a.ok)try{let c=await a.json();return{ok:!0,data:c.data??c}}catch{return{ok:!1,kind:"unavailable",status:a.status}}return await a.body?.cancel().catch(()=>{}),{ok:!1,kind:{400:"bad_request",401:"auth",403:"forbidden",404:"not_found",409:"limit",410:"revoked",429:"rate_limited"}[a.status]??"unavailable",status:a.status}}async workspaces(){let e=await this.call("GET","/api/prompt/workspaces",void 0,{userLevel:!0});return e.ok?{ok:!0,data:(Array.isArray(e.data?.workspaces)?e.data.workspaces:[]).filter(n=>typeof n?.slug=="string").map(n=>({slug:n.slug,name:String(n.name??n.slug),role:n.role??null}))}:e}agents(){return this.call("GET","/api/prompt/fda/agents")}register(e,t=gd.hostname()){return this.call("POST","/api/prompt/fda/machines",{machineId:e,label:t.slice(0,120)||"fda",daemonVersion:Pe.slice(0,40)})}bridgeRegister(e,t,n){return this.call("POST","/api/prompt/fda/bridge",{machineId:e,tracker:t,secret:n})}bridgeWait(e){return this.call("GET",`/api/prompt/fda/bridge/wait?token=${encodeURIComponent(e)}`,void 0,{timeoutMs:35e3})}heartbeat(e,t){return this.call("POST",`/api/prompt/fda/machines/${encodeURIComponent(e)}/heartbeat`,{state:t.state,queueDepth:Math.max(0,Math.min(1e4,Math.trunc(t.queueDepth))),agentId:t.agentId&&md.test(t.agentId)?t.agentId:null,slackBotName:t.slackBotName?.slice(0,80)??null,daemonVersion:Pe.slice(0,40),currentTitle:t.currentTitle?.slice(0,120)??null})}};function Ee(s){return s.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"skill"}var Qn=class{constructor(e){this.d=e}timer=null;registered=!1;agentChecked=!1;running=!1;start(){this.tick(),this.timer=setInterval(()=>void this.tick(),this.d.intervalMs??6e4),this.timer.unref()}stop(){this.timer&&clearInterval(this.timer),this.timer=null}reset(){this.registered=!1,this.agentChecked=!1}async tick(){if(!this.running){this.running=!0;try{let e=this.d.machineId();if(!e)return;if(!this.registered){let n=await this.d.client.register(e);if(!n.ok)return this.fail(n.kind);this.registered=!0,this.d.clearCondition("machine_revoked"),this.agentChecked=!1}this.agentChecked||(this.agentChecked=!0,await this.resolveAgent());let t=await this.d.client.heartbeat(e,this.d.heartbeat());if(!t.ok)return t.kind==="not_found"&&(this.registered=!1),t.kind==="rate_limited"?void 0:this.fail(t.kind);this.d.clearCondition("cloud"),t.data.agentRejected&&(this.agentChecked=!1),this.adoptAssignedAgent(t.data.assignedAgent)}catch(e){this.d.log?.(`cloud: ${e.message}`)}finally{this.running=!1}}}fail(e){e==="revoked"?(this.registered=!1,this.d.setCondition("machine_revoked","blocked","This machine was revoked in the SuperClawd App. If it should run again, a maintainer can register it anew with `superclawd fda setup --workspace <slug> --reset-id`.")):e==="auth"?this.d.setCondition("cloud","warn","SuperClawd rejected this machine's login. Run `superclawd login`."):e==="forbidden"?this.d.setCondition("cloud","warn","This machine was registered by another SuperClawd user. Log in as them, or ask a workspace maintainer."):e==="limit"?this.d.setCondition("cloud","warn","This workspace has reached its FDA machine limit. Remove an unused machine in the SuperClawd App."):e==="bad_request"?this.d.setCondition("cloud","warn","SuperClawd refused this machine's report. Updating SuperClawd FDA may help."):e!=="not_found"&&this.d.setCondition("cloud","warn","Can't reach SuperClawd right now; retrying.")}adoptAssignedAgent(e){if(!e||!this.d.setAgentName)return;let t=Ee(e.name);t===this.d.agentName()&&e.id===this.d.agentId()||(this.d.setAgentName(t),this.d.setAgentId(e.id),this.d.clearCondition("agent_cloud"),this.d.log?.(`cloud: agent switched to "${t}" (picked in the SuperClawd App)`))}async resolveAgent(){let e=this.d.agentName();if(!e)return;let t=await this.d.client.agents();if(!t.ok)return;let n=t.data.find(r=>Ee(r.name)===e||r.id===this.d.agentId());if(!n){this.d.agentId()&&this.d.setAgentId(null),this.d.setCondition("agent_cloud","blocked",`The selected agent "${e}" isn't an enabled Primary agent in this workspace. Pick another one.`);return}this.d.clearCondition("agent_cloud"),n.id!==this.d.agentId()&&this.d.setAgentId(n.id)}};function ca(s){switch(s){case"revoked":return"This machine was revoked in the SuperClawd App. Register it anew with --reset-id if it should run again.";case"auth":return"SuperClawd rejected this machine's login. Run `superclawd login`.";case"forbidden":return"This machine was registered by another SuperClawd user. Log in as them, or ask a workspace maintainer.";case"limit":return"This workspace has reached its FDA machine limit. Remove an unused machine in the SuperClawd App.";case"not_found":return"This SuperClawd server doesn't support FDA machines yet; the daemon will register when it does.";case"bad_request":return"SuperClawd refused this machine's report. Updating SuperClawd FDA may help.";default:return"Can't reach SuperClawd right now; the daemon will retry."}}import pt from"node:crypto";import es from"node:fs";var Ge={N:2**15,r:8,p:1,maxmem:64*1024*1024},ha=32,da=12*36e5,fd=7*24*36e5,wd=6e4,_d=6e4,kd=12,yd=30,bd=8,Sd=180*24*36e5,Td=/^[a-zA-Z0-9._-]{3,40}$/,Sr=0,Rr=[];async function Ed(s){Sr>=2&&await new Promise(e=>Rr.push(e)),Sr++;try{return await s()}finally{Sr--,Rr.shift()?.()}}function ga(s,e){return Ed(()=>new Promise((t,n)=>pt.scrypt(s,e,ha,Ge,(r,i)=>r?n(r):t(i))))}async function Tr(s){let e=pt.randomBytes(16),t=await ga(s,e);return`scrypt$${Ge.N}$${Ge.r}$${Ge.p}$${e.toString("base64")}$${t.toString("base64")}`}async function Er(s,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,n,r,i,o,a]=t;if(Number(n)!==Ge.N||Number(r)!==Ge.r||Number(i)!==Ge.p)return!1;let l=Buffer.from(a,"base64"),u=await ga(s,Buffer.from(o,"base64"));return u.length===l.length&&pt.timingSafeEqual(u,l)}function pa(s=20){let e="abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789",t=pt.randomBytes(s),n="";for(let r=0;r<s;r++)n+=e[t[r]%e.length];return n}function vr(s){return pt.createHash("sha256").update(s).digest("hex")}var Et=class{constructor(e,t=Date.now){this.db=e;this.now=t}failWindowStart=0;failsInWindow=0;toUser(e){return{id:e.id,username:e.username,mustChange:e.must_change===1}}async ensureAdmin(){if(this.db.get("SELECT id FROM admin_users LIMIT 1"))return{created:!1};let e=pa(),t=await Tr(e);return this.db.get("SELECT id FROM admin_users LIMIT 1")?{created:!1}:(this.db.run("INSERT INTO admin_users (id, username, password_hash, must_change, updated_at) VALUES (?, 'admin', ?, 1, ?)",pt.randomUUID(),t,this.now()),es.writeFileSync($.initialPassword,`${e}
582
582
  `,{mode:384}),{created:!0})}initialPassword(){let e=this.db.get("SELECT must_change FROM admin_users LIMIT 1");if(!e||e.must_change!==1)return null;try{return es.readFileSync($.initialPassword,"utf8").trim()||null}catch{return null}}async login(e,t,n){let r=`${n??"-"}|${e.trim().toLowerCase().slice(0,64)}`,i=this.now();if(i-this.failWindowStart>6e4&&(this.failWindowStart=i,this.failsInWindow=0),this.failsInWindow>=yd||Rr.length>=bd)return{ok:!1,code:"rate_limited",retryAfterSec:10};let o=this.db.get("SELECT failures, next_allowed_at FROM login_attempts WHERE key = ?",r);if(o&&o.next_allowed_at>i)return{ok:!1,code:"rate_limited",retryAfterSec:Math.ceil((o.next_allowed_at-i)/1e3)};let a=(o?.failures??0)+1;this.db.run("INSERT INTO login_attempts (key, failures, next_allowed_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET failures = excluded.failures, next_allowed_at = excluded.next_allowed_at",r,a,i+Math.min(_d,1e3*2**(a-1)));let l=this.db.get("SELECT * FROM admin_users WHERE username = ? COLLATE NOCASE",e.trim());return!(l?await Er(t,l.password_hash):(await Er(t,vd),!1))||!l?(this.failsInWindow++,{ok:!1,code:"invalid_credentials"}):(this.db.run("DELETE FROM login_attempts WHERE key = ?",r),{ok:!0,user:this.toUser(l)})}knownUsername(e){return this.db.get("SELECT username FROM admin_users WHERE username = ? COLLATE NOCASE",e.trim())?.username??null}createSession(e,t,n){let r=pt.randomBytes(32).toString("base64url"),i=this.now();return this.db.run("INSERT INTO admin_sessions (id_hash, user_id, created_at, last_seen_at, expires_at, ip, ua) VALUES (?, ?, ?, ?, ?, ?, ?)",vr(r),e,i,i,i+fd,t,n?.slice(0,200)??null),r}validate(e,t={}){if(!e||e.length>100)return null;let n=vr(e),r=this.db.get("SELECT u.*, s.last_seen_at, s.expires_at FROM admin_sessions s JOIN admin_users u ON u.id = s.user_id WHERE s.id_hash = ?",n);if(!r)return null;let i=this.now();return r.expires_at<=i||i-r.last_seen_at>da?(this.db.run("DELETE FROM admin_sessions WHERE id_hash = ?",n),null):(t.touch!==!1&&i-r.last_seen_at>wd&&this.db.run("UPDATE admin_sessions SET last_seen_at = ? WHERE id_hash = ?",i,n),this.toUser(r))}revoke(e){this.db.run("DELETE FROM admin_sessions WHERE id_hash = ?",vr(e))}async changePassword(e,t,n,r){let i=this.db.get("SELECT * FROM admin_users WHERE id = ?",e);if(!i||!await Er(t,i.password_hash))return{ok:!1,code:"invalid_credentials"};if(typeof n!="string"||n.length<kd||n.length>200||n===t)return{ok:!1,code:"weak_password"};let o=r?.trim()||i.username;if(!Td.test(o))return{ok:!1,code:"invalid_username"};let a=await Tr(n);return this.db.tx(()=>{this.db.run("UPDATE admin_users SET username = ?, password_hash = ?, must_change = 0, updated_at = ? WHERE id = ?",o,a,this.now(),e),this.db.run("DELETE FROM admin_sessions WHERE user_id = ?",e)}),es.rmSync($.initialPassword,{force:!0}),{ok:!0,user:{id:e,username:o,mustChange:!1}}}async resetPassword(){let e=this.db.get("SELECT * FROM admin_users ORDER BY rowid LIMIT 1"),t=pa(),n=await Tr(t),r=this.now(),i=e?.username??"admin";return this.db.tx(()=>{e?this.db.run("UPDATE admin_users SET password_hash = ?, must_change = 1, updated_at = ? WHERE id = ?",n,r,e.id):this.db.run("INSERT INTO admin_users (id, username, password_hash, must_change, updated_at) VALUES (?, 'admin', ?, 1, ?)",pt.randomUUID(),n,r),this.db.run("DELETE FROM admin_sessions"),this.db.run("DELETE FROM login_attempts")}),es.writeFileSync($.initialPassword,`${t}
583
583
  `,{mode:384}),{username:i,password:t}}prune(){let e=this.now();this.db.run("DELETE FROM admin_sessions WHERE expires_at <= ? OR last_seen_at < ?",e,e-da),this.db.run("DELETE FROM login_attempts WHERE next_allowed_at < ?",e-24*36e5),this.db.run("DELETE FROM audit_log WHERE ts < ?",e-Sd)}},vd=`scrypt$${Ge.N}$${Ge.r}$${Ge.p}$${Buffer.alloc(16).toString("base64")}$${Buffer.alloc(ha).toString("base64")}`;import ap from"node:crypto";import te from"node:fs";import Dr from"node:os";import ne from"node:path";import Cr from"express";var Rd=["app_mentions:read","chat:write","channels:history","groups:history","channels:read","groups:read","users:read","usergroups:read","reactions:write","files:read","files:write","im:history","reactions:read","users:read.email","im:write","mpim:write","mpim:history","assistant:write"],xd=["app_mention","message.channels","message.groups","message.im","message.mpim","reaction_added","app_home_opened","agent_session_stopped"];function Id(s){return s.toLowerCase().replace(/[^a-z0-9._-]+/g,"_").replace(/^[._-]+|[._-]+$/g,"").slice(0,80)||"superclawd_fda"}function ts(s){let e=s.trim().slice(0,35)||"SuperClawd FDA";return{display_information:{name:e,description:"A SuperClawd FDA: an AI engineer that takes requests in Slack.",background_color:"#111827"},features:{app_home:{home_tab_enabled:!0,messages_tab_enabled:!0,messages_tab_read_only_enabled:!1},bot_user:{display_name:Id(e),always_online:!0},agent_view:{agent_description:`${e}, the team's AI agent. Ask in a thread or a DM: it researches, writes documents and code, opens pull requests and follows up. It asks before big changes and never shares passwords or secrets.`.slice(0,300)}},oauth_config:{scopes:{bot:[...Rd]}},settings:{event_subscriptions:{bot_events:[...xd]},interactivity:{is_enabled:!0},org_deploy_enabled:!1,socket_mode_enabled:!0,token_rotation_enabled:!1}}}import ns from"node:fs";import Ad from"node:os";import ss from"node:path";function xr(s){return s.startsWith(".")&&s!=="."&&s!==".."}function Ft(s,e=Ad.homedir()){let t=s.trim();if(!t)return{ok:!1,message:"Pick a folder."};let n;try{n=ns.realpathSync(t.replace(/^~(?=$|\/)/,e))}catch{return{ok:!1,message:"That folder doesn't exist."}}let r=ns.realpathSync(e);return n===r||n.startsWith(r+ss.sep)?ss.relative(r,n).split(ss.sep).some(xr)?{ok:!1,message:"That folder can't be used."}:ns.statSync(n).isDirectory()?{ok:!0,path:n,kind:ns.existsSync(ss.join(n,".git"))?"repo":"folder"}:{ok:!1,message:"Not a folder."}:{ok:!1,message:"The folder must be inside your home directory."}}import Ir from"node:crypto";var fa="https://calendarmcp.googleapis.com/mcp/v1",Nd="https://accounts.google.com/o/oauth2/v2/auth",ma="https://oauth2.googleapis.com/token",Cd="https://oauth2.googleapis.com/revoke",Pd=["openid","email","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar.freebusy"],Ld=["openid","email","https://www.googleapis.com/auth/calendar.calendarlist.readonly","https://www.googleapis.com/auth/calendar.events.freebusy","https://www.googleapis.com/auth/calendar.events.readonly","https://www.googleapis.com/auth/calendar.events"],$d=10*6e4,ze=class extends Error{constructor(t,n){super(n??t);this.code=t}};function Ar(s){return s.toString("base64url")}var rs=class{constructor(e){this.d=e;this.now=e.now??Date.now}pending=new Map;access=null;refreshing=null;now;get http(){return this.d.fetch??fetch}status(){let e=this.d.settings;return{configured:!!e.get("googleClientId")&&!!e.getSecret("googleClientSecret"),connected:!!e.getSecret("googleRefreshToken"),account:e.get("calendarAccount"),enabled:e.get("calendarEnabled")}}active(){let e=this.status();return e.enabled&&e.configured&&e.connected}accountDomain(){let e=this.d.settings.get("calendarAccount");return e?e.split("@")[1].toLowerCase():null}authUrl(e){let t=this.d.settings.get("googleClientId");if(!t||!this.d.settings.getSecret("googleClientSecret"))throw new ze("not_configured","Enter the client ID and secret first.");let n=this.now();for(let[l,u]of this.pending)u.exp<=n&&this.pending.delete(l);let r=Ar(Ir.randomBytes(24)),i=Ar(Ir.randomBytes(32)),o=Ar(Ir.createHash("sha256").update(i).digest());this.pending.set(r,{verifier:i,redirectUri:e,exp:n+$d});let a=new URLSearchParams({client_id:t,redirect_uri:e,response_type:"code",scope:(this.d.settings.get("calendarBackend")==="google-mcp"?Ld:Pd).join(" "),access_type:"offline",prompt:"consent",include_granted_scopes:"true",state:r,code_challenge:o,code_challenge_method:"S256"});return`${Nd}?${a}`}async exchange(e,t){let n=this.pending.get(t);if(this.pending.delete(t),!n||n.exp<=this.now())throw new ze("bad_state","That sign-in link expired. Click Connect Google again.");let r=this.d.settings,i=await this.http(ma,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:n.redirectUri,client_id:r.get("googleClientId")??"",client_secret:r.getSecret("googleClientSecret")??"",code_verifier:n.verifier}),redirect:"error",signal:AbortSignal.timeout(15e3)}),o=await i.json().catch(()=>({}));if(!i.ok)throw new ze("exchange_failed",`Google refused the sign-in (${String(o.error??i.status)}).`);let a=typeof o.refresh_token=="string"?o.refresh_token:"";if(!a)throw new ze("no_refresh_token","Google didn't return offline access. Try Connect Google again.");if(!String(o.scope??"").split(/\s+/).includes("https://www.googleapis.com/auth/calendar.events"))throw new ze("scope_missing","Calendar access wasn't granted. Allow all requested permissions when signing in.");let u=Od(String(o.id_token??""));if(!u)throw new ze("no_account","Google didn't say which account signed in.");return r.setSecret("googleRefreshToken",a),r.set({calendarAccount:u}),typeof o.access_token=="string"&&(this.access={token:o.access_token,exp:this.now()+Number(o.expires_in??3600)*1e3}),{account:u}}async accessToken(){return this.access&&this.access.exp-6e4>this.now()?this.access.token:(this.refreshing??=this.refresh().finally(()=>{this.refreshing=null}),this.refreshing)}async refresh(){let e=this.d.settings,t=e.getSecret("googleRefreshToken");if(!t)return null;let n=await this.http(ma,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:e.get("googleClientId")??"",client_secret:e.getSecret("googleClientSecret")??""}),redirect:"error",signal:AbortSignal.timeout(15e3)}).catch(()=>null);if(!n)return null;let r=await n.json().catch(()=>({}));return n.ok?typeof r.access_token!="string"?null:(this.access={token:r.access_token,exp:this.now()+Number(r.expires_in??3600)*1e3},this.access.token):(r.error==="invalid_grant"&&(e.setSecret("googleRefreshToken",null),this.access=null,this.d.onLost?.("Google Calendar was disconnected (the sign-in was revoked or expired). Connect it again in the admin.")),null)}async disconnect(){let e=this.d.settings,t=e.getSecret("googleRefreshToken");e.setSecret("googleRefreshToken",null),e.set({calendarAccount:null}),this.access=null,t&&await this.http(Cd,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({token:t}),signal:AbortSignal.timeout(1e4)}).catch(()=>{})}};function Od(s){let e=s.split(".")[1];if(!e)return null;try{let t=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));return typeof t.email=="string"&&t.email_verified!==!1?t.email.toLowerCase():null}catch{return null}}function is(s,e=new Set){if(typeof s=="string")for(let t of s.matchAll(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g))e.add(t[0].toLowerCase());else if(Array.isArray(s))for(let t of s)is(t,e);else if(s&&typeof s=="object")for(let t of Object.values(s))is(t,e);return e}var wa=new Set(["create_event","update_event"]);import qd from"node:crypto";var Dd="https://linear.app/oauth/authorize",_a="https://api.linear.app/oauth/token",Md="https://api.linear.app/graphql",Ud=["read","write","app:assignable","app:mentionable"],Fd=10*6e4,ka=60*6e4,Xe=class extends Error{constructor(t,n){super(n??t);this.code=t}},Bd=`query FdaInbox {
584
584
  notifications(first: 30, orderBy: updatedAt) {
@@ -577,7 +577,7 @@ ALTER TABLE request_conversations ADD COLUMN opening TEXT;
577
577
  ${n}`:""}`;if(!s)return this.postMarkdown(e,i,`Question: ${t}`,{live:this.endLive(e),final:1}),this.status(e);let o=fi(this.clean(i),e.id,{...s,options:s.options.map(a=>this.clean(a))});this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:this.clean(`Question: ${t}`),blocks:o.blocks,overflow:o.overflow,choicesId:s.id,live:this.endLive(e),final:1}),this.status(e)}plan(e,t,n){let s=pi(this.clean(t.markdown),t.version,e.id,n?this.clean(n):null);this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:s.text,blocks:s.blocks,overflow:s.overflow,planVersion:t.version,live:this.endLive(e),final:1}),this.status(e)}handoff(e,t,n){let s=o=>o.replace(/[^A-Z0-9]/gi,""),i=`<@${s(t.to)}> ${this.clean(t.task)}
578
578
 
579
579
  _Hand-off for <@${s(t.requester)}>: react with \u2705 to approve it (only <@${s(t.requester)}> can)._`;this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:i.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:i.slice(0,2900)}}],overflow:null,metadata:n})}failed(e,t){this.postMarkdown(e,t,t,{live:this.endLive(e),final:1}),this.status(e)}cancelled(e,t){let n=t?`Stopped by <@${t}>.`:"Stopped.";this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:n,blocks:[],overflow:null,live:this.endLive(e)}),this.status(e)}conversationPost(e,t,n,s={}){let i=new Set(le(t).map(a=>a.id)),o=Qi(this.redactor.redact(n).text,i);this.add(t.channel_id,e.id,{op:"post",requestId:e.id,threadTs:null,text:o.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:o.slice(0,3e3)}}],overflow:null,...s.opening?{conversationOpen:t.id}:{}})}conversationNote(e,t){let n=this.redactor.redact(t).text.replace(/<!(channel|here|everyone|subteam)[^>]{0,200}>/gi,"").slice(0,2900);this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:n,blocks:[{type:"section",text:{type:"mrkdwn",text:n}}],overflow:null})}conversationReply(e,t,n){let s=this.store.getConversation(t);if(!s){let o=n.trim()||"Done.";return this.postMarkdown(e,o,o,{live:this.endLive(e),final:1}),this.status(e)}let i=this.endLive(e);n.trim()&&this.conversationPost(e,s,n),i&&this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:"Replied in the conversation.",blocks:[],overflow:null,live:i}),this.status(e)}info(e,t,n={}){this.postMarkdown(e,t,t,n.final?{live:this.endLive(e)}:{})}dropProgress(e){this.store.outboxDropPendingUpdates(e.id)}progress(e,t){this.postMarkdown(e,t,t,{progress:1})}scheduleCard(e,t){let n=ki({...t,title:this.clean(t.title),prompt:this.clean(t.prompt)});this.add(e.channel_id,e.id,{op:"post",requestId:e.id,threadTs:e.thread_ts,text:n.text,blocks:n.blocks,overflow:null,scheduleId:t.id})}prAnnounce(e,t,n){let i=[`:eyes: *${this.clean(n.title).replace(/[*\n]/g," ").trim().slice(0,200)||"Pull request"}*`,`${n.prLink}${n.ticketLink?` \xB7 Ticket ${n.ticketLink}`:""}`,...n.reviewers.length?[`Review: ${n.reviewers.join(", ")}`]:[]].join(`
580
- `);this.add(e,null,{op:"post",requestId:null,threadTs:null,text:i.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:i.slice(0,2900)}}],overflow:null,prFollowId:t})}reactTo(e,t,n){n.length&&this.add(e,null,{op:"react",requestId:"",reaction:n[0],ts:t,fallbacks:n.slice(1)})}dm(e,t){this.add(e,null,{op:"dm",user:e,text:this.clean(t)})}ephemeral(e,t,n,s){this.add(e,null,{op:"ephemeral",user:t,threadTs:n,text:s})}upload(e,t,n,s){this.add(e.channel_id,e.id,{op:"upload",requestId:e.id,threadTs:e.thread_ts,path:t,filename:n,title:this.clean(s)})}update(e,t,n,s,i){this.add(e,t,{op:"update",ts:n,text:s,blocks:i})}};import hc from"node:fs";var G=class extends Error{constructor(t,n=null){super(t);this.code=t;this.retryAfterSec=n}};function pc(r){return r.status==="awaiting_input"||r.status==="awaiting_approval"||r.plan_status==="proposed"?"suspended":r.status==="queued"||r.status==="running"?"processing":"active"}var gc=new Set(["feature_disabled","unknown_method","missing_scope","not_allowed_token_type","no_permission","access_denied"]),mc=6*36e5,fc=new Set(["invalid_auth","account_inactive","token_revoked","not_authed","missing_scope","token_expired"]),Co=new Set(["channel_not_found","is_archived","not_in_channel","thread_not_found","message_not_found","cant_update_message","msg_too_long","no_text","user_not_in_channel","file_not_found"]),wc=5,_c=new Set(["user_not_found","user_disabled","cannot_dm_bot","user_not_visible","not_allowed_token_type"]),Ct=class{constructor(e){this.d=e;this.now=e.now??Date.now}timer=null;busy=!1;stopped=!1;halted=!1;now;lastLive=new Map;dmScopeLogged=!1;sessionsOffUntil=0;lastSession=new Map;start(){this.stopped=!1,this.halted=!1,this.wake()}resume(){this.halted&&(this.halted=!1,this.d.store.outboxRetryNow(this.now()),this.wake())}stop(){this.stopped=!0,this.timer&&clearTimeout(this.timer)}wake(){this.stopped||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),0))}inflight=null;idle(){return this.inflight??Promise.resolve()}drain(){return this.busy||this.stopped||this.halted?this.idle():(this.inflight=this.drainOnce().finally(()=>{this.inflight=null}),this.inflight)}async drainOnce(){let e=this.d.lane==="tickets"?null:this.d.slack();if(!e&&this.d.lane!=="tickets")return;this.busy=!0;try{for(;;){let n=this.d.store.outboxDue(this.now(),20,this.d.lane);if(!n.length)break;for(let s of n){if(this.halted||this.stopped)break;await this.send(e,s)}if(this.halted||this.stopped)return}}finally{this.busy=!1}let t=this.d.store.outboxNextWakeAt(this.d.lane);t!==null&&!this.stopped&&(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),Math.max(50,t-this.now())),this.timer.unref?.())}async send(e,t){let{store:n}=this.d,s;try{s=JSON.parse(t.payload)}catch{n.outboxFinal(t.id,"dropped","bad payload");return}try{let i=await this.execute(e,t.channel,s);n.outboxSent(t.id,i)}catch(i){let o=i instanceof G?i.code:String(i?.message??i);i instanceof G&&o==="ratelimited"?n.outboxRetry(t.id,this.now()+Math.max(1,i.retryAfterSec??30)*1e3,o):fc.has(o)?(n.outboxHold(t.id,this.now()+36e5,o),this.halted=!0,this.d.onFatal(o)):Co.has(o)||t.attempts+1>=wc?(n.outboxFinal(t.id,"dropped",o),this.d.onDropped?.(o,t.channel)):o==="invalid_blocks"&&s.op==="post"?(n.outboxFinal(t.id,"dropped",o),n.outboxAdd({requestId:s.requestId,channel:t.channel,kind:"post",payload:{...s,blocks:[]}})):n.outboxRetry(t.id,this.now()+2**t.attempts*1e3,o)}}metadataFor(e){if(e.metadata)return e.metadata;if(e.requestId){if(e.final)try{let t=this.d.threadBlock?.(e.requestId,e.text);if(t)return t}catch{}return{event_type:"fda_message",event_payload:{request:e.requestId}}}}async finishLive(e,t,n,s){let{store:i}=this.d,o=i.getRequest(n.requestId),a=o?.status_ts??null,l=()=>{o&&i.updateRequest(o.id,{status_ts:null},o.updated_at),o&&this.lastLive.delete(o.id)};if(a&&!s.handoff)try{return await e.updateMessage({channel:t,ts:a,text:n.text,blocks:n.blocks,metadata:n.final?this.metadataFor(n):void 0}),n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,a),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,a),l(),a}catch(d){if(!(d instanceof G)||Co.has(d.code)===!1)throw d}let u=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});if(n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,u.ts),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,u.ts),a){let d=mi(this.now()-s.since);await e.updateMessage({channel:t,ts:a,text:d.text,blocks:d.blocks}).catch(()=>{})}return l(),u.ts}async execute(e,t,n){let{store:s}=this.d;if(t.startsWith("tk:"))return this.d.tickets?this.d.tickets(t,n):null;switch(n.op){case"post":{if(n.live&&n.requestId)return this.finishLive(e,t,n,n.live);let i=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});return n.planVersion&&n.requestId&&s.setPlanMessageTs(n.requestId,n.planVersion,i.ts),n.choicesId&&n.requestId&&s.setChoicesMessageTs(n.requestId,n.choicesId,i.ts),n.scheduleId&&s.updateSchedule(n.scheduleId,{card_ts:i.ts}),n.prFollowId&&s.updatePrFollow(n.prFollowId,{announce_ts:i.ts}),n.conversationOpen&&s.setConversationOpenedTs(n.conversationOpen,i.ts),i.ts}case"dm":{let i;try{if(!e.openDm)throw new G("missing_scope");i=await e.openDm(n.user)}catch(a){let l=a instanceof G?a.code:"";if(l==="missing_scope")return this.dmScopeLogged||this.d.log?.("slack: a direct message was skipped: the Slack app needs the im:write scope (add it under OAuth & Permissions and reinstall the app)"),this.dmScopeLogged=!0,null;if(_c.has(l))return null;throw a}return(await e.postMessage({channel:i,text:n.text})).ts}case"status":{if(!n.live)return null;let i=s.getRequest(n.requestId);if(!i||i.live_since!==n.live.since)return i&&this.lastLive.delete(i.id),null;let o=Yt({step:n.live.step,handoff:i.live_handoff===1,queued:i.status==="queued"&&this.now()-n.live.since>1500,icons:n.live.icons,stopFor:this.d.stopButton?.()?i.id:null}),a=JSON.stringify(o.blocks);if(i.status_ts)return this.lastLive.get(i.id)===a||(await e.updateMessage({channel:t,ts:i.status_ts,text:o.text,blocks:o.blocks}),this.lastLive.set(i.id,a)),i.status_ts;let l=null;try{l=this.d.presenceBlock?.(i.id)??null}catch{}let u=await e.postMessage({channel:t,threadTs:i.thread_ts,text:o.text,blocks:o.blocks,...l?{metadata:l}:{}});return s.updateRequest(i.id,{status_ts:u.ts},i.updated_at),this.lastLive.set(i.id,a),u.ts}case"session":{if(!e.setAgentSession||this.now()<this.sessionsOffUntil)return null;let i=s.getRequest(n.requestId);if(!i?.thread_ts)return null;let o=pc(i),a=i.title.trim(),l=this.lastSession.get(i.id);if(l?.status===o&&l.title===a)return null;try{await e.setAgentSession({channel:t,threadTs:i.thread_ts,status:o,title:a||void 0}),a&&l&&l.title!==a&&await e.renameAgentSession?.({channel:t,threadTs:i.thread_ts,title:a}),this.lastSession.set(i.id,{status:o,title:a})}catch(u){let d=u instanceof G?u.code:"";gc.has(d)&&(this.sessionsOffUntil||this.d.log?.(`slack: agent sessions are off for this app (${d}); turn on the Agent experience in the Slack app settings to show progress and a stop button`),this.sessionsOffUntil=this.now()+mc)}return o==="active"&&this.lastSession.delete(i.id),null}case"react":{if(n.ts){for(let l of[n.reaction,...n.fallbacks??[]])try{return await e.addReaction(t,n.ts,l),null}catch(u){if(!(u instanceof G)||u.code!=="invalid_name")throw u}return null}let i=s.getRequest(n.requestId);if(!i)return null;let o=i.status_reaction;if(o===n.reaction)return null;let a=o?[o]:No.filter(l=>l!==n.reaction);for(let l of a)await e.removeReaction(t,i.origin_ts,l);return await e.addReaction(t,i.origin_ts,n.reaction),s.updateRequest(i.id,{status_reaction:n.reaction},i.updated_at),null}case"ephemeral":return await e.postEphemeral({channel:t,user:n.user,text:n.text,threadTs:n.threadTs}),null;case"upload":{let i=hc.readFileSync(n.path);return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:i}),null}case"text_file":return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:Buffer.from(n.content,"utf8")}),null;case"update":return await e.updateMessage({channel:t,ts:n.ts,text:n.text,blocks:n.blocks}),n.ts}}};import{SocketModeClient as kc}from"@slack/socket-mode";var Sn=class{constructor(e){this.d=e}client=null;async start(){let e=new kc({appToken:this.d.appToken,logLevel:void 0});this.client=e,e.on("slack_event",async t=>{try{this.d.receive({type:t.type,envelope_id:t.envelope_id,body:t.body})}catch(n){this.d.log(`inbox insert failed: ${String(n)}`);return}try{await t.ack()}catch{}this.d.onReceived()}),e.on("connected",()=>this.d.onConnected()),e.on("disconnected",()=>this.d.onDisconnected()),await e.start()}async stop(){let e=this.client;if(this.client=null,e)try{await e.disconnect()}catch{}}};import{WebClient as Ks}from"@slack/web-api";var yc="files.slack.com";function bc(r){let e=r;throw e?.code==="slack_webapi_rate_limited_error"?new G("ratelimited",e.retryAfter??30):e?.data?.error?new G(e.data.error):e?.code==="slack_webapi_request_error"?new G("network_error"):new G(e?.message??"unknown_error")}async function X(r){try{return await r}catch(e){bc(e)}}var Pt=class{constructor(e){this.token=e;this.post=new Ks(e,{retryConfig:{retries:0},rejectRateLimitedCalls:!0,timeout:15e3}),this.read=new Ks(e,{retryConfig:{retries:3},timeout:15e3}),this.background=new Ks(e,{retryConfig:{retries:2},timeout:15e3})}post;read;background;async authTest(){let e=await X(this.read.auth.test());return{userId:String(e.user_id),botId:e.bot_id??null,teamId:String(e.team_id),team:String(e.team),user:String(e.user)}}async postMessage(e){let t=await X(this.post.chat.postMessage({channel:e.channel,thread_ts:e.threadTs??void 0,text:e.text,blocks:e.blocks,metadata:e.metadata,unfurl_links:!1,unfurl_media:!1}));return{ts:String(t.ts)}}async updateMessage(e){await X(this.post.chat.update({channel:e.channel,ts:e.ts,text:e.text,blocks:e.blocks,...e.metadata?{metadata:e.metadata}:{}}))}async postEphemeral(e){await X(this.post.chat.postEphemeral({channel:e.channel,user:e.user,text:e.text,thread_ts:e.threadTs??void 0}))}async addReaction(e,t,n){try{await X(this.post.reactions.add({channel:e,timestamp:t,name:n}))}catch(s){if(s.code!=="already_reacted")throw s}}async setAgentSession(e){await X(this.post.apiCall("agents.sessions.setStatus",{channel_id:e.channel,thread_ts:e.threadTs,status:e.status,...e.title?{title:e.title.slice(0,200)}:{}}))}async renameAgentSession(e){await X(this.post.apiCall("agents.sessions.rename",{channel_id:e.channel,thread_ts:e.threadTs,title:e.title.slice(0,200)}))}async openDm(e){let n=(await X(this.post.conversations.open({users:e}))).channel?.id;if(!n)throw new G("channel_not_found");return n}async openConversation(e){let n=(await X(this.post.conversations.open({users:e.join(",")}))).channel?.id;if(!n)throw new G("channel_not_found");return n}async removeReaction(e,t,n){try{await X(this.post.reactions.remove({channel:e,timestamp:t,name:n}))}catch(s){if(s.code!=="no_reaction")throw s}}async uploadFile(e){await X(this.post.filesUploadV2({channel_id:e.channel,thread_ts:e.threadTs,filename:e.filename,title:e.title,file:e.content}))}async permalink(e,t){try{return(await X(this.read.chat.getPermalink({channel:e,message_ts:t}))).permalink??null}catch{return null}}async replies(e,t,n,s=200,i=!1,o=!1){let a=i?this.background:this.read,l=[],u;do{let d=await X(a.conversations.replies({channel:e,ts:t,oldest:n,limit:Math.min(s,200),cursor:u,inclusive:!1,...o?{include_all_metadata:!0}:{}}));for(let h of d.messages??[])l.push({ts:String(h.ts),user:h.user??null,botId:h.bot_id??null,text:h.text??"",subtype:h.subtype??null,threadTs:h.thread_ts??null,files:Array.isArray(h.files)?h.files:[],botName:h.bot_profile?.name??h.username??null,metadata:h.metadata??null});u=d.response_metadata?.next_cursor||void 0}while(u&&l.length<s);return l}async userInfo(e){try{let n=(await X(this.read.users.info({user:e}))).user,s=n.profile??{};return{id:e,name:String(s.display_name||s.real_name||n.real_name||n.name||e),isBot:!!n.is_bot,teamId:n.team_id??null,tz:typeof n.tz=="string"?n.tz:null,isGuest:!!n.is_restricted||!!n.is_ultra_restricted,deleted:!!n.deleted,email:typeof s.email=="string"?s.email:null,realName:typeof s.real_name=="string"?s.real_name:null}}catch{return null}}async channelInfo(e){try{let t=await X(this.read.conversations.info({channel:e}));return Po(t.channel)}catch{return null}}async listChannels(){let e=[],t;do{let n=await X(this.read.conversations.list({types:"public_channel,private_channel",exclude_archived:!0,limit:200,cursor:t}));for(let s of n.channels??[])e.push(Po(s));t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<5e3);return e}async listUsers(){let e=[],t;do{let n=await X(this.read.users.list({limit:200,cursor:t}));for(let s of n.members??[]){if(s.deleted)continue;let i=s.profile??{};e.push({id:String(s.id),name:String(i.display_name||i.real_name||s.name),isBot:!!s.is_bot||s.id==="USLACKBOT",teamId:s.team_id??null,isGuest:!!s.is_restricted||!!s.is_ultra_restricted,email:typeof i.email=="string"?i.email:null,realName:typeof i.real_name=="string"?i.real_name:null})}t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<2e4);return e}async listUsergroups(){try{return((await X(this.read.usergroups.list({include_disabled:!1}))).usergroups??[]).map(t=>({id:String(t.id),handle:String(t.handle??""),name:String(t.name??"")}))}catch{return[]}}async isChannelMember(e,t){let n;for(let s=0;s<50;s++){let i=await X(this.read.conversations.members({channel:e,limit:1e3,cursor:n}));if((i.members??[]).includes(t))return!0;if(n=i.response_metadata?.next_cursor||void 0,!n)break}return!1}async usergroupMembers(e){return(await X(this.read.usergroups.users.list({usergroup:e}))).users??[]}async openModal(e,t){await X(this.post.views.open({trigger_id:e,view:t}))}async publishHome(e,t){await X(this.post.views.publish({user_id:e,view:t}))}async download(e,t){let n=new URL(e);if(n.protocol!=="https:"||n.hostname!==yc)throw new G("untrusted_file_host");let s=await fetch(n,{headers:{Authorization:`Bearer ${this.token}`},redirect:"error",signal:AbortSignal.timeout(12e4)});if(!s.ok||!s.body)throw new G(`download_http_${s.status}`);if(Number(s.headers.get("content-length")||0)>t)throw new G("file_too_large");let o=[],a=0;for await(let l of s.body){if(a+=l.byteLength,a>t)throw new G("file_too_large");o.push(Buffer.from(l))}return Buffer.concat(o)}};function Po(r){return{id:String(r.id),name:r.name??null,isPrivate:!!r.is_private,isExtShared:!!r.is_ext_shared||!!r.is_pending_ext_shared,isMember:!!r.is_member}}import Tc from"node:os";var Ec=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Rn=class{constructor(e){this.d=e;this.base=(e.baseUrl??Nr).replace(/\/$/,""),this.fetch=e.fetch??fetch}base;fetch;async call(e,t,n,s={}){let i=this.d.credential(),o=s.userLevel?null:this.d.workspaceSlug();if(!i||!o&&!s.userLevel)return{ok:!1,kind:"auth",status:0};let a;try{a=await this.fetch(`${this.base}${t}`,{method:e,headers:{"content-type":"application/json","x-mcp-key-id":i.keyId,"x-mcp-secret":i.secret,...o?{"x-workspace-slug":o}:{},"user-agent":`superclawd-fda/${Je}`},body:n===void 0?void 0:JSON.stringify(n),redirect:"error",signal:AbortSignal.timeout(s.timeoutMs??this.d.timeoutMs??1e4)})}catch{return{ok:!1,kind:"unavailable",status:0}}if(a.ok)try{let d=await a.json();return{ok:!0,data:d.data??d}}catch{return{ok:!1,kind:"unavailable",status:a.status}}return await a.body?.cancel().catch(()=>{}),{ok:!1,kind:{400:"bad_request",401:"auth",403:"forbidden",404:"not_found",409:"limit",410:"revoked",429:"rate_limited"}[a.status]??"unavailable",status:a.status}}async workspaces(){let e=await this.call("GET","/api/prompt/workspaces",void 0,{userLevel:!0});return e.ok?{ok:!0,data:(Array.isArray(e.data?.workspaces)?e.data.workspaces:[]).filter(n=>typeof n?.slug=="string").map(n=>({slug:n.slug,name:String(n.name??n.slug),role:n.role??null}))}:e}agents(){return this.call("GET","/api/prompt/fda/agents")}register(e,t=Tc.hostname()){return this.call("POST","/api/prompt/fda/machines",{machineId:e,label:t.slice(0,120)||"fda",daemonVersion:Je.slice(0,40)})}bridgeRegister(e,t,n){return this.call("POST","/api/prompt/fda/bridge",{machineId:e,tracker:t,secret:n})}bridgeWait(e){return this.call("GET",`/api/prompt/fda/bridge/wait?token=${encodeURIComponent(e)}`,void 0,{timeoutMs:35e3})}heartbeat(e,t){return this.call("POST",`/api/prompt/fda/machines/${encodeURIComponent(e)}/heartbeat`,{state:t.state,queueDepth:Math.max(0,Math.min(1e4,Math.trunc(t.queueDepth))),agentId:t.agentId&&Ec.test(t.agentId)?t.agentId:null,slackBotName:t.slackBotName?.slice(0,80)??null,daemonVersion:Je.slice(0,40),currentTitle:t.currentTitle?.slice(0,120)??null})}};function mt(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"skill"}var vn=class{constructor(e){this.d=e}timer=null;registered=!1;agentChecked=!1;running=!1;start(){this.tick(),this.timer=setInterval(()=>void this.tick(),this.d.intervalMs??6e4),this.timer.unref()}stop(){this.timer&&clearInterval(this.timer),this.timer=null}reset(){this.registered=!1,this.agentChecked=!1}async tick(){if(!this.running){this.running=!0;try{let e=this.d.machineId();if(!e)return;if(!this.registered){let n=await this.d.client.register(e);if(!n.ok)return this.fail(n.kind);this.registered=!0,this.d.clearCondition("machine_revoked"),this.agentChecked=!1}this.agentChecked||(this.agentChecked=!0,await this.resolveAgent());let t=await this.d.client.heartbeat(e,this.d.heartbeat());if(!t.ok)return t.kind==="not_found"&&(this.registered=!1),t.kind==="rate_limited"?void 0:this.fail(t.kind);this.d.clearCondition("cloud"),t.data.agentRejected&&(this.agentChecked=!1),this.adoptAssignedAgent(t.data.assignedAgent)}catch(e){this.d.log?.(`cloud: ${e.message}`)}finally{this.running=!1}}}fail(e){e==="revoked"?(this.registered=!1,this.d.setCondition("machine_revoked","blocked","This machine was revoked in the SuperClawd App. If it should run again, a maintainer can register it anew with `superclawd fda setup --workspace <slug> --reset-id`.")):e==="auth"?this.d.setCondition("cloud","warn","SuperClawd rejected this machine's login. Run `superclawd login`."):e==="forbidden"?this.d.setCondition("cloud","warn","This machine was registered by another SuperClawd user. Log in as them, or ask a workspace maintainer."):e==="limit"?this.d.setCondition("cloud","warn","This workspace has reached its FDA machine limit. Remove an unused machine in the SuperClawd App."):e==="bad_request"?this.d.setCondition("cloud","warn","SuperClawd refused this machine's report. Updating SuperClawd FDA may help."):e!=="not_found"&&this.d.setCondition("cloud","warn","Can't reach SuperClawd right now; retrying.")}adoptAssignedAgent(e){if(!e||!this.d.setAgentName)return;let t=mt(e.name);t===this.d.agentName()&&e.id===this.d.agentId()||(this.d.setAgentName(t),this.d.setAgentId(e.id),this.d.clearCondition("agent_cloud"),this.d.log?.(`cloud: agent switched to "${t}" (picked in the SuperClawd App)`))}async resolveAgent(){let e=this.d.agentName();if(!e)return;let t=await this.d.client.agents();if(!t.ok)return;let n=t.data.find(s=>mt(s.name)===e||s.id===this.d.agentId());if(!n){this.d.agentId()&&this.d.setAgentId(null),this.d.setCondition("agent_cloud","blocked",`The selected agent "${e}" isn't an enabled Primary agent in this workspace. Pick another one.`);return}this.d.clearCondition("agent_cloud"),n.id!==this.d.agentId()&&this.d.setAgentId(n.id)}};import Qe from"node:crypto";import xn from"node:fs";var $e={N:2**15,r:8,p:1,maxmem:64*1024*1024},$o=32,Lo=12*36e5,Sc=7*24*36e5,Rc=6e4,vc=6e4,xc=12,Ic=30,Ac=8,Nc=180*24*36e5,Cc=/^[a-zA-Z0-9._-]{3,40}$/,Ys=0,Qs=[];async function Pc(r){Ys>=2&&await new Promise(e=>Qs.push(e)),Ys++;try{return await r()}finally{Ys--,Qs.shift()?.()}}function qo(r,e){return Pc(()=>new Promise((t,n)=>Qe.scrypt(r,e,$o,$e,(s,i)=>s?n(s):t(i))))}async function Js(r){let e=Qe.randomBytes(16),t=await qo(r,e);return`scrypt$${$e.N}$${$e.r}$${$e.p}$${e.toString("base64")}$${t.toString("base64")}`}async function Vs(r,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,n,s,i,o,a]=t;if(Number(n)!==$e.N||Number(s)!==$e.r||Number(i)!==$e.p)return!1;let l=Buffer.from(a,"base64"),u=await qo(r,Buffer.from(o,"base64"));return u.length===l.length&&Qe.timingSafeEqual(u,l)}function Oo(r=20){let e="abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789",t=Qe.randomBytes(r),n="";for(let s=0;s<r;s++)n+=e[t[s]%e.length];return n}function Zs(r){return Qe.createHash("sha256").update(r).digest("hex")}var In=class{constructor(e,t=Date.now){this.db=e;this.now=t}failWindowStart=0;failsInWindow=0;toUser(e){return{id:e.id,username:e.username,mustChange:e.must_change===1}}async ensureAdmin(){if(this.db.get("SELECT id FROM admin_users LIMIT 1"))return{created:!1};let e=Oo(),t=await Js(e);return this.db.get("SELECT id FROM admin_users LIMIT 1")?{created:!1}:(this.db.run("INSERT INTO admin_users (id, username, password_hash, must_change, updated_at) VALUES (?, 'admin', ?, 1, ?)",Qe.randomUUID(),t,this.now()),xn.writeFileSync(q.initialPassword,`${e}
580
+ `);this.add(e,null,{op:"post",requestId:null,threadTs:null,text:i.slice(0,3e3),blocks:[{type:"section",text:{type:"mrkdwn",text:i.slice(0,2900)}}],overflow:null,prFollowId:t})}reactTo(e,t,n){n.length&&this.add(e,null,{op:"react",requestId:"",reaction:n[0],ts:t,fallbacks:n.slice(1)})}dm(e,t){this.add(e,null,{op:"dm",user:e,text:this.clean(t)})}ephemeral(e,t,n,s){this.add(e,null,{op:"ephemeral",user:t,threadTs:n,text:s})}upload(e,t,n,s){this.add(e.channel_id,e.id,{op:"upload",requestId:e.id,threadTs:e.thread_ts,path:t,filename:n,title:this.clean(s)})}update(e,t,n,s,i){this.add(e,t,{op:"update",ts:n,text:s,blocks:i})}};import hc from"node:fs";var G=class extends Error{constructor(t,n=null){super(t);this.code=t;this.retryAfterSec=n}};function pc(r){return r.status==="awaiting_input"||r.status==="awaiting_approval"||r.plan_status==="proposed"?"suspended":r.status==="queued"||r.status==="running"?"processing":"active"}var gc=new Set(["not_authorized","feature_disabled","unknown_method","missing_scope","not_allowed_token_type","no_permission","access_denied"]),mc=6*36e5,fc=new Set(["invalid_auth","account_inactive","token_revoked","not_authed","missing_scope","token_expired"]),Co=new Set(["channel_not_found","is_archived","not_in_channel","thread_not_found","message_not_found","cant_update_message","msg_too_long","no_text","user_not_in_channel","file_not_found"]),wc=5,_c=new Set(["user_not_found","user_disabled","cannot_dm_bot","user_not_visible","not_allowed_token_type"]),Ct=class{constructor(e){this.d=e;this.now=e.now??Date.now}timer=null;busy=!1;stopped=!1;halted=!1;now;lastLive=new Map;dmScopeLogged=!1;sessionsOffUntil=0;lastSession=new Map;sessionErrorsLogged=new Set;start(){this.stopped=!1,this.halted=!1,this.wake()}resume(){this.halted&&(this.halted=!1,this.d.store.outboxRetryNow(this.now()),this.wake())}stop(){this.stopped=!0,this.timer&&clearTimeout(this.timer)}wake(){this.stopped||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),0))}inflight=null;idle(){return this.inflight??Promise.resolve()}drain(){return this.busy||this.stopped||this.halted?this.idle():(this.inflight=this.drainOnce().finally(()=>{this.inflight=null}),this.inflight)}async drainOnce(){let e=this.d.lane==="tickets"?null:this.d.slack();if(!e&&this.d.lane!=="tickets")return;this.busy=!0;try{for(;;){let n=this.d.store.outboxDue(this.now(),20,this.d.lane);if(!n.length)break;for(let s of n){if(this.halted||this.stopped)break;await this.send(e,s)}if(this.halted||this.stopped)return}}finally{this.busy=!1}let t=this.d.store.outboxNextWakeAt(this.d.lane);t!==null&&!this.stopped&&(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>void this.drain(),Math.max(50,t-this.now())),this.timer.unref?.())}async send(e,t){let{store:n}=this.d,s;try{s=JSON.parse(t.payload)}catch{n.outboxFinal(t.id,"dropped","bad payload");return}try{let i=await this.execute(e,t.channel,s);n.outboxSent(t.id,i)}catch(i){let o=i instanceof G?i.code:String(i?.message??i);i instanceof G&&o==="ratelimited"?n.outboxRetry(t.id,this.now()+Math.max(1,i.retryAfterSec??30)*1e3,o):fc.has(o)?(n.outboxHold(t.id,this.now()+36e5,o),this.halted=!0,this.d.onFatal(o)):Co.has(o)||t.attempts+1>=wc?(n.outboxFinal(t.id,"dropped",o),this.d.onDropped?.(o,t.channel)):o==="invalid_blocks"&&s.op==="post"?(n.outboxFinal(t.id,"dropped",o),n.outboxAdd({requestId:s.requestId,channel:t.channel,kind:"post",payload:{...s,blocks:[]}})):n.outboxRetry(t.id,this.now()+2**t.attempts*1e3,o)}}metadataFor(e){if(e.metadata)return e.metadata;if(e.requestId){if(e.final)try{let t=this.d.threadBlock?.(e.requestId,e.text);if(t)return t}catch{}return{event_type:"fda_message",event_payload:{request:e.requestId}}}}async finishLive(e,t,n,s){let{store:i}=this.d,o=i.getRequest(n.requestId),a=o?.status_ts??null,l=()=>{o&&i.updateRequest(o.id,{status_ts:null},o.updated_at),o&&this.lastLive.delete(o.id)};if(a&&!s.handoff)try{return await e.updateMessage({channel:t,ts:a,text:n.text,blocks:n.blocks,metadata:n.final?this.metadataFor(n):void 0}),n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,a),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,a),l(),a}catch(d){if(!(d instanceof G)||Co.has(d.code)===!1)throw d}let u=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});if(n.planVersion&&i.setPlanMessageTs(n.requestId,n.planVersion,u.ts),n.choicesId&&i.setChoicesMessageTs(n.requestId,n.choicesId,u.ts),a){let d=mi(this.now()-s.since);await e.updateMessage({channel:t,ts:a,text:d.text,blocks:d.blocks}).catch(()=>{})}return l(),u.ts}async execute(e,t,n){let{store:s}=this.d;if(t.startsWith("tk:"))return this.d.tickets?this.d.tickets(t,n):null;switch(n.op){case"post":{if(n.live&&n.requestId)return this.finishLive(e,t,n,n.live);let i=await e.postMessage({channel:t,threadTs:n.threadTs,text:n.text,blocks:n.blocks.length?n.blocks:void 0,metadata:this.metadataFor(n)});return n.planVersion&&n.requestId&&s.setPlanMessageTs(n.requestId,n.planVersion,i.ts),n.choicesId&&n.requestId&&s.setChoicesMessageTs(n.requestId,n.choicesId,i.ts),n.scheduleId&&s.updateSchedule(n.scheduleId,{card_ts:i.ts}),n.prFollowId&&s.updatePrFollow(n.prFollowId,{announce_ts:i.ts}),n.conversationOpen&&s.setConversationOpenedTs(n.conversationOpen,i.ts),i.ts}case"dm":{let i;try{if(!e.openDm)throw new G("missing_scope");i=await e.openDm(n.user)}catch(a){let l=a instanceof G?a.code:"";if(l==="missing_scope")return this.dmScopeLogged||this.d.log?.("slack: a direct message was skipped: the Slack app needs the im:write scope (add it under OAuth & Permissions and reinstall the app)"),this.dmScopeLogged=!0,null;if(_c.has(l))return null;throw a}return(await e.postMessage({channel:i,text:n.text})).ts}case"status":{if(!n.live)return null;let i=s.getRequest(n.requestId);if(!i||i.live_since!==n.live.since)return i&&this.lastLive.delete(i.id),null;let o=Yt({step:n.live.step,handoff:i.live_handoff===1,queued:i.status==="queued"&&this.now()-n.live.since>1500,icons:n.live.icons,stopFor:this.d.stopButton?.()?i.id:null}),a=JSON.stringify(o.blocks);if(i.status_ts)return this.lastLive.get(i.id)===a||(await e.updateMessage({channel:t,ts:i.status_ts,text:o.text,blocks:o.blocks}),this.lastLive.set(i.id,a)),i.status_ts;let l=null;try{l=this.d.presenceBlock?.(i.id)??null}catch{}let u=await e.postMessage({channel:t,threadTs:i.thread_ts,text:o.text,blocks:o.blocks,...l?{metadata:l}:{}});return s.updateRequest(i.id,{status_ts:u.ts},i.updated_at),this.lastLive.set(i.id,a),u.ts}case"session":{if(!e.setAgentSession||this.now()<this.sessionsOffUntil)return null;let i=s.getRequest(n.requestId);if(!i?.thread_ts)return null;let o=pc(i),a=i.title.trim(),l=this.lastSession.get(i.id);if(l?.status===o&&l.title===a)return null;try{await e.setAgentSession({channel:t,threadTs:i.thread_ts,status:o,title:a||void 0}),a&&l&&l.title!==a&&await e.renameAgentSession?.({channel:t,threadTs:i.thread_ts,title:a}),this.lastSession.set(i.id,{status:o,title:a})}catch(u){let d=u instanceof G?u.code:"";gc.has(d)?(this.sessionsOffUntil||this.d.log?.(`slack: agent sessions are off for this app (${d}); turn on the Agent experience in the Slack app settings to show progress and a stop button`),this.sessionsOffUntil=this.now()+mc):this.sessionErrorsLogged.has(d)||(this.sessionErrorsLogged.add(d),this.d.log?.(`slack: an agent session update was skipped (${d||String(u)})`))}return o==="active"&&this.lastSession.delete(i.id),null}case"react":{if(n.ts){for(let l of[n.reaction,...n.fallbacks??[]])try{return await e.addReaction(t,n.ts,l),null}catch(u){if(!(u instanceof G)||u.code!=="invalid_name")throw u}return null}let i=s.getRequest(n.requestId);if(!i)return null;let o=i.status_reaction;if(o===n.reaction)return null;let a=o?[o]:No.filter(l=>l!==n.reaction);for(let l of a)await e.removeReaction(t,i.origin_ts,l);return await e.addReaction(t,i.origin_ts,n.reaction),s.updateRequest(i.id,{status_reaction:n.reaction},i.updated_at),null}case"ephemeral":return await e.postEphemeral({channel:t,user:n.user,text:n.text,threadTs:n.threadTs}),null;case"upload":{let i=hc.readFileSync(n.path);return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:i}),null}case"text_file":return await e.uploadFile({channel:t,threadTs:n.threadTs,filename:n.filename,title:n.title,content:Buffer.from(n.content,"utf8")}),null;case"update":return await e.updateMessage({channel:t,ts:n.ts,text:n.text,blocks:n.blocks}),n.ts}}};import{SocketModeClient as kc}from"@slack/socket-mode";var Sn=class{constructor(e){this.d=e}client=null;async start(){let e=new kc({appToken:this.d.appToken,logLevel:void 0});this.client=e,e.on("slack_event",async t=>{try{this.d.receive({type:t.type,envelope_id:t.envelope_id,body:t.body})}catch(n){this.d.log(`inbox insert failed: ${String(n)}`);return}try{await t.ack()}catch{}this.d.onReceived()}),e.on("connected",()=>this.d.onConnected()),e.on("disconnected",()=>this.d.onDisconnected()),await e.start()}async stop(){let e=this.client;if(this.client=null,e)try{await e.disconnect()}catch{}}};import{WebClient as Ks}from"@slack/web-api";var yc="files.slack.com";function bc(r){let e=r;throw e?.code==="slack_webapi_rate_limited_error"?new G("ratelimited",e.retryAfter??30):e?.data?.error?new G(e.data.error):e?.code==="slack_webapi_request_error"?new G("network_error"):new G(e?.message??"unknown_error")}async function X(r){try{return await r}catch(e){bc(e)}}var Pt=class{constructor(e){this.token=e;this.post=new Ks(e,{retryConfig:{retries:0},rejectRateLimitedCalls:!0,timeout:15e3}),this.read=new Ks(e,{retryConfig:{retries:3},timeout:15e3}),this.background=new Ks(e,{retryConfig:{retries:2},timeout:15e3})}post;read;background;async authTest(){let e=await X(this.read.auth.test());return{userId:String(e.user_id),botId:e.bot_id??null,teamId:String(e.team_id),team:String(e.team),user:String(e.user)}}async postMessage(e){let t=await X(this.post.chat.postMessage({channel:e.channel,thread_ts:e.threadTs??void 0,text:e.text,blocks:e.blocks,metadata:e.metadata,unfurl_links:!1,unfurl_media:!1}));return{ts:String(t.ts)}}async updateMessage(e){await X(this.post.chat.update({channel:e.channel,ts:e.ts,text:e.text,blocks:e.blocks,...e.metadata?{metadata:e.metadata}:{}}))}async postEphemeral(e){await X(this.post.chat.postEphemeral({channel:e.channel,user:e.user,text:e.text,thread_ts:e.threadTs??void 0}))}async addReaction(e,t,n){try{await X(this.post.reactions.add({channel:e,timestamp:t,name:n}))}catch(s){if(s.code!=="already_reacted")throw s}}async setAgentSession(e){await X(this.post.apiCall("agents.sessions.setStatus",{channel_id:e.channel,thread_ts:e.threadTs,status:e.status,...e.title?{title:e.title.slice(0,200)}:{}}))}async renameAgentSession(e){await X(this.post.apiCall("agents.sessions.rename",{channel_id:e.channel,thread_ts:e.threadTs,title:e.title.slice(0,200)}))}async openDm(e){let n=(await X(this.post.conversations.open({users:e}))).channel?.id;if(!n)throw new G("channel_not_found");return n}async openConversation(e){let n=(await X(this.post.conversations.open({users:e.join(",")}))).channel?.id;if(!n)throw new G("channel_not_found");return n}async removeReaction(e,t,n){try{await X(this.post.reactions.remove({channel:e,timestamp:t,name:n}))}catch(s){if(s.code!=="no_reaction")throw s}}async uploadFile(e){await X(this.post.filesUploadV2({channel_id:e.channel,thread_ts:e.threadTs,filename:e.filename,title:e.title,file:e.content}))}async permalink(e,t){try{return(await X(this.read.chat.getPermalink({channel:e,message_ts:t}))).permalink??null}catch{return null}}async replies(e,t,n,s=200,i=!1,o=!1){let a=i?this.background:this.read,l=[],u;do{let d=await X(a.conversations.replies({channel:e,ts:t,oldest:n,limit:Math.min(s,200),cursor:u,inclusive:!1,...o?{include_all_metadata:!0}:{}}));for(let h of d.messages??[])l.push({ts:String(h.ts),user:h.user??null,botId:h.bot_id??null,text:h.text??"",subtype:h.subtype??null,threadTs:h.thread_ts??null,files:Array.isArray(h.files)?h.files:[],botName:h.bot_profile?.name??h.username??null,metadata:h.metadata??null});u=d.response_metadata?.next_cursor||void 0}while(u&&l.length<s);return l}async userInfo(e){try{let n=(await X(this.read.users.info({user:e}))).user,s=n.profile??{};return{id:e,name:String(s.display_name||s.real_name||n.real_name||n.name||e),isBot:!!n.is_bot,teamId:n.team_id??null,tz:typeof n.tz=="string"?n.tz:null,isGuest:!!n.is_restricted||!!n.is_ultra_restricted,deleted:!!n.deleted,email:typeof s.email=="string"?s.email:null,realName:typeof s.real_name=="string"?s.real_name:null}}catch{return null}}async channelInfo(e){try{let t=await X(this.read.conversations.info({channel:e}));return Po(t.channel)}catch{return null}}async listChannels(){let e=[],t;do{let n=await X(this.read.conversations.list({types:"public_channel,private_channel",exclude_archived:!0,limit:200,cursor:t}));for(let s of n.channels??[])e.push(Po(s));t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<5e3);return e}async listUsers(){let e=[],t;do{let n=await X(this.read.users.list({limit:200,cursor:t}));for(let s of n.members??[]){if(s.deleted)continue;let i=s.profile??{};e.push({id:String(s.id),name:String(i.display_name||i.real_name||s.name),isBot:!!s.is_bot||s.id==="USLACKBOT",teamId:s.team_id??null,isGuest:!!s.is_restricted||!!s.is_ultra_restricted,email:typeof i.email=="string"?i.email:null,realName:typeof i.real_name=="string"?i.real_name:null})}t=n.response_metadata?.next_cursor||void 0}while(t&&e.length<2e4);return e}async listUsergroups(){try{return((await X(this.read.usergroups.list({include_disabled:!1}))).usergroups??[]).map(t=>({id:String(t.id),handle:String(t.handle??""),name:String(t.name??"")}))}catch{return[]}}async isChannelMember(e,t){let n;for(let s=0;s<50;s++){let i=await X(this.read.conversations.members({channel:e,limit:1e3,cursor:n}));if((i.members??[]).includes(t))return!0;if(n=i.response_metadata?.next_cursor||void 0,!n)break}return!1}async usergroupMembers(e){return(await X(this.read.usergroups.users.list({usergroup:e}))).users??[]}async openModal(e,t){await X(this.post.views.open({trigger_id:e,view:t}))}async publishHome(e,t){await X(this.post.views.publish({user_id:e,view:t}))}async download(e,t){let n=new URL(e);if(n.protocol!=="https:"||n.hostname!==yc)throw new G("untrusted_file_host");let s=await fetch(n,{headers:{Authorization:`Bearer ${this.token}`},redirect:"error",signal:AbortSignal.timeout(12e4)});if(!s.ok||!s.body)throw new G(`download_http_${s.status}`);if(Number(s.headers.get("content-length")||0)>t)throw new G("file_too_large");let o=[],a=0;for await(let l of s.body){if(a+=l.byteLength,a>t)throw new G("file_too_large");o.push(Buffer.from(l))}return Buffer.concat(o)}};function Po(r){return{id:String(r.id),name:r.name??null,isPrivate:!!r.is_private,isExtShared:!!r.is_ext_shared||!!r.is_pending_ext_shared,isMember:!!r.is_member}}import Tc from"node:os";var Ec=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Rn=class{constructor(e){this.d=e;this.base=(e.baseUrl??Nr).replace(/\/$/,""),this.fetch=e.fetch??fetch}base;fetch;async call(e,t,n,s={}){let i=this.d.credential(),o=s.userLevel?null:this.d.workspaceSlug();if(!i||!o&&!s.userLevel)return{ok:!1,kind:"auth",status:0};let a;try{a=await this.fetch(`${this.base}${t}`,{method:e,headers:{"content-type":"application/json","x-mcp-key-id":i.keyId,"x-mcp-secret":i.secret,...o?{"x-workspace-slug":o}:{},"user-agent":`superclawd-fda/${Je}`},body:n===void 0?void 0:JSON.stringify(n),redirect:"error",signal:AbortSignal.timeout(s.timeoutMs??this.d.timeoutMs??1e4)})}catch{return{ok:!1,kind:"unavailable",status:0}}if(a.ok)try{let d=await a.json();return{ok:!0,data:d.data??d}}catch{return{ok:!1,kind:"unavailable",status:a.status}}return await a.body?.cancel().catch(()=>{}),{ok:!1,kind:{400:"bad_request",401:"auth",403:"forbidden",404:"not_found",409:"limit",410:"revoked",429:"rate_limited"}[a.status]??"unavailable",status:a.status}}async workspaces(){let e=await this.call("GET","/api/prompt/workspaces",void 0,{userLevel:!0});return e.ok?{ok:!0,data:(Array.isArray(e.data?.workspaces)?e.data.workspaces:[]).filter(n=>typeof n?.slug=="string").map(n=>({slug:n.slug,name:String(n.name??n.slug),role:n.role??null}))}:e}agents(){return this.call("GET","/api/prompt/fda/agents")}register(e,t=Tc.hostname()){return this.call("POST","/api/prompt/fda/machines",{machineId:e,label:t.slice(0,120)||"fda",daemonVersion:Je.slice(0,40)})}bridgeRegister(e,t,n){return this.call("POST","/api/prompt/fda/bridge",{machineId:e,tracker:t,secret:n})}bridgeWait(e){return this.call("GET",`/api/prompt/fda/bridge/wait?token=${encodeURIComponent(e)}`,void 0,{timeoutMs:35e3})}heartbeat(e,t){return this.call("POST",`/api/prompt/fda/machines/${encodeURIComponent(e)}/heartbeat`,{state:t.state,queueDepth:Math.max(0,Math.min(1e4,Math.trunc(t.queueDepth))),agentId:t.agentId&&Ec.test(t.agentId)?t.agentId:null,slackBotName:t.slackBotName?.slice(0,80)??null,daemonVersion:Je.slice(0,40),currentTitle:t.currentTitle?.slice(0,120)??null})}};function mt(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"skill"}var vn=class{constructor(e){this.d=e}timer=null;registered=!1;agentChecked=!1;running=!1;start(){this.tick(),this.timer=setInterval(()=>void this.tick(),this.d.intervalMs??6e4),this.timer.unref()}stop(){this.timer&&clearInterval(this.timer),this.timer=null}reset(){this.registered=!1,this.agentChecked=!1}async tick(){if(!this.running){this.running=!0;try{let e=this.d.machineId();if(!e)return;if(!this.registered){let n=await this.d.client.register(e);if(!n.ok)return this.fail(n.kind);this.registered=!0,this.d.clearCondition("machine_revoked"),this.agentChecked=!1}this.agentChecked||(this.agentChecked=!0,await this.resolveAgent());let t=await this.d.client.heartbeat(e,this.d.heartbeat());if(!t.ok)return t.kind==="not_found"&&(this.registered=!1),t.kind==="rate_limited"?void 0:this.fail(t.kind);this.d.clearCondition("cloud"),t.data.agentRejected&&(this.agentChecked=!1),this.adoptAssignedAgent(t.data.assignedAgent)}catch(e){this.d.log?.(`cloud: ${e.message}`)}finally{this.running=!1}}}fail(e){e==="revoked"?(this.registered=!1,this.d.setCondition("machine_revoked","blocked","This machine was revoked in the SuperClawd App. If it should run again, a maintainer can register it anew with `superclawd fda setup --workspace <slug> --reset-id`.")):e==="auth"?this.d.setCondition("cloud","warn","SuperClawd rejected this machine's login. Run `superclawd login`."):e==="forbidden"?this.d.setCondition("cloud","warn","This machine was registered by another SuperClawd user. Log in as them, or ask a workspace maintainer."):e==="limit"?this.d.setCondition("cloud","warn","This workspace has reached its FDA machine limit. Remove an unused machine in the SuperClawd App."):e==="bad_request"?this.d.setCondition("cloud","warn","SuperClawd refused this machine's report. Updating SuperClawd FDA may help."):e!=="not_found"&&this.d.setCondition("cloud","warn","Can't reach SuperClawd right now; retrying.")}adoptAssignedAgent(e){if(!e||!this.d.setAgentName)return;let t=mt(e.name);t===this.d.agentName()&&e.id===this.d.agentId()||(this.d.setAgentName(t),this.d.setAgentId(e.id),this.d.clearCondition("agent_cloud"),this.d.log?.(`cloud: agent switched to "${t}" (picked in the SuperClawd App)`))}async resolveAgent(){let e=this.d.agentName();if(!e)return;let t=await this.d.client.agents();if(!t.ok)return;let n=t.data.find(s=>mt(s.name)===e||s.id===this.d.agentId());if(!n){this.d.agentId()&&this.d.setAgentId(null),this.d.setCondition("agent_cloud","blocked",`The selected agent "${e}" isn't an enabled Primary agent in this workspace. Pick another one.`);return}this.d.clearCondition("agent_cloud"),n.id!==this.d.agentId()&&this.d.setAgentId(n.id)}};import Qe from"node:crypto";import xn from"node:fs";var $e={N:2**15,r:8,p:1,maxmem:64*1024*1024},$o=32,Lo=12*36e5,Sc=7*24*36e5,Rc=6e4,vc=6e4,xc=12,Ic=30,Ac=8,Nc=180*24*36e5,Cc=/^[a-zA-Z0-9._-]{3,40}$/,Ys=0,Qs=[];async function Pc(r){Ys>=2&&await new Promise(e=>Qs.push(e)),Ys++;try{return await r()}finally{Ys--,Qs.shift()?.()}}function qo(r,e){return Pc(()=>new Promise((t,n)=>Qe.scrypt(r,e,$o,$e,(s,i)=>s?n(s):t(i))))}async function Js(r){let e=Qe.randomBytes(16),t=await qo(r,e);return`scrypt$${$e.N}$${$e.r}$${$e.p}$${e.toString("base64")}$${t.toString("base64")}`}async function Vs(r,e){let t=e.split("$");if(t.length!==6||t[0]!=="scrypt")return!1;let[,n,s,i,o,a]=t;if(Number(n)!==$e.N||Number(s)!==$e.r||Number(i)!==$e.p)return!1;let l=Buffer.from(a,"base64"),u=await qo(r,Buffer.from(o,"base64"));return u.length===l.length&&Qe.timingSafeEqual(u,l)}function Oo(r=20){let e="abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789",t=Qe.randomBytes(r),n="";for(let s=0;s<r;s++)n+=e[t[s]%e.length];return n}function Zs(r){return Qe.createHash("sha256").update(r).digest("hex")}var In=class{constructor(e,t=Date.now){this.db=e;this.now=t}failWindowStart=0;failsInWindow=0;toUser(e){return{id:e.id,username:e.username,mustChange:e.must_change===1}}async ensureAdmin(){if(this.db.get("SELECT id FROM admin_users LIMIT 1"))return{created:!1};let e=Oo(),t=await Js(e);return this.db.get("SELECT id FROM admin_users LIMIT 1")?{created:!1}:(this.db.run("INSERT INTO admin_users (id, username, password_hash, must_change, updated_at) VALUES (?, 'admin', ?, 1, ?)",Qe.randomUUID(),t,this.now()),xn.writeFileSync(q.initialPassword,`${e}
581
581
  `,{mode:384}),{created:!0})}initialPassword(){let e=this.db.get("SELECT must_change FROM admin_users LIMIT 1");if(!e||e.must_change!==1)return null;try{return xn.readFileSync(q.initialPassword,"utf8").trim()||null}catch{return null}}async login(e,t,n){let s=`${n??"-"}|${e.trim().toLowerCase().slice(0,64)}`,i=this.now();if(i-this.failWindowStart>6e4&&(this.failWindowStart=i,this.failsInWindow=0),this.failsInWindow>=Ic||Qs.length>=Ac)return{ok:!1,code:"rate_limited",retryAfterSec:10};let o=this.db.get("SELECT failures, next_allowed_at FROM login_attempts WHERE key = ?",s);if(o&&o.next_allowed_at>i)return{ok:!1,code:"rate_limited",retryAfterSec:Math.ceil((o.next_allowed_at-i)/1e3)};let a=(o?.failures??0)+1;this.db.run("INSERT INTO login_attempts (key, failures, next_allowed_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET failures = excluded.failures, next_allowed_at = excluded.next_allowed_at",s,a,i+Math.min(vc,1e3*2**(a-1)));let l=this.db.get("SELECT * FROM admin_users WHERE username = ? COLLATE NOCASE",e.trim());return!(l?await Vs(t,l.password_hash):(await Vs(t,Lc),!1))||!l?(this.failsInWindow++,{ok:!1,code:"invalid_credentials"}):(this.db.run("DELETE FROM login_attempts WHERE key = ?",s),{ok:!0,user:this.toUser(l)})}knownUsername(e){return this.db.get("SELECT username FROM admin_users WHERE username = ? COLLATE NOCASE",e.trim())?.username??null}createSession(e,t,n){let s=Qe.randomBytes(32).toString("base64url"),i=this.now();return this.db.run("INSERT INTO admin_sessions (id_hash, user_id, created_at, last_seen_at, expires_at, ip, ua) VALUES (?, ?, ?, ?, ?, ?, ?)",Zs(s),e,i,i,i+Sc,t,n?.slice(0,200)??null),s}validate(e,t={}){if(!e||e.length>100)return null;let n=Zs(e),s=this.db.get("SELECT u.*, s.last_seen_at, s.expires_at FROM admin_sessions s JOIN admin_users u ON u.id = s.user_id WHERE s.id_hash = ?",n);if(!s)return null;let i=this.now();return s.expires_at<=i||i-s.last_seen_at>Lo?(this.db.run("DELETE FROM admin_sessions WHERE id_hash = ?",n),null):(t.touch!==!1&&i-s.last_seen_at>Rc&&this.db.run("UPDATE admin_sessions SET last_seen_at = ? WHERE id_hash = ?",i,n),this.toUser(s))}revoke(e){this.db.run("DELETE FROM admin_sessions WHERE id_hash = ?",Zs(e))}async changePassword(e,t,n,s){let i=this.db.get("SELECT * FROM admin_users WHERE id = ?",e);if(!i||!await Vs(t,i.password_hash))return{ok:!1,code:"invalid_credentials"};if(typeof n!="string"||n.length<xc||n.length>200||n===t)return{ok:!1,code:"weak_password"};let o=s?.trim()||i.username;if(!Cc.test(o))return{ok:!1,code:"invalid_username"};let a=await Js(n);return this.db.tx(()=>{this.db.run("UPDATE admin_users SET username = ?, password_hash = ?, must_change = 0, updated_at = ? WHERE id = ?",o,a,this.now(),e),this.db.run("DELETE FROM admin_sessions WHERE user_id = ?",e)}),xn.rmSync(q.initialPassword,{force:!0}),{ok:!0,user:{id:e,username:o,mustChange:!1}}}async resetPassword(){let e=this.db.get("SELECT * FROM admin_users ORDER BY rowid LIMIT 1"),t=Oo(),n=await Js(t),s=this.now(),i=e?.username??"admin";return this.db.tx(()=>{e?this.db.run("UPDATE admin_users SET password_hash = ?, must_change = 1, updated_at = ? WHERE id = ?",n,s,e.id):this.db.run("INSERT INTO admin_users (id, username, password_hash, must_change, updated_at) VALUES (?, 'admin', ?, 1, ?)",Qe.randomUUID(),n,s),this.db.run("DELETE FROM admin_sessions"),this.db.run("DELETE FROM login_attempts")}),xn.writeFileSync(q.initialPassword,`${t}
582
582
  `,{mode:384}),{username:i,password:t}}prune(){let e=this.now();this.db.run("DELETE FROM admin_sessions WHERE expires_at <= ? OR last_seen_at < ?",e,e-Lo),this.db.run("DELETE FROM login_attempts WHERE next_allowed_at < ?",e-24*36e5),this.db.run("DELETE FROM audit_log WHERE ts < ?",e-Nc)}},Lc=`scrypt$${$e.N}$${$e.r}$${$e.p}$${Buffer.alloc(16).toString("base64")}$${Buffer.alloc($o).toString("base64")}`;import md from"node:crypto";import Z from"node:fs";import cr from"node:os";import Q from"node:path";import rr from"express";var Oc=["app_mentions:read","chat:write","channels:history","groups:history","channels:read","groups:read","users:read","usergroups:read","reactions:write","files:read","files:write","im:history","reactions:read","users:read.email","im:write","mpim:write","mpim:history","assistant:write"],$c=["app_mention","message.channels","message.groups","message.im","message.mpim","reaction_added","app_home_opened","agent_session_stopped"];function qc(r){return r.toLowerCase().replace(/[^a-z0-9._-]+/g,"_").replace(/^[._-]+|[._-]+$/g,"").slice(0,80)||"superclawd_fda"}function Do(r){let e=r.trim().slice(0,35)||"SuperClawd FDA";return{display_information:{name:e,description:"A SuperClawd FDA: an AI engineer that takes requests in Slack.",background_color:"#111827"},features:{app_home:{home_tab_enabled:!0,messages_tab_enabled:!0,messages_tab_read_only_enabled:!1},bot_user:{display_name:qc(e),always_online:!0},agent_view:{agent_description:`${e}, the team's AI agent. Ask in a thread or a DM: it researches, writes documents and code, opens pull requests and follows up. It asks before big changes and never shares passwords or secrets.`.slice(0,300)}},oauth_config:{scopes:{bot:[...Oc]}},settings:{event_subscriptions:{bot_events:[...$c]},interactivity:{is_enabled:!0},org_deploy_enabled:!1,socket_mode_enabled:!0,token_rotation_enabled:!1}}}import An from"node:fs";import Dc from"node:os";import Nn from"node:path";function er(r){return r.startsWith(".")&&r!=="."&&r!==".."}function Mo(r,e=Dc.homedir()){let t=r.trim();if(!t)return{ok:!1,message:"Pick a folder."};let n;try{n=An.realpathSync(t.replace(/^~(?=$|\/)/,e))}catch{return{ok:!1,message:"That folder doesn't exist."}}let s=An.realpathSync(e);return n===s||n.startsWith(s+Nn.sep)?Nn.relative(s,n).split(Nn.sep).some(er)?{ok:!1,message:"That folder can't be used."}:An.statSync(n).isDirectory()?{ok:!0,path:n,kind:An.existsSync(Nn.join(n,".git"))?"repo":"folder"}:{ok:!1,message:"Not a folder."}:{ok:!1,message:"The folder must be inside your home directory."}}import tr from"node:crypto";var Fo="https://calendarmcp.googleapis.com/mcp/v1",Mc="https://accounts.google.com/o/oauth2/v2/auth",Uo="https://oauth2.googleapis.com/token",Uc="https://oauth2.googleapis.com/revoke",Fc=["openid","email","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar.freebusy"],Bc=["openid","email","https://www.googleapis.com/auth/calendar.calendarlist.readonly","https://www.googleapis.com/auth/calendar.events.freebusy","https://www.googleapis.com/auth/calendar.events.readonly","https://www.googleapis.com/auth/calendar.events"],jc=10*6e4,qe=class extends Error{constructor(t,n){super(n??t);this.code=t}};function nr(r){return r.toString("base64url")}var Cn=class{constructor(e){this.d=e;this.now=e.now??Date.now}pending=new Map;access=null;refreshing=null;now;get http(){return this.d.fetch??fetch}status(){let e=this.d.settings;return{configured:!!e.get("googleClientId")&&!!e.getSecret("googleClientSecret"),connected:!!e.getSecret("googleRefreshToken"),account:e.get("calendarAccount"),enabled:e.get("calendarEnabled")}}active(){let e=this.status();return e.enabled&&e.configured&&e.connected}accountDomain(){let e=this.d.settings.get("calendarAccount");return e?e.split("@")[1].toLowerCase():null}authUrl(e){let t=this.d.settings.get("googleClientId");if(!t||!this.d.settings.getSecret("googleClientSecret"))throw new qe("not_configured","Enter the client ID and secret first.");let n=this.now();for(let[l,u]of this.pending)u.exp<=n&&this.pending.delete(l);let s=nr(tr.randomBytes(24)),i=nr(tr.randomBytes(32)),o=nr(tr.createHash("sha256").update(i).digest());this.pending.set(s,{verifier:i,redirectUri:e,exp:n+jc});let a=new URLSearchParams({client_id:t,redirect_uri:e,response_type:"code",scope:(this.d.settings.get("calendarBackend")==="google-mcp"?Bc:Fc).join(" "),access_type:"offline",prompt:"consent",include_granted_scopes:"true",state:s,code_challenge:o,code_challenge_method:"S256"});return`${Mc}?${a}`}async exchange(e,t){let n=this.pending.get(t);if(this.pending.delete(t),!n||n.exp<=this.now())throw new qe("bad_state","That sign-in link expired. Click Connect Google again.");let s=this.d.settings,i=await this.http(Uo,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:n.redirectUri,client_id:s.get("googleClientId")??"",client_secret:s.getSecret("googleClientSecret")??"",code_verifier:n.verifier}),redirect:"error",signal:AbortSignal.timeout(15e3)}),o=await i.json().catch(()=>({}));if(!i.ok)throw new qe("exchange_failed",`Google refused the sign-in (${String(o.error??i.status)}).`);let a=typeof o.refresh_token=="string"?o.refresh_token:"";if(!a)throw new qe("no_refresh_token","Google didn't return offline access. Try Connect Google again.");if(!String(o.scope??"").split(/\s+/).includes("https://www.googleapis.com/auth/calendar.events"))throw new qe("scope_missing","Calendar access wasn't granted. Allow all requested permissions when signing in.");let u=Hc(String(o.id_token??""));if(!u)throw new qe("no_account","Google didn't say which account signed in.");return s.setSecret("googleRefreshToken",a),s.set({calendarAccount:u}),typeof o.access_token=="string"&&(this.access={token:o.access_token,exp:this.now()+Number(o.expires_in??3600)*1e3}),{account:u}}async accessToken(){return this.access&&this.access.exp-6e4>this.now()?this.access.token:(this.refreshing??=this.refresh().finally(()=>{this.refreshing=null}),this.refreshing)}async refresh(){let e=this.d.settings,t=e.getSecret("googleRefreshToken");if(!t)return null;let n=await this.http(Uo,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:e.get("googleClientId")??"",client_secret:e.getSecret("googleClientSecret")??""}),redirect:"error",signal:AbortSignal.timeout(15e3)}).catch(()=>null);if(!n)return null;let s=await n.json().catch(()=>({}));return n.ok?typeof s.access_token!="string"?null:(this.access={token:s.access_token,exp:this.now()+Number(s.expires_in??3600)*1e3},this.access.token):(s.error==="invalid_grant"&&(e.setSecret("googleRefreshToken",null),this.access=null,this.d.onLost?.("Google Calendar was disconnected (the sign-in was revoked or expired). Connect it again in the admin.")),null)}async disconnect(){let e=this.d.settings,t=e.getSecret("googleRefreshToken");e.setSecret("googleRefreshToken",null),e.set({calendarAccount:null}),this.access=null,t&&await this.http(Uc,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({token:t}),signal:AbortSignal.timeout(1e4)}).catch(()=>{})}};function Hc(r){let e=r.split(".")[1];if(!e)return null;try{let t=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));return typeof t.email=="string"&&t.email_verified!==!1?t.email.toLowerCase():null}catch{return null}}function Pn(r,e=new Set){if(typeof r=="string")for(let t of r.matchAll(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g))e.add(t[0].toLowerCase());else if(Array.isArray(r))for(let t of r)Pn(t,e);else if(r&&typeof r=="object")for(let t of Object.values(r))Pn(t,e);return e}var Bo=new Set(["create_event","update_event"]);import Wc from"node:crypto";var Gc="https://linear.app/oauth/authorize",jo="https://api.linear.app/oauth/token",zc="https://api.linear.app/graphql",Xc=["read","write","app:assignable","app:mentionable"],Kc=10*6e4,Ho=60*6e4,De=class extends Error{constructor(t,n){super(n??t);this.code=t}},Yc=`query FdaInbox {
583
583
  notifications(first: 30, orderBy: updatedAt) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superclawd-ai/fda",
3
- "version": "0.1.63",
3
+ "version": "0.1.64",
4
4
  "private": false,
5
5
  "description": "SuperClawd FDA — a forward deployed agent for your team: a Slack-driven AI developer that runs on its own machine with your SuperClawd workspace.",
6
6
  "author": "SuperClawd <support@superclawd.com>",