create checks if CLI or SLack, so don't process/return both formats every time
This commit is contained in:
parent
964eaa8ae9
commit
b98502284a
4 changed files with 123 additions and 102 deletions
|
@ -2,7 +2,6 @@
|
||||||
* sigma_create_handler.js
|
* sigma_create_handler.js
|
||||||
*
|
*
|
||||||
* Handles Sigma rule conversion requests from Slack commands
|
* Handles Sigma rule conversion requests from Slack commands
|
||||||
* Action handlers moved to sigma_action_core.js
|
|
||||||
*/
|
*/
|
||||||
const logger = require('../../utils/logger');
|
const logger = require('../../utils/logger');
|
||||||
const { handleError } = require('../../utils/error_handler');
|
const { handleError } = require('../../utils/error_handler');
|
||||||
|
|
|
@ -22,6 +22,9 @@ const handleCommand = async (command, respond) => {
|
||||||
try {
|
try {
|
||||||
logger.debug(`${FILE_NAME}: Processing sigma-details command: ${command.text}`);
|
logger.debug(`${FILE_NAME}: Processing sigma-details command: ${command.text}`);
|
||||||
|
|
||||||
|
// Determine if request is from CLI
|
||||||
|
const isCliRequest = command.channel_id === 'cli' || command.channel_name === 'cli';
|
||||||
|
|
||||||
if (!command || !command.text) {
|
if (!command || !command.text) {
|
||||||
logger.warn(`${FILE_NAME}: Empty command received for sigma-details`);
|
logger.warn(`${FILE_NAME}: Empty command received for sigma-details`);
|
||||||
await respond({
|
await respond({
|
||||||
|
@ -61,25 +64,28 @@ const handleCommand = async (command, respond) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Slack responses, generate Block Kit blocks
|
// Create response based on interface type
|
||||||
let blocks;
|
if (isCliRequest) {
|
||||||
try {
|
// For CLI, just return the raw data
|
||||||
// This is for Slack - get the Block Kit UI components
|
await respond({
|
||||||
blocks = getSigmaRuleDetailsBlocks(sigmaRuleDetailsResult.explanation);
|
responseData: sigmaRuleDetailsResult.explanation,
|
||||||
} catch (blockError) {
|
response_type: 'cli'
|
||||||
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
|
||||||
responseType: 'ephemeral',
|
|
||||||
customMessage: 'Error generating rule details view'
|
|
||||||
});
|
});
|
||||||
return;
|
} else {
|
||||||
|
// For Slack, generate and return Block Kit blocks
|
||||||
|
try {
|
||||||
|
const blocks = getSigmaRuleDetailsBlocks(sigmaRuleDetailsResult.explanation);
|
||||||
|
await respond({
|
||||||
|
blocks: blocks,
|
||||||
|
response_type: 'in_channel'
|
||||||
|
});
|
||||||
|
} catch (blockError) {
|
||||||
|
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
||||||
|
responseType: 'ephemeral',
|
||||||
|
customMessage: 'Error generating rule details view'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the response with both blocks for Slack and responseData for CLI
|
|
||||||
await respond({
|
|
||||||
blocks: blocks, // For Slack interface
|
|
||||||
responseData: sigmaRuleDetailsResult.explanation, // For CLI interface
|
|
||||||
response_type: 'in_channel'
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await handleError(error, `${FILE_NAME}: Details command handler`, respond, {
|
await handleError(error, `${FILE_NAME}: Details command handler`, respond, {
|
||||||
responseType: 'ephemeral'
|
responseType: 'ephemeral'
|
||||||
|
|
|
@ -24,18 +24,18 @@ const MAX_RESULTS_THRESHOLD = 99;
|
||||||
const handleCommand = async (command, respond) => {
|
const handleCommand = async (command, respond) => {
|
||||||
try {
|
try {
|
||||||
logger.debug(`${FILE_NAME}: Processing sigma-search command: ${JSON.stringify(command.text)}`);
|
logger.debug(`${FILE_NAME}: Processing sigma-search command: ${JSON.stringify(command.text)}`);
|
||||||
|
|
||||||
if (!command || !command.text) {
|
if (!command || !command.text) {
|
||||||
logger.warn(`${FILE_NAME}: Empty command received for sigma-search`);
|
logger.warn(`${FILE_NAME}: Empty command received for sigma-search`);
|
||||||
await respond('Invalid command. Usage: /sigma-search [keyword]');
|
await respond('Invalid command. Usage: /sigma-search [keyword]');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract search keyword and check for pagination parameters
|
// Extract search keyword and check for pagination parameters
|
||||||
let keyword = command.text.trim();
|
let keyword = command.text.trim();
|
||||||
let page = 1;
|
let page = 1;
|
||||||
let pageSize = MAX_RESULTS_PER_PAGE;
|
let pageSize = MAX_RESULTS_PER_PAGE;
|
||||||
|
|
||||||
// Check for pagination format: keyword page=X
|
// Check for pagination format: keyword page=X
|
||||||
const pagingMatch = keyword.match(/(.+)\s+page=(\d+)$/i);
|
const pagingMatch = keyword.match(/(.+)\s+page=(\d+)$/i);
|
||||||
if (pagingMatch) {
|
if (pagingMatch) {
|
||||||
|
@ -43,7 +43,7 @@ const handleCommand = async (command, respond) => {
|
||||||
page = parseInt(pagingMatch[2], 10) || 1;
|
page = parseInt(pagingMatch[2], 10) || 1;
|
||||||
logger.debug(`${FILE_NAME}: Detected pagination request: "${keyword}" page ${page}`);
|
logger.debug(`${FILE_NAME}: Detected pagination request: "${keyword}" page ${page}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for page size format: keyword limit=X
|
// Check for page size format: keyword limit=X
|
||||||
const limitMatch = keyword.match(/(.+)\s+limit=(\d+)$/i);
|
const limitMatch = keyword.match(/(.+)\s+limit=(\d+)$/i);
|
||||||
if (limitMatch) {
|
if (limitMatch) {
|
||||||
|
@ -53,27 +53,27 @@ const handleCommand = async (command, respond) => {
|
||||||
pageSize = Math.min(Math.max(pageSize, 1), 100);
|
pageSize = Math.min(Math.max(pageSize, 1), 100);
|
||||||
logger.debug(`${FILE_NAME}: Detected page size request: "${keyword}" limit ${pageSize}`);
|
logger.debug(`${FILE_NAME}: Detected page size request: "${keyword}" limit ${pageSize}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!keyword) {
|
if (!keyword) {
|
||||||
logger.warn(`${FILE_NAME}: Missing keyword in sigma-search command`);
|
logger.warn(`${FILE_NAME}: Missing keyword in sigma-search command`);
|
||||||
await respond('Invalid command: missing keyword. Usage: /sigma-search [keyword]');
|
await respond('Invalid command: missing keyword. Usage: /sigma-search [keyword]');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`${FILE_NAME}: Searching for rules with keyword: ${keyword} (page ${page}, size ${pageSize})`);
|
logger.info(`${FILE_NAME}: Searching for rules with keyword: ${keyword} (page ${page}, size ${pageSize})`);
|
||||||
logger.debug(`${FILE_NAME}: Search keyword length: ${keyword.length}`);
|
logger.debug(`${FILE_NAME}: Search keyword length: ${keyword.length}`);
|
||||||
|
|
||||||
await respond({
|
await respond({
|
||||||
text: 'Searching for rules... This may take a moment.',
|
text: 'Searching for rules... This may take a moment.',
|
||||||
response_type: 'ephemeral'
|
response_type: 'ephemeral'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Search for rules using the service function with pagination
|
// Search for rules using the service function with pagination
|
||||||
const searchResult = await searchAndConvertRules(keyword, page, pageSize);
|
const searchResult = await searchAndConvertRules(keyword, page, pageSize);
|
||||||
logger.debug(`${FILE_NAME}: Search result status: ${searchResult.success}`);
|
logger.debug(`${FILE_NAME}: Search result status: ${searchResult.success}`);
|
||||||
logger.debug(`${FILE_NAME}: Found ${searchResult.results?.length || 0} results out of ${searchResult.pagination?.totalResults || 0} total matches`);
|
logger.debug(`${FILE_NAME}: Found ${searchResult.results?.length || 0} results out of ${searchResult.pagination?.totalResults || 0} total matches`);
|
||||||
logger.debug(`${FILE_NAME}: About to generate blocks for search results`);
|
logger.debug(`${FILE_NAME}: About to generate blocks for search results`);
|
||||||
|
|
||||||
if (!searchResult.success) {
|
if (!searchResult.success) {
|
||||||
logger.error(`${FILE_NAME}: Search failed: ${searchResult.message}`);
|
logger.error(`${FILE_NAME}: Search failed: ${searchResult.message}`);
|
||||||
await respond({
|
await respond({
|
||||||
|
@ -82,17 +82,17 @@ const handleCommand = async (command, respond) => {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total count for validation
|
// Get total count for validation
|
||||||
const totalCount = searchResult.pagination?.totalResults || 0;
|
const totalCount = searchResult.pagination?.totalResults || 0;
|
||||||
|
|
||||||
// Check if search returned too many results
|
// Check if search returned too many results
|
||||||
if (totalCount > MAX_RESULTS_THRESHOLD) {
|
if (totalCount > MAX_RESULTS_THRESHOLD) {
|
||||||
logger.warn(`${FILE_NAME}: Search for "${keyword}" returned too many results (${totalCount}), displaying first page with warning`);
|
logger.warn(`${FILE_NAME}: Search for "${keyword}" returned too many results (${totalCount}), displaying first page with warning`);
|
||||||
// Continue processing but add a notification
|
// Continue processing but add a notification
|
||||||
searchResult.tooManyResults = true;
|
searchResult.tooManyResults = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!searchResult.results || searchResult.results.length === 0) {
|
if (!searchResult.results || searchResult.results.length === 0) {
|
||||||
if (totalCount > 0) {
|
if (totalCount > 0) {
|
||||||
logger.warn(`${FILE_NAME}: No rules found on page ${page} for "${keyword}", but ${totalCount} total matches exist`);
|
logger.warn(`${FILE_NAME}: No rules found on page ${page} for "${keyword}", but ${totalCount} total matches exist`);
|
||||||
|
@ -109,48 +109,57 @@ const handleCommand = async (command, respond) => {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate blocks with pagination support
|
const isCliRequest = command.channel_id === 'cli' || command.channel_name === 'cli';
|
||||||
let blocks;
|
|
||||||
try {
|
if (isCliRequest) {
|
||||||
logger.debug(`${FILE_NAME}: Calling getSearchResultBlocks with ${searchResult.results.length} results`);
|
// For CLI, just return the raw data
|
||||||
// If we have too many results, add a warning block at the beginning
|
await respond({
|
||||||
if (searchResult.tooManyResults) {
|
responseData: searchResult.results,
|
||||||
blocks = getSearchResultBlocks(keyword, searchResult.results, searchResult.pagination);
|
response_type: 'cli'
|
||||||
// Insert warning at the beginning of blocks (after the header)
|
|
||||||
blocks.splice(1, 0, {
|
|
||||||
"type": "section",
|
|
||||||
"text": {
|
|
||||||
"type": "mrkdwn",
|
|
||||||
"text": `:warning: Your search for "${keyword}" returned ${totalCount} results, which is a lot. Displaying the first page. Consider using a more specific keyword for narrower results.`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
blocks = getSearchResultBlocks(keyword, searchResult.results, searchResult.pagination);
|
|
||||||
}
|
|
||||||
logger.debug(`${FILE_NAME}: Successfully generated ${blocks?.length || 0} blocks`);
|
|
||||||
} catch (blockError) {
|
|
||||||
// Use error handler for block generation errors
|
|
||||||
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
|
||||||
responseType: 'in_channel',
|
|
||||||
customMessage: `Found ${searchResult.results.length} of ${totalCount} rules matching "${keyword}" (page ${page} of ${searchResult.pagination?.totalPages || 1}). Use /sigma-details [id] to view details.`
|
|
||||||
});
|
});
|
||||||
return;
|
} else {
|
||||||
|
// For Slack, generate and return Block Kit blocks
|
||||||
|
let blocks;
|
||||||
|
try {
|
||||||
|
logger.debug(`${FILE_NAME}: Calling getSearchResultBlocks with ${searchResult.results.length} results`);
|
||||||
|
// If we have too many results, add a warning block at the beginning
|
||||||
|
if (searchResult.tooManyResults) {
|
||||||
|
blocks = getSearchResultBlocks(keyword, searchResult.results, searchResult.pagination);
|
||||||
|
// Insert warning at the beginning of blocks (after the header)
|
||||||
|
blocks.splice(1, 0, {
|
||||||
|
"type": "section",
|
||||||
|
"text": {
|
||||||
|
"type": "mrkdwn",
|
||||||
|
"text": `:warning: Your search for "${keyword}" returned ${totalCount} results, which is a lot. Displaying the first page. Consider using a more specific keyword for narrower results.`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
blocks = getSearchResultBlocks(keyword, searchResult.results, searchResult.pagination);
|
||||||
|
}
|
||||||
|
logger.debug(`${FILE_NAME}: Successfully generated ${blocks?.length || 0} blocks`);
|
||||||
|
|
||||||
|
// Determine if this should be visible to everyone or just the user
|
||||||
|
const isEphemeral = totalCount > 20;
|
||||||
|
|
||||||
|
// Add debug log before sending response
|
||||||
|
logger.debug(`${FILE_NAME}: About to send response with ${blocks?.length || 0} blocks`);
|
||||||
|
|
||||||
|
// Respond with the search results
|
||||||
|
// Respond with the search results
|
||||||
|
await respond({
|
||||||
|
blocks: blocks,
|
||||||
|
response_type: isEphemeral ? 'ephemeral' : 'in_channel'
|
||||||
|
});
|
||||||
|
} catch (blockError) {
|
||||||
|
// Use error handler for block generation errors
|
||||||
|
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
||||||
|
responseType: 'in_channel',
|
||||||
|
customMessage: `Found ${searchResult.results.length} of ${totalCount} rules matching "${keyword}" (page ${page} of ${searchResult.pagination?.totalPages || 1}). Use /sigma-details [id] to view details.`
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add debug log before sending response
|
|
||||||
logger.debug(`${FILE_NAME}: About to send response with ${blocks?.length || 0} blocks`);
|
|
||||||
|
|
||||||
// Determine if this should be visible to everyone or just the user
|
|
||||||
const isEphemeral = totalCount > 20;
|
|
||||||
|
|
||||||
// Respond with the search results
|
|
||||||
await respond({
|
|
||||||
blocks: blocks,
|
|
||||||
responseData: searchResult.results,
|
|
||||||
response_type: isEphemeral ? 'ephemeral' : 'in_channel'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add debug log after sending response
|
// Add debug log after sending response
|
||||||
logger.debug(`${FILE_NAME}: Response sent successfully`);
|
logger.debug(`${FILE_NAME}: Response sent successfully`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -171,18 +180,18 @@ const handleCommand = async (command, respond) => {
|
||||||
const handleComplexSearch = async (command, respond) => {
|
const handleComplexSearch = async (command, respond) => {
|
||||||
try {
|
try {
|
||||||
logger.debug(`${FILE_NAME}: Processing complex search command: ${JSON.stringify(command.text)}`);
|
logger.debug(`${FILE_NAME}: Processing complex search command: ${JSON.stringify(command.text)}`);
|
||||||
|
|
||||||
if (!command || !command.text) {
|
if (!command || !command.text) {
|
||||||
logger.warn(`${FILE_NAME}: Empty command received for complex search`);
|
logger.warn(`${FILE_NAME}: Empty command received for complex search`);
|
||||||
await respond('Invalid command. Usage: /sigma-search where [conditions]');
|
await respond('Invalid command. Usage: /sigma-search where [conditions]');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract query string
|
// Extract query string
|
||||||
let queryString = command.text.trim();
|
let queryString = command.text.trim();
|
||||||
let page = 1;
|
let page = 1;
|
||||||
let pageSize = MAX_RESULTS_PER_PAGE;
|
let pageSize = MAX_RESULTS_PER_PAGE;
|
||||||
|
|
||||||
// Check for pagination format: query page=X
|
// Check for pagination format: query page=X
|
||||||
const pagingMatch = queryString.match(/(.+)\s+page=(\d+)$/i);
|
const pagingMatch = queryString.match(/(.+)\s+page=(\d+)$/i);
|
||||||
if (pagingMatch) {
|
if (pagingMatch) {
|
||||||
|
@ -190,7 +199,7 @@ const handleComplexSearch = async (command, respond) => {
|
||||||
page = parseInt(pagingMatch[2], 10) || 1;
|
page = parseInt(pagingMatch[2], 10) || 1;
|
||||||
logger.debug(`${FILE_NAME}: Detected pagination request in complex search: page ${page}`);
|
logger.debug(`${FILE_NAME}: Detected pagination request in complex search: page ${page}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for page size format: query limit=X
|
// Check for page size format: query limit=X
|
||||||
const limitMatch = queryString.match(/(.+)\s+limit=(\d+)$/i);
|
const limitMatch = queryString.match(/(.+)\s+limit=(\d+)$/i);
|
||||||
if (limitMatch) {
|
if (limitMatch) {
|
||||||
|
@ -200,17 +209,17 @@ const handleComplexSearch = async (command, respond) => {
|
||||||
pageSize = Math.min(Math.max(pageSize, 1), 100);
|
pageSize = Math.min(Math.max(pageSize, 1), 100);
|
||||||
logger.debug(`${FILE_NAME}: Detected page size request in complex search: limit ${pageSize}`);
|
logger.debug(`${FILE_NAME}: Detected page size request in complex search: limit ${pageSize}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`${FILE_NAME}: Performing complex search with query: ${queryString}`);
|
logger.info(`${FILE_NAME}: Performing complex search with query: ${queryString}`);
|
||||||
|
|
||||||
await respond({
|
await respond({
|
||||||
text: 'Processing complex search query... This may take a moment.',
|
text: 'Processing complex search query... This may take a moment.',
|
||||||
response_type: 'ephemeral'
|
response_type: 'ephemeral'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Perform the complex search
|
// Perform the complex search
|
||||||
const searchResult = await searchSigmaRulesComplex(queryString, page, pageSize);
|
const searchResult = await searchSigmaRulesComplex(queryString, page, pageSize);
|
||||||
|
|
||||||
if (!searchResult.success) {
|
if (!searchResult.success) {
|
||||||
logger.error(`${FILE_NAME}: Complex search failed: ${searchResult.message}`);
|
logger.error(`${FILE_NAME}: Complex search failed: ${searchResult.message}`);
|
||||||
await respond({
|
await respond({
|
||||||
|
@ -219,7 +228,7 @@ const handleComplexSearch = async (command, respond) => {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have results
|
// Check if we have results
|
||||||
if (!searchResult.results || searchResult.results.length === 0) {
|
if (!searchResult.results || searchResult.results.length === 0) {
|
||||||
logger.warn(`${FILE_NAME}: No rules found matching complex query criteria`);
|
logger.warn(`${FILE_NAME}: No rules found matching complex query criteria`);
|
||||||
|
@ -229,17 +238,17 @@ const handleComplexSearch = async (command, respond) => {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate blocks with pagination support
|
// Generate blocks with pagination support
|
||||||
let blocks;
|
let blocks;
|
||||||
try {
|
try {
|
||||||
// Use the standard search result blocks but with a modified header
|
// Use the standard search result blocks but with a modified header
|
||||||
blocks = getSearchResultBlocks(
|
blocks = getSearchResultBlocks(
|
||||||
`Complex Query: ${queryString}`,
|
`Complex Query: ${queryString}`,
|
||||||
searchResult.results,
|
searchResult.results,
|
||||||
searchResult.pagination
|
searchResult.pagination
|
||||||
);
|
);
|
||||||
|
|
||||||
// Replace the header to indicate it's a complex search
|
// Replace the header to indicate it's a complex search
|
||||||
// TODO: should be moved to dedicated block file
|
// TODO: should be moved to dedicated block file
|
||||||
if (blocks && blocks.length > 0) {
|
if (blocks && blocks.length > 0) {
|
||||||
|
@ -251,7 +260,7 @@ const handleComplexSearch = async (command, respond) => {
|
||||||
emoji: true
|
emoji: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add a description of the search criteria
|
// Add a description of the search criteria
|
||||||
blocks.splice(1, 0, {
|
blocks.splice(1, 0, {
|
||||||
type: "section",
|
type: "section",
|
||||||
|
@ -268,14 +277,14 @@ const handleComplexSearch = async (command, respond) => {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond with the search results
|
// Respond with the search results
|
||||||
await respond({
|
await respond({
|
||||||
blocks: blocks,
|
blocks: blocks,
|
||||||
responseData: searchResult.results,
|
responseData: searchResult.results,
|
||||||
response_type: 'ephemeral' // Complex searches are usually more specific to the user
|
response_type: 'ephemeral' // Complex searches are usually more specific to the user
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info(`${FILE_NAME}: Complex search response sent successfully with ${searchResult.results.length} results`);
|
logger.info(`${FILE_NAME}: Complex search response sent successfully with ${searchResult.results.length} results`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await handleError(error, `${FILE_NAME}: Complex search handler`, respond, {
|
await handleError(error, `${FILE_NAME}: Complex search handler`, respond, {
|
||||||
|
|
|
@ -22,6 +22,9 @@ const handleCommand = async (command, respond) => {
|
||||||
try {
|
try {
|
||||||
logger.info(`${FILE_NAME}: Processing sigma-stats command`);
|
logger.info(`${FILE_NAME}: Processing sigma-stats command`);
|
||||||
|
|
||||||
|
// Determine if request is from CLI by checking channel properties
|
||||||
|
const isCliRequest = command.channel_id === 'cli' || command.channel_name === 'cli';
|
||||||
|
|
||||||
await respond({
|
await respond({
|
||||||
text: 'Gathering Sigma rule statistics... This may take a moment.',
|
text: 'Gathering Sigma rule statistics... This may take a moment.',
|
||||||
response_type: 'ephemeral'
|
response_type: 'ephemeral'
|
||||||
|
@ -39,24 +42,28 @@ const handleCommand = async (command, respond) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Slack responses, generate Block Kit blocks
|
// For CLI, only include responseData
|
||||||
let blocks;
|
if (isCliRequest) {
|
||||||
try {
|
await respond({
|
||||||
blocks = getStatsBlocks(statsResult.stats);
|
responseData: statsResult.stats,
|
||||||
} catch (blockError) {
|
response_type: 'cli'
|
||||||
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
|
||||||
responseType: 'ephemeral',
|
|
||||||
customMessage: 'Error generating statistics view'
|
|
||||||
});
|
});
|
||||||
return;
|
}
|
||||||
|
// For Slack, only generate Block Kit blocks
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
const blocks = getStatsBlocks(statsResult.stats);
|
||||||
|
await respond({
|
||||||
|
blocks: blocks,
|
||||||
|
response_type: 'in_channel'
|
||||||
|
});
|
||||||
|
} catch (blockError) {
|
||||||
|
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
||||||
|
responseType: 'ephemeral',
|
||||||
|
customMessage: 'Error generating statistics view'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the response with both blocks for Slack and responseData for CLI
|
|
||||||
await respond({
|
|
||||||
blocks: blocks,
|
|
||||||
responseData: statsResult.stats, // Include raw data for CLI
|
|
||||||
response_type: 'in_channel'
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await handleError(error, `${FILE_NAME}: Stats command handler`, respond, {
|
await handleError(error, `${FILE_NAME}: Stats command handler`, respond, {
|
||||||
responseType: 'ephemeral'
|
responseType: 'ephemeral'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue