a fun bot for the hc slack
at v0.0.3 4.0 kB view raw
1import { environment, slackApp } from "../../../index"; 2import handleHelp from "../handlers/help"; 3import { handleHistory } from "../handlers/history"; 4import handlePause from "../handlers/pause"; 5import handleResume from "../handlers/resume"; 6import handleStart from "../handlers/start"; 7import handleStatus from "../handlers/status"; 8import handleStop from "../handlers/stop"; 9import { getActiveTake, getPausedTake } from "../services/database"; 10import { 11 checkActiveSessions, 12 expirePausedSessions, 13} from "../services/notifications"; 14import type { MessageResponse } from "../types"; 15import { getDescriptionBlocks, getEditDescriptionBlocks } from "../ui/blocks"; 16import * as Sentry from "@sentry/bun"; 17import { blog } from "../../../libs/Logger"; 18 19export default function setupCommands() { 20 // Main command handler 21 slackApp.command( 22 environment === "dev" ? "/takes-dev" : "/takes", 23 async ({ payload, context }): Promise<void> => { 24 try { 25 const userId = payload.user_id; 26 const channelId = payload.channel_id; 27 const text = payload.text || ""; 28 const args = text.trim().split(/\s+/); 29 let subcommand = args[0]?.toLowerCase() || ""; 30 31 // Check for active takes session 32 const activeTake = await getActiveTake(userId); 33 34 // Check for paused session if no active one 35 const pausedTakeCheck = 36 activeTake.length === 0 ? await getPausedTake(userId) : []; 37 38 // Run checks for expired or about-to-expire sessions 39 await expirePausedSessions(); 40 await checkActiveSessions(); 41 42 // Default to status if we have an active or paused session and no command specified 43 if ( 44 subcommand === "" && 45 (activeTake.length > 0 || pausedTakeCheck.length > 0) 46 ) { 47 subcommand = "status"; 48 } else if (subcommand === "") { 49 subcommand = "help"; 50 } 51 52 let response: MessageResponse | undefined; 53 54 // Special handling for start command to show modal 55 if (subcommand === "start" && !activeTake.length) { 56 response = getDescriptionBlocks(); 57 } 58 59 // Route to the appropriate handler function 60 switch (subcommand) { 61 case "start": { 62 if (args.length < 2) { 63 response = getDescriptionBlocks(); 64 break; 65 } 66 67 const descriptionInput = args.slice(1).join(" "); 68 69 if (!descriptionInput.trim()) { 70 response = getDescriptionBlocks( 71 "Please enter a note for your session.", 72 ); 73 break; 74 } 75 76 response = await handleStart( 77 userId, 78 channelId, 79 descriptionInput, 80 ); 81 break; 82 } 83 case "pause": 84 response = await handlePause(userId); 85 break; 86 case "resume": 87 response = await handleResume(userId); 88 break; 89 case "stop": 90 response = await handleStop(userId, args); 91 break; 92 case "edit": 93 response = getEditDescriptionBlocks( 94 activeTake[0]?.description || "", 95 ); 96 break; 97 case "status": 98 response = await handleStatus(userId); 99 break; 100 case "history": 101 response = await handleHistory(userId); 102 break; 103 case "help": 104 response = await handleHelp(); 105 break; 106 default: 107 response = await handleHelp(); 108 break; 109 } 110 111 if (!response) { 112 throw new Error("No response received from handler"); 113 } 114 115 if (context.respond) { 116 await context.respond(response); 117 } 118 } catch (error) { 119 if (error instanceof Error) 120 blog( 121 `Error in \`${payload.command}\` command: ${error.message}`, 122 "error", 123 ); 124 125 // Capture the error in Sentry 126 Sentry.captureException(error, { 127 extra: { 128 command: payload.command, 129 userId: payload.user_id, 130 channelId: payload.channel_id, 131 text: payload.text, 132 }, 133 }); 134 135 // Respond with error message to user 136 if (context.respond) { 137 await context.respond({ 138 text: "An error occurred while processing your request. Please be patent while we try to put out the fire.", 139 response_type: "ephemeral", 140 }); 141 } 142 } 143 }, 144 ); 145}