feat(tools): added more slack tools (#2212)

This commit is contained in:
Waleed
2025-12-05 13:22:35 -08:00
committed by GitHub
parent 7752beac01
commit 5d6c1f7b88
13 changed files with 999 additions and 147 deletions

View File

@@ -696,8 +696,8 @@ export function GrafanaIcon(props: SVGProps<SVGSVGElement>) {
y2='5.356'
gradientUnits='userSpaceOnUse'
>
<stop stop-color='#FFF200' />
<stop offset='1' stop-color='#F15A29' />
<stop stopColor='#FFF200' />
<stop offset='1' stopColor='#F15A29' />
</linearGradient>
</defs>
</svg>
@@ -2757,111 +2757,19 @@ export function MicrosoftSharepointIcon(props: SVGProps<SVGSVGElement>) {
export function MicrosoftPlannerIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
xmlnsXlink='http://www.w3.org/1999/xlink'
viewBox='0 0 24 24'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<g clipPath='url(#msplanner_clip0)'>
<path
d='M8.25809 15.7412C7.22488 16.7744 5.54971 16.7744 4.5165 15.7412L0.774909 11.9996C-0.258303 10.9664 -0.258303 9.29129 0.774908 8.25809L4.5165 4.51655C5.54971 3.48335 7.22488 3.48335 8.25809 4.51655L11.9997 8.2581C13.0329 9.29129 13.0329 10.9664 11.9997 11.9996L8.25809 15.7412Z'
fill='url(#msplanner_paint0_linear)'
/>
<path
d='M8.25809 15.7412C7.22488 16.7744 5.54971 16.7744 4.5165 15.7412L0.774909 11.9996C-0.258303 10.9664 -0.258303 9.29129 0.774908 8.25809L4.5165 4.51655C5.54971 3.48335 7.22488 3.48335 8.25809 4.51655L11.9997 8.2581C13.0329 9.29129 13.0329 10.9664 11.9997 11.9996L8.25809 15.7412Z'
fill='url(#msplanner_paint1_linear)'
/>
<path
d='M0.774857 11.9999C1.80809 13.0331 3.48331 13.0331 4.51655 11.9999L15.7417 0.774926C16.7749 -0.258304 18.4501 -0.258309 19.4834 0.774914L23.225 4.51655C24.2583 5.54977 24.2583 7.22496 23.225 8.25819L11.9999 19.4832C10.9667 20.5164 9.29146 20.5164 8.25822 19.4832L0.774857 11.9999Z'
fill='url(#msplanner_paint2_linear)'
/>
<path
d='M0.774857 11.9999C1.80809 13.0331 3.48331 13.0331 4.51655 11.9999L15.7417 0.774926C16.7749 -0.258304 18.4501 -0.258309 19.4834 0.774914L23.225 4.51655C24.2583 5.54977 24.2583 7.22496 23.225 8.25819L11.9999 19.4832C10.9667 20.5164 9.29146 20.5164 8.25822 19.4832L0.774857 11.9999Z'
fill='url(#msplanner_paint3_linear)'
/>
<path
d='M4.51642 15.7413C5.54966 16.7746 7.22487 16.7746 8.25812 15.7413L15.7415 8.25803C16.7748 7.2248 18.45 7.2248 19.4832 8.25803L23.2249 11.9997C24.2582 13.0329 24.2582 14.7081 23.2249 15.7413L15.7415 23.2246C14.7083 24.2579 13.033 24.2579 11.9998 23.2246L4.51642 15.7413Z'
fill='url(#msplanner_paint4_linear)'
/>
<path
d='M4.51642 15.7413C5.54966 16.7746 7.22487 16.7746 8.25812 15.7413L15.7415 8.25803C16.7748 7.2248 18.45 7.2248 19.4832 8.25803L23.2249 11.9997C24.2582 13.0329 24.2582 14.7081 23.2249 15.7413L15.7415 23.2246C14.7083 24.2579 13.033 24.2579 11.9998 23.2246L4.51642 15.7413Z'
fill='url(#msplanner_paint5_linear)'
/>
</g>
<defs>
<linearGradient
id='msplanner_paint0_linear'
x1='6.38724'
y1='3.74167'
x2='2.15779'
y2='12.777'
gradientUnits='userSpaceOnUse'
>
<stop stopColor='#8752E0' />
<stop offset='1' stopColor='#541278' />
</linearGradient>
<linearGradient
id='msplanner_paint1_linear'
x1='8.38032'
y1='11.0696'
x2='4.94062'
y2='7.69244'
gradientUnits='userSpaceOnUse'
>
<stop offset='0.12172' stopColor='#3D0D59' />
<stop offset='1' stopColor='#7034B0' stopOpacity='0' />
</linearGradient>
<linearGradient
id='msplanner_paint2_linear'
x1='18.3701'
y1='-3.33385e-05'
x2='9.85717'
y2='20.4192'
gradientUnits='userSpaceOnUse'
>
<stop stopColor='#DB45E0' />
<stop offset='1' stopColor='#6C0F71' />
</linearGradient>
<linearGradient
id='msplanner_paint3_linear'
x1='18.3701'
y1='-3.33385e-05'
x2='9.85717'
y2='20.4192'
gradientUnits='userSpaceOnUse'
>
<stop stopColor='#DB45E0' />
<stop offset='0.677403' stopColor='#A829AE' />
<stop offset='1' stopColor='#8F28B3' />
</linearGradient>
<linearGradient
id='msplanner_paint4_linear'
x1='18.0002'
y1='7.49958'
x2='14.0004'
y2='23.9988'
gradientUnits='userSpaceOnUse'
>
<stop stopColor='#3DCBFF' />
<stop offset='1' stopColor='#00479E' />
</linearGradient>
<linearGradient
id='msplanner_paint5_linear'
x1='18.2164'
y1='7.92626'
x2='10.5237'
y2='22.9363'
gradientUnits='userSpaceOnUse'
>
<stop stopColor='#3DCBFF' />
<stop offset='1' stopColor='#4A40D4' />
</linearGradient>
<clipPath id='msplanner_clip0'>
<rect width='24' height='24' fill='white' />
</clipPath>
</defs>
<svg {...props} viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
d='M8.25809 15.7412C7.22488 16.7744 5.54971 16.7744 4.5165 15.7412L0.774909 11.9996C-0.258303 10.9664 -0.258303 9.29129 0.774908 8.25809L4.5165 4.51655C5.54971 3.48335 7.22488 3.48335 8.25809 4.51655L11.9997 8.2581C13.0329 9.29129 13.0329 10.9664 11.9997 11.9996L8.25809 15.7412Z'
fill='#185ABD'
/>
<path
d='M0.774857 11.9999C1.80809 13.0331 3.48331 13.0331 4.51655 11.9999L15.7417 0.774926C16.7749 -0.258304 18.4501 -0.258309 19.4834 0.774914L23.225 4.51655C24.2583 5.54977 24.2583 7.22496 23.225 8.25819L11.9999 19.4832C10.9667 20.5164 9.29146 20.5164 8.25822 19.4832L0.774857 11.9999Z'
fill='#41A5EE'
/>
<path
d='M4.51642 15.7413C5.54966 16.7746 7.22487 16.7746 8.25812 15.7413L15.7415 8.25803C16.7748 7.2248 18.45 7.2248 19.4832 8.25803L23.2249 11.9997C24.2582 13.0329 24.2582 14.7081 23.2249 15.7413L15.7415 23.2246C14.7083 24.2579 13.033 24.2579 11.9998 23.2246L4.51642 15.7413Z'
fill='#2B7CD3'
/>
</svg>
)
}
@@ -3344,29 +3252,10 @@ export function TrelloIcon(props: SVGProps<SVGSVGElement>) {
export function AsanaIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
xmlns='http://www.w3.org/2000/svg'
width='24'
height='24'
viewBox='781.361 0 944.893 873.377'
>
<radialGradient
id='asana_radial_gradient'
cx='943.992'
cy='1221.416'
r='.663'
gradientTransform='matrix(944.8934 0 0 -873.3772 -890717.875 1067234.75)'
gradientUnits='userSpaceOnUse'
>
<stop offset='0' stopColor='#ffb900' />
<stop offset='.6' stopColor='#f95d8f' />
<stop offset='.999' stopColor='#f95353' />
</radialGradient>
<path
fill='url(#asana_radial_gradient)'
d='M1520.766 462.371c-113.508 0-205.508 92-205.508 205.488 0 113.499 92 205.518 205.508 205.518 113.489 0 205.488-92.019 205.488-205.518 0-113.488-91.999-205.488-205.488-205.488zm-533.907.01c-113.489.01-205.498 91.99-205.498 205.488 0 113.489 92.009 205.498 205.498 205.498 113.498 0 205.508-92.009 205.508-205.498 0-113.499-92.01-205.488-205.518-205.488h.01zm472.447-256.883c0 113.489-91.999 205.518-205.488 205.518-113.508 0-205.508-92.029-205.508-205.518S1140.31 0 1253.817 0c113.489 0 205.479 92.009 205.479 205.498h.01z'
/>
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'>
<circle cx='18' cy='16' r='4' fill='#F06A6A' />
<circle cx='6' cy='16' r='4' fill='#F06A6A' />
<circle cx='12' cy='6.5' r='4' fill='#F06A6A' />
</svg>
)
}
@@ -3975,6 +3864,33 @@ export function DynamoDBIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function McpIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
width='16'
height='16'
viewBox='0 0 16 16'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<g clipPath='url(#mcp-clip)'>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M14.5572 7.87503L14.5022 7.92903L8.69824 13.62C8.68102 13.6368 8.66728 13.6569 8.65781 13.679C8.64834 13.7011 8.64332 13.7248 8.64304 13.7489C8.64276 13.773 8.64723 13.7968 8.65619 13.8192C8.66514 13.8415 8.67842 13.8618 8.69524 13.879L8.69824 13.882L9.89024 15.052C9.99431 15.1536 10.0539 15.2923 10.056 15.4378C10.058 15.5832 10.0024 15.7235 9.90124 15.828L9.89124 15.838C9.78385 15.9428 9.63977 16.0014 9.48974 16.0014C9.33972 16.0014 9.19564 15.9428 9.08824 15.838L7.89624 14.67C7.77347 14.5507 7.67588 14.408 7.60923 14.2503C7.54259 14.0927 7.50825 13.9232 7.50825 13.752C7.50825 13.5808 7.54259 13.4114 7.60923 13.2537C7.67588 13.096 7.77347 12.9533 7.89624 12.834L13.7012 7.14203C14.0139 6.83733 14.1928 6.42097 14.1986 5.98444C14.2044 5.54792 14.0367 5.12694 13.7322 4.81403L13.7012 4.78203L13.6672 4.75003C13.3455 4.43669 12.9143 4.26118 12.4651 4.2608C12.016 4.26043 11.5845 4.43522 11.2622 4.74803L6.48124 9.43803H6.47924L6.41424 9.50303C6.30685 9.60778 6.16277 9.66642 6.01274 9.66642C5.86272 9.66642 5.71864 9.60778 5.61124 9.50303C5.50731 9.40128 5.44791 9.26252 5.44604 9.11709C5.44417 8.97166 5.49997 8.83141 5.60124 8.72703L5.61124 8.71703L10.4602 3.96003C11.1102 3.32403 11.1232 2.28203 10.4872 1.63103L10.4582 1.60103C10.1362 1.28736 9.70433 1.11183 9.25474 1.11183C8.80516 1.11183 8.37333 1.28736 8.05124 1.60103L1.63524 7.89603C1.5279 8.00048 1.38403 8.05893 1.23424 8.05893C1.08446 8.05893 0.940591 8.00048 0.833243 7.89603C0.729179 7.79442 0.669597 7.65573 0.667536 7.5103C0.665474 7.36487 0.7211 7.22454 0.822243 7.12003L0.833243 7.11003L7.25024 0.814026C7.78698 0.291743 8.50633 -0.000488281 9.25524 -0.000488281C10.0042 -0.000488281 10.7235 0.291743 11.2602 0.814026C11.8902 1.42703 12.1892 2.30403 12.0632 3.17403C12.9432 3.04903 13.8332 3.34003 14.4692 3.96103L14.5032 3.99403C14.7616 4.24525 14.9679 4.54492 15.1104 4.87591C15.2529 5.2069 15.3287 5.56272 15.3337 5.92304C15.3386 6.28337 15.2725 6.64113 15.1391 6.97589C15.0057 7.31064 14.8076 7.61584 14.5562 7.87403M12.8652 6.32103C12.9692 6.21928 13.0286 6.08052 13.0304 5.93509C13.0323 5.78966 12.9765 5.64941 12.8752 5.54503L12.8652 5.53503C12.7578 5.43027 12.6138 5.37164 12.4637 5.37164C12.3137 5.37164 12.1696 5.43027 12.0622 5.53503L7.31724 10.19C6.99515 10.5037 6.56333 10.6792 6.11374 10.6792C5.66416 10.6792 5.23233 10.5037 4.91024 10.19C4.7552 10.0391 4.63143 9.85901 4.54601 9.66018C4.46058 9.46135 4.41518 9.24763 4.4124 9.03124C4.40961 8.81486 4.4495 8.60004 4.52977 8.39908C4.61005 8.19812 4.72914 8.01494 4.88024 7.86003L4.91124 7.82903L9.65824 3.17403C9.76231 3.07242 9.82189 2.93373 9.82395 2.7883C9.82601 2.64287 9.77039 2.50254 9.66924 2.39803L9.65824 2.38803C9.55085 2.28327 9.40677 2.22464 9.25674 2.22464C9.10672 2.22464 8.96264 2.28327 8.85524 2.38803L4.10824 7.04203C3.84537 7.29765 3.63642 7.60338 3.49374 7.94115C3.35107 8.27892 3.27755 8.64186 3.27755 9.00853C3.27755 9.37519 3.35107 9.73814 3.49374 10.0759C3.63642 10.4137 3.84537 10.7194 4.10824 10.975C4.64515 11.4974 5.36467 11.7896 6.11374 11.7896C6.86282 11.7896 7.58234 11.4974 8.11924 10.975L12.8652 6.32103Z'
fill='currentColor'
/>
</g>
<defs>
<clipPath id='mcp-clip'>
<rect width='16' height='16' fill='white' />
</clipPath>
</defs>
</svg>
)
}
export function WordpressIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.925 25.925'>

