227
bin/qqbot-cli.js
Normal file
227
bin/qqbot-cli.js
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QQBot CLI - 用于升级和管理 QQBot 插件
|
||||||
|
*
|
||||||
|
* 用法:
|
||||||
|
* npx @sliverp/qqbot upgrade # 升级插件
|
||||||
|
* npx @sliverp/qqbot install # 安装插件
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { existsSync, readFileSync, writeFileSync, rmSync } from 'fs';
|
||||||
|
import { homedir } from 'os';
|
||||||
|
import { join, dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
// 获取包的根目录
|
||||||
|
const PKG_ROOT = join(__dirname, '..');
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const command = args[0];
|
||||||
|
|
||||||
|
// 检测使用的是 clawdbot 还是 openclaw
|
||||||
|
function detectInstallation() {
|
||||||
|
const home = homedir();
|
||||||
|
if (existsSync(join(home, '.openclaw'))) {
|
||||||
|
return 'openclaw';
|
||||||
|
}
|
||||||
|
if (existsSync(join(home, '.clawdbot'))) {
|
||||||
|
return 'clawdbot';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理旧版本插件,返回旧的 qqbot 配置
|
||||||
|
function cleanupInstallation(appName) {
|
||||||
|
const home = homedir();
|
||||||
|
const appDir = join(home, `.${appName}`);
|
||||||
|
const configFile = join(appDir, `${appName}.json`);
|
||||||
|
const extensionDir = join(appDir, 'extensions', 'qqbot');
|
||||||
|
|
||||||
|
let oldQqbotConfig = null;
|
||||||
|
|
||||||
|
console.log(`\n>>> 处理 ${appName} 安装...`);
|
||||||
|
|
||||||
|
// 1. 先读取旧的 qqbot 配置
|
||||||
|
if (existsSync(configFile)) {
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(readFileSync(configFile, 'utf8'));
|
||||||
|
if (config.channels?.qqbot) {
|
||||||
|
oldQqbotConfig = { ...config.channels.qqbot };
|
||||||
|
console.log('已保存旧的 qqbot 配置');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('读取配置文件失败:', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 删除旧的扩展目录
|
||||||
|
if (existsSync(extensionDir)) {
|
||||||
|
console.log(`删除旧版本插件: ${extensionDir}`);
|
||||||
|
rmSync(extensionDir, { recursive: true, force: true });
|
||||||
|
} else {
|
||||||
|
console.log('未找到旧版本插件目录,跳过删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 清理配置文件中的 qqbot 相关字段
|
||||||
|
if (existsSync(configFile)) {
|
||||||
|
console.log('清理配置文件中的 qqbot 字段...');
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(readFileSync(configFile, 'utf8'));
|
||||||
|
|
||||||
|
// 删除 channels.qqbot
|
||||||
|
if (config.channels?.qqbot) {
|
||||||
|
delete config.channels.qqbot;
|
||||||
|
console.log(' - 已删除 channels.qqbot');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除 plugins.entries.qqbot
|
||||||
|
if (config.plugins?.entries?.qqbot) {
|
||||||
|
delete config.plugins.entries.qqbot;
|
||||||
|
console.log(' - 已删除 plugins.entries.qqbot');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除 plugins.installs.qqbot
|
||||||
|
if (config.plugins?.installs?.qqbot) {
|
||||||
|
delete config.plugins.installs.qqbot;
|
||||||
|
console.log(' - 已删除 plugins.installs.qqbot');
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(configFile, JSON.stringify(config, null, 2));
|
||||||
|
console.log('配置文件已更新');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('清理配置文件失败:', err.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`未找到配置文件: ${configFile}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldQqbotConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行命令并继承 stdio
|
||||||
|
function runCommand(cmd, args = []) {
|
||||||
|
try {
|
||||||
|
execSync([cmd, ...args].join(' '), { stdio: 'inherit' });
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 升级命令
|
||||||
|
function upgrade() {
|
||||||
|
console.log('=== QQBot 插件升级脚本 ===');
|
||||||
|
|
||||||
|
let foundInstallation = null;
|
||||||
|
let savedConfig = null;
|
||||||
|
const home = homedir();
|
||||||
|
|
||||||
|
// 检查 openclaw
|
||||||
|
if (existsSync(join(home, '.openclaw'))) {
|
||||||
|
savedConfig = cleanupInstallation('openclaw');
|
||||||
|
foundInstallation = 'openclaw';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 clawdbot
|
||||||
|
if (existsSync(join(home, '.clawdbot'))) {
|
||||||
|
const clawdbotConfig = cleanupInstallation('clawdbot');
|
||||||
|
if (!savedConfig) savedConfig = clawdbotConfig;
|
||||||
|
foundInstallation = 'clawdbot';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundInstallation) {
|
||||||
|
console.log('\n未找到 clawdbot 或 openclaw 安装目录');
|
||||||
|
console.log('请确认已安装 clawdbot 或 openclaw');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n=== 清理完成 ===');
|
||||||
|
|
||||||
|
// 自动安装插件
|
||||||
|
console.log('\n[1/2] 安装新版本插件...');
|
||||||
|
runCommand(foundInstallation, ['plugins', 'install', '@sliverp/qqbot']);
|
||||||
|
|
||||||
|
// 自动配置通道(使用保存的 appId 和 clientSecret)
|
||||||
|
console.log('\n[2/2] 配置机器人通道...');
|
||||||
|
if (savedConfig?.appId && savedConfig?.clientSecret) {
|
||||||
|
const token = `${savedConfig.appId}:${savedConfig.clientSecret}`;
|
||||||
|
console.log(`使用已保存的配置: appId=${savedConfig.appId}`);
|
||||||
|
runCommand(foundInstallation, ['channels', 'add', '--channel', 'qqbot', '--token', `"${token}"`]);
|
||||||
|
|
||||||
|
// 恢复其他配置项(如 markdownSupport)
|
||||||
|
if (savedConfig.markdownSupport !== undefined) {
|
||||||
|
runCommand(foundInstallation, ['config', 'set', 'channels.qqbot.markdownSupport', String(savedConfig.markdownSupport)]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('未找到已保存的 qqbot 配置,请手动配置:');
|
||||||
|
console.log(` ${foundInstallation} channels add --channel qqbot --token "AppID:AppSecret"`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n=== 升级完成 ===');
|
||||||
|
console.log(`\n可以运行以下命令前台运行启动机器人:`);
|
||||||
|
console.log(` ${foundInstallation} gateway stop && ${foundInstallation} gateway --port 18789 --verbose`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安装命令
|
||||||
|
function install() {
|
||||||
|
console.log('=== QQBot 插件安装 ===');
|
||||||
|
|
||||||
|
const cmd = detectInstallation();
|
||||||
|
if (!cmd) {
|
||||||
|
console.log('未找到 clawdbot 或 openclaw 安装');
|
||||||
|
console.log('请先安装 openclaw 或 clawdbot');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n使用 ${cmd} 安装插件...`);
|
||||||
|
runCommand(cmd, ['plugins', 'install', '@sliverp/qqbot']);
|
||||||
|
|
||||||
|
console.log('\n=== 安装完成 ===');
|
||||||
|
console.log('\n请配置机器人通道:');
|
||||||
|
console.log(` ${cmd} channels add --channel qqbot --token "AppID:AppSecret"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示帮助
|
||||||
|
function showHelp() {
|
||||||
|
console.log(`
|
||||||
|
QQBot CLI - QQ机器人插件管理工具
|
||||||
|
|
||||||
|
用法:
|
||||||
|
npx @sliverp/qqbot <命令>
|
||||||
|
|
||||||
|
命令:
|
||||||
|
upgrade 清理旧版本插件(升级前执行)
|
||||||
|
install 安装插件到 openclaw/clawdbot
|
||||||
|
|
||||||
|
示例:
|
||||||
|
npx @sliverp/qqbot upgrade
|
||||||
|
npx @sliverp/qqbot install
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主入口
|
||||||
|
switch (command) {
|
||||||
|
case 'upgrade':
|
||||||
|
upgrade();
|
||||||
|
break;
|
||||||
|
case 'install':
|
||||||
|
install();
|
||||||
|
break;
|
||||||
|
case '-h':
|
||||||
|
case '--help':
|
||||||
|
case 'help':
|
||||||
|
showHelp();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (command) {
|
||||||
|
console.log(`未知命令: ${command}`);
|
||||||
|
}
|
||||||
|
showHelp();
|
||||||
|
process.exit(command ? 1 : 0);
|
||||||
|
}
|
||||||
1153
package-lock.json
generated
1153
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -1,9 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "qqbot",
|
"name": "@sliverp/qqbot",
|
||||||
"version": "1.3.0",
|
"version": "1.3.14",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
"bin": {
|
||||||
|
"qqbot": "./bin/qqbot-cli.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"bin",
|
||||||
|
"src",
|
||||||
|
"index.ts",
|
||||||
|
"tsconfig.json",
|
||||||
|
"openclaw.plugin.json",
|
||||||
|
"clawdbot.plugin.json",
|
||||||
|
"moltbot.plugin.json"
|
||||||
|
],
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
"extensions": ["./index.ts"]
|
"extensions": ["./index.ts"]
|
||||||
},
|
},
|
||||||
@@ -33,5 +46,6 @@
|
|||||||
"clawdbot": "*",
|
"clawdbot": "*",
|
||||||
"moltbot": "*",
|
"moltbot": "*",
|
||||||
"openclaw": "*"
|
"openclaw": "*"
|
||||||
}
|
},
|
||||||
|
"homepage": "https://github.com/sliverp/qqbot"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,20 @@ export const qqbotPlugin: ChannelPlugin<ResolvedQQBotAccount> = {
|
|||||||
configured: Boolean(account?.appId && account?.clientSecret),
|
configured: Boolean(account?.appId && account?.clientSecret),
|
||||||
tokenSource: account?.secretSource,
|
tokenSource: account?.secretSource,
|
||||||
}),
|
}),
|
||||||
|
// 关键:解析 allowFrom 配置,用于命令授权
|
||||||
|
resolveAllowFrom: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string }) => {
|
||||||
|
const account = resolveQQBotAccount(cfg, accountId);
|
||||||
|
const allowFrom = account.config?.allowFrom ?? [];
|
||||||
|
console.log(`[qqbot] resolveAllowFrom: accountId=${accountId}, allowFrom=${JSON.stringify(allowFrom)}`);
|
||||||
|
return allowFrom.map((entry: string | number) => String(entry));
|
||||||
|
},
|
||||||
|
// 格式化 allowFrom 条目(移除 qqbot: 前缀,统一大写)
|
||||||
|
formatAllowFrom: ({ allowFrom }: { allowFrom: Array<string | number> }) =>
|
||||||
|
allowFrom
|
||||||
|
.map((entry: string | number) => String(entry).trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((entry: string) => entry.replace(/^qqbot:/i, ""))
|
||||||
|
.map((entry: string) => entry.toUpperCase()), // QQ openid 是大写的
|
||||||
},
|
},
|
||||||
setup: {
|
setup: {
|
||||||
// 新增:规范化账户 ID
|
// 新增:规范化账户 ID
|
||||||
@@ -159,18 +173,6 @@ export const qqbotPlugin: ChannelPlugin<ResolvedQQBotAccount> = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 新增:消息目标解析
|
|
||||||
messaging: {
|
|
||||||
normalizeTarget: (target) => {
|
|
||||||
// 支持格式: qqbot:openid, qqbot:group:xxx, openid, group:xxx
|
|
||||||
const normalized = target.replace(/^qqbot:/i, "");
|
|
||||||
return { ok: true, to: normalized };
|
|
||||||
},
|
|
||||||
targetResolver: {
|
|
||||||
looksLikeId: (id) => /^[A-F0-9]{32}$/i.test(id) || id.startsWith("group:") || id.startsWith("channel:"),
|
|
||||||
hint: "<openid> or group:<groupOpenid>",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
outbound: {
|
outbound: {
|
||||||
deliveryMode: "direct",
|
deliveryMode: "direct",
|
||||||
chunker: chunkText,
|
chunker: chunkText,
|
||||||
|
|||||||
@@ -128,11 +128,16 @@ export function applyQQBotAccountConfig(
|
|||||||
const next = { ...cfg };
|
const next = { ...cfg };
|
||||||
|
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
||||||
|
// 如果没有设置过 allowFrom,默认设置为 ["*"]
|
||||||
|
const existingConfig = (next.channels?.qqbot as QQBotChannelConfig) || {};
|
||||||
|
const allowFrom = existingConfig.allowFrom ?? ["*"];
|
||||||
|
|
||||||
next.channels = {
|
next.channels = {
|
||||||
...next.channels,
|
...next.channels,
|
||||||
qqbot: {
|
qqbot: {
|
||||||
...(next.channels?.qqbot as Record<string, unknown> || {}),
|
...(next.channels?.qqbot as Record<string, unknown> || {}),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
allowFrom,
|
||||||
...(input.appId ? { appId: input.appId } : {}),
|
...(input.appId ? { appId: input.appId } : {}),
|
||||||
...(input.clientSecret
|
...(input.clientSecret
|
||||||
? { clientSecret: input.clientSecret }
|
? { clientSecret: input.clientSecret }
|
||||||
@@ -144,6 +149,10 @@ export function applyQQBotAccountConfig(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
// 如果没有设置过 allowFrom,默认设置为 ["*"]
|
||||||
|
const existingAccountConfig = (next.channels?.qqbot as QQBotChannelConfig)?.accounts?.[accountId] || {};
|
||||||
|
const allowFrom = existingAccountConfig.allowFrom ?? ["*"];
|
||||||
|
|
||||||
next.channels = {
|
next.channels = {
|
||||||
...next.channels,
|
...next.channels,
|
||||||
qqbot: {
|
qqbot: {
|
||||||
@@ -154,6 +163,7 @@ export function applyQQBotAccountConfig(
|
|||||||
[accountId]: {
|
[accountId]: {
|
||||||
...((next.channels?.qqbot as QQBotChannelConfig)?.accounts?.[accountId] || {}),
|
...((next.channels?.qqbot as QQBotChannelConfig)?.accounts?.[accountId] || {}),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
allowFrom,
|
||||||
...(input.appId ? { appId: input.appId } : {}),
|
...(input.appId ? { appId: input.appId } : {}),
|
||||||
...(input.clientSecret
|
...(input.clientSecret
|
||||||
? { clientSecret: input.clientSecret }
|
? { clientSecret: input.clientSecret }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import WebSocket from "ws";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import * as fs from "node:fs";
|
import * as fs from "node:fs";
|
||||||
import type { ResolvedQQBotAccount, WSPayload, C2CMessageEvent, GuildMessageEvent, GroupMessageEvent } from "./types.js";
|
import type { ResolvedQQBotAccount, WSPayload, C2CMessageEvent, GuildMessageEvent, GroupMessageEvent } from "./types.js";
|
||||||
import { getAccessToken, getGatewayUrl, sendC2CMessage, sendChannelMessage, sendGroupMessage, clearTokenCache, sendC2CImageMessage, sendGroupImageMessage, initApiConfig, startBackgroundTokenRefresh, stopBackgroundTokenRefresh } from "./api.js";
|
import { getAccessToken, getGatewayUrl, sendC2CMessage, sendChannelMessage, sendGroupMessage, clearTokenCache, sendC2CImageMessage, sendGroupImageMessage, initApiConfig, startBackgroundTokenRefresh, stopBackgroundTokenRefresh, sendC2CInputNotify } from "./api.js";
|
||||||
import { loadSession, saveSession, clearSession, type SessionState } from "./session-store.js";
|
import { loadSession, saveSession, clearSession, type SessionState } from "./session-store.js";
|
||||||
import { recordKnownUser, flushKnownUsers } from "./known-users.js";
|
import { recordKnownUser, flushKnownUsers } from "./known-users.js";
|
||||||
import { getQQBotRuntime } from "./runtime.js";
|
import { getQQBotRuntime } from "./runtime.js";
|
||||||
@@ -412,6 +412,13 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
direction: "inbound",
|
direction: "inbound",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try{
|
||||||
|
await sendC2CInputNotify(accessToken, event.senderId, event.messageId, 60);
|
||||||
|
log?.info(`[qqbot:${account.accountId}] Sent input notify to ${event.senderId}`);
|
||||||
|
}catch(err){
|
||||||
|
log?.error(`[qqbot:${account.accountId}] sendC2CInputNotify error: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
const isGroup = event.type === "guild" || event.type === "group";
|
const isGroup = event.type === "guild" || event.type === "group";
|
||||||
const peerId = event.type === "guild" ? `channel:${event.channelId}`
|
const peerId = event.type === "guild" ? `channel:${event.channelId}`
|
||||||
: event.type === "group" ? `group:${event.groupOpenid}`
|
: event.type === "group" ? `group:${event.groupOpenid}`
|
||||||
@@ -568,10 +575,15 @@ openclaw cron add \\
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userContent = event.content + attachmentInfo;
|
const userContent = event.content + attachmentInfo;
|
||||||
const messageBody = `【系统提示】\n${systemPrompts.join("\n")}\n\n【用户输入】\n${userContent}`;
|
let messageBody = `【系统提示】\n${systemPrompts.join("\n")}\n\n【用户输入】\n${userContent}`;
|
||||||
|
|
||||||
|
if(userContent.startsWith("/")){ // 保留Openclaw原始命令
|
||||||
|
messageBody = userContent
|
||||||
|
}
|
||||||
|
log?.info(`[qqbot:${account.accountId}] messageBody: ${messageBody}`);
|
||||||
|
|
||||||
const body = pluginRuntime.channel.reply.formatInboundEnvelope({
|
const body = pluginRuntime.channel.reply.formatInboundEnvelope({
|
||||||
channel: "QQBot",
|
channel: "qqbot",
|
||||||
from: event.senderName ?? event.senderId,
|
from: event.senderName ?? event.senderId,
|
||||||
timestamp: new Date(event.timestamp).getTime(),
|
timestamp: new Date(event.timestamp).getTime(),
|
||||||
body: messageBody,
|
body: messageBody,
|
||||||
@@ -590,6 +602,14 @@ openclaw cron add \\
|
|||||||
: `qqbot:c2c:${event.senderId}`;
|
: `qqbot:c2c:${event.senderId}`;
|
||||||
const toAddress = fromAddress;
|
const toAddress = fromAddress;
|
||||||
|
|
||||||
|
// 计算命令授权状态
|
||||||
|
// allowFrom: ["*"] 表示允许所有人,否则检查 senderId 是否在 allowFrom 列表中
|
||||||
|
const allowFromList = account.config?.allowFrom ?? [];
|
||||||
|
const allowAll = allowFromList.length === 0 || allowFromList.some((entry: string) => entry === "*");
|
||||||
|
const commandAuthorized = allowAll || allowFromList.some((entry: string) =>
|
||||||
|
entry.toUpperCase() === event.senderId.toUpperCase()
|
||||||
|
);
|
||||||
|
|
||||||
const ctxPayload = pluginRuntime.channel.reply.finalizeInboundContext({
|
const ctxPayload = pluginRuntime.channel.reply.finalizeInboundContext({
|
||||||
Body: body,
|
Body: body,
|
||||||
RawBody: event.content,
|
RawBody: event.content,
|
||||||
@@ -610,6 +630,7 @@ openclaw cron add \\
|
|||||||
QQChannelId: event.channelId,
|
QQChannelId: event.channelId,
|
||||||
QQGuildId: event.guildId,
|
QQGuildId: event.guildId,
|
||||||
QQGroupOpenid: event.groupOpenid,
|
QQGroupOpenid: event.groupOpenid,
|
||||||
|
CommandAuthorized: commandAuthorized,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 发送消息的辅助函数,带 token 过期重试
|
// 发送消息的辅助函数,带 token 过期重试
|
||||||
@@ -810,7 +831,7 @@ openclaw cron add \\
|
|||||||
log?.info(`[qqbot:${account.accountId}] Sent image via <qqimg> tag: ${imagePath.slice(0, 60)}...`);
|
log?.info(`[qqbot:${account.accountId}] Sent image via <qqimg> tag: ${imagePath.slice(0, 60)}...`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log?.error(`[qqbot:${account.accountId}] Failed to send image from <qqimg>: ${err}`);
|
log?.error(`[qqbot:${account.accountId}] Failed to send image from <qqimg>: ${err}`);
|
||||||
await sendErrorMessage(`发送图片失败: ${err}`);
|
await sendErrorMessage(`图片发送失败,图片似乎不存在哦,图片路径:${imagePath}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1250,7 +1271,9 @@ openclaw cron add \\
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
replyOptions: {},
|
replyOptions: {
|
||||||
|
disableBlockStreaming: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 等待分发完成或超时
|
// 等待分发完成或超时
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ interface QQBotChannelConfig {
|
|||||||
clientSecretFile?: string;
|
clientSecretFile?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
imageServerBaseUrl?: string;
|
imageServerBaseUrl?: string;
|
||||||
|
allowFrom?: string[];
|
||||||
accounts?: Record<string, {
|
accounts?: Record<string, {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
appId?: string;
|
appId?: string;
|
||||||
@@ -28,6 +29,7 @@ interface QQBotChannelConfig {
|
|||||||
clientSecretFile?: string;
|
clientSecretFile?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
imageServerBaseUrl?: string;
|
imageServerBaseUrl?: string;
|
||||||
|
allowFrom?: string[];
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +139,7 @@ statusLines: [`QQ Bot: ${configured ? "已配置" : "需要 AppID 和 ClientSecr
|
|||||||
qqbot: {
|
qqbot: {
|
||||||
...(next.channels?.qqbot as Record<string, unknown> || {}),
|
...(next.channels?.qqbot as Record<string, unknown> || {}),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
allowFrom: resolvedAccount.config?.allowFrom ?? ["*"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -200,6 +203,9 @@ statusLines: [`QQ Bot: ${configured ? "已配置" : "需要 AppID 和 ClientSecr
|
|||||||
).trim();
|
).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 默认允许所有人执行命令(用户无感知)
|
||||||
|
const allowFrom: string[] = resolvedAccount.config?.allowFrom ?? ["*"];
|
||||||
|
|
||||||
// 应用配置
|
// 应用配置
|
||||||
if (appId && clientSecret) {
|
if (appId && clientSecret) {
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
||||||
@@ -212,6 +218,7 @@ statusLines: [`QQ Bot: ${configured ? "已配置" : "需要 AppID 和 ClientSecr
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
appId,
|
appId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
|
allowFrom,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -230,6 +237,7 @@ statusLines: [`QQ Bot: ${configured ? "已配置" : "需要 AppID 和 ClientSecr
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
appId,
|
appId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
|
allowFrom,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user