chore: Enable "curly" rule to avoid single-statement if confusion/errors.

This commit is contained in:
cpojer
2026-01-31 16:19:20 +09:00
parent 009b16fab8
commit 5ceff756e1
1266 changed files with 27871 additions and 9393 deletions

View File

@@ -2,7 +2,9 @@ import type { AllowlistMatch } from "../../channels/allowlist-match.js";
export function normalizeSlackSlug(raw?: string) {
const trimmed = raw?.trim().toLowerCase() ?? "";
if (!trimmed) return "";
if (!trimmed) {
return "";
}
const dashed = trimmed.replace(/\s+/g, "-");
const cleaned = dashed.replace(/[^a-z0-9#@._+-]+/g, "-");
return cleaned.replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "");
@@ -26,7 +28,9 @@ export function resolveSlackAllowListMatch(params: {
name?: string;
}): SlackAllowListMatch {
const allowList = params.allowList;
if (allowList.length === 0) return { allowed: false };
if (allowList.length === 0) {
return { allowed: false };
}
if (allowList.includes("*")) {
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
}
@@ -42,7 +46,9 @@ export function resolveSlackAllowListMatch(params: {
{ value: slug, source: "slug" },
];
for (const candidate of candidates) {
if (!candidate.value) continue;
if (!candidate.value) {
continue;
}
if (allowList.includes(candidate.value)) {
return {
allowed: true,
@@ -64,7 +70,9 @@ export function resolveSlackUserAllowed(params: {
userName?: string;
}) {
const allowList = normalizeAllowListLower(params.allowList);
if (allowList.length === 0) return true;
if (allowList.length === 0) {
return true;
}
return allowListMatches({
allowList,
id: params.userId,

View File

@@ -21,7 +21,9 @@ export type SlackChannelConfigResolved = {
function firstDefined<T>(...values: Array<T | undefined>) {
for (const value of values) {
if (typeof value !== "undefined") return value;
if (typeof value !== "undefined") {
return value;
}
}
return undefined;
}
@@ -36,13 +38,19 @@ export function shouldEmitSlackReactionNotification(params: {
}) {
const { mode, botId, messageAuthorId, userId, userName, allowlist } = params;
const effectiveMode = mode ?? "own";
if (effectiveMode === "off") return false;
if (effectiveMode === "off") {
return false;
}
if (effectiveMode === "own") {
if (!botId || !messageAuthorId) return false;
if (!botId || !messageAuthorId) {
return false;
}
return messageAuthorId === botId;
}
if (effectiveMode === "allowlist") {
if (!Array.isArray(allowlist) || allowlist.length === 0) return false;
if (!Array.isArray(allowlist) || allowlist.length === 0) {
return false;
}
const users = normalizeAllowListLower(allowlist);
return allowListMatches({
allowList: users,

View File

@@ -18,10 +18,18 @@ export function inferSlackChannelType(
channelId?: string | null,
): SlackMessageEvent["channel_type"] | undefined {
const trimmed = channelId?.trim();
if (!trimmed) return undefined;
if (trimmed.startsWith("D")) return "im";
if (trimmed.startsWith("C")) return "channel";
if (trimmed.startsWith("G")) return "group";
if (!trimmed) {
return undefined;
}
if (trimmed.startsWith("D")) {
return "im";
}
if (trimmed.startsWith("C")) {
return "channel";
}
if (trimmed.startsWith("G")) {
return "group";
}
return undefined;
}
@@ -169,7 +177,9 @@ export function createSlackMonitorContext(params: {
const defaultRequireMention = params.defaultRequireMention ?? true;
const markMessageSeen = (channelId: string | undefined, ts?: string) => {
if (!channelId || !ts) return false;
if (!channelId || !ts) {
return false;
}
return seenMessages.check(`${channelId}:${ts}`);
};
@@ -178,7 +188,9 @@ export function createSlackMonitorContext(params: {
channelType?: string | null;
}) => {
const channelId = p.channelId?.trim() ?? "";
if (!channelId) return params.mainKey;
if (!channelId) {
return params.mainKey;
}
const channelType = normalizeSlackChannelType(p.channelType, channelId);
const isDirectMessage = channelType === "im";
const isGroup = channelType === "mpim";
@@ -197,7 +209,9 @@ export function createSlackMonitorContext(params: {
const resolveChannelName = async (channelId: string) => {
const cached = channelCache.get(channelId);
if (cached) return cached;
if (cached) {
return cached;
}
try {
const info = await params.app.client.conversations.info({
token: params.botToken,
@@ -227,7 +241,9 @@ export function createSlackMonitorContext(params: {
const resolveUserName = async (userId: string) => {
const cached = userCache.get(userId);
if (cached) return cached;
if (cached) {
return cached;
}
try {
const info = await params.app.client.users.info({
token: params.botToken,
@@ -248,7 +264,9 @@ export function createSlackMonitorContext(params: {
threadTs?: string;
status: string;
}) => {
if (!p.threadTs) return;
if (!p.threadTs) {
return;
}
const payload = {
token: params.botToken,
channel_id: p.channelId,
@@ -286,8 +304,12 @@ export function createSlackMonitorContext(params: {
const isGroupDm = channelType === "mpim";
const isRoom = channelType === "channel" || channelType === "group";
if (isDirectMessage && !params.dmEnabled) return false;
if (isGroupDm && !params.groupDmEnabled) return false;
if (isDirectMessage && !params.dmEnabled) {
return false;
}
if (isGroupDm && !params.groupDmEnabled) {
return false;
}
if (isGroupDm && groupDmChannels.length > 0) {
const allowList = normalizeAllowListLower(groupDmChannels);
@@ -301,7 +323,9 @@ export function createSlackMonitorContext(params: {
.map((value) => value.toLowerCase());
const permitted =
allowList.includes("*") || candidates.some((candidate) => allowList.includes(candidate));
if (!permitted) return false;
if (!permitted) {
return false;
}
}
if (isRoom && p.channelId) {
@@ -342,7 +366,9 @@ export function createSlackMonitorContext(params: {
};
const shouldDropMismatchedSlackEvent = (body: unknown) => {
if (!body || typeof body !== "object") return false;
if (!body || typeof body !== "object") {
return false;
}
const raw = body as { api_app_id?: unknown; team_id?: unknown };
const incomingApiAppId = typeof raw.api_app_id === "string" ? raw.api_app_id : "";
const incomingTeamId = typeof raw.team_id === "string" ? raw.team_id : "";

View File

@@ -21,7 +21,9 @@ export function registerSlackChannelEvents(params: { ctx: SlackMonitorContext })
"channel_created",
async ({ event, body }: SlackEventMiddlewareArgs<"channel_created">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackChannelCreatedEvent;
const channelId = payload.channel?.id;
@@ -54,7 +56,9 @@ export function registerSlackChannelEvents(params: { ctx: SlackMonitorContext })
"channel_rename",
async ({ event, body }: SlackEventMiddlewareArgs<"channel_rename">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackChannelRenamedEvent;
const channelId = payload.channel?.id;
@@ -87,12 +91,16 @@ export function registerSlackChannelEvents(params: { ctx: SlackMonitorContext })
"channel_id_changed",
async ({ event, body }: SlackEventMiddlewareArgs<"channel_id_changed">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackChannelIdChangedEvent;
const oldChannelId = payload.old_channel_id;
const newChannelId = payload.new_channel_id;
if (!oldChannelId || !newChannelId) return;
if (!oldChannelId || !newChannelId) {
return;
}
const channelInfo = await ctx.resolveChannelName(newChannelId);
const label = resolveSlackChannelLabel({

View File

@@ -14,7 +14,9 @@ export function registerSlackMemberEvents(params: { ctx: SlackMonitorContext })
"member_joined_channel",
async ({ event, body }: SlackEventMiddlewareArgs<"member_joined_channel">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackMemberChannelEvent;
const channelId = payload.channel;
const channelInfo = channelId ? await ctx.resolveChannelName(channelId) : {};
@@ -52,7 +54,9 @@ export function registerSlackMemberEvents(params: { ctx: SlackMonitorContext })
"member_left_channel",
async ({ event, body }: SlackEventMiddlewareArgs<"member_left_channel">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackMemberChannelEvent;
const channelId = payload.channel;
const channelInfo = channelId ? await ctx.resolveChannelName(channelId) : {};

View File

@@ -21,7 +21,9 @@ export function registerSlackMessageEvents(params: {
ctx.app.event("message", async ({ event, body }: SlackEventMiddlewareArgs<"message">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const message = event as SlackMessageEvent;
if (message.subtype === "message_changed") {
@@ -119,7 +121,9 @@ export function registerSlackMessageEvents(params: {
ctx.app.event("app_mention", async ({ event, body }: SlackEventMiddlewareArgs<"app_mention">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const mention = event as SlackAppMentionEvent;
await handleSlackMessage(mention as unknown as SlackMessageEvent, {

View File

@@ -12,7 +12,9 @@ export function registerSlackPinEvents(params: { ctx: SlackMonitorContext }) {
ctx.app.event("pin_added", async ({ event, body }: SlackEventMiddlewareArgs<"pin_added">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackPinEvent;
const channelId = payload.channel_id;
@@ -49,7 +51,9 @@ export function registerSlackPinEvents(params: { ctx: SlackMonitorContext }) {
ctx.app.event("pin_removed", async ({ event, body }: SlackEventMiddlewareArgs<"pin_removed">) => {
try {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
const payload = event as SlackPinEvent;
const channelId = payload.channel_id;

View File

@@ -13,7 +13,9 @@ export function registerSlackReactionEvents(params: { ctx: SlackMonitorContext }
const handleReactionEvent = async (event: SlackReactionEvent, action: string) => {
try {
const item = event.item;
if (!item || item.type !== "message") return;
if (!item || item.type !== "message") {
return;
}
const channelInfo = item.channel ? await ctx.resolveChannelName(item.channel) : {};
const channelType = channelInfo?.type;
@@ -54,7 +56,9 @@ export function registerSlackReactionEvents(params: { ctx: SlackMonitorContext }
ctx.app.event(
"reaction_added",
async ({ event, body }: SlackEventMiddlewareArgs<"reaction_added">) => {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
await handleReactionEvent(event as SlackReactionEvent, "added");
},
);
@@ -62,7 +66,9 @@ export function registerSlackReactionEvents(params: { ctx: SlackMonitorContext }
ctx.app.event(
"reaction_removed",
async ({ event, body }: SlackEventMiddlewareArgs<"reaction_removed">) => {
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
if (ctx.shouldDropMismatchedSlackEvent(body)) {
return;
}
await handleReactionEvent(event as SlackReactionEvent, "removed");
},
);

View File

@@ -49,7 +49,9 @@ export async function resolveSlackMedia(params: {
const files = params.files ?? [];
for (const file of files) {
const url = file.url_private_download ?? file.url_private;
if (!url) continue;
if (!url) {
continue;
}
try {
// Note: We ignore init options because fetchWithSlackAuth handles
// redirect behavior specially. fetchRemoteMedia only passes the URL.
@@ -63,7 +65,9 @@ export async function resolveSlackMedia(params: {
fetchImpl,
filePathHint: file.name,
});
if (fetched.buffer.byteLength > params.maxBytes) continue;
if (fetched.buffer.byteLength > params.maxBytes) {
continue;
}
const saved = await saveMediaBuffer(
fetched.buffer,
fetched.contentType ?? file.mimetype,
@@ -99,7 +103,9 @@ export async function resolveSlackThreadStarter(params: {
}): Promise<SlackThreadStarter | null> {
const cacheKey = `${params.channelId}:${params.threadTs}`;
const cached = THREAD_STARTER_CACHE.get(cacheKey);
if (cached) return cached;
if (cached) {
return cached;
}
try {
const response = (await params.client.conversations.replies({
channel: params.channelId,
@@ -109,7 +115,9 @@ export async function resolveSlackThreadStarter(params: {
})) as { messages?: Array<{ text?: string; user?: string; ts?: string; files?: SlackFile[] }> };
const message = response?.messages?.[0];
const text = (message?.text ?? "").trim();
if (!message || !text) return null;
if (!message || !text) {
return null;
}
const starter: SlackThreadStarter = {
text,
userId: message.user,

View File

@@ -30,7 +30,9 @@ export function createSlackMessageHandler(params: {
debounceMs,
buildKey: (entry) => {
const senderId = entry.message.user ?? entry.message.bot_id;
if (!senderId) return null;
if (!senderId) {
return null;
}
const messageTs = entry.message.ts ?? entry.message.event_ts;
// If Slack flags a thread reply but omits thread_ts, isolate it from root debouncing.
const threadKey = entry.message.thread_ts
@@ -42,13 +44,19 @@ export function createSlackMessageHandler(params: {
},
shouldDebounce: (entry) => {
const text = entry.message.text ?? "";
if (!text.trim()) return false;
if (entry.message.files && entry.message.files.length > 0) return false;
if (!text.trim()) {
return false;
}
if (entry.message.files && entry.message.files.length > 0) {
return false;
}
return !hasControlCommand(text, ctx.cfg);
},
onFlush: async (entries) => {
const last = entries.at(-1);
if (!last) return;
if (!last) {
return;
}
const combinedText =
entries.length === 1
? (last.message.text ?? "")
@@ -70,7 +78,9 @@ export function createSlackMessageHandler(params: {
wasMentioned: combinedMentioned || last.opts.wasMentioned,
},
});
if (!prepared) return;
if (!prepared) {
return;
}
if (entries.length > 1) {
const ids = entries.map((entry) => entry.message.ts).filter(Boolean) as string[];
if (ids.length > 0) {
@@ -87,7 +97,9 @@ export function createSlackMessageHandler(params: {
});
return async (message, opts) => {
if (opts.source === "message" && message.type !== "message") return;
if (opts.source === "message" && message.type !== "message") {
return;
}
if (
opts.source === "message" &&
message.subtype &&
@@ -96,7 +108,9 @@ export function createSlackMessageHandler(params: {
) {
return;
}
if (ctx.markMessageSeen(message.channel, message.ts)) return;
if (ctx.markMessageSeen(message.channel, message.ts)) {
return;
}
const resolvedMessage = await threadTsResolver.resolve({ message, source: opts.source });
await debouncer.enqueue({ message: resolvedMessage, opts });
};

View File

@@ -67,7 +67,9 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
});
},
stop: async () => {
if (!didSetStatus) return;
if (!didSetStatus) {
return;
}
didSetStatus = false;
await ctx.setSlackThreadStatus({
channelId: message.channel,

View File

@@ -92,7 +92,9 @@ export async function prepareSlackMessage(params: {
const isBotMessage = Boolean(message.bot_id);
if (isBotMessage) {
if (message.user && ctx.botUserId && message.user === ctx.botUserId) return null;
if (message.user && ctx.botUserId && message.user === ctx.botUserId) {
return null;
}
if (!allowBots) {
logVerbose(`slack: drop bot message ${message.bot_id ?? "unknown"} (allowBots=false)`);
return null;
@@ -337,7 +339,9 @@ export async function prepareSlackMessage(params: {
maxBytes: ctx.mediaMaxBytes,
});
const rawBody = (message.text ?? "").trim() || media?.placeholder || "";
if (!rawBody) return null;
if (!rawBody) {
return null;
}
const ackReaction = resolveAckReaction(cfg, route.agentId);
const ackReactionValue = ackReaction ?? "";
@@ -552,7 +556,9 @@ export async function prepareSlackMessage(params: {
});
const replyTarget = ctxPayload.To ?? undefined;
if (!replyTarget) return null;
if (!replyTarget) {
return null;
}
if (shouldLogVerbose()) {
logVerbose(`slack inbound: channel=${message.channel} from=${slackFrom} preview="${preview}"`);

View File

@@ -4,8 +4,14 @@ export function isSlackChannelAllowedByPolicy(params: {
channelAllowed: boolean;
}): boolean {
const { groupPolicy, channelAllowlistConfigured, channelAllowed } = params;
if (groupPolicy === "disabled") return false;
if (groupPolicy === "open") return true;
if (!channelAllowlistConfigured) return false;
if (groupPolicy === "disabled") {
return false;
}
if (groupPolicy === "open") {
return true;
}
if (!channelAllowlistConfigured) {
return false;
}
return channelAllowed;
}

View File

@@ -36,7 +36,9 @@ const slackBolt =
const { App, HTTPReceiver } = slackBolt;
function parseApiAppIdFromAppToken(raw?: string) {
const token = raw?.trim();
if (!token) return undefined;
if (!token) {
return undefined;
}
const match = /^xapp-\d-([a-z0-9]+)-/i.exec(token);
return match?.[1]?.toUpperCase();
}
@@ -220,7 +222,9 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
if (resolveToken) {
void (async () => {
if (opts.abortSignal?.aborted) return;
if (opts.abortSignal?.aborted) {
return;
}
if (channelsConfig && Object.keys(channelsConfig).length > 0) {
try {
@@ -235,7 +239,9 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
const unresolved: string[] = [];
for (const entry of resolved) {
const source = channelsConfig?.[entry.input];
if (!source) continue;
if (!source) {
continue;
}
if (!entry.resolved || !entry.id) {
unresolved.push(entry.input);
continue;
@@ -284,12 +290,18 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
if (channelsConfig && Object.keys(channelsConfig).length > 0) {
const userEntries = new Set<string>();
for (const channel of Object.values(channelsConfig)) {
if (!channel || typeof channel !== "object") continue;
if (!channel || typeof channel !== "object") {
continue;
}
const channelUsers = (channel as { users?: Array<string | number> }).users;
if (!Array.isArray(channelUsers)) continue;
if (!Array.isArray(channelUsers)) {
continue;
}
for (const entry of channelUsers) {
const trimmed = String(entry).trim();
if (trimmed && trimmed !== "*") userEntries.add(trimmed);
if (trimmed && trimmed !== "*") {
userEntries.add(trimmed);
}
}
}
@@ -309,14 +321,20 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
const nextChannels = { ...channelsConfig };
for (const [channelKey, channelConfig] of Object.entries(channelsConfig)) {
if (!channelConfig || typeof channelConfig !== "object") continue;
if (!channelConfig || typeof channelConfig !== "object") {
continue;
}
const channelUsers = (channelConfig as { users?: Array<string | number> }).users;
if (!Array.isArray(channelUsers) || channelUsers.length === 0) continue;
if (!Array.isArray(channelUsers) || channelUsers.length === 0) {
continue;
}
const additions: string[] = [];
for (const entry of channelUsers) {
const trimmed = String(entry).trim();
const resolved = resolvedMap.get(trimmed);
if (resolved?.resolved && resolved.id) additions.push(resolved.id);
if (resolved?.resolved && resolved.id) {
additions.push(resolved.id);
}
}
nextChannels[channelKey] = {
...channelConfig,
@@ -337,7 +355,9 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
}
const stopOnAbort = () => {
if (opts.abortSignal?.aborted && slackMode === "socket") void app.stop();
if (opts.abortSignal?.aborted && slackMode === "socket") {
void app.stop();
}
};
opts.abortSignal?.addEventListener("abort", stopOnAbort, { once: true });
@@ -348,7 +368,9 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
} else {
runtime.log?.(`slack http mode listening at ${slackWebhookPath}`);
}
if (opts.abortSignal?.aborted) return;
if (opts.abortSignal?.aborted) {
return;
}
await new Promise<void>((resolve) => {
opts.abortSignal?.addEventListener("abort", () => resolve(), {
once: true,

View File

@@ -21,11 +21,15 @@ export async function deliverReplies(params: {
const threadTs = payload.replyToId ?? params.replyThreadTs;
const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
const text = payload.text ?? "";
if (!text && mediaList.length === 0) continue;
if (!text && mediaList.length === 0) {
continue;
}
if (mediaList.length === 0) {
const trimmed = text.trim();
if (!trimmed || isSilentReplyText(trimmed, SILENT_REPLY_TOKEN)) continue;
if (!trimmed || isSilentReplyText(trimmed, SILENT_REPLY_TOKEN)) {
continue;
}
await sendMessageSlack(params.target, trimmed, {
token: params.token,
threadTs,
@@ -131,7 +135,9 @@ export async function deliverSlackSlashReplies(params: {
const combined = [text ?? "", ...mediaList.map((url) => url.trim()).filter(Boolean)]
.filter(Boolean)
.join("\n");
if (!combined) continue;
if (!combined) {
continue;
}
const chunkMode = params.chunkMode ?? "length";
const markdownChunks =
chunkMode === "newline"
@@ -140,13 +146,17 @@ export async function deliverSlackSlashReplies(params: {
const chunks = markdownChunks.flatMap((markdown) =>
markdownToSlackMrkdwnChunks(markdown, chunkLimit, { tableMode: params.tableMode }),
);
if (!chunks.length && combined) chunks.push(combined);
if (!chunks.length && combined) {
chunks.push(combined);
}
for (const chunk of chunks) {
messages.push(chunk);
}
}
if (messages.length === 0) return;
if (messages.length === 0) {
return;
}
// Slack slash command responses can be multi-part by sending follow-ups via response_url.
const responseType = params.ephemeral ? "ephemeral" : "in_channel";

View File

@@ -103,7 +103,9 @@ describe("Slack native command argument menus", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = commands.get("/usage");
if (!handler) throw new Error("Missing /usage handler");
if (!handler) {
throw new Error("Missing /usage handler");
}
const respond = vi.fn().mockResolvedValue(undefined);
const ack = vi.fn().mockResolvedValue(undefined);
@@ -132,7 +134,9 @@ describe("Slack native command argument menus", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = actions.get("openclaw_cmdarg");
if (!handler) throw new Error("Missing arg-menu action handler");
if (!handler) {
throw new Error("Missing arg-menu action handler");
}
const respond = vi.fn().mockResolvedValue(undefined);
await handler({
@@ -158,7 +162,9 @@ describe("Slack native command argument menus", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = actions.get("openclaw_cmdarg");
if (!handler) throw new Error("Missing arg-menu action handler");
if (!handler) {
throw new Error("Missing arg-menu action handler");
}
const respond = vi.fn().mockResolvedValue(undefined);
await handler({
@@ -186,7 +192,9 @@ describe("Slack native command argument menus", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = actions.get("openclaw_cmdarg");
if (!handler) throw new Error("Missing arg-menu action handler");
if (!handler) {
throw new Error("Missing arg-menu action handler");
}
await handler({
ack: vi.fn().mockResolvedValue(undefined),
@@ -208,7 +216,9 @@ describe("Slack native command argument menus", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = actions.get("openclaw_cmdarg");
if (!handler) throw new Error("Missing arg-menu action handler");
if (!handler) {
throw new Error("Missing arg-menu action handler");
}
await handler({
ack: vi.fn().mockResolvedValue(undefined),

View File

@@ -101,7 +101,9 @@ describe("slack slash commands channel policy", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = [...commands.values()][0];
if (!handler) throw new Error("Missing slash handler");
if (!handler) {
throw new Error("Missing slash handler");
}
const respond = vi.fn().mockResolvedValue(undefined);
await handler({
@@ -133,7 +135,9 @@ describe("slack slash commands channel policy", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = [...commands.values()][0];
if (!handler) throw new Error("Missing slash handler");
if (!handler) {
throw new Error("Missing slash handler");
}
const respond = vi.fn().mockResolvedValue(undefined);
await handler({
@@ -166,7 +170,9 @@ describe("slack slash commands channel policy", () => {
registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never });
const handler = [...commands.values()][0];
if (!handler) throw new Error("Missing slash handler");
if (!handler) {
throw new Error("Missing slash handler");
}
const respond = vi.fn().mockResolvedValue(undefined);
await handler({

View File

@@ -45,7 +45,9 @@ const SLACK_COMMAND_ARG_ACTION_ID = "openclaw_cmdarg";
const SLACK_COMMAND_ARG_VALUE_PREFIX = "cmdarg";
function chunkItems<T>(items: T[], size: number): T[][] {
if (size <= 0) return [items];
if (size <= 0) {
return [items];
}
const rows: T[][] = [];
for (let i = 0; i < items.length; i += size) {
rows.push(items.slice(i, i + size));
@@ -74,11 +76,17 @@ function parseSlackCommandArgValue(raw?: string | null): {
value: string;
userId: string;
} | null {
if (!raw) return null;
if (!raw) {
return null;
}
const parts = raw.split("|");
if (parts.length !== 5 || parts[0] !== SLACK_COMMAND_ARG_VALUE_PREFIX) return null;
if (parts.length !== 5 || parts[0] !== SLACK_COMMAND_ARG_VALUE_PREFIX) {
return null;
}
const [, command, arg, value, userId] = parts;
if (!command || !arg || !value || !userId) return null;
if (!command || !arg || !value || !userId) {
return null;
}
const decode = (text: string) => {
try {
return decodeURIComponent(text);
@@ -90,7 +98,9 @@ function parseSlackCommandArgValue(raw?: string | null): {
const decodedArg = decode(arg);
const decodedValue = decode(value);
const decodedUserId = decode(userId);
if (!decodedCommand || !decodedArg || !decodedValue || !decodedUserId) return null;
if (!decodedCommand || !decodedArg || !decodedValue || !decodedUserId) {
return null;
}
return {
command: decodedCommand,
arg: decodedArg,
@@ -163,7 +173,9 @@ export function registerSlackMonitorSlashCommands(params: {
}
await ack();
if (ctx.botUserId && command.user_id === ctx.botUserId) return;
if (ctx.botUserId && command.user_id === ctx.botUserId) {
return;
}
const channelInfo = await ctx.resolveChannelName(command.channel_id);
const channelType =
@@ -526,7 +538,9 @@ export function registerSlackMonitorSlashCommands(params: {
logVerbose("slack: slash commands disabled");
}
if (nativeCommands.length === 0 || !supportsInteractiveArgMenus) return;
if (nativeCommands.length === 0 || !supportsInteractiveArgMenus) {
return;
}
const registerArgAction = (actionId: string) => {
(
@@ -540,7 +554,9 @@ export function registerSlackMonitorSlashCommands(params: {
const respondFn =
respond ??
(async (payload: { text: string; blocks?: SlackBlock[]; response_type?: string }) => {
if (!body.channel?.id || !body.user?.id) return;
if (!body.channel?.id || !body.user?.id) {
return;
}
await ctx.app.client.chat.postEphemeral({
token: ctx.botToken,
channel: body.channel.id,

View File

@@ -54,7 +54,9 @@ export function createSlackThreadTsResolver(params: {
const getCached = (key: string, now: number) => {
const entry = cache.get(key);
if (!entry) return undefined;
if (!entry) {
return undefined;
}
if (ttlMs > 0 && now - entry.updatedAt > ttlMs) {
cache.delete(key);
return undefined;
@@ -73,7 +75,9 @@ export function createSlackThreadTsResolver(params: {
}
while (cache.size > maxSize) {
const oldestKey = cache.keys().next().value;
if (!oldestKey) break;
if (!oldestKey) {
break;
}
cache.delete(oldestKey);
}
};