diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/.DS_Store differ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dd868ed --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +DISCORD_TOKEN="" +TEST_GUILD_ID="" +BOT_OWNER_ID="" +HF_TOKEN="" +OPENAI_API_KEY="" +REPLICATE_API_TOKEN="" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a17df00 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# Build stage +FROM oven/bun:1 AS builder + +WORKDIR /app + +# Copy package files +COPY package.json bun.lockb ./ + +# Install dependencies +RUN bun install --frozen-lockfile --production + +# Copy source code +COPY src ./src +COPY tsconfig.json drizzle.config.ts ./ + +# Production stage +FROM oven/bun:1-slim + +WORKDIR /app + +# Copy from builder +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/src ./src +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/tsconfig.json ./ + +# Set environment variables +ENV NODE_ENV=production +ENV LOG_LEVEL=info + +# Run the bot +CMD ["bun", "run", "src/index.ts"] diff --git a/README.md b/README.md index e2f1a87..004b6d2 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,54 @@ -# crunk-bun +# Joel Discord Bot -To install dependencies: +A Discord bot with AI-powered responses and message tracking. + +## Quick Start ```bash +# Install dependencies bun install + +# Set environment variables +cp .env.example .env +# Edit .env with your tokens + +# Run in development mode +bun run dev + +# Run in production +bun run start ``` -To run: +## Project Structure -```bash -bun run index.ts +See [src/README.md](src/README.md) for detailed architecture documentation. + +``` +src/ +├── core/ # Bot client, config, logging +├── commands/ # Slash commands +├── events/ # Discord event handlers +├── features/ # Feature modules (Joel AI, message logging) +├── services/ # External services (AI providers) +├── database/ # Database schema and repositories +└── utils/ # Shared utilities ``` -This project was created using `bun init` in bun v1.1.3. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. +## Environment Variables + +| Variable | Description | +| --------------------- | -------------------------- | +| `DISCORD_TOKEN` | Discord bot token | +| `REPLICATE_API_TOKEN` | Replicate API token for AI | + +## Scripts + +| Script | Description | +| --------------------- | --------------------------- | +| `bun run dev` | Development with hot reload | +| `bun run start` | Production start | +| `bun run build` | Build for production | +| `bun run db:generate` | Generate DB migrations | +| `bun run db:migrate` | Run DB migrations | +| `bun run db:studio` | Open Drizzle Studio | +| `bun run typecheck` | Type check without emit | diff --git a/build/index.js b/build/index.js deleted file mode 100644 index ccdee56..0000000 --- a/build/index.js +++ /dev/null @@ -1,65 +0,0 @@ -// @bun -var zy=Object.create;var{defineProperty:ez,getPrototypeOf:Vy,getOwnPropertyNames:Wy}=Object;var qy=Object.prototype.hasOwnProperty;var bZ=($,Y,X)=>{X=$!=null?zy(Vy($)):{};const Z=Y||!$||!$.__esModule?ez(X,"default",{value:$,enumerable:!0}):X;for(let Q of Wy($))if(!qy.call(Z,Q))ez(Z,Q,{get:()=>$[Q],enumerable:!0});return Z};var V=($,Y)=>()=>(Y||$((Y={exports:{}}).exports,Y),Y.exports);var fV=V((WH0,K5)=>{var $V,YV,XV,ZV,QV,KV,HV,zV,VV,WV,qV,UV,BV,Z5,kZ,LV,wV,JV,Y$,FV,jV,DV,PV,GV,NV,MV,_V,xV,Q5,AV,OV;(function($){var Y=typeof global==="object"?global:typeof self==="object"?self:typeof this==="object"?this:{};if(typeof define==="function"&&define.amd)define("tslib",["exports"],function(Z){$(X(Y,X(Z)))});else if(typeof K5==="object"&&typeof WH0==="object")$(X(Y,X(WH0)));else $(X(Y));function X(Z,Q){if(Z!==Y)if(typeof Object.create==="function")Object.defineProperty(Z,"__esModule",{value:!0});else Z.__esModule=!0;return function(K,H){return Z[K]=Q?Q(K,H):H}}})(function($){var Y=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(Q,K){Q.__proto__=K}||function(Q,K){for(var H in K)if(Object.prototype.hasOwnProperty.call(K,H))Q[H]=K[H]};$V=function(Q,K){if(typeof K!=="function"&&K!==null)throw new TypeError("Class extends value "+String(K)+" is not a constructor or null");Y(Q,K);function H(){this.constructor=Q}Q.prototype=K===null?Object.create(K):(H.prototype=K.prototype,new H)},YV=Object.assign||function(Q){for(var K,H=1,z=arguments.length;H=0;w--)if(U=Q[w])q=(W<3?U(q):W>3?U(K,H,q):U(K,H))||q;return W>3&&q&&Object.defineProperty(K,H,q),q},QV=function(Q,K){return function(H,z){K(H,z,Q)}},KV=function(Q,K,H,z,W,q){function U(D0){if(D0!==void 0&&typeof D0!=="function")throw new TypeError("Function expected");return D0}var w=z.kind,j=w==="getter"?"get":w==="setter"?"set":"value",J=!K&&Q?z.static?Q:Q.prototype:null,G=K||(J?Object.getOwnPropertyDescriptor(J,z.name):{}),x,M=!1;for(var T=H.length-1;T>=0;T--){var R={};for(var E in z)R[E]=E==="access"?{}:z[E];for(var E in z.access)R.access[E]=z.access[E];R.addInitializer=function(D0){if(M)throw new TypeError("Cannot add initializers after decoration has completed");q.push(U(D0||null))};var h=H[T](w==="accessor"?{get:G.get,set:G.set}:G[j],R);if(w==="accessor"){if(h===void 0)continue;if(h===null||typeof h!=="object")throw new TypeError("Object expected");if(x=U(h.get))G.get=x;if(x=U(h.set))G.set=x;if(x=U(h.init))W.unshift(x)}else if(x=U(h))if(w==="field")W.unshift(x);else G[j]=x}if(J)Object.defineProperty(J,z.name,G);M=!0},HV=function(Q,K,H){var z=arguments.length>2;for(var W=0;W0&&q[q.length-1]))&&(J[0]===6||J[0]===2)){H=0;continue}if(J[0]===3&&(!q||J[1]>q[0]&&J[1]=Q.length)Q=void 0;return{value:Q&&Q[z++],done:!Q}}};throw new TypeError(K?"Object is not iterable.":"Symbol.iterator is not defined.")},kZ=function(Q,K){var H=typeof Symbol==="function"&&Q[Symbol.iterator];if(!H)return Q;var z=H.call(Q),W,q=[],U;try{while((K===void 0||K-- >0)&&!(W=z.next()).done)q.push(W.value)}catch(w){U={error:w}}finally{try{if(W&&!W.done&&(H=z.return))H.call(z)}finally{if(U)throw U.error}}return q},LV=function(){for(var Q=[],K=0;K1||w(M,T)})}}function w(M,T){try{j(z[M](T))}catch(R){x(q[0][3],R)}}function j(M){M.value instanceof Y$?Promise.resolve(M.value.v).then(J,G):x(q[0][2],M)}function J(M){w("next",M)}function G(M){w("throw",M)}function x(M,T){if(M(T),q.shift(),q.length)w(q[0][0],q[0][1])}},jV=function(Q){var K,H;return K={},z("next"),z("throw",function(W){throw W}),z("return"),K[Symbol.iterator]=function(){return this},K;function z(W,q){K[W]=Q[W]?function(U){return(H=!H)?{value:Y$(Q[W](U)),done:!1}:q?q(U):U}:q}},DV=function(Q){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var K=Q[Symbol.asyncIterator],H;return K?K.call(Q):(Q=typeof Z5==="function"?Z5(Q):Q[Symbol.iterator](),H={},z("next"),z("throw"),z("return"),H[Symbol.asyncIterator]=function(){return this},H);function z(q){H[q]=Q[q]&&function(U){return new Promise(function(w,j){U=Q[q](U),W(w,j,U.done,U.value)})}}function W(q,U,w,j){Promise.resolve(j).then(function(J){q({value:J,done:w})},U)}},PV=function(Q,K){if(Object.defineProperty)Object.defineProperty(Q,"raw",{value:K});else Q.raw=K;return Q};var X=Object.create?function(Q,K){Object.defineProperty(Q,"default",{enumerable:!0,value:K})}:function(Q,K){Q.default=K};GV=function(Q){if(Q&&Q.__esModule)return Q;var K={};if(Q!=null){for(var H in Q)if(H!=="default"&&Object.prototype.hasOwnProperty.call(Q,H))Q5(K,Q,H)}return X(K,Q),K},NV=function(Q){return Q&&Q.__esModule?Q:{default:Q}},MV=function(Q,K,H,z){if(H==="a"&&!z)throw new TypeError("Private accessor was defined without a getter");if(typeof K==="function"?Q!==K||!z:!K.has(Q))throw new TypeError("Cannot read private member from an object whose class did not declare it");return H==="m"?z:H==="a"?z.call(Q):z?z.value:K.get(Q)},_V=function(Q,K,H,z,W){if(z==="m")throw new TypeError("Private method is not writable");if(z==="a"&&!W)throw new TypeError("Private accessor was defined without a setter");if(typeof K==="function"?Q!==K||!W:!K.has(Q))throw new TypeError("Cannot write private member to an object whose class did not declare it");return z==="a"?W.call(Q,H):W?W.value=H:K.set(Q,H),H},xV=function(Q,K){if(K===null||typeof K!=="object"&&typeof K!=="function")throw new TypeError("Cannot use 'in' operator on non-object");return typeof Q==="function"?K===Q:Q.has(K)},AV=function(Q,K,H){if(K!==null&&K!==void 0){if(typeof K!=="object"&&typeof K!=="function")throw new TypeError("Object expected.");var z;if(H){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");z=K[Symbol.asyncDispose]}if(z===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");z=K[Symbol.dispose]}if(typeof z!=="function")throw new TypeError("Object not disposable.");Q.stack.push({value:K,dispose:z,async:H})}else if(H)Q.stack.push({async:!0});return K};var Z=typeof SuppressedError==="function"?SuppressedError:function(Q,K,H){var z=new Error(H);return z.name="SuppressedError",z.error=Q,z.suppressed=K,z};OV=function(Q){function K(z){Q.error=Q.hasError?new Z(z,Q.error,"An error was suppressed during disposal."):z,Q.hasError=!0}function H(){while(Q.stack.length){var z=Q.stack.pop();try{var W=z.dispose&&z.dispose.call(z.value);if(z.async)return Promise.resolve(W).then(H,function(q){return K(q),H()})}catch(q){K(q)}}if(Q.hasError)throw Q.error}return H()},$("__extends",$V),$("__assign",YV),$("__rest",XV),$("__decorate",ZV),$("__param",QV),$("__esDecorate",KV),$("__runInitializers",HV),$("__propKey",zV),$("__setFunctionName",VV),$("__metadata",WV),$("__awaiter",qV),$("__generator",UV),$("__exportStar",BV),$("__createBinding",Q5),$("__values",Z5),$("__read",kZ),$("__spread",LV),$("__spreadArrays",wV),$("__spreadArray",JV),$("__await",Y$),$("__asyncGenerator",FV),$("__asyncDelegator",jV),$("__asyncValues",DV),$("__makeTemplateObject",PV),$("__importStar",GV),$("__importDefault",NV),$("__classPrivateFieldGet",MV),$("__classPrivateFieldSet",_V),$("__classPrivateFieldIn",xV),$("__addDisposableResource",AV),$("__disposeResources",OV)})});var d=V((qH0,yV)=>{var kV=function($){let Y;return()=>Y??=$()};function*IV($){let Y,X=0,Z=1;if(typeof $==="number")Y=$;else X=$.start,Y=$.end,Z=$.step??1;for(let Q=X;Q>22n)%Y},TV=function(){if(typeof globalThis.process==="undefined")return"fetch"in globalThis&&"WebSocket"in globalThis;if("versions"in globalThis.process)return"deno"in globalThis.process.versions||"bun"in globalThis.process.versions;return!1},CV=function(){if(typeof globalThis.EdgeRuntime!=="undefined")return"Vercel-Edge-Functions";if(typeof globalThis.R2!=="undefined"&&typeof globalThis.WebSocketPair!=="undefined")return"Cloudflare-Workers";if(typeof globalThis.Netlify!=="undefined")return"Netlify-Edge-Functions";if(typeof globalThis.process!=="object"){if(typeof globalThis.navigator==="object")return globalThis.navigator.userAgent;return"UnknownEnvironment"}if("versions"in globalThis.process){if("deno"in globalThis.process.versions)return`Deno/${globalThis.process.versions.deno}`;if("bun"in globalThis.process.versions)return`Bun/${globalThis.process.versions.bun}`;if("node"in globalThis.process.versions)return`Node.js/${globalThis.process.versions.node}`}return"UnknownEnvironment"},SV=function($){return $!==null&&typeof $==="object"&&"toJSON"in $},vV=function($){return $!==null&&typeof $==="object"&&"equals"in $},H5=Object.defineProperty,Uy=Object.getOwnPropertyDescriptor,By=Object.getOwnPropertyNames,Ly=Object.prototype.hasOwnProperty,u6=($,Y)=>H5($,"name",{value:Y,configurable:!0}),wy=($,Y)=>{for(var X in Y)H5($,X,{get:Y[X],enumerable:!0})},Jy=($,Y,X,Z)=>{if(Y&&typeof Y==="object"||typeof Y==="function"){for(let Q of By(Y))if(!Ly.call($,Q)&&Q!==X)H5($,Q,{get:()=>Y[Q],enumerable:!(Z=Uy(Y,Q))||Z.enumerable})}return $},Fy=($)=>Jy(H5({},"__esModule",{value:!0}),$),bV={};wy(bV,{calculateShardId:()=>RV,getUserAgentAppendix:()=>CV,isEquatable:()=>vV,isJSONEncodable:()=>SV,lazy:()=>kV,range:()=>IV,shouldUseGlobalFetchAndWebSocket:()=>TV});yV.exports=Fy(bV);u6(kV,"lazy");u6(IV,"range");u6(RV,"calculateShardId");u6(TV,"shouldUseGlobalFetchAndWebSocket");u6(CV,"getUserAgentAppendix");u6(SV,"isJSONEncodable");u6(vV,"isEquatable")});var EV=V((hV)=>{Object.defineProperty(hV,"__esModule",{value:!0})});var gV=V((H0)=>{var jy=H0&&H0.__createBinding||(Object.create?function($,Y,X,Z){if(Z===void 0)Z=X;var Q=Object.getOwnPropertyDescriptor(Y,X);if(!Q||("get"in Q?!Y.__esModule:Q.writable||Q.configurable))Q={enumerable:!0,get:function(){return Y[X]}};Object.defineProperty($,Z,Q)}:function($,Y,X,Z){if(Z===void 0)Z=X;$[Z]=Y[X]}),Dy=H0&&H0.__exportStar||function($,Y){for(var X in $)if(X!=="default"&&!Object.prototype.hasOwnProperty.call(Y,X))jy(Y,$,X)};Object.defineProperty(H0,"__esModule",{value:!0});H0.GatewayDispatchEvents=H0.GatewayIntentBits=H0.GatewayCloseCodes=H0.GatewayOpcodes=H0.GatewayVersion=void 0;Dy(EV(),H0);H0.GatewayVersion="10";var Py;(function($){$[$.Dispatch=0]="Dispatch",$[$.Heartbeat=1]="Heartbeat",$[$.Identify=2]="Identify",$[$.PresenceUpdate=3]="PresenceUpdate",$[$.VoiceStateUpdate=4]="VoiceStateUpdate",$[$.Resume=6]="Resume",$[$.Reconnect=7]="Reconnect",$[$.RequestGuildMembers=8]="RequestGuildMembers",$[$.InvalidSession=9]="InvalidSession",$[$.Hello=10]="Hello",$[$.HeartbeatAck=11]="HeartbeatAck"})(Py=H0.GatewayOpcodes||(H0.GatewayOpcodes={}));var Gy;(function($){$[$.UnknownError=4000]="UnknownError",$[$.UnknownOpcode=4001]="UnknownOpcode",$[$.DecodeError=4002]="DecodeError",$[$.NotAuthenticated=4003]="NotAuthenticated",$[$.AuthenticationFailed=4004]="AuthenticationFailed",$[$.AlreadyAuthenticated=4005]="AlreadyAuthenticated",$[$.InvalidSeq=4007]="InvalidSeq",$[$.RateLimited=4008]="RateLimited",$[$.SessionTimedOut=4009]="SessionTimedOut",$[$.InvalidShard=4010]="InvalidShard",$[$.ShardingRequired=4011]="ShardingRequired",$[$.InvalidAPIVersion=4012]="InvalidAPIVersion",$[$.InvalidIntents=4013]="InvalidIntents",$[$.DisallowedIntents=4014]="DisallowedIntents"})(Gy=H0.GatewayCloseCodes||(H0.GatewayCloseCodes={}));var Ny;(function($){$[$.Guilds=1]="Guilds",$[$.GuildMembers=2]="GuildMembers",$[$.GuildModeration=4]="GuildModeration",$[$.GuildBans=4]="GuildBans",$[$.GuildEmojisAndStickers=8]="GuildEmojisAndStickers",$[$.GuildIntegrations=16]="GuildIntegrations",$[$.GuildWebhooks=32]="GuildWebhooks",$[$.GuildInvites=64]="GuildInvites",$[$.GuildVoiceStates=128]="GuildVoiceStates",$[$.GuildPresences=256]="GuildPresences",$[$.GuildMessages=512]="GuildMessages",$[$.GuildMessageReactions=1024]="GuildMessageReactions",$[$.GuildMessageTyping=2048]="GuildMessageTyping",$[$.DirectMessages=4096]="DirectMessages",$[$.DirectMessageReactions=8192]="DirectMessageReactions",$[$.DirectMessageTyping=16384]="DirectMessageTyping",$[$.MessageContent=32768]="MessageContent",$[$.GuildScheduledEvents=65536]="GuildScheduledEvents",$[$.AutoModerationConfiguration=1048576]="AutoModerationConfiguration",$[$.AutoModerationExecution=2097152]="AutoModerationExecution"})(Ny=H0.GatewayIntentBits||(H0.GatewayIntentBits={}));var My;(function($){$.ApplicationCommandPermissionsUpdate="APPLICATION_COMMAND_PERMISSIONS_UPDATE",$.ChannelCreate="CHANNEL_CREATE",$.ChannelDelete="CHANNEL_DELETE",$.ChannelPinsUpdate="CHANNEL_PINS_UPDATE",$.ChannelUpdate="CHANNEL_UPDATE",$.GuildBanAdd="GUILD_BAN_ADD",$.GuildBanRemove="GUILD_BAN_REMOVE",$.GuildCreate="GUILD_CREATE",$.GuildDelete="GUILD_DELETE",$.GuildEmojisUpdate="GUILD_EMOJIS_UPDATE",$.GuildIntegrationsUpdate="GUILD_INTEGRATIONS_UPDATE",$.GuildMemberAdd="GUILD_MEMBER_ADD",$.GuildMemberRemove="GUILD_MEMBER_REMOVE",$.GuildMembersChunk="GUILD_MEMBERS_CHUNK",$.GuildMemberUpdate="GUILD_MEMBER_UPDATE",$.GuildRoleCreate="GUILD_ROLE_CREATE",$.GuildRoleDelete="GUILD_ROLE_DELETE",$.GuildRoleUpdate="GUILD_ROLE_UPDATE",$.GuildStickersUpdate="GUILD_STICKERS_UPDATE",$.GuildUpdate="GUILD_UPDATE",$.IntegrationCreate="INTEGRATION_CREATE",$.IntegrationDelete="INTEGRATION_DELETE",$.IntegrationUpdate="INTEGRATION_UPDATE",$.InteractionCreate="INTERACTION_CREATE",$.InviteCreate="INVITE_CREATE",$.InviteDelete="INVITE_DELETE",$.MessageCreate="MESSAGE_CREATE",$.MessageDelete="MESSAGE_DELETE",$.MessageDeleteBulk="MESSAGE_DELETE_BULK",$.MessageReactionAdd="MESSAGE_REACTION_ADD",$.MessageReactionRemove="MESSAGE_REACTION_REMOVE",$.MessageReactionRemoveAll="MESSAGE_REACTION_REMOVE_ALL",$.MessageReactionRemoveEmoji="MESSAGE_REACTION_REMOVE_EMOJI",$.MessageUpdate="MESSAGE_UPDATE",$.PresenceUpdate="PRESENCE_UPDATE",$.StageInstanceCreate="STAGE_INSTANCE_CREATE",$.StageInstanceDelete="STAGE_INSTANCE_DELETE",$.StageInstanceUpdate="STAGE_INSTANCE_UPDATE",$.Ready="READY",$.Resumed="RESUMED",$.ThreadCreate="THREAD_CREATE",$.ThreadDelete="THREAD_DELETE",$.ThreadListSync="THREAD_LIST_SYNC",$.ThreadMembersUpdate="THREAD_MEMBERS_UPDATE",$.ThreadMemberUpdate="THREAD_MEMBER_UPDATE",$.ThreadUpdate="THREAD_UPDATE",$.TypingStart="TYPING_START",$.UserUpdate="USER_UPDATE",$.VoiceServerUpdate="VOICE_SERVER_UPDATE",$.VoiceStateUpdate="VOICE_STATE_UPDATE",$.WebhooksUpdate="WEBHOOKS_UPDATE",$.GuildScheduledEventCreate="GUILD_SCHEDULED_EVENT_CREATE",$.GuildScheduledEventUpdate="GUILD_SCHEDULED_EVENT_UPDATE",$.GuildScheduledEventDelete="GUILD_SCHEDULED_EVENT_DELETE",$.GuildScheduledEventUserAdd="GUILD_SCHEDULED_EVENT_USER_ADD",$.GuildScheduledEventUserRemove="GUILD_SCHEDULED_EVENT_USER_REMOVE",$.AutoModerationRuleCreate="AUTO_MODERATION_RULE_CREATE",$.AutoModerationRuleUpdate="AUTO_MODERATION_RULE_UPDATE",$.AutoModerationRuleDelete="AUTO_MODERATION_RULE_DELETE",$.AutoModerationActionExecution="AUTO_MODERATION_ACTION_EXECUTION",$.GuildAuditLogEntryCreate="GUILD_AUDIT_LOG_ENTRY_CREATE",$.EntitlementCreate="ENTITLEMENT_CREATE",$.EntitlementUpdate="ENTITLEMENT_UPDATE",$.EntitlementDelete="ENTITLEMENT_DELETE"})(My=H0.GatewayDispatchEvents||(H0.GatewayDispatchEvents={}))});var uV=V((mV)=>{Object.defineProperty(mV,"__esModule",{value:!0});mV.FormattingPatterns=void 0;mV.FormattingPatterns={User:/<@(?\d{17,20})>/,UserWithNickname:/<@!(?\d{17,20})>/,UserWithOptionalNickname:/<@!?(?\d{17,20})>/,Channel:/<#(?\d{17,20})>/,Role:/<@&(?\d{17,20})>/,SlashCommand:/<\/(?(?[-_\p{Letter}\p{Number}\p{sc=Deva}\p{sc=Thai}]{1,32})(?: (?[-_\p{Letter}\p{Number}\p{sc=Deva}\p{sc=Thai}]{1,32}))?(?: (?[-_\p{Letter}\p{Number}\p{sc=Deva}\p{sc=Thai}]{1,32}))?):(?\d{17,20})>/u,Emoji:/<(?a)?:(?\w{2,32}):(?\d{17,20})>/,AnimatedEmoji:/<(?a):(?\w{2,32}):(?\d{17,20})>/,StaticEmoji:/<:(?\w{2,32}):(?\d{17,20})>/,Timestamp:/-?\d{1,13})(:(?