diff --git a/atall/atall.ts b/atall/atall.ts new file mode 100644 index 00000000..fca8e756 --- /dev/null +++ b/atall/atall.ts @@ -0,0 +1,195 @@ +import { Plugin } from "@utils/pluginBase"; +import { Api } from "telegram"; +import { getGlobalClient } from "@utils/globalClient"; +import { getPrefixes } from "@utils/pluginManager"; + +// HTML转义函数 +const htmlEscape = (text: string): string => + text.replace(/[&<>"']/g, m => ({ + '&': '&', '<': '<', '>': '>', + '"': '"', "'": ''' + }[m] || m)); + +// 消息分割函数(限制调整为4000字符) +const splitMessagesByMention = (mentions: string[], maxLength = 4000): string[] => { + const messages: string[] = []; + let currentMessage = ""; + + for (const mention of mentions) { + // 如果当前消息为空,直接添加第一个mention + if (currentMessage === "") { + currentMessage = mention; + } + // 如果添加下一个mention后不会超过限制,则添加空格和mention + else if (currentMessage.length + 1 + mention.length <= maxLength) { + currentMessage += " " + mention; + } + // 否则保存当前消息,开始新消息 + else { + messages.push(currentMessage); + currentMessage = mention; + } + } + + // 添加最后一个消息 + if (currentMessage) { + messages.push(currentMessage); + } + + return messages; +}; + +// 帮助文本 +const help_text = `📢 AtAll + +📝 功能描述: +• 一键@群组中的所有成员 +• 自动处理无用户名用户 +• 智能消息分割 + +🔧 使用方法: +• ${getPrefixes()[0]}atall - @群组中的所有成员 + +⚠️ 注意事项: +• 极大封号风险,后果自负 +• 大群组中可能会生成很多条消息 +• 一般来说你可以通过置顶消息来提醒所有人的`; + +class AtAllPlugin extends Plugin { + description = help_text; + + cmdHandlers = { + atall: async (msg: Api.Message) => { + try { + const client = await getGlobalClient(); + if (!client) { + await msg.edit({ text: "❌ 无法获取客户端", parseMode: "html" }); + return; + } + + // 获取当前聊天 + const chat = await msg.getChat(); + if (!chat || !("id" in chat)) { + await msg.edit({ text: "❌ 此命令只能在群组中使用", parseMode: "html" }); + return; + } + + const chatId = chat.id; + + // 显示处理中 + const processingMsg = await msg.edit({ + text: "🔄 正在获取群组成员列表...", + parseMode: "html" + }); + + // 获取所有群组成员 + const participants = await client.getParticipants(chatId, {}); + + if (!participants || participants.length === 0) { + await processingMsg.edit({ + text: "❌ 无法获取群组成员或群组为空", + parseMode: "html" + }); + return; + } + + // 生成@列表 + let mentionList: string[] = []; + + for (const participant of participants) { + // 跳过机器人自身 + if (participant.bot) continue; + + // 尝试获取用户实体 + let userEntity; + try { + userEntity = await client.getEntity(participant.id); + } catch { + continue; // 跳过无法获取实体的用户 + } + + if (userEntity && "username" in userEntity && userEntity.username) { + // 有用户名的情况 - 直接使用@username + mentionList.push(`@${userEntity.username}`); + } else { + // 无用户名,使用mention链接 + let displayName = ""; + if ("firstName" in participant && participant.firstName) { + displayName = participant.firstName; + if ("lastName" in participant && participant.lastName) { + displayName += ` ${participant.lastName}`; + } + } else if ("title" in participant && participant.title) { + displayName = participant.title; + } else { + displayName = ""; + } + + // 使用Telegram mention链接 + mentionList.push(`${htmlEscape(displayName)}`); + } + } + + if (mentionList.length === 0) { + await processingMsg.edit({ + text: "❌ 没有可@的成员", + parseMode: "html" + }); + return; + } + + // 更新处理状态 + await processingMsg.edit({ + text: `🔄 正在生成@列表... (${mentionList.length} 个成员)`, + parseMode: "html" + }); + + // 分割消息(基于mention单位),限制调整为4000 + const messageParts = splitMessagesByMention(mentionList, 4000); + + // 删除处理中消息 + await processingMsg.delete({ revoke: true }).catch(() => {}); + + // 发送所有消息部分 + for (let i = 0; i < messageParts.length; i++) { + const part = messageParts[i]; + + // 在每条消息开头加上"@所有人:"标题 + const messageContent = `@所有人:\n${part}`; + + await client.sendMessage(chatId, { + message: messageContent, + parseMode: "html", + replyTo: i === 0 ? msg.id : undefined + }); + + // 为避免消息发送过快,添加短暂延迟 + if (i < messageParts.length - 1) { + await new Promise(resolve => setTimeout(resolve, 500)); + } + } + + } catch (error: any) { + console.error("[AtAll Plugin] Error:", error); + + let errorMessage = "❌ 发生错误: "; + if (error.message?.includes("CHAT_ADMIN_REQUIRED")) { + errorMessage += "需要管理员权限来获取成员列表"; + } else if (error.message?.includes("USER_NOT_PARTICIPANT")) { + errorMessage += "不是群组成员"; + } else if (error.message?.includes("CHANNEL_PRIVATE")) { + errorMessage += "无法访问私有频道"; + } else { + errorMessage += htmlEscape(error.message || "未知错误"); + } + + await msg.edit({ + text: errorMessage, + parseMode: "html" + }); + } + } + }; +} + +export default new AtAllPlugin(); \ No newline at end of file diff --git a/clean/clean.ts b/clean/clean.ts index 2288bc0f..a6aa959b 100644 --- a/clean/clean.ts +++ b/clean/clean.ts @@ -61,10 +61,14 @@ class CleanPlugin extends Plugin { // 插件配置 private readonly PLUGIN_NAME = "clean"; private readonly PLUGIN_VERSION = "2.0.0"; + public description: string = ""; // 清理进度状态 private cleanupStartTime: number = 0; private blockedCleanupStartTime: number = 0; + + // 命令处理器 + private cmdHandlers: { [key: string]: (msg: Api.Message) => Promise }; constructor() { super(); @@ -410,7 +414,7 @@ class CleanPlugin extends Plugin { let bannedUsers = await getBannedUsers(client, chatEntity); if (!includeAll) { - bannedUsers = bannedUsers.filter(u => u.kickedBy === myId); + bannedUsers = bannedUsers.filter((u: any) => u.kickedBy === myId); } if (bannedUsers.length === 0) { @@ -423,7 +427,7 @@ class CleanPlugin extends Plugin { await this.editMessage(msg, `⚡ 正在解封 ${bannedUsers.length} 个实体...`); const entityStats = { users: 0, channels: 0, chats: 0 }; - bannedUsers.forEach(entity => { + bannedUsers.forEach((entity: any) => { if (entity.type === 'user') entityStats.users++; else if (entity.type === 'channel') entityStats.channels++; else if (entity.type === 'chat') entityStats.chats++; diff --git a/diss/diss.ts b/diss/diss.ts index 048abd65..fa324716 100644 --- a/diss/diss.ts +++ b/diss/diss.ts @@ -42,7 +42,8 @@ class DissPlugin extends Plugin { } } } catch (error) { - console.warn(`[diss] 第${attempt}次尝试失败:`, error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + console.warn(`[diss] 第${attempt}次尝试失败:`, errorMessage); // 如果不是最后一次尝试,等待一下再重试 if (attempt < 5) { diff --git a/komari/komari.ts b/komari/komari.ts index 6c662cb8..b1a341e7 100644 --- a/komari/komari.ts +++ b/komari/komari.ts @@ -575,6 +575,7 @@ async function handleKomariRequest(msg: Api.Message): Promise { return; } + displayName = "Komari URL"; ConfigManager.set(CONFIG_KEYS.KOMARI_URL, configValue); const displayValue = configValue; diff --git a/listusernames/listusernames.ts b/listusernames/listusernames.ts index f9d4b3f7..acd15747 100644 --- a/listusernames/listusernames.ts +++ b/listusernames/listusernames.ts @@ -41,7 +41,7 @@ class ListUsernamesPlugin extends Plugin { // 调用Telegram API获取公开频道 const result = await client.invoke( - new Api.channels.GetAdminedPublicChannels() + new Api.channels.GetAdminedPublicChannels({}) ); if (!result.chats || result.chats.length === 0) { diff --git a/lu_bs/lu_bs.ts b/lu_bs/lu_bs.ts index daab90dd..376a8a31 100644 --- a/lu_bs/lu_bs.ts +++ b/lu_bs/lu_bs.ts @@ -154,8 +154,8 @@ class LuBsPlugin extends Plugin { console.error(`[${this.PLUGIN_NAME}] 发送失败到 ${chatId}:`, error); // 如果发送失败,可能是聊天不存在或没有权限,移除订阅 - if (error.message?.includes("CHAT_WRITE_FORBIDDEN") || - error.message?.includes("CHAT_NOT_FOUND")) { + if ((error as any).message?.includes("CHAT_WRITE_FORBIDDEN") || + (error as any).message?.includes("CHAT_NOT_FOUND")) { this.db.data.subscriptions = this.db.data.subscriptions.filter((id: string) => id !== chatId); delete this.db.data.lastMessages[chatId]; await this.db.write(); @@ -174,6 +174,9 @@ class LuBsPlugin extends Plugin { const chat = await msg.getChat(); const sender = await msg.getSender(); + // 检查chat和sender是否存在 + if (!chat || !sender) return false; + // 私聊总是允许 if (chat.className === "User") { return true; diff --git a/oxost/oxost.ts b/oxost/oxost.ts index 98537b76..a4b8e49e 100644 --- a/oxost/oxost.ts +++ b/oxost/oxost.ts @@ -5,6 +5,7 @@ import { getPrefixes } from "@utils/pluginManager"; import { Plugin } from "@utils/pluginBase"; import { Api } from "telegram"; import { getGlobalClient } from "@utils/globalClient"; +import { Buffer } from "buffer"; // HTML转义 const htmlEscape = (text: string): string => @@ -141,7 +142,7 @@ class Ox0Plugin extends Plugin { // 使用 Node.js 原生 FormData(无需 form-data 依赖) const form = new globalThis.FormData(); - form.append("file", new Blob([buffer], { type: "application/octet-stream" }), filename); + form.append("file", new Blob([new Uint8Array(buffer)], { type: "application/octet-stream" }), filename); if (expires) form.append("expires", expires); if (secret) form.append("secret", "1"); const headers = { 'User-Agent': 'curl/8.0.1' }; diff --git a/plugins.json b/plugins.json index b6e8b70d..0dc37e76 100644 --- a/plugins.json +++ b/plugins.json @@ -23,6 +23,10 @@ "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/annualreport/annualreport.ts?raw=true", "desc": "年度报告" }, + "atadmins": { + "url": "https://github.com/TeleBoxDev/TeleBox_Plugins/blob/main/atall/atall.ts?raw=true", + "desc": "一键艾特全部成员" + }, "atadmins": { "url": "https://github.com/TeleBoxDev/TeleBox_Plugins/blob/main/atadmins/atadmins.ts?raw=true", "desc": "一键艾特全部管理员" diff --git a/premium/premium.ts b/premium/premium.ts index 794cf8bc..94aaa198 100644 --- a/premium/premium.ts +++ b/premium/premium.ts @@ -108,7 +108,10 @@ class PremiumPlugin extends Plugin { // 处理不同类型的participant if (participant instanceof Api.ChannelParticipant) { - user = participant.user as Api.User; + if ((participant as any).user) { + user = (participant as any).user as Api.User; + } + continue; } else if (participant instanceof Api.ChatParticipant) { user = participant.userId as unknown as Api.User; } else if (participant instanceof Api.User) { diff --git a/restore_pin/restore_pin.ts b/restore_pin/restore_pin.ts index 386d2078..1143360d 100644 --- a/restore_pin/restore_pin.ts +++ b/restore_pin/restore_pin.ts @@ -1,5 +1,5 @@ import { Plugin } from "@utils/pluginBase"; -import { Api } from "telegram"; +import { Api, types } from "telegram"; import { getGlobalClient } from "@utils/globalClient"; // HTML转义函数(必需) @@ -41,8 +41,8 @@ class RestorePinPlugin extends Plugin { new Api.channels.GetAdminLog({ channel: chatId, q: "", - maxId: BigInt(0), - minId: BigInt(0), + maxId: 0, + minId: 0, limit: 100, eventsFilter: new Api.ChannelAdminLogEventsFilter({ pinned: true @@ -62,7 +62,7 @@ class RestorePinPlugin extends Plugin { for (const event of events.events) { // 检查是否为取消置顶事件 if (event.action instanceof Api.ChannelAdminLogEventActionUpdatePinned) { - if (!event.action.message.pinned) { // 取消置顶 + if (!(event.action.message instanceof Api.MessageEmpty) && !event.action.message.pinned) { // 取消置顶 const messageId = event.action.message.id; messageIds.push(messageId); } @@ -173,10 +173,16 @@ class RestorePinPlugin extends Plugin { } // 检查管理员权限 + const sender = await msg.getSender(); + if (!sender) { + await msg.edit({ text: "❌ 无法获取发送者信息", parseMode: "html" }); + return; + } + const participant = await client.invoke( new Api.channels.GetParticipant({ channel: chat.id, - participant: await msg.getSender() as Api.InputUser + participant: sender as unknown as Api.InputUser }) ); diff --git a/subinfo/subinfo.ts b/subinfo/subinfo.ts index 961af585..860ad887 100644 --- a/subinfo/subinfo.ts +++ b/subinfo/subinfo.ts @@ -170,7 +170,7 @@ async function getNodeInfo(url: string): Promise<{ node_count: number | string, let identified = 0; const protocols = ['vmess://', 'trojan://', 'ss://', 'ssr://', 'vless://', 'hy2://', 'hysteria://', 'hy://', 'tuic://', 'wireguard://', 'socks5://', 'http://', 'https://', 'shadowtls://', 'naive://']; - decoded.split('\n').forEach(line => { + decoded.split('\n').forEach((line: string) => { if (!line.trim()) return; for (const pattern of protocols) { if (line.startsWith(pattern)) { @@ -373,7 +373,7 @@ class SubinfoPlugin extends Plugin { expireTs: number; startTs: number; websiteInfo: { website: string | null; websiteName: string | null }; - nodeInfo: Awaited> | null; + nodeInfo: { node_count: string | number; type_count: Record; regions: Record } | null; errorMessage: string | null; }> { const websiteInfo = await getWebsiteInfo(url); @@ -382,12 +382,12 @@ class SubinfoPlugin extends Plugin { configName: '未知', status: '失败', statusEmoji: '❓', - profileUrl: null, + profileUrl: null as string | null, used: 0, upload: 0, download: 0, total: 0, remain: 0, percent: 0, expireTs: 0, startTs: 0, websiteInfo, - nodeInfo: null, - errorMessage: null, + nodeInfo: null as { node_count: string | number; type_count: Record; regions: Record } | null, + errorMessage: null as string | null, }; try { @@ -414,7 +414,7 @@ class SubinfoPlugin extends Plugin { result.configName = configName || '未知'; const userInfoHeader = response.headers['subscription-userinfo']; - result.profileUrl = response.headers['profile-web-page-url'] as string || null; + result.profileUrl = (response.headers['profile-web-page-url'] as string | null) || null; if (!userInfoHeader) { result.errorMessage = "无流量统计信息"; @@ -423,7 +423,7 @@ class SubinfoPlugin extends Plugin { // 解析用户信息 const userInfoParts: Record = {}; - userInfoHeader.split(';').forEach(part => { + userInfoHeader.split(';').forEach((part: string) => { const equalsIndex = part.indexOf('='); if (equalsIndex > 0) userInfoParts[part.substring(0, equalsIndex).trim().toLowerCase()] = part.substring(equalsIndex + 1).trim(); }); diff --git a/teletype/teletype.ts b/teletype/teletype.ts index efd4738a..5f724b9d 100644 --- a/teletype/teletype.ts +++ b/teletype/teletype.ts @@ -199,12 +199,7 @@ class TeletypePlugin extends Plugin { } private async getPrefixes(): Promise { - try { - const { getPrefixes } = await import("@utils/pluginManager"); - return getPrefixes(); - } catch (error) { - return [".", "。", "!"]; - } + return [".", "。", "!"]; } private async executeTeletype(msg: Api.Message, text: string): Promise { @@ -217,6 +212,8 @@ class TeletypePlugin extends Plugin { parseMode: "html" }); + if (!currentMsg) return; + await this.sleep(interval); for (const character of text) { @@ -224,18 +221,22 @@ class TeletypePlugin extends Plugin { const bufferWithCursor = `${htmlEscape(buffer)}${cursor}`; try { - currentMsg = await currentMsg.edit({ + currentMsg = await currentMsg?.edit({ text: bufferWithCursor, parseMode: "html" }); + if (!currentMsg) return; + await this.sleep(interval); - if (buffer.length > 0) { + if (buffer.length > 0 && currentMsg) { currentMsg = await currentMsg.edit({ text: htmlEscape(buffer), parseMode: "html" }); + + if (!currentMsg) return; } } catch (error: any) { @@ -250,10 +251,12 @@ class TeletypePlugin extends Plugin { const finalText = htmlEscape(text); try { - await currentMsg.edit({ - text: finalText, - parseMode: "html" - }); + if (currentMsg) { + await currentMsg.edit({ + text: finalText, + parseMode: "html" + }); + } } catch (error: any) { if (!error.message?.includes("MESSAGE_NOT_MODIFIED")) { throw error; diff --git a/uai/uai.ts b/uai/uai.ts index aeb4adbd..9415e9d5 100644 --- a/uai/uai.ts +++ b/uai/uai.ts @@ -1,6 +1,7 @@ /** * UAI 插件 - 引用消息 AI 分析 * 引用某用户/频道的消息,回复 .uai zj/fx 进行总结/分析 + * 支持消息折叠显示,保持AI回答中的HTML格式 */ import { Plugin } from "@utils/pluginBase"; import { getPrefixes } from "@utils/pluginManager"; @@ -32,6 +33,7 @@ type UAIConfig = { default_provider?: string; prompts: Record; timeout: number; + collapse: boolean; // 新增:折叠开关 }; // ========== 常量 ========== @@ -48,7 +50,8 @@ const DEFAULT_CONFIG: UAIConfig = { providers: {}, default_provider: undefined, prompts: {}, - timeout: DEFAULT_TIMEOUT + timeout: DEFAULT_TIMEOUT, + collapse: true // 默认折叠 }; // ========== 工具函数 ========== @@ -61,7 +64,22 @@ function htmlEscape(t: string): string { .replace(/'/g, "'"); } -// Markdown 转 Telegram HTML +// HTML转义函数(确保用户输入安全) +const escapeHtml = (text: string): string => + text.replace(/[&<>"']/g, m => ({ + '&': '&', '<': '<', '>': '>', + '"': '"', "'": ''' + }[m] || m)); + +// 应用折叠功能 +const applyWrap = (s: string, collapse?: boolean): string => { + if (!collapse) return s; + // 检查是否已经是块引用 + if (/|\/)\/?>/i.test(s)) return s; + return `
${s}
`; +}; + +// Markdown 转 Telegram HTML,保留特殊格式 function markdownToHtml(text: string): string { return text // 粗体 **text** 或 __text__ @@ -73,7 +91,11 @@ function markdownToHtml(text: string): string { // 代码 `code` .replace(/`([^`]+)`/g, "$1") // 删除线 ~~text~~ - .replace(/~~(.+?)~~/g, "$1"); + .replace(/~~(.+?)~~/g, "$1") + // 保留已有的HTML标签 + .replace(/<(.+?)>/g, "<$1>") + // 处理块引用 > text + .replace(/^>\s?(.+)$/gm, "
$1
"); } function trimBase(url: string): string { @@ -109,9 +131,11 @@ function parseTimeLimit(s: string): number | null { // ========== 数据库 ========== async function getDB() { const db = await JSONFilePreset(DB_PATH, DEFAULT_CONFIG); + // 确保所有字段都存在 if (!db.data.providers) db.data.providers = {}; if (!db.data.prompts) db.data.prompts = {}; if (!db.data.timeout) db.data.timeout = DEFAULT_TIMEOUT; + if (typeof db.data.collapse !== "boolean") db.data.collapse = false; return db; } @@ -281,18 +305,23 @@ function formatMessagesForAI(messages: MessageData[]): string { } // ========== 帮助文本 ========== -const getHelpText = () => `⚙️ UAI +const getHelpText = () => `⚙️ UAI - 用户消息AI分析 📝 功能描述: -• 引用消息,AI 自动收集并分析/总结目标用户的历史消息 +• 引用用户消息,AI自动收集并分析/总结目标用户的历史消息 +• 支持折叠显示AI回答,保持格式完整 -🔧 使用方法: +🔧 核心功能:${mainPrefix}uai zj - 总结(当天消息) • ${mainPrefix}uai fx - 分析(当天消息) -• ${mainPrefix}uai zj 50 - 总结最近 50 条 -• ${mainPrefix}uai fx 2h - 分析最近 2 小时 +• ${mainPrefix}uai zj 50 - 总结最近50条 +• ${mainPrefix}uai fx 2h - 分析最近2小时 • ${mainPrefix}uai 自定义名 - 使用自定义提示词 +⚙️ 折叠显示: +• ${mainPrefix}uai collapse on - 开启AI回答折叠 +• ${mainPrefix}uai collapse off - 关闭AI回答折叠 + 🔌 供应商配置:${mainPrefix}uai add <名称> <url> <key> <type> - 添加供应商 • ${mainPrefix}uai set <名称> - 设置默认供应商 @@ -301,13 +330,23 @@ const getHelpText = () => `⚙️ UAI${mainPrefix}uai model <名称> <模型> - 修改模型 📝 提示词配置: -• ${mainPrefix}uai prompt add <名称> <内容> - 添加 -• ${mainPrefix}uai prompt del <名称> - 删除 -• ${mainPrefix}uai prompt list - 列表 +• ${mainPrefix}uai prompt add <名称> <内容> - 添加自定义提示词 +• ${mainPrefix}uai prompt del <名称> - 删除自定义提示词 +• ${mainPrefix}uai prompt list - 列出所有提示词 + +💡 内置提示词: +• zj - 总结(提取关键信息) +• fx - 分析(观点、态度分析) -💡 参数说明: +📋 参数说明: • type: openai / gemini -• 内置提示词: zj(总结) fx(分析)`; +• 时间格式: 2h(2小时), 30m(30分钟) +• 数量格式: 50(最近50条) + +🔍 使用示例: +1. 引用用户消息,回复: .uai zj - 总结当天消息 +2. 引用用户消息,回复: .uai fx 100 - 分析最近100条 +3. 引用频道消息,回复: .uai zj - 总结频道消息`; // ========== 插件类 ========== class UAIPlugin extends Plugin { @@ -328,6 +367,34 @@ class UAIPlugin extends Plugin { return; } + // 折叠开关配置 + if (subCmd === "collapse") { + const action = parts[1]?.toLowerCase(); + if (action === "on") { + db.data.collapse = true; + await db.write(); + await msg.edit({ + text: "✅ 已开启AI回答折叠显示\n\nAI回答将显示在可折叠的块引用中", + parseMode: "html" + }); + return; + } else if (action === "off") { + db.data.collapse = false; + await db.write(); + await msg.edit({ + text: "✅ 已关闭AI回答折叠显示\n\nAI回答将正常显示", + parseMode: "html" + }); + return; + } else { + await msg.edit({ + text: `📊 当前折叠状态: ${db.data.collapse ? "开启" : "关闭"}\n\n使用: ${mainPrefix}uai collapse on/off`, + parseMode: "html" + }); + return; + } + } + // 配置命令 if (subCmd === "add" && parts.length >= 5) { const [, name, baseUrl, apiKey, typeStr] = parts; @@ -382,7 +449,11 @@ class UAIPlugin extends Plugin { const isDefault = db.data.default_provider === p.name ? " ⭐" : ""; return `• ${htmlEscape(p.name)}${isDefault} (${p.type}, ${p.model})`; }).join("\n"); - await msg.edit({ text: `📋 供应商列表\n\n${list}`, parseMode: "html" }); + const collapseStatus = `折叠显示: ${db.data.collapse ? "✅ 开启" : "❌ 关闭"}`; + await msg.edit({ + text: `📋 供应商列表\n\n${list}\n\n${collapseStatus}`, + parseMode: "html" + }); return; } @@ -527,7 +598,13 @@ class UAIPlugin extends Plugin { const userInfo = `来源: ${channelName}${channelUsername ? ` (@${channelUsername})` : ""}`; const result = await callAI(provider, prompt, `${userInfo}\n\n${content}`, db.data.timeout); - const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${markdownToHtml(result)}`; + + // 处理AI回答,保留格式并应用折叠 + const aiContent = markdownToHtml(result); + const foldedContent = applyWrap(aiContent, db.data.collapse); + + const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${foldedContent}`; + await msg.delete({ revoke: true }); await client.sendMessage(chatPeerId, { message: resultText, parseMode: "html" }); return; @@ -572,7 +649,13 @@ class UAIPlugin extends Plugin { const provider = db.data.providers[db.data.default_provider!]; const result = await callAI(provider, prompt, `${userInfo}\n\n${content}`, db.data.timeout); - const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${markdownToHtml(result)}`; + + // 处理AI回答,保留格式并应用折叠 + const aiContent = markdownToHtml(result); + const foldedContent = applyWrap(aiContent, db.data.collapse); + + const resultText = `📊 ${promptKey === "zj" ? "总结" : "分析"}结果(${displayName},${messages.length} 条)\n\n${foldedContent}`; + await msg.delete({ revoke: true }); await client.sendMessage(chatPeerId, { message: resultText, parseMode: "html" });