@tencent-connect/dsh-qqbot 0.1.0
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 +68 -0
- package/LICENSE +21 -0
- package/README.md +142 -0
- package/README_EN.md +142 -0
- package/cordis.patch.yml +32 -0
- package/cordis.yml +69 -0
- package/dist/commands/help.d.ts +11 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +21 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +27 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/misc.d.ts +12 -0
- package/dist/commands/misc.d.ts.map +1 -0
- package/dist/commands/misc.js +30 -0
- package/dist/commands/misc.js.map +1 -0
- package/dist/commands/model.d.ts +7 -0
- package/dist/commands/model.d.ts.map +1 -0
- package/dist/commands/model.js +58 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/session.d.ts +10 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +26 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +24 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/types.d.ts +12 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/config.d.ts +50 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +33 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +1 -0
- package/dist/model/index.d.ts +10 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +9 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/model-resolver.d.ts +82 -0
- package/dist/model/model-resolver.d.ts.map +1 -0
- package/dist/model/model-resolver.js +142 -0
- package/dist/model/model-resolver.js.map +1 -0
- package/dist/model/prefs-store.d.ts +24 -0
- package/dist/model/prefs-store.d.ts.map +1 -0
- package/dist/model/prefs-store.js +94 -0
- package/dist/model/prefs-store.js.map +1 -0
- package/dist/model/settings-reader.d.ts +19 -0
- package/dist/model/settings-reader.d.ts.map +1 -0
- package/dist/model/settings-reader.js +76 -0
- package/dist/model/settings-reader.js.map +1 -0
- package/dist/model/types.d.ts +15 -0
- package/dist/model/types.d.ts.map +1 -0
- package/dist/model/types.js +5 -0
- package/dist/model/types.js.map +1 -0
- package/dist/session/idle-evictor.d.ts +18 -0
- package/dist/session/idle-evictor.d.ts.map +1 -0
- package/dist/session/idle-evictor.js +31 -0
- package/dist/session/idle-evictor.js.map +1 -0
- package/dist/session/index.d.ts +9 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +8 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/session-manager.d.ts +44 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +341 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/types.d.ts +124 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/setup.d.ts +24 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +135 -0
- package/dist/setup.js.map +1 -0
- package/dist/shared/index.d.ts +7 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +7 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/scope.d.ts +14 -0
- package/dist/shared/scope.d.ts.map +1 -0
- package/dist/shared/scope.js +12 -0
- package/dist/shared/scope.js.map +1 -0
- package/dist/shared/send-helper.d.ts +11 -0
- package/dist/shared/send-helper.d.ts.map +1 -0
- package/dist/shared/send-helper.js +13 -0
- package/dist/shared/send-helper.js.map +1 -0
- package/dist/shared/utils.d.ts +19 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/dist/shared/utils.js +66 -0
- package/dist/shared/utils.js.map +1 -0
- package/dist/transport/chunker.d.ts +14 -0
- package/dist/transport/chunker.d.ts.map +1 -0
- package/dist/transport/chunker.js +78 -0
- package/dist/transport/chunker.js.map +1 -0
- package/dist/transport/inbound.d.ts +8 -0
- package/dist/transport/inbound.d.ts.map +1 -0
- package/dist/transport/inbound.js +223 -0
- package/dist/transport/inbound.js.map +1 -0
- package/dist/transport/index.d.ts +10 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +10 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/outbound-buffer.d.ts +32 -0
- package/dist/transport/outbound-buffer.d.ts.map +1 -0
- package/dist/transport/outbound-buffer.js +65 -0
- package/dist/transport/outbound-buffer.js.map +1 -0
- package/dist/transport/outbound.d.ts +26 -0
- package/dist/transport/outbound.d.ts.map +1 -0
- package/dist/transport/outbound.js +92 -0
- package/dist/transport/outbound.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/install.sh +108 -0
- package/package.json +75 -0
- package/pnpm-workspace.yaml +16 -0
- package/scripts/prepare-test-pkg.js +23 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { chunkMarkdownText } from './chunker.js';
|
|
2
|
+
export class OutboundBuffer {
|
|
3
|
+
record;
|
|
4
|
+
bot;
|
|
5
|
+
limit;
|
|
6
|
+
logger;
|
|
7
|
+
buffer = '';
|
|
8
|
+
timer = null;
|
|
9
|
+
flushing = false;
|
|
10
|
+
constructor(record, bot, limit, logger) {
|
|
11
|
+
this.record = record;
|
|
12
|
+
this.bot = bot;
|
|
13
|
+
this.limit = limit;
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
}
|
|
16
|
+
/** 追加文本增量 */
|
|
17
|
+
append(text) {
|
|
18
|
+
this.buffer += text;
|
|
19
|
+
}
|
|
20
|
+
/** 获取当前累积文本 */
|
|
21
|
+
get text() {
|
|
22
|
+
return this.buffer;
|
|
23
|
+
}
|
|
24
|
+
/** 安排延迟发送(debounce) */
|
|
25
|
+
scheduleSend(delayMs) {
|
|
26
|
+
if (this.timer)
|
|
27
|
+
return;
|
|
28
|
+
this.timer = setTimeout(() => {
|
|
29
|
+
this.timer = null;
|
|
30
|
+
void this.flush();
|
|
31
|
+
}, delayMs);
|
|
32
|
+
}
|
|
33
|
+
/** 立即发送所有累积文本 */
|
|
34
|
+
async flush() {
|
|
35
|
+
if (this.flushing || !this.buffer.trim())
|
|
36
|
+
return;
|
|
37
|
+
this.flushing = true;
|
|
38
|
+
if (this.timer) {
|
|
39
|
+
clearTimeout(this.timer);
|
|
40
|
+
this.timer = null;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const chunks = chunkMarkdownText(this.buffer, this.limit);
|
|
44
|
+
for (const chunk of chunks) {
|
|
45
|
+
await this.bot.sendMarkdown(this.record.replyTarget, chunk);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
this.logger.error(`im-qqbot: sendMarkdown failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
this.buffer = '';
|
|
53
|
+
this.flushing = false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** 取消未发送的定时器 */
|
|
57
|
+
cancel() {
|
|
58
|
+
if (this.timer) {
|
|
59
|
+
clearTimeout(this.timer);
|
|
60
|
+
this.timer = null;
|
|
61
|
+
}
|
|
62
|
+
this.buffer = '';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=outbound-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-buffer.js","sourceRoot":"","sources":["../../src/transport/outbound-buffer.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOjD,MAAM,OAAO,cAAc;IAMN;IACA;IACA;IACA;IARX,MAAM,GAAG,EAAE,CAAC;IACZ,KAAK,GAAyC,IAAI,CAAC;IACnD,QAAQ,GAAG,KAAK,CAAC;IAEzB,YACmB,MAAqB,EACrB,GAAgB,EAChB,KAAa,EACb,MAAc;QAHd,WAAM,GAAN,MAAM,CAAe;QACrB,QAAG,GAAH,GAAG,CAAa;QAChB,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAQ;IAC9B,CAAC;IAEJ,aAAa;IACb,MAAM,CAAC,IAAY;QACjB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IACtB,CAAC;IAED,eAAe;IACf,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,uBAAuB;IACvB,YAAY,CAAC,OAAe;QAC1B,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,EAAE,OAAO,CAAC,CAAC;IACd,CAAC;IAED,iBAAiB;IACjB,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1G,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 出站处理器 — dsh session/event → QQ 消息发送
|
|
3
|
+
*/
|
|
4
|
+
import type { SessionManager } from '../session/index.js';
|
|
5
|
+
import type { ImQQBotConfig } from '../config.js';
|
|
6
|
+
import type { Logger } from '../types.js';
|
|
7
|
+
import { type QQBotSender } from './outbound-buffer.js';
|
|
8
|
+
export type { QQBotSender } from './outbound-buffer.js';
|
|
9
|
+
/** dsh SessionEvent 简化类型 */
|
|
10
|
+
export interface SessionEvent {
|
|
11
|
+
type: string;
|
|
12
|
+
data: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** dsh Session 简化类型 */
|
|
15
|
+
export interface SessionLike {
|
|
16
|
+
header: {
|
|
17
|
+
id: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 创建出站事件处理器
|
|
22
|
+
*
|
|
23
|
+
* 返回一个 handler 函数,应注册到 ctx.on('session/event', handler)
|
|
24
|
+
*/
|
|
25
|
+
export declare function createOutboundHandler(manager: SessionManager, bot: QQBotSender, config: ImQQBotConfig, logger: Logger): (session: SessionLike, event: SessionEvent) => void;
|
|
26
|
+
//# sourceMappingURL=outbound.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,uBAAuB;AACvB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CA0BrD"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { chunkMarkdownText } from './chunker.js';
|
|
2
|
+
import { OutboundBuffer } from './outbound-buffer.js';
|
|
3
|
+
/**
|
|
4
|
+
* 创建出站事件处理器
|
|
5
|
+
*
|
|
6
|
+
* 返回一个 handler 函数,应注册到 ctx.on('session/event', handler)
|
|
7
|
+
*/
|
|
8
|
+
export function createOutboundHandler(manager, bot, config, logger) {
|
|
9
|
+
const buffers = new Map();
|
|
10
|
+
const limit = config.textChunkLimit;
|
|
11
|
+
return (session, event) => {
|
|
12
|
+
const sessionId = session.header.id;
|
|
13
|
+
const record = manager.findBySessionId(sessionId);
|
|
14
|
+
if (!record)
|
|
15
|
+
return;
|
|
16
|
+
switch (event.type) {
|
|
17
|
+
case 'assistant/chunk': {
|
|
18
|
+
handleChunk(sessionId, record, event, buffers, bot, limit, logger);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
case 'assistant/message': {
|
|
22
|
+
handleMessage(sessionId, record, event, buffers, bot, limit, logger);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
case 'turn/end': {
|
|
26
|
+
handleTurnEnd(sessionId, buffers, logger);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** 处理流式文本增量 */
|
|
33
|
+
function handleChunk(sessionId, record, event, buffers, bot, limit, logger) {
|
|
34
|
+
const chunk = event.data.chunk;
|
|
35
|
+
if (!chunk || chunk.type !== 'text-delta' || !chunk.text)
|
|
36
|
+
return;
|
|
37
|
+
let buffer = buffers.get(sessionId);
|
|
38
|
+
if (!buffer) {
|
|
39
|
+
buffer = new OutboundBuffer(record, bot, limit, logger);
|
|
40
|
+
buffers.set(sessionId, buffer);
|
|
41
|
+
}
|
|
42
|
+
buffer.append(chunk.text);
|
|
43
|
+
}
|
|
44
|
+
/** 处理完整 assistant 消息 */
|
|
45
|
+
function handleMessage(sessionId, record, event, buffers, bot, limit, logger) {
|
|
46
|
+
const buffer = buffers.get(sessionId);
|
|
47
|
+
if (buffer && buffer.text.trim()) {
|
|
48
|
+
void buffer.flush();
|
|
49
|
+
buffers.delete(sessionId);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const message = event.data;
|
|
53
|
+
const blocks = message?.message?.content;
|
|
54
|
+
if (!blocks || !Array.isArray(blocks))
|
|
55
|
+
return;
|
|
56
|
+
const textParts = [];
|
|
57
|
+
for (const block of blocks) {
|
|
58
|
+
if (block.type === 'text' && block.text) {
|
|
59
|
+
textParts.push(block.text);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const fullText = textParts.join('\n');
|
|
63
|
+
if (!fullText.trim())
|
|
64
|
+
return;
|
|
65
|
+
const chunks = chunkMarkdownText(fullText, limit);
|
|
66
|
+
void (async () => {
|
|
67
|
+
for (const chunk of chunks) {
|
|
68
|
+
try {
|
|
69
|
+
await bot.sendMarkdown(record.replyTarget, chunk);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
logger.error(`im-qqbot: sendMarkdown failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})();
|
|
76
|
+
buffers.delete(sessionId);
|
|
77
|
+
}
|
|
78
|
+
/** 处理轮次结束,清理 buffer */
|
|
79
|
+
function handleTurnEnd(sessionId, buffers, logger) {
|
|
80
|
+
const buffer = buffers.get(sessionId);
|
|
81
|
+
if (buffer) {
|
|
82
|
+
if (buffer.text.trim()) {
|
|
83
|
+
void buffer.flush();
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
buffer.cancel();
|
|
87
|
+
}
|
|
88
|
+
buffers.delete(sessionId);
|
|
89
|
+
}
|
|
90
|
+
logger.debug(`im-qqbot: turn/end sessionId=${sessionId}`);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=outbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../../src/transport/outbound.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-im-qqbot 插件内部类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 会话作用域 */
|
|
5
|
+
export type ChatScope = 'c2c' | 'group';
|
|
6
|
+
/** QQ 回复目标 */
|
|
7
|
+
export interface ReplyTarget {
|
|
8
|
+
scope: ChatScope;
|
|
9
|
+
targetId: string;
|
|
10
|
+
msgId?: string;
|
|
11
|
+
}
|
|
12
|
+
/** QQ 入站消息(简化) */
|
|
13
|
+
export interface QQInboundMessage {
|
|
14
|
+
content?: string;
|
|
15
|
+
senderId: string;
|
|
16
|
+
groupOpenid?: string;
|
|
17
|
+
replyTarget: ReplyTarget;
|
|
18
|
+
attachments?: QQAttachment[];
|
|
19
|
+
}
|
|
20
|
+
/** QQ 附件 */
|
|
21
|
+
export interface QQAttachment {
|
|
22
|
+
contentType: string;
|
|
23
|
+
filename?: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
size?: number;
|
|
26
|
+
}
|
|
27
|
+
/** 插件 Logger 接口 */
|
|
28
|
+
export interface Logger {
|
|
29
|
+
info(msg: string, ...args: unknown[]): void;
|
|
30
|
+
warn(msg: string, ...args: unknown[]): void;
|
|
31
|
+
error(msg: string, ...args: unknown[]): void;
|
|
32
|
+
debug(msg: string, ...args: unknown[]): void;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY;AACZ,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC;AAExC,cAAc;AACd,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,kBAAkB;AAClB,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;CAC9B;AAED,YAAY;AACZ,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,mBAAmB;AACnB,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC9C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/install.sh
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# @tencent-connect/dsh-qqbot 一键安装
|
|
3
|
+
#
|
|
4
|
+
# 走 dsh CLI 的 profile 插件机制:`add` 自动初始化 profile(首层
|
|
5
|
+
# dsh-base),pnpm 安装后按 dsh.bundle.patch 元数据把本包追加为 bundle 层。
|
|
6
|
+
# 无需 DSH 源码,无需 workspace 链接。
|
|
7
|
+
#
|
|
8
|
+
# 用法:
|
|
9
|
+
# sh install.sh # 安装默认包最新版本
|
|
10
|
+
# sh install.sh --version 0.2.0 # 指定版本
|
|
11
|
+
# sh install.sh --pkg @myorg/my-plugin # 指定包名
|
|
12
|
+
# sh install.sh --pkg @myorg/my-plugin --version 1.0.0 # 指定包名+版本
|
|
13
|
+
# sh install.sh --registry https://registry.npmmirror.com # 指定 npm registry
|
|
14
|
+
set -eu
|
|
15
|
+
|
|
16
|
+
# ── 默认值 ──
|
|
17
|
+
PACKAGE="@tencent-connect/dsh-qqbot"
|
|
18
|
+
VERSION=""
|
|
19
|
+
REGISTRY=""
|
|
20
|
+
PROFILE="qqbot"
|
|
21
|
+
|
|
22
|
+
# ── 参数解析 ──
|
|
23
|
+
while [ $# -gt 0 ]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
--pkg)
|
|
26
|
+
shift; PACKAGE="$1" ;;
|
|
27
|
+
--pkg=*)
|
|
28
|
+
PACKAGE="${1#--pkg=}" ;;
|
|
29
|
+
--version)
|
|
30
|
+
shift; VERSION="$1" ;;
|
|
31
|
+
--version=*)
|
|
32
|
+
VERSION="${1#--version=}" ;;
|
|
33
|
+
--registry)
|
|
34
|
+
shift; REGISTRY="$1" ;;
|
|
35
|
+
--registry=*)
|
|
36
|
+
REGISTRY="${1#--registry=}" ;;
|
|
37
|
+
--profile)
|
|
38
|
+
shift; PROFILE="$1" ;;
|
|
39
|
+
--profile=*)
|
|
40
|
+
PROFILE="${1#--profile=}" ;;
|
|
41
|
+
-h|--help)
|
|
42
|
+
echo "用法: sh install.sh [选项]"
|
|
43
|
+
echo
|
|
44
|
+
echo "选项:"
|
|
45
|
+
echo " --pkg <name> 指定 npm 包名 (默认: @tencent-connect/dsh-qqbot)"
|
|
46
|
+
echo " --version <ver> 指定包版本 (默认: latest)"
|
|
47
|
+
echo " --registry <url> 指定 npm registry"
|
|
48
|
+
echo " --profile <name> 指定 dsh profile 名 (默认: qqbot)"
|
|
49
|
+
echo " -h, --help 显示帮助"
|
|
50
|
+
exit 0
|
|
51
|
+
;;
|
|
52
|
+
*)
|
|
53
|
+
echo "未知参数: $1 (使用 --help 查看用法)" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
;;
|
|
56
|
+
esac
|
|
57
|
+
shift
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
# ── 预检 ──
|
|
61
|
+
if ! command -v dsh >/dev/null 2>&1; then
|
|
62
|
+
echo "未检测到 dsh CLI。先安装:" >&2
|
|
63
|
+
echo " npm install -g @deepseek-ai/dsh" >&2
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if ! command -v pnpm >/dev/null 2>&1; then
|
|
68
|
+
echo "未检测到 pnpm。dsh plugin 依赖 pnpm,请先安装:" >&2
|
|
69
|
+
echo " npm install -g pnpm" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# ── 构造安装标识 ──
|
|
74
|
+
INSTALL_SPEC="$PACKAGE"
|
|
75
|
+
if [ -n "$VERSION" ]; then
|
|
76
|
+
INSTALL_SPEC="${PACKAGE}@${VERSION}"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
REGISTRY_ARG=""
|
|
80
|
+
if [ -n "$REGISTRY" ]; then
|
|
81
|
+
REGISTRY_ARG="--registry ${REGISTRY}"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# ── 安装 ──
|
|
85
|
+
echo "=================================================="
|
|
86
|
+
echo " 安装 QQ Bot 插件到 dsh"
|
|
87
|
+
echo "=================================================="
|
|
88
|
+
echo
|
|
89
|
+
echo " 包名: ${INSTALL_SPEC}"
|
|
90
|
+
echo " Profile: ${PROFILE}"
|
|
91
|
+
[ -n "$REGISTRY" ] && echo " Registry: ${REGISTRY}"
|
|
92
|
+
echo
|
|
93
|
+
|
|
94
|
+
dsh plugin --profile "$PROFILE" add "$INSTALL_SPEC" $REGISTRY_ARG
|
|
95
|
+
|
|
96
|
+
echo
|
|
97
|
+
echo "=================================================="
|
|
98
|
+
echo " 安装完成"
|
|
99
|
+
echo "=================================================="
|
|
100
|
+
echo
|
|
101
|
+
echo "配置环境变量:"
|
|
102
|
+
echo " export QQBOT_APPID=\"你的AppID\""
|
|
103
|
+
echo " export QQBOT_SECRET=\"你的AppSecret\""
|
|
104
|
+
echo " export DEEPSEEK_API_KEY=\"你的API Key\""
|
|
105
|
+
echo
|
|
106
|
+
echo "启动:"
|
|
107
|
+
echo " dsh --profile ${PROFILE}"
|
|
108
|
+
echo
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tencent-connect/dsh-qqbot",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "QQ Bot IM channel plugin for deepseek-harness (dsh)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"lint": "eslint src/",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"ci:prepare-test-pkg": "node scripts/prepare-test-pkg.js"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"deepseek-harness",
|
|
24
|
+
"dsh",
|
|
25
|
+
"qqbot",
|
|
26
|
+
"cordis",
|
|
27
|
+
"plugin"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dsh": {
|
|
31
|
+
"bundle": {
|
|
32
|
+
"patch": "./cordis.patch.yml"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@tencent-connect/qqbot-connector": "1.2.0",
|
|
37
|
+
"@tencent-connect/qqbot-nodejs": "^1.0.4",
|
|
38
|
+
"js-yaml": "^4.1.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@tencent-connect/qqbot-connector": "1.2.0",
|
|
42
|
+
"@deepseek-ai/cordis": ">=4.0.1",
|
|
43
|
+
"@deepseek-ai/dsh-agent": ">=0.1.0-rc.6",
|
|
44
|
+
"@deepseek-ai/dsh-llm": ">=0.1.0-rc.6",
|
|
45
|
+
"@deepseek-ai/dsh-session": ">=0.1.0-rc.6",
|
|
46
|
+
"@deepseek-ai/schemastery": ">=3.18.1"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"@deepseek-ai/cordis": {
|
|
50
|
+
"optional": false
|
|
51
|
+
},
|
|
52
|
+
"@deepseek-ai/schemastery": {
|
|
53
|
+
"optional": false
|
|
54
|
+
},
|
|
55
|
+
"@deepseek-ai/dsh-agent": {
|
|
56
|
+
"optional": false
|
|
57
|
+
},
|
|
58
|
+
"@deepseek-ai/dsh-session": {
|
|
59
|
+
"optional": false
|
|
60
|
+
},
|
|
61
|
+
"@deepseek-ai/dsh-llm": {
|
|
62
|
+
"optional": false
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
67
|
+
"@deepseek-ai/dsh-agent": "0.1.0-rc.6",
|
|
68
|
+
"@deepseek-ai/dsh-llm": "0.1.0-rc.6",
|
|
69
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.6",
|
|
70
|
+
"@deepseek-ai/schemastery": "3.18.1",
|
|
71
|
+
"@types/js-yaml": "^4.0.9",
|
|
72
|
+
"@types/node": "^26.2.0",
|
|
73
|
+
"typescript": "^5.5.0"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
allowBuilds:
|
|
2
|
+
esbuild: true
|
|
3
|
+
minimumReleaseAgeExclude:
|
|
4
|
+
- '@deepseek-ai/cordis@4.0.1'
|
|
5
|
+
- '@deepseek-ai/cosmokit@1.8.2'
|
|
6
|
+
- '@deepseek-ai/dsh-agent@0.1.0-rc.6'
|
|
7
|
+
- '@deepseek-ai/dsh-attachment@0.1.0-rc.6'
|
|
8
|
+
- '@deepseek-ai/dsh-brand@0.1.0-rc.6'
|
|
9
|
+
- '@deepseek-ai/dsh-invariants@0.1.0-rc.6'
|
|
10
|
+
- '@deepseek-ai/dsh-llm@0.1.0-rc.6'
|
|
11
|
+
- '@deepseek-ai/dsh-scope@0.1.0-rc.6'
|
|
12
|
+
- '@deepseek-ai/dsh-session@0.1.0-rc.6'
|
|
13
|
+
- '@deepseek-ai/dsh-system-prompt@0.1.0-rc.6'
|
|
14
|
+
- '@deepseek-ai/dsh-timeout@0.1.0-rc.6'
|
|
15
|
+
- '@deepseek-ai/dsh-typert-protocol@0.1.0-rc.6'
|
|
16
|
+
- '@deepseek-ai/schemastery@3.18.1'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
6
|
+
const INTRANET_NAME = '@tencent/dsh-qqbot';
|
|
7
|
+
|
|
8
|
+
// 1. 修改 package.json 的 name
|
|
9
|
+
const pkgPath = join(root, 'package.json');
|
|
10
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
11
|
+
pkg.name = INTRANET_NAME;
|
|
12
|
+
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
13
|
+
|
|
14
|
+
// 2. 同步 cordis.patch.yml 中的插件 name
|
|
15
|
+
const patchFile = pkg.dsh?.bundle?.patch;
|
|
16
|
+
if (patchFile) {
|
|
17
|
+
const patchPath = join(root, patchFile);
|
|
18
|
+
const patch = readFileSync(patchPath, 'utf8');
|
|
19
|
+
writeFileSync(
|
|
20
|
+
patchPath,
|
|
21
|
+
patch.replace(/name:\s*'@tencent-connect\/dsh-qqbot'/, `name: '${INTRANET_NAME}'`),
|
|
22
|
+
);
|
|
23
|
+
}
|