{"id":25257283,"url":"https://github.com/zowe/zowe-bot","last_synced_at":"2026-02-27T22:42:23.414Z","repository":{"id":62087721,"uuid":"551347925","full_name":"zowe/zowe-bot","owner":"zowe","description":"Combot Framework for use by Zowe-Chat project","archived":false,"fork":false,"pushed_at":"2025-03-06T14:47:14.000Z","size":1236,"stargazers_count":1,"open_issues_count":9,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-06T15:36:14.380Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zowe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-14T08:28:50.000Z","updated_at":"2025-03-06T14:46:18.000Z","dependencies_parsed_at":"2025-02-12T06:38:48.595Z","dependency_job_id":"827c7795-2463-4a1f-a2fc-72b0cfdb456d","html_url":"https://github.com/zowe/zowe-bot","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zowe%2Fzowe-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zowe%2Fzowe-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zowe%2Fzowe-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zowe%2Fzowe-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zowe","download_url":"https://codeload.github.com/zowe/zowe-bot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247419808,"owners_count":20936012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-12T06:38:44.127Z","updated_at":"2026-02-27T22:42:18.382Z","avatar_url":"https://github.com/zowe.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Common Bot Framework\n\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/zowe/zowe-bot/badge)](https://api.securityscorecards.dev/projects/github.com/zowe/zowe-bot)\n\nThe Common Bot Framework is a NPM library that provides a set of uniform interface for developers to create chat bots and chat with them for different chat platforms including Mattermost, Slack and Microsoft Teams so as to to enable chat functionality for your products.\n\n## Content\n  - [Features](#features)\n  - [Interfaces](#interfaces)\n  - [Environment variables](#environment-variables)\n  - [Supported Chat Platforms](#supported-chat-platforms)\n  - [Supported Message Types](#supported-message-types)\n  - [Create chat bot](#create-chat-bot)\n  - [Create message listeners](#create-message-listeners)\n  - [Create routers](#create-routers)\n  - [Chat tool limitation](#chat-tool-limitation)\n\n## Features\n* Support the latest version of 3 chat platforms\n  * Microsoft Teams\n  * Slack\n  * Mattermost\n* Support to chat with bot in 3 different places\n  * in a channel via @mention bot\n  * in a thread  via @mention bot\n  * 1 on 1 directly\n* Support to interact with bot via interactive components\n  * Dropdown box\n  * Button\n  * Show popup dialog to collect sensitive input: operator account and password\n* Support to create multiple bots in user applications\n\n## Interfaces\n* Messaging App\n* Bot APIs\n  * listen(matcher, handler)\n  * route(basePath, handler)\n  * send(chatContextData, message)\n  * getLimit()\n* Chat context data\n  * Context data for chatting, including message, bot, user / channel / team / tenant information\n  * Context data specific for different chat platforms\n\n## Environment variables\n* COMMONBOT_LOG_FILE\n\n  Specifies the log file of your Common Bot Framework. The default value is $ZOWE_CHAT_HOME/node_modules/@zowe/bot/log/common-bot.log.\n* COMMONBOT_LOG_LEVEL\n\n  Specifies the level of logs. The value can be error, warn, info, verbose, debug, or silly. The default value is info.\n* COMMONBOT_LOG_MAX_SIZE\n\n  Specifies the maximum size of the file after which the log will rotate. The value can be a number of bytes without any unit or a number with the suffix k, m, or g as units for KB, MB, or GB separately. The default value is null, which means that the file size is unlimited except the operating system limit.\n\n* COMMONBOT_LOG_MAX_FILE\n  Specifies the maximum file number of logs to keep. The default value is null, which means all the log files will be kept and no logs will be removed.\n​\n## Supported Chat Platforms\nThe Common Bot Framework supports 3 chat platforms below at present.\n* Mattermost\n* Slack\n* Microsoft Teams\n\n## Supported Message Types\nExcept pure plain text and markdown format, most of chat platforms provide their own type of messages to support richer functions like interactive components (buttons, dropdown, etc). The Common Bot Framework supports 7 message types as below:\n* **PLAIN_TEXT**: _**Any**_ Pure plain text and markdown format message. Please be noted that the supported elements syntax for markdown usually is different for different chat platforms.\n* **MATTERMOST_ATTACHMENT**: _**Mattermost only**_ Interactive message including buttons etc. [Learn More ...](https://developers.mattermost.com/integrate/admin-guide/admin-message-attachments/)\n* **MATTERMOST_DIALOG_OPEN**: _**Mattermost only**_ Open a dialog\n* **SLACK_BLOCK**: _**Slack only**_ Message including multiple interactive elements including buttons etc. [Learn More ...](https://api.slack.com/reference/block-kit/blocks)\n* **SLACK_VIEW_OPEN**: _**Slack only**_ Open a dialog\n* **SLACK_VIEW_UPDATE**:  _**Slack only**_ Close a dialog\n* **MSTEAMS_ADAPTIVE_CARD**: _**Teams only**_ Message including multiple interactive component including buttons etc. [Learn More ...](https://docs.microsoft.com/en-us/adaptive-cards/)\n* **MSTEAMS_DIALOG_OPEN**: _**Teams only**_ Open a dialog\n\n## Create chat bot\nBefore you can leverage Common Bot Framework to create one chat bot, you must create one required chat platform app and configure your chat platform and write down the values for all required properties. [Learn more ...](https://www.ibm.com/docs/en/z-chatops/1.1.2?topic=software-configuring-your-chat-platform)\n* Mattermost\n``` TypeScript\n// Create messaging app\nconst app = express(); // Your Express.JS app\n\n// Set chat bot option\nconst botOption: IBotOption = {\n    'messagingApp': app,\n    'chatTool': {\n        'type': IChatToolType.MATTERMOST,\n        'option': {\n            'protocol': IProtocol.HTTPS,\n            'hostName': '\u003cYour host name\u003e',\n            'port': 443,\n            'basePath': '/api/v4',\n            'tlsCertificate': fs.readFileSync('\u003cThe absolute file path of your Mattermost server TLS certificate\u003e', 'utf8'),\n            'teamUrl': '\u003cYour team URL\u003e',\n            'botUserName': '\u003cYour bot user name\u003e',\n            'botAccessToken': '\u003cYour bot access token\u003e',\n        },\n    },\n};\n\n// Create bot\nconst bot = new CommonBot(botOption);\n```\n\n* Slack\n``` TypeScript\n// Create messaging app\nconst app = null; // Your Express.JS app, not set here due to socket mode will be used\n\n// Set chat bot option\nconst botOption: IBotOption = {\n    'messagingApp': null,\n    'chatTool': {\n        'type': IChatToolType.SLACK,\n        'option': {\n            'botUserName': '\u003cYour bot user name\u003e',\n            'signingSecret': '\u003cYour signing secret\u003e',\n            'endpoints': '', // Must be set if socketMode is false\n            'receiver': undefined, // Must be set if socketMode is false\n            'token': '\u003cYour bot user OAuth token\u003e',\n            'logLevel': ILogLevel.DEBUG,\n            'socketMode': true,\n            'appToken': '\u003cYour app level token\u003e', // Must be set if socketMode is true\n        },\n    },\n};\n\n// Create bot\nconst bot = new CommonBot(botOption);\n```\n* Microsoft Teams\n``` TypeScript\n// Create messaging app\nconst app = express(); // Your Express.JS app\n\n// Set chat bot option\nconst botOption: IBotOption = {\n    'messagingApp': this.app.getApplication(),\n    'chatTool': {\n        'type': IChatToolType.MSTEAMS,\n        'option': {\n            'botUserName': '\u003cYour bot user name\u003e',\n            'botId': '\u003cYour bot ID\u003e',\n            'botPassword': '\u003cYour bot password\u003e',\n        },\n    },\n};\n\n// Create bot\nconst bot = new CommonBot(botOption);\n```\n## Create message listeners\nThe bot created by you usually can receive all @mention messages for the bot. You must create listeners to match and process the message that you are interested in.\n``` TypeScript\n// Callback function used to match message\nfunction matchMessage(message: string): boolean {\n    // Print end log\n    console.log(`MattermostChatbot : matchMessage  start ===\u003e`);\n\n    // print incoming message\n    console.info(`Incoming message: ${message}`);\n    this.message = message;\n\n    // Match the bot name\n    let matched = false;\n    if (this.message.indexOf(`@${this.botName}`) !== -1) {\n        matched = true; //\n    } else {\n        console.info(`The message is not for @${this.botName}`);\n    }\n\n    // print end log\n    console.log(`MattermostChatbot : matchMessage    end \u003c===`);\n\n    return matched;\n}\n\n// Callback function used to process matched message\nasync function processMessage(chatContextData: IChatContextData): Promise\u003cvoid\u003e {\n    // print start log\n    console.log(`MattermostChatbot : processMessage  start ===\u003e`);\n\n    // Create executor\n    const executor: IExecutor = {\n        id: chatContextData.user.id,\n        name: chatContextData.user.name,\n        team: chatContextData.team,\n        channel: chatContextData.channel,\n        email: chatContextData.user.email,\n        conversationType: chatContextData.chattingType,\n    };\n\n    const messageText = this.message.substring(this.message.indexOf(`@${this.botName}`) + this.botName.length + 2);\n    console.info(`messageText: ${messageText}`);\n\n    if (messageText.toLowerCase().indexOf('hello') !== -1 || messageText.toLowerCase().indexOf('hi') !== -1) {\n        let commandOutput: IMessage[] = [];\n        commandOutput = this.view.getHelloView(executor);\n\n        await this.bot.send(chatContextData, commandOutput);\n    }\n\n    console.log(`MattermostChatbot : processMessage    end \u003c===`);\n}\n\n// Register message listener\nbot.listen(matchMessage, processMessage);\n```\n\n## Create routers\nNote: This part must be enhanced to support extendability\nIf some interactive components are included in your bot response, the bot will receive corresponding events when users click interactive components. You must create one callback function to process it and register the function as a router.\n\n``` TypeScript\n// Callback function used to process users' click events\nasync function processRoute(chatContextData: IChatContextData): Promise\u003cvoid\u003e {\n        // Print start log\n        console.log(`SlackChatbot : processRoute  start ===\u003e`);\n\n        let botResponse: IMessage[] = [];\n        let payload: Record\u003cstring, any\u003e = {}; // eslint-disable-line @typescript-eslint/no-explicit-any\n        try {\n            // Get payload\n            payload = chatContextData.chatToolContext.body;\n            console.debug(`payload: ${JSON.stringify(payload, null, 2)}`);\n\n            const executor: IExecutor = {\n                id: chatContextData.user.id,\n                name: chatContextData.user.name,\n                email: chatContextData.user.email,\n                team: {\n                    id: '',\n                    name: '',\n                },\n                channel: {\n                    id: chatContextData.channel.id,\n                    name: chatContextData.channel.name,\n                },\n                conversationType: chatContextData.chattingType,\n            };\n\n            if (payload.type === 'view_submission') {\n                const privateMetadata = JSON.parse(payload.view.private_metadata);\n                console.debug(`privateMetadata: ${JSON.stringify(privateMetadata)}`);\n\n                if (chatContextData.channel.id === '') {\n                    chatContextData.channel.id = ( privateMetadata.channelId ? privateMetadata.channelId : '' );\n                }\n\n                const stateValues = payload.view.state.values;\n                const comment = (stateValues[`block_comment`] ? stateValues[`block_comment`][`action_comment`].value : '');\n                botResponse = this.view.getDialogSubmit(executor, comment);\n                // Handle the view submission\n            } else if (payload.actions[0].type === 'static_select') { // Dropdown box\n                // Handle drop down\n            } else if (payload.actions[0].type === 'button') { // Button\n                botResponse = this.view.getDialog(executor, payload);\n            } else {\n                const errorMessage = `Unsupported Slack interactive component: ${payload.actions[0].type}`;\n                console.error(errorMessage);\n                botResponse = [{\n                    type: IMessageType.SLACK_BLOCK,\n                    message: errorMessage,\n                }];\n                return;\n            }\n        } catch (err) {\n            // Print exception stack\n            console.error(`Exception occurred when processing inbound Slack message!`);\n            console.error(err.stack);\n\n            botResponse = [{\n                type: IMessageType.SLACK_BLOCK,\n                message: err.name,\n            }];\n        } finally {\n            // Send response to chat tool\n            try {\n                console.info(`Command output: ${JSON.stringify(botResponse)}`);\n                for (const msg of botResponse) {\n                    let replyData: IMessage;\n                    if (msg.type === IMessageType.PLAIN_TEXT) {\n                        let isThread = false;\n                        let threadTs = '';\n                        if (payload.container !== undefined \u0026\u0026 payload.container.thread_ts !== undefined) {\n                            isThread = true;\n                        }\n                        if (isThread) {\n                            threadTs = payload.container.thread_ts;\n                            console.debug(`Message thread_ts: ${threadTs}`);\n                        }\n                    } else if (msg.type === IMessageType.SLACK_BLOCK) {\n                        let isThread = false;\n                        if (payload.container !== undefined \u0026\u0026 payload.container.thread_ts !== undefined) {\n                            isThread = true;\n                        }\n                        if (isThread) {\n                            msg.message.thread_ts = payload.container.thread_ts;\n                            console.debug(`Message thread_ts: ${msg.message.thread_ts}`);\n                        }\n\n                        msg.message.channel = chatContextData.channel.id;\n                        replyData = msg;\n                    } else if (msg.type === IMessageType.SLACK_VIEW) {\n                        replyData = msg;\n                    } else if (msg.type === IMessageType.SLACK_VIEW_UPDATE) {\n                        replyData = msg;\n                    } else {\n                        console.error(`Unsupported message type: ${JSON.stringify(msg, null, 2)}`);\n                    }\n                    await this.bot.send(chatContextData, [replyData]);\n                }\n            } catch (err) {\n                // Print exception stack\n                console.error(`Exception occurred when send message to Slack!`);\n                console.error(err.stack);\n            } finally {\n                // print end log\n                console.log(`SlackChatbot : processRoute    end \u003c===`);\n            }\n        }\n    }\n}\n\n\n// Register event handler\nbot.route('\u003cYour base path\u003e', processRoute);\n```\n\n## Chat Tool Limitation\nDifferent chat tool usually has different limitation. You can use the bot API `getLimit()` to retrieve the corresponding limitation of your chat tool.\n* Mattermost\n```TypeScript\n{\n    // Unit for MaxLength: character\n    // Unit for MaxNumber: item\n    'messageMaxLength': 16383, // Message supports at most 16383 (multi-byte) characters (65535 bytes)since v5.0.0\n    //                            https://developers.mattermost.com/integrate/webhooks/incoming/#tips-and-best-practices\n};\n```\n\n* Slack\n```TypeScript\n {\n    // Unit for MaxLength: character\n    // Unit for MaxNumber: item\n    'messageMaxLength': 40000, // https://api.slack.com/changelog/2018-04-truncating-really-long-messages\n    'blockIdMaxLength': 255,\n    'actionBlockElementsMaxNumber': 25, // https://api.slack.com/reference/block-kit/blocks#actions_fields\n    'contextBlockElementsMaxNumber': 10, // https://api.slack.com/reference/block-kit/blocks#context_fields\n    'headerBlockTextMaxLength': 150, // https://api.slack.com/reference/block-kit/blocks#header_fields\n    'imageBlockUrlMaxLength': 3000, // https://api.slack.com/reference/block-kit/blocks#image_fields\n    'imageBlockAltTextMaxLength': 2000,\n    'imageBlockTitleTextMaxLength': 2000,\n    'inputBlockLabelTextMaxLength': 2000, // https://api.slack.com/reference/block-kit/blocks#input_fields\n    'inputBlockHintTextMaxLength': 2000,\n    'sectionBlockTextMaxLength': 3000, // https://api.slack.com/reference/block-kit/blocks#section_fields\n    'sectionBlockFieldsMaxNumber': 10,\n    'sectionBlockFieldsTextMaxLength': 2000,\n    'videoBlockAuthorNameMaxLength': 50, // https://api.slack.com/reference/block-kit/blocks#video_fields\n    'videoBlockTitleTextMaxLength': 200,\n}\n```\n* Microsoft Teams\n```TypeScript\n{\n    // Unit for MaxLength: byte\n    // Unit for MaxNumber: item\n    'messageMaxLength': 28 * 1024, // https://docs.microsoft.com/en-us/microsoftteams/limits-specifications-teams#chat\n    'fileAttachmentMaxNumber': 10,\n};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzowe%2Fzowe-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzowe%2Fzowe-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzowe%2Fzowe-bot/lists"}