mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-16 20:40:45 +00:00
* wip * copy polugin files * wip type changes * refactor: improve Twitch plugin code quality and fix all tests - Extract client manager registry for centralized lifecycle management - Refactor to use early returns and reduce mutations - Fix status check logic for clientId detection - Add comprehensive test coverage for new modules - Remove tests for unimplemented features (index.test.ts, resolver.test.ts) - Fix mock setup issues in test suite (149 tests now passing) - Improve error handling with errorResponse helper in actions.ts - Normalize token handling to eliminate duplication Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * use accountId * delete md file * delte tsconfig * adjust log level * fix probe logic * format * fix monitor * code review fixes * format * no mutation * less mutation * chain debug log * await authProvider setup * use uuid * use spread * fix tests * update docs and remove bot channel fallback * more readme fixes * remove comments + fromat * fix tests * adjust access control logic * format * install * simplify config object * remove duplicate log tags + log received messages * update docs * update tests * format * strip markdown in monitor * remove strip markdown config, enabled by default * default requireMention to true * fix store path arg * fix multi account id + add unit test * fix multi account id + add unit test * make channel required and update docs * remove whisper functionality * remove duplicate connect log * update docs with convert twitch link * make twitch message processing non blocking * schema consistent casing * remove noisy ignore log * use coreLogger --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
93 lines
2.8 KiB
TypeScript
93 lines
2.8 KiB
TypeScript
/**
|
|
* Markdown utilities for Twitch chat
|
|
*
|
|
* Twitch chat doesn't support markdown formatting, so we strip it before sending.
|
|
* Based on Clawdbot's markdownToText in src/agents/tools/web-fetch-utils.ts.
|
|
*/
|
|
|
|
/**
|
|
* Strip markdown formatting from text for Twitch compatibility.
|
|
*
|
|
* Removes images, links, bold, italic, strikethrough, code blocks, inline code,
|
|
* headers, and list formatting. Replaces newlines with spaces since Twitch
|
|
* is a single-line chat medium.
|
|
*
|
|
* @param markdown - The markdown text to strip
|
|
* @returns Plain text with markdown removed
|
|
*/
|
|
export function stripMarkdownForTwitch(markdown: string): string {
|
|
return (
|
|
markdown
|
|
// Images
|
|
.replace(/!\[[^\]]*]\([^)]+\)/g, "")
|
|
// Links
|
|
.replace(/\[([^\]]+)]\([^)]+\)/g, "$1")
|
|
// Bold (**text**)
|
|
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
|
// Bold (__text__)
|
|
.replace(/__([^_]+)__/g, "$1")
|
|
// Italic (*text*)
|
|
.replace(/\*([^*]+)\*/g, "$1")
|
|
// Italic (_text_)
|
|
.replace(/_([^_]+)_/g, "$1")
|
|
// Strikethrough (~~text~~)
|
|
.replace(/~~([^~]+)~~/g, "$1")
|
|
// Code blocks
|
|
.replace(/```[\s\S]*?```/g, (block) => block.replace(/```[^\n]*\n?/g, "").replace(/```/g, ""))
|
|
// Inline code
|
|
.replace(/`([^`]+)`/g, "$1")
|
|
// Headers
|
|
.replace(/^#{1,6}\s+/gm, "")
|
|
// Lists
|
|
.replace(/^\s*[-*+]\s+/gm, "")
|
|
.replace(/^\s*\d+\.\s+/gm, "")
|
|
// Normalize whitespace
|
|
.replace(/\r/g, "") // Remove carriage returns
|
|
.replace(/[ \t]+\n/g, "\n") // Remove trailing spaces before newlines
|
|
.replace(/\n/g, " ") // Replace newlines with spaces (for Twitch)
|
|
.replace(/[ \t]{2,}/g, " ") // Reduce multiple spaces to single
|
|
.trim()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Simple word-boundary chunker for Twitch (500 char limit).
|
|
* Strips markdown before chunking to avoid breaking markdown patterns.
|
|
*
|
|
* @param text - The text to chunk
|
|
* @param limit - Maximum characters per chunk (Twitch limit is 500)
|
|
* @returns Array of text chunks
|
|
*/
|
|
export function chunkTextForTwitch(text: string, limit: number): string[] {
|
|
// First, strip markdown
|
|
const cleaned = stripMarkdownForTwitch(text);
|
|
if (!cleaned) return [];
|
|
if (limit <= 0) return [cleaned];
|
|
if (cleaned.length <= limit) return [cleaned];
|
|
|
|
const chunks: string[] = [];
|
|
let remaining = cleaned;
|
|
|
|
while (remaining.length > limit) {
|
|
// Find the last space before the limit
|
|
const window = remaining.slice(0, limit);
|
|
const lastSpaceIndex = window.lastIndexOf(" ");
|
|
|
|
if (lastSpaceIndex === -1) {
|
|
// No space found, hard split at limit
|
|
chunks.push(window);
|
|
remaining = remaining.slice(limit);
|
|
} else {
|
|
// Split at the last space
|
|
chunks.push(window.slice(0, lastSpaceIndex));
|
|
remaining = remaining.slice(lastSpaceIndex + 1);
|
|
}
|
|
}
|
|
|
|
if (remaining) {
|
|
chunks.push(remaining);
|
|
}
|
|
|
|
return chunks;
|
|
}
|