refactor: share slack text truncation

This commit is contained in:
Peter Steinberger 2026-03-14 01:18:12 +00:00
parent d886ca6474
commit f4094ab19e
4 changed files with 17 additions and 37 deletions

View File

@ -1,4 +1,5 @@
import { parseSlackBlocksInput } from "../../slack/blocks-input.js";
import { truncateSlackText } from "../../slack/truncate.js";
import type { ReplyPayload } from "../types.js";
const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
@ -21,17 +22,6 @@ type SlackChoice = {
value: string;
};
function truncateSlackText(value: string, max: number): string {
const trimmed = value.trim();
if (trimmed.length <= max) {
return trimmed;
}
if (max <= 1) {
return trimmed.slice(0, max);
}
return `${trimmed.slice(0, max - 1)}`;
}
function parseChoice(raw: string): SlackChoice | null {
const trimmed = raw.trim();
if (!trimmed) {

View File

@ -1,6 +1,7 @@
import type { SlackActionMiddlewareArgs } from "@slack/bolt";
import type { Block, KnownBlock } from "@slack/web-api";
import { enqueueSystemEvent } from "../../../infra/system-events.js";
import { truncateSlackText } from "../../truncate.js";
import { authorizeSlackSystemEventSender } from "../auth.js";
import type { SlackMonitorContext } from "../context.js";
import { escapeSlackMrkdwn } from "../mrkdwn.js";
@ -53,17 +54,6 @@ type InteractionSummary = InteractionSelectionFields & {
threadTs?: string;
};
function truncateInteractionString(
value: string,
max = SLACK_INTERACTION_STRING_MAX_CHARS,
): string {
const trimmed = value.trim();
if (trimmed.length <= max) {
return trimmed;
}
return `${trimmed.slice(0, max - 1)}`;
}
function sanitizeSlackInteractionPayloadValue(value: unknown, key?: string): unknown {
if (value === undefined) {
return undefined;
@ -75,7 +65,7 @@ function sanitizeSlackInteractionPayloadValue(value: unknown, key?: string): unk
return REDACTED_INTERACTION_VALUE;
}
if (typeof value === "string") {
return truncateInteractionString(value);
return truncateSlackText(value, SLACK_INTERACTION_STRING_MAX_CHARS);
}
if (Array.isArray(value)) {
const sanitized = value

View File

@ -10,6 +10,7 @@ import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "../../
import { danger, logVerbose } from "../../globals.js";
import { chunkItems } from "../../utils/chunk-items.js";
import type { ResolvedSlackAccount } from "../accounts.js";
import { truncateSlackText } from "../truncate.js";
import { resolveSlackAllowListMatch, resolveSlackUserAllowed } from "./allow-list.js";
import { resolveSlackEffectiveAllowFrom } from "./auth.js";
import { resolveSlackChannelConfig, type SlackChannelConfigResolved } from "./channel-config.js";
@ -62,17 +63,6 @@ function loadSlashSkillCommandsRuntime() {
type EncodedMenuChoice = SlackExternalArgMenuChoice;
const slackExternalArgMenuStore = createSlackExternalArgMenuStore();
function truncatePlainText(value: string, max: number): string {
const trimmed = value.trim();
if (trimmed.length <= max) {
return trimmed;
}
if (max <= 1) {
return trimmed.slice(0, max);
}
return `${trimmed.slice(0, max - 1)}`;
}
function buildSlackArgMenuConfirm(params: { command: string; arg: string }) {
const command = escapeSlackMrkdwn(params.command);
const arg = escapeSlackMrkdwn(params.arg);
@ -255,12 +245,12 @@ function buildSlackCommandArgMenuBlocks(params: {
],
}),
);
const headerText = truncatePlainText(
const headerText = truncateSlackText(
`/${params.command}: choose ${params.arg}`,
SLACK_HEADER_TEXT_MAX,
);
const sectionText = truncatePlainText(params.title, 3000);
const contextText = truncatePlainText(
const sectionText = truncateSlackText(params.title, 3000);
const contextText = truncateSlackText(
`Select one option to continue /${params.command} (${params.arg})`,
3000,
);

10
src/slack/truncate.ts Normal file
View File

@ -0,0 +1,10 @@
export function truncateSlackText(value: string, max: number): string {
const trimmed = value.trim();
if (trimmed.length <= max) {
return trimmed;
}
if (max <= 1) {
return trimmed.slice(0, max);
}
return `${trimmed.slice(0, max - 1)}`;
}