View File

@@ -45,9 +45,9 @@ Create a new event in Google Calendar
| `summary` | string | Yes | Event title/summary |
| `description` | string | No | Event description |
| `location` | string | No | Event location |
| `startDateTime` | string | Yes | Start date and time \(RFC3339 format, e.g., 2025-06-03T10:00:00-08:00\) |
| `endDateTime` | string | Yes | End date and time \(RFC3339 format, e.g., 2025-06-03T11:00:00-08:00\) |
| `timeZone` | string | No | Time zone \(e.g., America/Los_Angeles\) |
| `startDateTime` | string | Yes | Start date and time. MUST include timezone offset \(e.g., 2025-06-03T10:00:00-08:00\) OR provide timeZone parameter |
| `endDateTime` | string | Yes | End date and time. MUST include timezone offset \(e.g., 2025-06-03T11:00:00-08:00\) OR provide timeZone parameter |
| `timeZone` | string | No | Time zone \(e.g., America/Los_Angeles\). Required if datetime does not include offset. Defaults to America/Los_Angeles if not provided. |
| `attendees` | array | No | Array of attendee email addresses |
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |

View File

@@ -113,8 +113,8 @@ List files and folders in Google Drive
| --------- | ---- | -------- | ----------- |
| `folderSelector` | string | No | Select the folder to list files from |
| `folderId` | string | No | The ID of the folder to list files from \(internal use\) |
| `query` | string | No | A query to filter the files |
| `pageSize` | number | No | The number of files to return |
| `query` | string | No | Search term to filter files by name \(e.g. "budget" finds files with "budget" in the name\). Do NOT use Google Drive query syntax here - just provide a plain search term. |
| `pageSize` | number | No | The maximum number of files to return \(default: 100\) |
| `pageToken` | string | No | The page token to use for pagination |
#### Output

