@tencent-connect/dsh-qqbot 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.orange-ci.yml +2 -68
- package/CHANGELOG.md +56 -0
- package/CHANGELOG_EN.md +95 -0
- package/README.md +119 -18
- package/README_EN.md +107 -17
- package/cordis.patch.yml +1 -1
- package/cordis.yml +46 -3
- package/dist/commands/help.d.ts +6 -7
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +23 -7
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/index.d.ts +7 -5
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +12 -12
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/misc.d.ts +10 -8
- package/dist/commands/misc.d.ts.map +1 -1
- package/dist/commands/misc.js +45 -8
- package/dist/commands/misc.js.map +1 -1
- package/dist/commands/model.d.ts +3 -4
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +8 -7
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/preset.d.ts +8 -0
- package/dist/commands/preset.d.ts.map +1 -0
- package/dist/commands/preset.js +52 -0
- package/dist/commands/preset.js.map +1 -0
- package/dist/commands/session.d.ts +11 -7
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +29 -13
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/status.d.ts +3 -4
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +2 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/types.d.ts +9 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/config.d.ts +40 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -9
- package/dist/config.js.map +1 -1
- package/dist/features/answer-parser.d.ts +9 -0
- package/dist/features/answer-parser.d.ts.map +1 -0
- package/dist/features/answer-parser.js +23 -0
- package/dist/features/answer-parser.js.map +1 -0
- package/dist/features/approval-channel.d.ts +76 -0
- package/dist/features/approval-channel.d.ts.map +1 -0
- package/dist/features/approval-channel.js +142 -0
- package/dist/features/approval-channel.js.map +1 -0
- package/dist/features/approval-renderer.d.ts +18 -0
- package/dist/features/approval-renderer.d.ts.map +1 -0
- package/dist/features/approval-renderer.js +52 -0
- package/dist/features/approval-renderer.js.map +1 -0
- package/dist/features/button-utils.d.ts +33 -0
- package/dist/features/button-utils.d.ts.map +1 -0
- package/dist/features/button-utils.js +27 -0
- package/dist/features/button-utils.js.map +1 -0
- package/dist/features/history-store.d.ts.map +1 -1
- package/dist/features/history-store.js +0 -1
- package/dist/features/history-store.js.map +1 -1
- package/dist/features/question-channel.d.ts +96 -0
- package/dist/features/question-channel.d.ts.map +1 -0
- package/dist/features/question-channel.js +234 -0
- package/dist/features/question-channel.js.map +1 -0
- package/dist/features/question-renderer.d.ts +20 -0
- package/dist/features/question-renderer.d.ts.map +1 -0
- package/dist/features/question-renderer.js +70 -0
- package/dist/features/question-renderer.js.map +1 -0
- package/dist/gateway/bootstrap.d.ts +3 -3
- package/dist/gateway/bootstrap.d.ts.map +1 -1
- package/dist/gateway/bootstrap.js +84 -8
- package/dist/gateway/bootstrap.js.map +1 -1
- package/dist/gateway/index.d.ts +2 -2
- package/dist/gateway/index.js +2 -2
- package/dist/gateway/middleware-setup.d.ts +3 -3
- package/dist/gateway/middleware-setup.d.ts.map +1 -1
- package/dist/gateway/middleware-setup.js +9 -7
- package/dist/gateway/middleware-setup.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -25
- package/dist/index.js.map +1 -1
- package/dist/media/media-cleaner.d.ts +19 -0
- package/dist/media/media-cleaner.d.ts.map +1 -0
- package/dist/media/media-cleaner.js +81 -0
- package/dist/media/media-cleaner.js.map +1 -0
- package/dist/media/send-file-tool.d.ts +35 -0
- package/dist/media/send-file-tool.d.ts.map +1 -0
- package/dist/media/send-file-tool.js +150 -0
- package/dist/media/send-file-tool.js.map +1 -0
- package/dist/media/vision-tool.d.ts +16 -0
- package/dist/media/vision-tool.d.ts.map +1 -0
- package/dist/media/vision-tool.js +241 -0
- package/dist/media/vision-tool.js.map +1 -0
- package/dist/middleware/attachment.d.ts +3 -3
- package/dist/middleware/attachment.d.ts.map +1 -1
- package/dist/middleware/attachment.js +17 -4
- package/dist/middleware/attachment.js.map +1 -1
- package/dist/middleware/question-answer.d.ts +10 -0
- package/dist/middleware/question-answer.d.ts.map +1 -0
- package/dist/middleware/question-answer.js +19 -0
- package/dist/middleware/question-answer.js.map +1 -0
- package/dist/model/index.d.ts +4 -4
- package/dist/model/index.js +3 -3
- package/dist/model/model-resolver.d.ts +27 -13
- package/dist/model/model-resolver.d.ts.map +1 -1
- package/dist/model/model-resolver.js +82 -27
- package/dist/model/model-resolver.js.map +1 -1
- package/dist/model/prefs-store.d.ts +6 -1
- package/dist/model/prefs-store.d.ts.map +1 -1
- package/dist/model/prefs-store.js +25 -1
- package/dist/model/prefs-store.js.map +1 -1
- package/dist/model/settings-reader.d.ts +1 -1
- package/dist/session/idle-evictor.d.ts +2 -2
- package/dist/session/idle-evictor.d.ts.map +1 -1
- package/dist/session/idle-evictor.js +1 -1
- package/dist/session/idle-evictor.js.map +1 -1
- package/dist/session/index.d.ts +3 -3
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +2 -2
- package/dist/session/session-manager.d.ts +67 -9
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +216 -20
- package/dist/session/session-manager.js.map +1 -1
- package/dist/session/types.d.ts +47 -1
- package/dist/session/types.d.ts.map +1 -1
- package/dist/setup/bind-routes.d.ts +78 -0
- package/dist/setup/bind-routes.d.ts.map +1 -0
- package/dist/setup/bind-routes.js +311 -0
- package/dist/setup/bind-routes.js.map +1 -0
- package/dist/setup/binding-service.d.ts +86 -0
- package/dist/setup/binding-service.d.ts.map +1 -0
- package/dist/setup/binding-service.js +175 -0
- package/dist/setup/binding-service.js.map +1 -0
- package/dist/setup/index.d.ts +50 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +98 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/persist.d.ts +41 -0
- package/dist/setup/persist.d.ts.map +1 -0
- package/dist/setup/persist.js +201 -0
- package/dist/setup/persist.js.map +1 -0
- package/dist/setup/presenters.d.ts +40 -0
- package/dist/setup/presenters.d.ts.map +1 -0
- package/dist/setup/presenters.js +84 -0
- package/dist/setup/presenters.js.map +1 -0
- package/dist/setup/qr-svg.d.ts +8 -0
- package/dist/setup/qr-svg.d.ts.map +1 -0
- package/dist/setup/qr-svg.js +20 -0
- package/dist/setup/qr-svg.js.map +1 -0
- package/dist/shared/bind-protocol.d.ts +42 -0
- package/dist/shared/bind-protocol.d.ts.map +1 -0
- package/dist/shared/bind-protocol.js +19 -0
- package/dist/shared/bind-protocol.js.map +1 -0
- package/dist/shared/index.d.ts +3 -3
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +3 -3
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/send-helper.js +1 -1
- package/dist/shared/utils.d.ts +10 -3
- package/dist/shared/utils.d.ts.map +1 -1
- package/dist/shared/utils.js +47 -6
- package/dist/shared/utils.js.map +1 -1
- package/dist/transport/attachment.d.ts +18 -7
- package/dist/transport/attachment.d.ts.map +1 -1
- package/dist/transport/attachment.js +77 -30
- package/dist/transport/attachment.js.map +1 -1
- package/dist/transport/inbound.d.ts +5 -4
- package/dist/transport/inbound.d.ts.map +1 -1
- package/dist/transport/inbound.js +120 -80
- package/dist/transport/inbound.js.map +1 -1
- package/dist/transport/index.d.ts +4 -4
- package/dist/transport/index.js +4 -4
- package/dist/transport/msgid-cache.d.ts +23 -0
- package/dist/transport/msgid-cache.d.ts.map +1 -0
- package/dist/transport/msgid-cache.js +57 -0
- package/dist/transport/msgid-cache.js.map +1 -0
- package/dist/transport/outbound-buffer.d.ts +9 -6
- package/dist/transport/outbound-buffer.d.ts.map +1 -1
- package/dist/transport/outbound-buffer.js +5 -5
- package/dist/transport/outbound-buffer.js.map +1 -1
- package/dist/transport/outbound.d.ts +9 -9
- package/dist/transport/outbound.d.ts.map +1 -1
- package/dist/transport/outbound.js +7 -7
- package/dist/transport/outbound.js.map +1 -1
- package/dist/transport/reply-limiter.d.ts +31 -0
- package/dist/transport/reply-limiter.d.ts.map +1 -0
- package/dist/transport/reply-limiter.js +50 -0
- package/dist/transport/reply-limiter.js.map +1 -0
- package/dist/transport/reply-target.d.ts +29 -0
- package/dist/transport/reply-target.d.ts.map +1 -0
- package/dist/transport/reply-target.js +55 -0
- package/dist/transport/reply-target.js.map +1 -0
- package/dist/transport/streaming-writer.d.ts +3 -3
- package/dist/transport/streaming-writer.d.ts.map +1 -1
- package/dist/transport/streaming-writer.js +1 -1
- package/dist/transport/streaming-writer.js.map +1 -1
- package/dist/transport/tool-presenter.d.ts +0 -1
- package/dist/transport/tool-presenter.d.ts.map +1 -1
- package/dist/transport/tool-presenter.js +0 -1
- package/dist/transport/tool-presenter.js.map +1 -1
- package/dist/types.d.ts +9 -15
- package/dist/types.d.ts.map +1 -1
- package/docs/assets/qqchannel.jpg +0 -0
- package/docs/assets/qqgroup.jpg +0 -0
- package/docs/assets/qrcode.png +0 -0
- package/lib/client.js +996 -0
- package/lib/client.js.map +1 -0
- package/package.json +44 -7
- package/pnpm-workspace.yaml +1 -0
- package/tsconfig.client.json +19 -0
- package/tsdown.client.config.ts +58 -0
- package/dist/setup.d.ts +0 -24
- package/dist/setup.d.ts.map +0 -1
- package/dist/setup.js +0 -170
- package/dist/setup.js.map +0 -1
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
import { QQBot } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
-
import { SessionManager } from
|
|
3
|
-
import { handleInbound, createOutboundHandler } from
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { SessionManager } from "../session/index.js";
|
|
3
|
+
import { handleInbound, createOutboundHandler } from "../transport/index.js";
|
|
4
|
+
import { ReplyLimiter } from "../transport/reply-limiter.js";
|
|
5
|
+
import { cacheMsgId, cacheEventId } from "../transport/msgid-cache.js";
|
|
6
|
+
import { resolveReplyTarget, sendResolvedMarkdown } from "../transport/reply-target.js";
|
|
7
|
+
import { QuestionChannel } from "../features/question-channel.js";
|
|
8
|
+
import { ApprovalChannel } from "../features/approval-channel.js";
|
|
9
|
+
import { decodeButtonData } from "../features/button-utils.js";
|
|
10
|
+
import { buildUserAgent } from "../shared/index.js";
|
|
11
|
+
import { setupMiddlewares } from "./middleware-setup.js";
|
|
12
|
+
import { startMediaCleanup } from "../media/media-cleaner.js";
|
|
13
|
+
import { ensureVisionInputModal, registerDescribeImageTool } from "../media/vision-tool.js";
|
|
14
|
+
import { registerSendFileTool } from "../media/send-file-tool.js";
|
|
15
|
+
/**
|
|
16
|
+
* interaction 统一分发器:按 button_data 的顶层 `t` 判别字段,路由到对应
|
|
17
|
+
* channel(question / approval)。QQ 只有一个 interaction 入口,集中路由
|
|
18
|
+
* 避免多通道各自 try 导致误判。
|
|
19
|
+
*/
|
|
20
|
+
function dispatchInteraction(event, manager) {
|
|
21
|
+
const raw = event.data?.resolved?.button_data;
|
|
22
|
+
if (!raw)
|
|
23
|
+
return false;
|
|
24
|
+
const button = decodeButtonData(raw);
|
|
25
|
+
if (!button)
|
|
26
|
+
return false;
|
|
27
|
+
if (button.t === 'question')
|
|
28
|
+
return manager.questionChannel?.handleInteraction(event) ?? false;
|
|
29
|
+
if (button.t === 'approval')
|
|
30
|
+
return manager.approvalChannel?.handleInteraction(event) ?? false;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
6
33
|
export async function bootstrapGateway(ctx, agents, config, logger) {
|
|
7
34
|
const manager = new SessionManager(ctx, agents, config, logger);
|
|
8
35
|
// ── 初始化 QQ Bot SDK ──
|
|
@@ -22,13 +49,15 @@ export async function bootstrapGateway(ctx, agents, config, logger) {
|
|
|
22
49
|
// ── 入站:经过中间件链后的消息交给 dsh agent ──
|
|
23
50
|
bot.on('message', async (mCtx) => {
|
|
24
51
|
const msg = mCtx.message;
|
|
52
|
+
// 记录最近 msgId,供无上下文的出站发送(文件发送显式 target、主动推送等)获取被动回复目标
|
|
53
|
+
cacheMsgId(mCtx.replyTarget.scope, mCtx.replyTarget.targetId, mCtx.replyTarget.msgId);
|
|
25
54
|
if (config.debug) {
|
|
26
55
|
logger.debug(`← message (post-middleware): ${JSON.stringify(msg, null, 2).slice(0, 500)}`);
|
|
27
56
|
}
|
|
28
|
-
await handleInbound(
|
|
57
|
+
await handleInbound(mCtx, manager, config, logger);
|
|
29
58
|
});
|
|
30
59
|
// ── 出站:dsh session/event → QQ 消息 ──
|
|
31
|
-
// 获取 tools
|
|
60
|
+
// 获取 tools 服务(工具结果结构化展示),可选
|
|
32
61
|
let toolsRegistry;
|
|
33
62
|
try {
|
|
34
63
|
toolsRegistry = ctx.get('tools');
|
|
@@ -36,9 +65,11 @@ export async function bootstrapGateway(ctx, agents, config, logger) {
|
|
|
36
65
|
catch {
|
|
37
66
|
toolsRegistry = undefined;
|
|
38
67
|
}
|
|
39
|
-
// 发送适配器:将 QQBot 实例适配为 QQBotSender(openStream
|
|
68
|
+
// 发送适配器:将 QQBot 实例适配为 QQBotSender(openStream 参数形态不同)。
|
|
69
|
+
// sendMarkdown 统一做被动回复限额管控:同一 msgId 超限/过期时降级主动推送。
|
|
70
|
+
const replyLimiter = new ReplyLimiter({ limit: 4 });
|
|
40
71
|
const sender = {
|
|
41
|
-
sendMarkdown: (target, content) => bot
|
|
72
|
+
sendMarkdown: (target, content, opts) => sendResolvedMarkdown(bot, resolveReplyTarget(target, replyLimiter, true), content, opts),
|
|
42
73
|
openStream: (target) => bot.openStream({
|
|
43
74
|
target: {
|
|
44
75
|
scope: target.scope,
|
|
@@ -50,12 +81,57 @@ export async function bootstrapGateway(ctx, agents, config, logger) {
|
|
|
50
81
|
const outboundHandler = createOutboundHandler(manager, sender, config, logger, toolsRegistry);
|
|
51
82
|
ctx
|
|
52
83
|
.on('session/event', outboundHandler);
|
|
84
|
+
// ── 问答通道(ask_user_question → QQ 文本 + 按钮) ──
|
|
85
|
+
const questionChannel = new QuestionChannel(manager, sender, config, logger);
|
|
86
|
+
manager.questionChannel = questionChannel;
|
|
87
|
+
questionChannel.install(ctx);
|
|
88
|
+
// ── 审批通道(approval/request → QQ 两按钮审批) ──
|
|
89
|
+
const approvalChannel = new ApprovalChannel(manager, sender, logger);
|
|
90
|
+
manager.approvalChannel = approvalChannel;
|
|
91
|
+
approvalChannel.install(ctx);
|
|
92
|
+
// ── 按钮点击回调(interaction):统一分发到问答/审批通道 ──
|
|
93
|
+
bot.on('interaction', async (_iCtx, event) => {
|
|
94
|
+
// scope/targetId 推导对齐消息事件(inbound.ts):按 scene 判定类型,群用 group_openid,私聊用 user_openid
|
|
95
|
+
const scope = event.scene === 'group' ? 'group' : 'c2c';
|
|
96
|
+
const targetId = scope === 'group' ? (event.group_openid ?? event.user_openid) : event.user_openid;
|
|
97
|
+
// 记录互动事件 id,作为后续被动回复候选(event_id)
|
|
98
|
+
cacheEventId(scope, targetId, event.id);
|
|
99
|
+
const matched = dispatchInteraction(event, manager);
|
|
100
|
+
await bot.acknowledgeInteraction(event.id, matched ? 0 : 3).catch(() => { });
|
|
101
|
+
});
|
|
53
102
|
bot.on('error', (err) => {
|
|
54
103
|
logger.error(`bot error: ${err instanceof Error ? err.message : String(err)}`);
|
|
55
104
|
});
|
|
105
|
+
// 掉线可观测:willReconnect=false 表示不会再重连(随后 bot.start() 的 Promise 会失败)
|
|
106
|
+
bot.on('disconnected', (event) => {
|
|
107
|
+
const detail = `code=${event.code}${event.reason ? ` reason=${event.reason}` : ''}`;
|
|
108
|
+
if (event.willReconnect) {
|
|
109
|
+
logger.warn(`Bot disconnected (${detail}), reconnecting...`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
logger.error(`Bot disconnected permanently (${detail}), giving up`);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
56
115
|
bot.on('ready', () => {
|
|
57
116
|
console.log(`[im-qqbot] Bot ready! appId=${config.appId}`);
|
|
58
117
|
});
|
|
118
|
+
// ── 富媒体过期清理 ──
|
|
119
|
+
if (config.media.enabled) {
|
|
120
|
+
startMediaCleanup(ctx, config.media.ttlHours, logger);
|
|
121
|
+
}
|
|
122
|
+
// ── 视觉工具注册(qqbot_describe_image,复用 dsh llm + attachments) ──
|
|
123
|
+
ensureVisionInputModal(config.vision, logger);
|
|
124
|
+
registerDescribeImageTool(ctx, config.vision, logger);
|
|
125
|
+
// ── 附件发送工具注册(qqbot_send_file) ──
|
|
126
|
+
// 包装 bot:让文件发送也走 msgId 兜底 + 被动回复限额管控。
|
|
127
|
+
// 注意:SDK 文件发送暂不支持 event_id,故 allowEvent=false,跳过 event 候选。
|
|
128
|
+
const mediaSender = {
|
|
129
|
+
sendImage: (target, source) => bot.sendImage(resolveReplyTarget(target, replyLimiter, false), source),
|
|
130
|
+
sendVideo: (target, source) => bot.sendVideo(resolveReplyTarget(target, replyLimiter, false), source),
|
|
131
|
+
sendVoice: (target, source) => bot.sendVoice(resolveReplyTarget(target, replyLimiter, false), source),
|
|
132
|
+
sendFile: (target, source, opts) => bot.sendFile(resolveReplyTarget(target, replyLimiter, false), source, opts),
|
|
133
|
+
};
|
|
134
|
+
registerSendFileTool(ctx, mediaSender, manager, config, logger);
|
|
59
135
|
// ── 生命周期 ──
|
|
60
136
|
ctx
|
|
61
137
|
.effect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAyB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"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"}
|
package/dist/gateway/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { setupMiddlewares } from './middleware-setup.
|
|
2
|
-
export { bootstrapGateway } from './bootstrap.
|
|
1
|
+
export { setupMiddlewares } from './middleware-setup.ts';
|
|
2
|
+
export { bootstrapGateway } from './bootstrap.ts';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/gateway/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { setupMiddlewares } from
|
|
2
|
-
export { bootstrapGateway } from
|
|
1
|
+
export { setupMiddlewares } from "./middleware-setup.js";
|
|
2
|
+
export { bootstrapGateway } from "./bootstrap.js";
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* 中间件负责过滤与上下文富化;最终消息统一由 bot.on('message') 处理转发。
|
|
6
6
|
*/
|
|
7
7
|
import type { QQBot } from '@tencent-connect/qqbot-nodejs';
|
|
8
|
-
import type { ImQQBotConfig } from '../config.
|
|
9
|
-
import type { SessionManager } from '../session/index.
|
|
10
|
-
import type { Logger } from '../types.
|
|
8
|
+
import type { ImQQBotConfig } from '../config.ts';
|
|
9
|
+
import type { SessionManager } from '../session/index.ts';
|
|
10
|
+
import type { Logger } from '../types.ts';
|
|
11
11
|
export declare function setupMiddlewares(bot: QQBot, config: ImQQBotConfig, manager: SessionManager, logger: Logger): void;
|
|
12
12
|
//# sourceMappingURL=middleware-setup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware-setup.d.ts","sourceRoot":"","sources":["../../src/gateway/middleware-setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"middleware-setup.d.ts","sourceRoot":"","sources":["../../src/gateway/middleware-setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAe3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,KAAK,EACV,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb,IAAI,CAuFN"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { errorHandler, messageFilter, accessPolicy, mentionGate, contentSanitizer, rateLimiter, slashCommand, concurrencyGuard, typingIndicator, quoteRef, historyBuffer, envelopeFormatter, } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
-
import { buildCommandList } from
|
|
3
|
-
import { attachmentProcessor } from
|
|
4
|
-
import {
|
|
2
|
+
import { buildCommandList } from "../commands/index.js";
|
|
3
|
+
import { attachmentProcessor } from "../middleware/attachment.js";
|
|
4
|
+
import { questionAnswer } from "../middleware/question-answer.js";
|
|
5
|
+
import { getHistoryStore, historyGroupKey } from "../features/history-store.js";
|
|
5
6
|
export function setupMiddlewares(bot, config, manager, logger) {
|
|
6
7
|
// 1. 错误兜底(最外层洋葱皮)
|
|
7
8
|
bot.use(errorHandler());
|
|
@@ -48,18 +49,19 @@ export function setupMiddlewares(bot, config, manager, logger) {
|
|
|
48
49
|
bot.use(rateLimiter());
|
|
49
50
|
// 8. 斜杠命令(在 concurrencyGuard 之前,命令匹配后不排队直接响应)
|
|
50
51
|
const slash = slashCommand({
|
|
51
|
-
autoHelp
|
|
52
|
+
// 关闭 autoHelp:help 命令由 qqbot 注册为 /bot-help,
|
|
53
|
+
// 避免 SDK 再自动注册一个无前缀的 /help 造成重复
|
|
54
|
+
autoHelp: false,
|
|
52
55
|
commands: buildCommandList({ manager, config }),
|
|
53
56
|
});
|
|
54
57
|
bot.use(slash.middleware);
|
|
58
|
+
// 8.5. 待答问题截获(在 concurrencyGuard 之前,答案消息不排队直接作答)
|
|
59
|
+
bot.use(questionAnswer(manager));
|
|
55
60
|
// 9. 并发串行 + 消息合并(同 peer 排队,避免 session 冲突)
|
|
56
61
|
bot.use(concurrencyGuard({
|
|
57
62
|
strategy: 'merge',
|
|
58
63
|
maxQueue: config.maxQueue,
|
|
59
64
|
maxProcessingMs: config.processingTimeoutMs,
|
|
60
|
-
urgentPredicate: (mCtx) => {
|
|
61
|
-
return (mCtx.message.content ?? '').trim() === '/bot-stop';
|
|
62
|
-
},
|
|
63
65
|
}));
|
|
64
66
|
// 10. C2C 输入状态指示
|
|
65
67
|
bot.use(typingIndicator());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware-setup.js","sourceRoot":"","sources":["../../src/gateway/middleware-setup.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,aAAa,EACb,iBAAiB,GAClB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEhF,MAAM,UAAU,gBAAgB,CAC9B,GAAU,EACV,MAAqB,EACrB,OAAuB,EACvB,MAAc;IAEd,kBAAkB;IAClB,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAExB,wBAAwB;IACxB,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAEhD,qBAAqB;IACrB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QACnB,GAAG,EAAE;YACH,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;YAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;SAC1E;QACD,KAAK,EAAE;YACL,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS;YAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;SAC9E;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACzB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,MAAM,CAAC,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;KACF,CAAC,CAAC,CAAC;IAEJ,0CAA0C;IAC1C,6DAA6D;IAC7D,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC,YAAY;QAC1B,KAAK,EAAE,eAAe,EAAE;QACxB,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;YAChB,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;YACpC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,GAAG;gBAAE,OAAO,SAAS,CAAC;YAC3D,OAAO,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;KACF,CAAC,CAAC,CAAC;IAEJ,gBAAgB;IAChB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;QAClB,qBAAqB,EAAE,MAAM,CAAC,cAAc;KAC7C,CAAC,CAAC,CAAC;IAEJ,+BAA+B;IAC/B,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC;QACvB,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC,CAAC;IAEJ,mCAAmC;IACnC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;IAEvB,8CAA8C;IAC9C,MAAM,KAAK,GAAG,YAAY,CAAC;QACzB,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"middleware-setup.js","sourceRoot":"","sources":["../../src/gateway/middleware-setup.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* dsh-im-qqbot — QQ Bot IM channel plugin for deepseek-harness
|
|
3
3
|
*
|
|
4
4
|
* Cordis 插件入口。将 QQ 消息平台作为 dsh 的前端协议驱动。
|
|
5
|
-
* 网关组装(中间件编排 + 事件 + 出站 + 生命周期)见 src/gateway
|
|
5
|
+
* 网关组装(中间件编排 + 事件 + 出站 + 生命周期)见 src/gateway/;
|
|
6
|
+
* 凭据绑定编排(扫码状态机 + 端内绑定页路由)见 src/setup/。
|
|
6
7
|
*/
|
|
7
8
|
import type { Context } from '@deepseek-ai/cordis';
|
|
8
|
-
import { type ImQQBotConfig } from './config.
|
|
9
|
+
import { type ImQQBotConfig } from './config.ts';
|
|
9
10
|
export declare const name = "im-qqbot";
|
|
10
11
|
export declare const inject: string[];
|
|
11
12
|
export declare const Config: import("@deepseek-ai/schemastery").default<ImQQBotConfig>;
|
|
12
|
-
export type { ImQQBotConfig } from './config.
|
|
13
|
+
export type { ImQQBotConfig } from './config.ts';
|
|
13
14
|
export declare function apply(ctx: Context, config: ImQQBotConfig): Promise<void>;
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ/D,eAAO,MAAM,IAAI,aAAa,CAAC;AAC/B,eAAO,MAAM,MAAM,UAAa,CAAC;AACjC,eAAO,MAAM,MAAM,2DAAe,CAAC;AAEnC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D9E"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ConfigSchema } from
|
|
2
|
-
import { bootstrapGateway } from
|
|
3
|
-
import { getProfileDir, resolveEnv } from
|
|
4
|
-
import {
|
|
1
|
+
import { ConfigSchema } from "./config.js";
|
|
2
|
+
import { bootstrapGateway } from "./gateway/index.js";
|
|
3
|
+
import { getProfileDir, resolveEnv } from "./shared/index.js";
|
|
4
|
+
import { ensureCredentials, persistCredentialsToProfile, registerBoundCredentialRoutes } from "./setup/index.js";
|
|
5
5
|
// ── Cordis 插件元数据 ──
|
|
6
6
|
export const name = 'im-qqbot';
|
|
7
7
|
export const inject = ['agents'];
|
|
@@ -10,32 +10,51 @@ export const Config = ConfigSchema;
|
|
|
10
10
|
export async function apply(ctx, config) {
|
|
11
11
|
const agents = ctx.agents;
|
|
12
12
|
const logger = ctx.logger ?? console;
|
|
13
|
-
console.log('[im-qqbot] apply() called');
|
|
14
13
|
let appId = resolveEnv(config.appId, 'QQBOT_APPID');
|
|
15
14
|
let appSecret = resolveEnv(config.appSecret, 'QQBOT_SECRET');
|
|
16
15
|
// ── 凭据缺失时唤起扫码绑定 ──
|
|
17
16
|
if (!appId || !appSecret) {
|
|
18
|
-
logger.info('
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
logger.info('凭据未配置,启动扫码绑定...');
|
|
18
|
+
// 关键:不 await 扫码结果。boot 会等 Loader 树稳定(loader.await()),
|
|
19
|
+
// 无限期等待用户扫码会阻塞 Host ready——Desktop 界面无法进入、
|
|
20
|
+
// Web 的 URL 延迟输出。绑定编排(路由/呈现/生命周期)在
|
|
21
|
+
// ensureCredentials 的同步阶段即完成,凭据就绪后由异步链接管。
|
|
22
|
+
void ensureCredentials(ctx, { logger, config: { ...config } })
|
|
23
|
+
.then((credentials) => {
|
|
24
|
+
if (!credentials) {
|
|
25
|
+
// null 包括:扫码取消、手动提交(已另行持久化)、流程失败
|
|
26
|
+
logger.info('扫码绑定流程结束(未获取凭据或已手动配置)');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// 持久化到 profile:成功则等待热更新重载,失败则用凭据直接启动。
|
|
30
|
+
// 注意:不写入 process.env——resolveEnv 的 env 回退属于用户显式
|
|
31
|
+
// export 的配置语义,运行时写入会与解绑清理不对齐(解绑后 HMR
|
|
32
|
+
// 重载的新 fiber 仍从 env 读到旧凭据,状态停留 bound)
|
|
33
|
+
const persisted = persistCredentialsToProfile(credentials, getProfileDir() ?? undefined, logger);
|
|
34
|
+
if (persisted) {
|
|
35
|
+
// 写入 cordis.patch.yml 会触发 dsh 热更新,自动重新加载本插件。
|
|
36
|
+
logger.info('配置已保存,等待热更新重新加载...');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
logger.warn('凭据未能持久化,本次进程将使用环境变量凭据启动(重启后需重新绑定)');
|
|
40
|
+
// 本 fiber 已激活(ctx 有效),直接以凭据启动网关
|
|
41
|
+
void bootstrapGateway(ctx, agents, {
|
|
42
|
+
...config,
|
|
43
|
+
appId: credentials.appId,
|
|
44
|
+
appSecret: credentials.appSecret,
|
|
45
|
+
}, logger).catch((err) => {
|
|
46
|
+
logger.error(`网关启动失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
47
|
+
});
|
|
48
|
+
})
|
|
49
|
+
.catch((err) => {
|
|
50
|
+
// 全兜:unhandled rejection 会被宿主 fail-loud 判致命
|
|
51
|
+
logger.error(`扫码绑定流程异常: ${err instanceof Error ? err.message : String(err)}`);
|
|
52
|
+
});
|
|
53
|
+
// apply 立即完成,插件 fiber 进入 ACTIVE,Host ready 不再被阻塞
|
|
54
|
+
return;
|
|
38
55
|
}
|
|
56
|
+
// 已绑定:注册常驻路由(状态回显 + 手动编辑/更换凭据 + 配置编辑)
|
|
57
|
+
registerBoundCredentialRoutes(ctx, logger, appId, { ...config });
|
|
39
58
|
const resolvedConfig = { ...config, appId, appSecret };
|
|
40
59
|
await bootstrapGateway(ctx, agents, resolvedConfig, logger);
|
|
41
60
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Logger } from '../types.ts';
|
|
3
|
+
/** 富媒体下载根目录(attachment.ts 复用) */
|
|
4
|
+
export declare const MEDIA_ROOT: string;
|
|
5
|
+
/**
|
|
6
|
+
* 清理过期的富媒体文件(按文件 mtime 判断,异步并发执行,不阻塞事件循环)
|
|
7
|
+
*
|
|
8
|
+
* @param ttlHours 保留时长(小时),<=0 表示永不过期(跳过清理)
|
|
9
|
+
* @returns 删除的文件数
|
|
10
|
+
*/
|
|
11
|
+
export declare function cleanupExpiredMedia(ttlHours: number, logger?: Logger): Promise<number>;
|
|
12
|
+
/**
|
|
13
|
+
* 启动富媒体过期清理:启动时清理一次 + 定期清理(每 1 小时)
|
|
14
|
+
*
|
|
15
|
+
* 用 ctx.effect 挂载定时器,插件卸载时自动 clearInterval。
|
|
16
|
+
* ttlHours <= 0 时不启动(永不过期)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function startMediaCleanup(ctx: Context, ttlHours: number, logger: Logger): void;
|
|
19
|
+
//# sourceMappingURL=media-cleaner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-cleaner.d.ts","sourceRoot":"","sources":["../../src/media/media-cleaner.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,iCAAiC;AACjC,eAAO,MAAM,UAAU,QAA4C,CAAC;AAKpE;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB5F;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA4BtF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 富媒体过期清理 — 避免下载文件持续膨胀
|
|
3
|
+
*
|
|
4
|
+
* 下载目录 ~/.dsh-qqbot/media,文件写入后不再变更,故文件 mtime 即「下载时间」。
|
|
5
|
+
* 清理时按文件 mtime 判断是否超过保留时长。
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { readdir, rm, stat } from 'node:fs/promises';
|
|
9
|
+
import { join, resolve } from 'node:path';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
/** 富媒体下载根目录(attachment.ts 复用) */
|
|
12
|
+
export const MEDIA_ROOT = resolve(homedir(), '.dsh-qqbot', 'media');
|
|
13
|
+
/** 定期清理间隔(毫秒),固定 1 小时 */
|
|
14
|
+
const CLEANUP_INTERVAL_MS = 60 * 60 * 1000;
|
|
15
|
+
/**
|
|
16
|
+
* 清理过期的富媒体文件(按文件 mtime 判断,异步并发执行,不阻塞事件循环)
|
|
17
|
+
*
|
|
18
|
+
* @param ttlHours 保留时长(小时),<=0 表示永不过期(跳过清理)
|
|
19
|
+
* @returns 删除的文件数
|
|
20
|
+
*/
|
|
21
|
+
export async function cleanupExpiredMedia(ttlHours, logger) {
|
|
22
|
+
if (ttlHours <= 0)
|
|
23
|
+
return 0;
|
|
24
|
+
if (!existsSync(MEDIA_ROOT))
|
|
25
|
+
return 0;
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
const ttlMs = ttlHours * 60 * 60 * 1000;
|
|
28
|
+
const entries = await readdir(MEDIA_ROOT, { withFileTypes: true });
|
|
29
|
+
const files = entries.filter(entry => entry.isFile()).map(entry => entry.name);
|
|
30
|
+
const results = await Promise.all(files.map(async (name) => {
|
|
31
|
+
const filePath = join(MEDIA_ROOT, name);
|
|
32
|
+
try {
|
|
33
|
+
const info = await stat(filePath);
|
|
34
|
+
if (now - info.mtimeMs <= ttlMs)
|
|
35
|
+
return false;
|
|
36
|
+
await rm(filePath, { force: true });
|
|
37
|
+
logger?.debug(`im-qqbot: cleaned expired media: ${name}`);
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
logger?.warn(`im-qqbot: media cleanup failed for ${name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}));
|
|
45
|
+
return results.filter(Boolean).length;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 启动富媒体过期清理:启动时清理一次 + 定期清理(每 1 小时)
|
|
49
|
+
*
|
|
50
|
+
* 用 ctx.effect 挂载定时器,插件卸载时自动 clearInterval。
|
|
51
|
+
* ttlHours <= 0 时不启动(永不过期)。
|
|
52
|
+
*/
|
|
53
|
+
export function startMediaCleanup(ctx, ttlHours, logger) {
|
|
54
|
+
if (ttlHours <= 0)
|
|
55
|
+
return;
|
|
56
|
+
logger.info(`im-qqbot: media cleanup started (ttl=${ttlHours}h, interval=1h, root=${MEDIA_ROOT})`);
|
|
57
|
+
// 启动时立即清理一次(异步,不阻塞启动流程)
|
|
58
|
+
void cleanupExpiredMedia(ttlHours, logger)
|
|
59
|
+
.then((cleaned) => {
|
|
60
|
+
if (cleaned > 0)
|
|
61
|
+
logger.info(`im-qqbot: cleaned ${cleaned} expired media files`);
|
|
62
|
+
})
|
|
63
|
+
.catch((err) => {
|
|
64
|
+
logger.warn(`im-qqbot: media cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
65
|
+
});
|
|
66
|
+
ctx
|
|
67
|
+
.effect(() => {
|
|
68
|
+
const timer = setInterval(() => {
|
|
69
|
+
void cleanupExpiredMedia(ttlHours, logger)
|
|
70
|
+
.then((n) => {
|
|
71
|
+
if (n > 0)
|
|
72
|
+
logger.info(`im-qqbot: cleaned ${n} expired media files`);
|
|
73
|
+
})
|
|
74
|
+
.catch((err) => {
|
|
75
|
+
logger.warn(`im-qqbot: media cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
76
|
+
});
|
|
77
|
+
}, CLEANUP_INTERVAL_MS);
|
|
78
|
+
return async () => { clearInterval(timer); };
|
|
79
|
+
}, 'im-qqbot.media-cleanup');
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=media-cleaner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-cleaner.js","sourceRoot":"","sources":["../../src/media/media-cleaner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { ImQQBotConfig } from '../config.ts';
|
|
3
|
+
import type { SessionManager } from '../session/index.ts';
|
|
4
|
+
import type { Logger, ReplyTarget } from '../types.ts';
|
|
5
|
+
/** 工具名(qqbot 前缀避免与其他通道的同名工具冲突) */
|
|
6
|
+
export declare const SEND_FILE_TOOL_NAME = "qqbot_send_file";
|
|
7
|
+
/** 发送器最小接口(QQBot 实例满足) */
|
|
8
|
+
interface MediaSendResult {
|
|
9
|
+
upload: {
|
|
10
|
+
file_uuid: string;
|
|
11
|
+
};
|
|
12
|
+
message?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface MediaSenderLike {
|
|
17
|
+
sendImage(target: ReplyTarget, source: {
|
|
18
|
+
localPath?: string;
|
|
19
|
+
}): Promise<MediaSendResult>;
|
|
20
|
+
sendVideo(target: ReplyTarget, source: {
|
|
21
|
+
localPath?: string;
|
|
22
|
+
}): Promise<MediaSendResult>;
|
|
23
|
+
sendVoice(target: ReplyTarget, source: {
|
|
24
|
+
localPath?: string;
|
|
25
|
+
}): Promise<MediaSendResult>;
|
|
26
|
+
sendFile(target: ReplyTarget, source: {
|
|
27
|
+
localPath?: string;
|
|
28
|
+
}, opts?: {
|
|
29
|
+
fileName?: string;
|
|
30
|
+
}): Promise<MediaSendResult>;
|
|
31
|
+
}
|
|
32
|
+
/** 注册 qqbot_send_file 工具(tools 服务缺失时优雅降级,不阻断插件启动) */
|
|
33
|
+
export declare function registerSendFileTool(ctx: Context, bot: MediaSenderLike, manager: SessionManager, config: ImQQBotConfig, logger: Logger): void;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=send-file-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-file-tool.d.ts","sourceRoot":"","sources":["../../src/media/send-file-tool.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGvD,kCAAkC;AAClC,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAQrD,0BAA0B;AAC1B,UAAU,eAAe;IACvB,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACzF,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACzF,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACzF,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACvH;AAwCD,qDAAqD;AACrD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,IAAI,CA4GN"}
|