feat: add status reactions across messaging channels

This commit is contained in:
xmanrui 2026-08-25 17:12:28 +08:00
parent aa8fd71b93
commit da01e3acee
30 changed files with 1853 additions and 274 deletions

View file

@ -20,6 +20,7 @@ oauth_config:
- files:read
- files:write
- im:history
- reactions:write
settings:
event_subscriptions:
bot_events:

View file

@ -276,6 +276,34 @@ export class SlackApi {
});
}
addReaction({ channelId, messageTs, emojiName, signal, timeoutMs }) {
return this.#request('reactions.add', {
tokenKind: 'bot',
signal,
timeoutMs,
retry: false,
body: {
channel: slackId(channelId, 'channel id'),
timestamp: requiredString(messageTs, 'message timestamp'),
name: requiredString(emojiName, 'reaction name'),
},
});
}
removeReaction({ channelId, messageTs, emojiName, signal, timeoutMs }) {
return this.#request('reactions.remove', {
tokenKind: 'bot',
signal,
timeoutMs,
retry: false,
body: {
channel: slackId(channelId, 'channel id'),
timestamp: requiredString(messageTs, 'message timestamp'),
name: requiredString(emojiName, 'reaction name'),
},
});
}
startStream({ channelId, threadTs, recipientTeamId, recipientUserId, markdownText, signal }) {
return this.#request('chat.startStream', {
tokenKind: 'bot',

View file

@ -4,6 +4,11 @@ export const SLACK_DESCRIPTOR = Object.freeze({
key: 'slack',
label: 'Slack',
connectionLabel: ' Socket Mode 长连接',
reactions: Object.freeze({
processing: 'eyes',
success: 'white_check_mark',
error: 'x',
}),
});
export class SlackHarnessBridge extends TextHarnessBridge {

View file

@ -127,6 +127,10 @@ export function normalizeSlackEvent(payload, botUserId, {
? event.files.map((file) => slackFileSource(file, loadFileStream, loadFileInfo)).filter(Boolean)
: [],
addressed: direct || mentioned,
reactionTarget: {
channelId: String(event.channel),
messageTs: String(event.ts),
},
replyTarget: {
channelId: String(event.channel),
threadTs,
@ -284,6 +288,26 @@ export class SlackBotClient {
return { providerMessageIds };
}
async addReaction(target, emoji, { signal } = {}) {
const reactionKey = String(emoji ?? '').trim();
await this.#api.addReaction({
channelId: target.channelId,
messageTs: target.messageTs,
emojiName: reactionKey,
signal: signal ?? this.#signal,
});
return reactionKey;
}
removeReaction(target, reactionKey, { signal } = {}) {
return this.#api.removeReaction({
channelId: target.channelId,
messageTs: target.messageTs,
emojiName: reactionKey,
signal: signal ?? this.#signal,
});
}
openStream(target) {
return createSlackMessageStream({
api: this.#api,