View File

@@ -91,8 +91,8 @@ Read data from a Google Sheets spreadsheet
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to read from |
| `range` | string | No | The range of cells to read from |
| `spreadsheetId` | string | Yes | The ID of the spreadsheet \(found in the URL: docs.google.com/spreadsheets/d/\{SPREADSHEET_ID\}/edit\). |
| `range` | string | No | The A1 notation range to read \(e.g. "Sheet1!A1:D10", "A1:B5"\). Defaults to first sheet A1:Z1000 if not specified. |
#### Output
@@ -109,9 +109,9 @@ Write data to a Google Sheets spreadsheet
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to write to |
| `range` | string | No | The range of cells to write to |
| `values` | array | Yes | The data to write to the spreadsheet |
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
| `range` | string | No | The A1 notation range to write to \(e.g. "Sheet1!A1:D10", "A1:B5"\) |
| `values` | array | Yes | The data to write as a 2D array \(e.g. \[\["Name", "Age"\], \["Alice", 30\], \["Bob", 25\]\]\) or array of objects. |
| `valueInputOption` | string | No | The format of the data to write |
| `includeValuesInResponse` | boolean | No | Whether to include the written values in the response |
@@ -134,8 +134,8 @@ Update data in a Google Sheets spreadsheet
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to update |
| `range` | string | No | The range of cells to update |
| `values` | array | Yes | The data to update in the spreadsheet |
| `range` | string | No | The A1 notation range to update \(e.g. "Sheet1!A1:D10", "A1:B5"\) |
| `values` | array | Yes | The data to update as a 2D array \(e.g. \[\["Name", "Age"\], \["Alice", 30\]\]\) or array of objects. |
| `valueInputOption` | string | No | The format of the data to update |
| `includeValuesInResponse` | boolean | No | Whether to include the updated values in the response |
@@ -158,8 +158,8 @@ Append data to the end of a Google Sheets spreadsheet
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to append to |
| `range` | string | No | The range of cells to append after |
| `values` | array | Yes | The data to append to the spreadsheet |
| `range` | string | No | The A1 notation range to append after \(e.g. "Sheet1", "Sheet1!A:D"\) |
| `values` | array | Yes | The data to append as a 2D array \(e.g. \[\["Alice", 30\], \["Bob", 25\]\]\) or array of objects. |
| `valueInputOption` | string | No | The format of the data to append |
| `insertDataOption` | string | No | How to insert the data \(OVERWRITE or INSERT_ROWS\) |
| `includeValuesInResponse` | boolean | No | Whether to include the appended values in the response |

