This commit is contained in:
claude-chapter 2026-01-29 13:57:47 -05:00 committed by GitHub
commit db612e920c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 100 additions and 0 deletions

View File

@ -5,10 +5,12 @@ import { resolveSlackAccount } from "../../slack/accounts.js";
import {
deleteSlackMessage,
editSlackMessage,
getSlackChannelInfo,
getSlackMemberInfo,
listSlackEmojis,
listSlackPins,
listSlackReactions,
markSlackChannelRead,
pinSlackMessage,
reactSlackMessage,
readSlackMessages,
@ -296,5 +298,30 @@ export async function handleSlackAction(
return jsonResult({ ok: true, emojis });
}
if (action === "channelInfo") {
if (!isActionEnabled("channelInfo")) {
throw new Error("Slack channel info is disabled.");
}
const channelId = resolveChannelId();
const info = readOpts
? await getSlackChannelInfo(channelId, readOpts)
: await getSlackChannelInfo(channelId);
return jsonResult({ ok: true, ...info });
}
if (action === "markRead") {
if (!isActionEnabled("channelInfo")) {
throw new Error("Slack channel info is disabled.");
}
const channelId = resolveChannelId();
const timestamp = readStringParam(params, "timestamp", { required: true });
if (writeOpts) {
await markSlackChannelRead(channelId, timestamp, writeOpts);
} else {
await markSlackChannelRead(channelId, timestamp);
}
return jsonResult({ ok: true, markedAt: timestamp });
}
throw new Error(`Unknown action: ${action}`);
}

View File

@ -34,6 +34,7 @@ export const CHANNEL_MESSAGE_ACTION_NAMES = [
"role-add",
"role-remove",
"channel-info",
"mark-read",
"channel-list",
"channel-create",
"channel-edit",

View File

@ -46,6 +46,10 @@ export function createSlackActions(providerId: string): ChannelMessageActionAdap
}
if (isActionEnabled("memberInfo")) actions.add("member-info");
if (isActionEnabled("emojiList")) actions.add("emoji-list");
if (isActionEnabled("channelInfo")) {
actions.add("channel-info");
actions.add("mark-read");
}
return Array.from(actions);
},
extractToolSend: ({ args }): ChannelToolSend | null => {
@ -204,6 +208,30 @@ export function createSlackActions(providerId: string): ChannelMessageActionAdap
);
}
if (action === "channel-info") {
return await handleSlackAction(
{
action: "channelInfo",
channelId: resolveChannelId(),
accountId: accountId ?? undefined,
},
cfg,
);
}
if (action === "mark-read") {
const timestamp = readStringParam(params, "timestamp", { required: true });
return await handleSlackAction(
{
action: "markRead",
channelId: resolveChannelId(),
timestamp,
accountId: accountId ?? undefined,
},
cfg,
);
}
throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
},
};

View File

@ -39,6 +39,7 @@ export const MESSAGE_ACTION_TARGET_MODE: Record<ChannelMessageActionName, Messag
"role-add": "none",
"role-remove": "none",
"channel-info": "channelId",
"mark-read": "channelId",
"channel-list": "none",
"channel-create": "none",
"channel-edit": "channelId",

View File

@ -258,3 +258,46 @@ export async function listSlackPins(
const result = await client.pins.list({ channel: channelId });
return (result.items ?? []) as SlackPin[];
}
export type SlackChannelInfo = {
id?: string;
name?: string;
lastRead?: string;
unreadCount?: number;
unreadCountDisplay?: number;
latest?: string;
};
/**
* Get channel info including unread state (last_read, unread_count).
* Useful for tracking what messages the bot hasn't processed yet.
*/
export async function getSlackChannelInfo(
channelId: string,
opts: SlackActionClientOpts = {},
): Promise<SlackChannelInfo> {
const client = await getClient(opts);
const result = await client.conversations.info({ channel: channelId });
const channel = result.channel as Record<string, unknown> | undefined;
return {
id: channel?.id as string | undefined,
name: channel?.name as string | undefined,
lastRead: channel?.last_read as string | undefined,
unreadCount: channel?.unread_count as number | undefined,
unreadCountDisplay: channel?.unread_count_display as number | undefined,
latest: (channel?.latest as Record<string, unknown> | undefined)?.ts as string | undefined,
};
}
/**
* Mark a channel as read up to a specific timestamp.
* Updates the bot's read cursor for the channel.
*/
export async function markSlackChannelRead(
channelId: string,
timestamp: string,
opts: SlackActionClientOpts = {},
): Promise<void> {
const client = await getClient(opts);
await client.conversations.mark({ channel: channelId, ts: timestamp });
}