mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-05 21:51:36 +00:00
truncateSlackText sliced by UTF-16 code unit ('trimmed.slice(0, max - 1)'), so an
emoji or other astral character straddling the limit was cut in half, leaving a
lone high surrogate before the ellipsis — e.g. truncateSlackText('abc😀def', 5)
returned 'abc\uD83D…' instead of 'abc…'. That invalid half-character is sent in
live Slack payloads (message text and Block Kit section/button/header/option
labels, which truncate at limits as small as 75).
Use the repo's canonical sliceUtf16Safe (already re-exported from
plugin-sdk/text-utility-runtime, the module slack code imports from) so a
straddling pair is dropped whole. Behavior is byte-identical for all-BMP input.
Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
17 lines
639 B
TypeScript
17 lines
639 B
TypeScript
// Slack plugin module implements truncate behavior.
|
|
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
|
|
export function truncateSlackText(value: string, max: number): string {
|
|
const trimmed = value.trim();
|
|
if (trimmed.length <= max) {
|
|
return trimmed;
|
|
}
|
|
// Slice on a code-point boundary so a surrogate pair (emoji / astral char)
|
|
// straddling the limit is dropped whole, instead of leaving a lone surrogate
|
|
// half that serializes to an invalid `\uD83D` in the Slack payload.
|
|
if (max <= 1) {
|
|
return sliceUtf16Safe(trimmed, 0, max);
|
|
}
|
|
return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
|
|
}
|