View File

@@ -122,6 +122,82 @@ Read the latest messages from Slack channels. Retrieve conversation history with
| --------- | ---- | ----------- |
| `messages` | array | Array of message objects from the channel |
### `slack_list_channels`
List all channels in a Slack workspace. Returns public and private channels the bot has access to.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `includePrivate` | boolean | No | Include private channels the bot is a member of \(default: true\) |
| `excludeArchived` | boolean | No | Exclude archived channels \(default: true\) |
| `limit` | number | No | Maximum number of channels to return \(default: 100, max: 200\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `channels` | array | Array of channel objects from the workspace |
### `slack_list_members`
List all members (user IDs) in a Slack channel. Use with Get User Info to resolve IDs to names.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `channel` | string | Yes | Channel ID to list members from |
| `limit` | number | No | Maximum number of members to return \(default: 100, max: 200\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `members` | array | Array of user IDs who are members of the channel \(e.g., U1234567890\) |
### `slack_list_users`
List all users in a Slack workspace. Returns user profiles with names and avatars.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `includeDeleted` | boolean | No | Include deactivated/deleted users \(default: false\) |
| `limit` | number | No | Maximum number of users to return \(default: 100, max: 200\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `users` | array | Array of user objects from the workspace |
### `slack_get_user`
Get detailed information about a specific Slack user by their user ID.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `userId` | string | Yes | User ID to look up \(e.g., U1234567890\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | object | Detailed user information |
### `slack_download`
Download a file from Slack

View File

@@ -26,6 +26,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
{ label: 'Send Message', id: 'send' },
{ label: 'Create Canvas', id: 'canvas' },
{ label: 'Read Messages', id: 'read' },
{ label: 'List Channels', id: 'list_channels' },
{ label: 'List Channel Members', id: 'list_members' },
{ label: 'List Users', id: 'list_users' },
{ label: 'Get User Info', id: 'get_user' },
{ label: 'Download File', id: 'download' },
{ label: 'Update Message', id: 'update' },
{ label: 'Delete Message', id: 'delete' },
@@ -88,6 +92,11 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
placeholder: 'Select Slack channel',
mode: 'basic',
dependsOn: ['credential', 'authMethod'],
condition: {
field: 'operation',
value: ['list_channels', 'list_users', 'get_user'],
not: true,
},
},
// Manual channel ID input (advanced mode)
{
@@ -97,6 +106,11 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
canonicalParamId: 'channel',
placeholder: 'Enter Slack channel ID (e.g., C1234567890)',
mode: 'advanced',
condition: {
field: 'operation',
value: ['list_channels', 'list_users', 'get_user'],
not: true,
},
},
{
id: 'text',
@@ -178,6 +192,82 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
value: 'read',
},
},
// List Channels specific fields
{
id: 'includePrivate',
title: 'Include Private Channels',
type: 'dropdown',
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'true',
condition: {
field: 'operation',
value: 'list_channels',
},
},
{
id: 'channelLimit',
title: 'Channel Limit',
type: 'short-input',
canonicalParamId: 'limit',
placeholder: '100',
condition: {
field: 'operation',
value: 'list_channels',
},
},
// List Members specific fields
{
id: 'memberLimit',
title: 'Member Limit',
type: 'short-input',
canonicalParamId: 'limit',
placeholder: '100',
condition: {
field: 'operation',
value: 'list_members',
},
},
// List Users specific fields
{
id: 'includeDeleted',
title: 'Include Deactivated Users',
type: 'dropdown',
options: [
{ label: 'No', id: 'false' },
{ label: 'Yes', id: 'true' },
],
value: () => 'false',
condition: {
field: 'operation',
value: 'list_users',
},
},
{
id: 'userLimit',
title: 'User Limit',
type: 'short-input',
canonicalParamId: 'limit',
placeholder: '100',
condition: {
field: 'operation',
value: 'list_users',
},
},
// Get User specific fields
{
id: 'userId',
title: 'User ID',
type: 'short-input',
placeholder: 'Enter Slack user ID (e.g., U1234567890)',
condition: {
field: 'operation',
value: 'get_user',
},
required: true,
},
{
id: 'oldest',
title: 'Oldest Timestamp',
@@ -280,6 +370,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
'slack_message',
'slack_canvas',
'slack_message_reader',
'slack_list_channels',
'slack_list_members',
'slack_list_users',
'slack_get_user',
'slack_download',
'slack_update_message',
'slack_delete_message',
@@ -294,6 +388,14 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
return 'slack_canvas'
case 'read':
return 'slack_message_reader'
case 'list_channels':
return 'slack_list_channels'
case 'list_members':
return 'slack_list_members'
case 'list_users':
return 'slack_list_users'
case 'get_user':
return 'slack_get_user'
case 'download':
return 'slack_download'
case 'update':
@@ -327,18 +429,31 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
deleteTimestamp,
reactionTimestamp,
emojiName,
includePrivate,
channelLimit,
memberLimit,
includeDeleted,
userLimit,
userId,
...rest
} = params
// Handle both selector and manual channel input
const effectiveChannel = (channel || manualChannel || '').trim()
if (!effectiveChannel) {
// Operations that don't require a channel
const noChannelOperations = ['list_channels', 'list_users', 'get_user']
// Channel is required for most operations
if (!effectiveChannel && !noChannelOperations.includes(operation)) {
throw new Error('Channel is required.')
}
const baseParams: Record<string, any> = {
channel: effectiveChannel,
const baseParams: Record<string, any> = {}
// Only add channel if we have one (not needed for list_channels)
if (effectiveChannel) {
baseParams.channel = effectiveChannel
}
// Handle authentication based on method
@@ -394,6 +509,43 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
}
break
case 'list_channels':
baseParams.includePrivate = includePrivate !== 'false'
baseParams.excludeArchived = true
if (channelLimit) {
const parsedLimit = Number.parseInt(channelLimit, 10)
baseParams.limit = !Number.isNaN(parsedLimit) ? parsedLimit : 100
} else {
baseParams.limit = 100
}
break
case 'list_members':
if (memberLimit) {
const parsedLimit = Number.parseInt(memberLimit, 10)
baseParams.limit = !Number.isNaN(parsedLimit) ? parsedLimit : 100
} else {
baseParams.limit = 100
}
break
case 'list_users':
baseParams.includeDeleted = includeDeleted === 'true'
if (userLimit) {
const parsedLimit = Number.parseInt(userLimit, 10)
baseParams.limit = !Number.isNaN(parsedLimit) ? parsedLimit : 100
} else {
baseParams.limit = 100
}
break
case 'get_user':
if (!userId) {
throw new Error('User ID is required for get user operation')
}
baseParams.userId = userId
break
case 'download': {
const fileId = (rest as any).fileId
const downloadFileName = (rest as any).downloadFileName
@@ -461,6 +613,16 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
name: { type: 'string', description: 'Emoji name' },
threadTs: { type: 'string', description: 'Thread timestamp' },
thread_ts: { type: 'string', description: 'Thread timestamp for reply' },
// List Channels inputs
includePrivate: { type: 'string', description: 'Include private channels (true/false)' },
channelLimit: { type: 'string', description: 'Maximum number of channels to return' },
// List Members inputs
memberLimit: { type: 'string', description: 'Maximum number of members to return' },
// List Users inputs
includeDeleted: { type: 'string', description: 'Include deactivated users (true/false)' },
userLimit: { type: 'string', description: 'Maximum number of users to return' },
// Get User inputs
userId: { type: 'string', description: 'User ID to look up' },
},
outputs: {
// slack_message outputs (send operation)
@@ -488,6 +650,37 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
'Array of message objects with comprehensive properties: text, user, timestamp, reactions, threads, files, attachments, blocks, stars, pins, and edit history',
},
// slack_list_channels outputs (list_channels operation)
channels: {
type: 'json',
description:
'Array of channel objects with properties: id, name, is_private, is_archived, is_member, num_members, topic, purpose, created, creator',
},
count: {
type: 'number',
description: 'Total number of items returned (channels, members, or users)',
},
// slack_list_members outputs (list_members operation)
members: {
type: 'json',
description: 'Array of user IDs who are members of the channel',
},
// slack_list_users outputs (list_users operation)
users: {
type: 'json',
description:
'Array of user objects with properties: id, name, real_name, display_name, is_bot, is_admin, deleted, timezone, avatar, status_text, status_emoji',
},
// slack_get_user outputs (get_user operation)
user: {
type: 'json',
description:
'Detailed user object with properties: id, name, real_name, display_name, first_name, last_name, title, is_bot, is_admin, deleted, timezone, avatars, status',
},
// slack_download outputs
file: {
type: 'json',

View File

@@ -987,6 +987,10 @@ import {
slackCanvasTool,
slackDeleteMessageTool,
slackDownloadTool,
slackGetUserTool,
slackListChannelsTool,
slackListMembersTool,
slackListUsersTool,
slackMessageReaderTool,
slackMessageTool,
slackUpdateMessageTool,
@@ -1397,6 +1401,10 @@ export const tools: Record<string, ToolConfig> = {
polymarket_get_trades: polymarketGetTradesTool,
slack_message: slackMessageTool,
slack_message_reader: slackMessageReaderTool,
slack_list_channels: slackListChannelsTool,
slack_list_members: slackListMembersTool,
slack_list_users: slackListUsersTool,
slack_get_user: slackGetUserTool,
slack_canvas: slackCanvasTool,
slack_download: slackDownloadTool,
slack_update_message: slackUpdateMessageTool,

View File

@@ -0,0 +1,155 @@
import type { SlackGetUserParams, SlackGetUserResponse } from '@/tools/slack/types'
import type { ToolConfig } from '@/tools/types'
export const slackGetUserTool: ToolConfig<SlackGetUserParams, SlackGetUserResponse> = {
id: 'slack_get_user',
name: 'Slack Get User Info',
description: 'Get detailed information about a specific Slack user by their user ID.',
version: '1.0.0',
oauth: {
required: true,
provider: 'slack',
},
params: {
authMethod: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication method: oauth or bot_token',
},
botToken: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Bot token for Custom Bot',
},
accessToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'OAuth access token or bot token for Slack API',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'User ID to look up (e.g., U1234567890)',
},
},
request: {
url: (params: SlackGetUserParams) => {
const url = new URL('https://slack.com/api/users.info')
url.searchParams.append('user', params.userId)
return url.toString()
},
method: 'GET',
headers: (params: SlackGetUserParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken || params.botToken}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.ok) {
if (data.error === 'user_not_found') {
throw new Error('User not found. Please check the user ID and try again.')
}
if (data.error === 'missing_scope') {
throw new Error(
'Missing required permissions. Please reconnect your Slack account with the necessary scopes (users:read).'
)
}
if (data.error === 'invalid_auth') {
throw new Error('Invalid authentication. Please check your Slack credentials.')
}
throw new Error(data.error || 'Failed to get user info from Slack')
}
const user = data.user
const profile = user.profile || {}
return {
success: true,
output: {
user: {
id: user.id,
name: user.name,
real_name: user.real_name || profile.real_name || '',
display_name: profile.display_name || '',
first_name: profile.first_name || '',
last_name: profile.last_name || '',
title: profile.title || '',
phone: profile.phone || '',
skype: profile.skype || '',
is_bot: user.is_bot || false,
is_admin: user.is_admin || false,
is_owner: user.is_owner || false,
is_primary_owner: user.is_primary_owner || false,
is_restricted: user.is_restricted || false,
is_ultra_restricted: user.is_ultra_restricted || false,
deleted: user.deleted || false,
timezone: user.tz,
timezone_label: user.tz_label,
timezone_offset: user.tz_offset,
avatar_24: profile.image_24,
avatar_48: profile.image_48,
avatar_72: profile.image_72,
avatar_192: profile.image_192,
avatar_512: profile.image_512,
status_text: profile.status_text || '',
status_emoji: profile.status_emoji || '',
status_expiration: profile.status_expiration,
updated: user.updated,
},
},
}
},
outputs: {
user: {
type: 'object',
description: 'Detailed user information',
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'Username (handle)' },
real_name: { type: 'string', description: 'Full real name' },
display_name: { type: 'string', description: 'Display name shown in Slack' },
first_name: { type: 'string', description: 'First name' },
last_name: { type: 'string', description: 'Last name' },
title: { type: 'string', description: 'Job title' },
phone: { type: 'string', description: 'Phone number' },
skype: { type: 'string', description: 'Skype handle' },
is_bot: { type: 'boolean', description: 'Whether the user is a bot' },
is_admin: { type: 'boolean', description: 'Whether the user is a workspace admin' },
is_owner: { type: 'boolean', description: 'Whether the user is the workspace owner' },
is_primary_owner: { type: 'boolean', description: 'Whether the user is the primary owner' },
is_restricted: { type: 'boolean', description: 'Whether the user is a guest (restricted)' },
is_ultra_restricted: {
type: 'boolean',
description: 'Whether the user is a single-channel guest',
},
deleted: { type: 'boolean', description: 'Whether the user is deactivated' },
timezone: {
type: 'string',
description: 'Timezone identifier (e.g., America/Los_Angeles)',
},
timezone_label: { type: 'string', description: 'Human-readable timezone label' },
timezone_offset: { type: 'number', description: 'Timezone offset in seconds from UTC' },
avatar_24: { type: 'string', description: 'URL to 24px avatar' },
avatar_48: { type: 'string', description: 'URL to 48px avatar' },
avatar_72: { type: 'string', description: 'URL to 72px avatar' },
avatar_192: { type: 'string', description: 'URL to 192px avatar' },
avatar_512: { type: 'string', description: 'URL to 512px avatar' },
status_text: { type: 'string', description: 'Custom status text' },
status_emoji: { type: 'string', description: 'Custom status emoji' },
status_expiration: { type: 'number', description: 'Unix timestamp when status expires' },
updated: { type: 'number', description: 'Unix timestamp of last profile update' },
},
},
},
}

View File

@@ -2,6 +2,10 @@ import { slackAddReactionTool } from '@/tools/slack/add_reaction'
import { slackCanvasTool } from '@/tools/slack/canvas'
import { slackDeleteMessageTool } from '@/tools/slack/delete_message'
import { slackDownloadTool } from '@/tools/slack/download'
import { slackGetUserTool } from '@/tools/slack/get_user'
import { slackListChannelsTool } from '@/tools/slack/list_channels'
import { slackListMembersTool } from '@/tools/slack/list_members'
import { slackListUsersTool } from '@/tools/slack/list_users'
import { slackMessageTool } from '@/tools/slack/message'
import { slackMessageReaderTool } from '@/tools/slack/message_reader'
import { slackUpdateMessageTool } from '@/tools/slack/update_message'
@@ -14,4 +18,8 @@ export {
slackUpdateMessageTool,
slackDeleteMessageTool,
slackAddReactionTool,
slackListChannelsTool,
slackListMembersTool,
slackListUsersTool,
slackGetUserTool,
}

View File

@@ -0,0 +1,150 @@
import type { SlackListChannelsParams, SlackListChannelsResponse } from '@/tools/slack/types'
import type { ToolConfig } from '@/tools/types'
export const slackListChannelsTool: ToolConfig<SlackListChannelsParams, SlackListChannelsResponse> =
{
id: 'slack_list_channels',
name: 'Slack List Channels',
description:
'List all channels in a Slack workspace. Returns public and private channels the bot has access to.',
version: '1.0.0',
oauth: {
required: true,
provider: 'slack',
},
params: {
authMethod: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication method: oauth or bot_token',
},
botToken: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Bot token for Custom Bot',
},
accessToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'OAuth access token or bot token for Slack API',
},
includePrivate: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Include private channels the bot is a member of (default: true)',
},
excludeArchived: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Exclude archived channels (default: true)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of channels to return (default: 100, max: 200)',
},
},
request: {
url: (params: SlackListChannelsParams) => {
const url = new URL('https://slack.com/api/conversations.list')
// Determine channel types to include
const includePrivate = params.includePrivate !== false
if (includePrivate) {
url.searchParams.append('types', 'public_channel,private_channel')
} else {
url.searchParams.append('types', 'public_channel')
}
// Exclude archived by default
const excludeArchived = params.excludeArchived !== false
url.searchParams.append('exclude_archived', String(excludeArchived))
// Set limit (default 100, max 200)
const limit = params.limit ? Math.min(Number(params.limit), 200) : 100
url.searchParams.append('limit', String(limit))
return url.toString()
},
method: 'GET',
headers: (params: SlackListChannelsParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken || params.botToken}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.ok) {
if (data.error === 'missing_scope') {
throw new Error(
'Missing required permissions. Please reconnect your Slack account with the necessary scopes (channels:read, groups:read).'
)
}
if (data.error === 'invalid_auth') {
throw new Error('Invalid authentication. Please check your Slack credentials.')
}
throw new Error(data.error || 'Failed to list channels from Slack')
}
const channels = (data.channels || []).map((channel: any) => ({
id: channel.id,
name: channel.name,
is_private: channel.is_private || false,
is_archived: channel.is_archived || false,
is_member: channel.is_member || false,
num_members: channel.num_members,
topic: channel.topic?.value || '',
purpose: channel.purpose?.value || '',
created: channel.created,
creator: channel.creator,
}))
return {
success: true,
output: {
channels,
count: channels.length,
},
}
},
outputs: {
channels: {
type: 'array',
description: 'Array of channel objects from the workspace',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Channel ID (e.g., C1234567890)' },
name: { type: 'string', description: 'Channel name without # prefix' },
is_private: { type: 'boolean', description: 'Whether the channel is private' },
is_archived: { type: 'boolean', description: 'Whether the channel is archived' },
is_member: {
type: 'boolean',
description: 'Whether the bot is a member of the channel',
},
num_members: { type: 'number', description: 'Number of members in the channel' },
topic: { type: 'string', description: 'Channel topic' },
purpose: { type: 'string', description: 'Channel purpose/description' },
created: { type: 'number', description: 'Unix timestamp when channel was created' },
creator: { type: 'string', description: 'User ID of channel creator' },
},
},
},
count: {
type: 'number',
description: 'Total number of channels returned',
},
},
}

View File

@@ -0,0 +1,109 @@
import type { SlackListMembersParams, SlackListMembersResponse } from '@/tools/slack/types'
import type { ToolConfig } from '@/tools/types'
export const slackListMembersTool: ToolConfig<SlackListMembersParams, SlackListMembersResponse> = {
id: 'slack_list_members',
name: 'Slack List Channel Members',
description:
'List all members (user IDs) in a Slack channel. Use with Get User Info to resolve IDs to names.',
version: '1.0.0',
oauth: {
required: true,
provider: 'slack',
},
params: {
authMethod: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication method: oauth or bot_token',
},
botToken: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Bot token for Custom Bot',
},
accessToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'OAuth access token or bot token for Slack API',
},
channel: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Channel ID to list members from',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of members to return (default: 100, max: 200)',
},
},
request: {
url: (params: SlackListMembersParams) => {
const url = new URL('https://slack.com/api/conversations.members')
url.searchParams.append('channel', params.channel)
// Set limit (default 100, max 200)
const limit = params.limit ? Math.min(Number(params.limit), 200) : 100
url.searchParams.append('limit', String(limit))
return url.toString()
},
method: 'GET',
headers: (params: SlackListMembersParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken || params.botToken}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.ok) {
if (data.error === 'channel_not_found') {
throw new Error('Channel not found. Please check the channel ID and try again.')
}
if (data.error === 'missing_scope') {
throw new Error(
'Missing required permissions. Please reconnect your Slack account with the necessary scopes (channels:read, groups:read).'
)
}
if (data.error === 'invalid_auth') {
throw new Error('Invalid authentication. Please check your Slack credentials.')
}
throw new Error(data.error || 'Failed to list channel members from Slack')
}
const members = data.members || []
return {
success: true,
output: {
members,
count: members.length,
},
}
},
outputs: {
members: {
type: 'array',
description: 'Array of user IDs who are members of the channel (e.g., U1234567890)',
items: {
type: 'string',
},
},
count: {
type: 'number',
description: 'Total number of members returned',
},
},
}

View File

@@ -0,0 +1,141 @@
import type { SlackListUsersParams, SlackListUsersResponse } from '@/tools/slack/types'
import type { ToolConfig } from '@/tools/types'
export const slackListUsersTool: ToolConfig<SlackListUsersParams, SlackListUsersResponse> = {
id: 'slack_list_users',
name: 'Slack List Users',
description: 'List all users in a Slack workspace. Returns user profiles with names and avatars.',
version: '1.0.0',
oauth: {
required: true,
provider: 'slack',
},
params: {
authMethod: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication method: oauth or bot_token',
},
botToken: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Bot token for Custom Bot',
},
accessToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'OAuth access token or bot token for Slack API',
},
includeDeleted: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Include deactivated/deleted users (default: false)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of users to return (default: 100, max: 200)',
},
},
request: {
url: (params: SlackListUsersParams) => {
const url = new URL('https://slack.com/api/users.list')
// Set limit (default 100, max 200)
const limit = params.limit ? Math.min(Number(params.limit), 200) : 100
url.searchParams.append('limit', String(limit))
return url.toString()
},
method: 'GET',
headers: (params: SlackListUsersParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken || params.botToken}`,
}),
},
transformResponse: async (response: Response, params?: SlackListUsersParams) => {
const data = await response.json()
if (!data.ok) {
if (data.error === 'missing_scope') {
throw new Error(
'Missing required permissions. Please reconnect your Slack account with the necessary scopes (users:read).'
)
}
if (data.error === 'invalid_auth') {
throw new Error('Invalid authentication. Please check your Slack credentials.')
}
throw new Error(data.error || 'Failed to list users from Slack')
}
const includeDeleted = params?.includeDeleted === true
const users = (data.members || [])
.filter((user: any) => {
// Always filter out Slackbot
if (user.id === 'USLACKBOT') return false
// Filter deleted users unless includeDeleted is true
if (!includeDeleted && user.deleted) return false
return true
})
.map((user: any) => ({
id: user.id,
name: user.name,
real_name: user.real_name || user.profile?.real_name || '',
display_name: user.profile?.display_name || '',
is_bot: user.is_bot || false,
is_admin: user.is_admin || false,
is_owner: user.is_owner || false,
deleted: user.deleted || false,
timezone: user.tz,
avatar: user.profile?.image_72 || user.profile?.image_48 || '',
status_text: user.profile?.status_text || '',
status_emoji: user.profile?.status_emoji || '',
}))
return {
success: true,
output: {
users,
count: users.length,
},
}
},
outputs: {
users: {
type: 'array',
description: 'Array of user objects from the workspace',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'User ID (e.g., U1234567890)' },
name: { type: 'string', description: 'Username (handle)' },
real_name: { type: 'string', description: 'Full real name' },
display_name: { type: 'string', description: 'Display name shown in Slack' },
is_bot: { type: 'boolean', description: 'Whether the user is a bot' },
is_admin: { type: 'boolean', description: 'Whether the user is a workspace admin' },
is_owner: { type: 'boolean', description: 'Whether the user is the workspace owner' },
deleted: { type: 'boolean', description: 'Whether the user is deactivated' },
timezone: { type: 'string', description: 'User timezone identifier' },
avatar: { type: 'string', description: 'URL to user avatar image' },
status_text: { type: 'string', description: 'Custom status text' },
status_emoji: { type: 'string', description: 'Custom status emoji' },
},
},
},
count: {
type: 'number',
description: 'Total number of users returned',
},
},
}

View File

@@ -49,6 +49,26 @@ export interface SlackAddReactionParams extends SlackBaseParams {
name: string
}
export interface SlackListChannelsParams extends SlackBaseParams {
includePrivate?: boolean
excludeArchived?: boolean
limit?: number
}
export interface SlackListMembersParams extends SlackBaseParams {
channel: string
limit?: number
}
export interface SlackListUsersParams extends SlackBaseParams {
includeDeleted?: boolean
limit?: number
}
export interface SlackGetUserParams extends SlackBaseParams {
userId: string
}
export interface SlackMessageResponse extends ToolResponse {
output: {
// Legacy properties for backward compatibility
@@ -207,6 +227,78 @@ export interface SlackAddReactionResponse extends ToolResponse {
}
}
export interface SlackChannel {
id: string
name: string
is_private: boolean
is_archived: boolean
is_member: boolean
num_members?: number
topic?: string
purpose?: string
created?: number
creator?: string
}
export interface SlackListChannelsResponse extends ToolResponse {
output: {
channels: SlackChannel[]
count: number
}
}
export interface SlackListMembersResponse extends ToolResponse {
output: {
members: string[]
count: number
}
}
export interface SlackUser {
id: string
name: string
real_name: string
display_name: string
first_name?: string
last_name?: string
title?: string
phone?: string
skype?: string
is_bot: boolean
is_admin: boolean
is_owner: boolean
is_primary_owner?: boolean
is_restricted?: boolean
is_ultra_restricted?: boolean
deleted: boolean
timezone?: string
timezone_label?: string
timezone_offset?: number
avatar?: string
avatar_24?: string
avatar_48?: string
avatar_72?: string
avatar_192?: string
avatar_512?: string
status_text?: string
status_emoji?: string
status_expiration?: number
updated?: number
}
export interface SlackListUsersResponse extends ToolResponse {
output: {
users: SlackUser[]
count: number
}
}
export interface SlackGetUserResponse extends ToolResponse {
output: {
user: SlackUser
}
}
export type SlackResponse =
| SlackCanvasResponse
| SlackMessageReaderResponse
@@ -215,3 +307,7 @@ export type SlackResponse =
| SlackUpdateMessageResponse
| SlackDeleteMessageResponse
| SlackAddReactionResponse
| SlackListChannelsResponse
| SlackListMembersResponse
| SlackListUsersResponse
| SlackGetUserResponse