@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.
Files changed (126) hide show
  1. package/.orange-ci.yml +68 -0
  2. package/LICENSE +21 -0
  3. package/README.md +142 -0
  4. package/README_EN.md +142 -0
  5. package/cordis.patch.yml +32 -0
  6. package/cordis.yml +69 -0
  7. package/dist/commands/help.d.ts +11 -0
  8. package/dist/commands/help.d.ts.map +1 -0
  9. package/dist/commands/help.js +21 -0
  10. package/dist/commands/help.js.map +1 -0
  11. package/dist/commands/index.d.ts +13 -0
  12. package/dist/commands/index.d.ts.map +1 -0
  13. package/dist/commands/index.js +27 -0
  14. package/dist/commands/index.js.map +1 -0
  15. package/dist/commands/misc.d.ts +12 -0
  16. package/dist/commands/misc.d.ts.map +1 -0
  17. package/dist/commands/misc.js +30 -0
  18. package/dist/commands/misc.js.map +1 -0
  19. package/dist/commands/model.d.ts +7 -0
  20. package/dist/commands/model.d.ts.map +1 -0
  21. package/dist/commands/model.js +58 -0
  22. package/dist/commands/model.js.map +1 -0
  23. package/dist/commands/session.d.ts +10 -0
  24. package/dist/commands/session.d.ts.map +1 -0
  25. package/dist/commands/session.js +26 -0
  26. package/dist/commands/session.js.map +1 -0
  27. package/dist/commands/status.d.ts +8 -0
  28. package/dist/commands/status.d.ts.map +1 -0
  29. package/dist/commands/status.js +24 -0
  30. package/dist/commands/status.js.map +1 -0
  31. package/dist/commands/types.d.ts +12 -0
  32. package/dist/commands/types.d.ts.map +1 -0
  33. package/dist/commands/types.js +2 -0
  34. package/dist/commands/types.js.map +1 -0
  35. package/dist/config.d.ts +50 -0
  36. package/dist/config.d.ts.map +1 -0
  37. package/dist/config.js +33 -0
  38. package/dist/config.js.map +1 -0
  39. package/dist/index.d.ts +14 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +154 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/model/index.d.ts +10 -0
  44. package/dist/model/index.d.ts.map +1 -0
  45. package/dist/model/index.js +9 -0
  46. package/dist/model/index.js.map +1 -0
  47. package/dist/model/model-resolver.d.ts +82 -0
  48. package/dist/model/model-resolver.d.ts.map +1 -0
  49. package/dist/model/model-resolver.js +142 -0
  50. package/dist/model/model-resolver.js.map +1 -0
  51. package/dist/model/prefs-store.d.ts +24 -0
  52. package/dist/model/prefs-store.d.ts.map +1 -0
  53. package/dist/model/prefs-store.js +94 -0
  54. package/dist/model/prefs-store.js.map +1 -0
  55. package/dist/model/settings-reader.d.ts +19 -0
  56. package/dist/model/settings-reader.d.ts.map +1 -0
  57. package/dist/model/settings-reader.js +76 -0
  58. package/dist/model/settings-reader.js.map +1 -0
  59. package/dist/model/types.d.ts +15 -0
  60. package/dist/model/types.d.ts.map +1 -0
  61. package/dist/model/types.js +5 -0
  62. package/dist/model/types.js.map +1 -0
  63. package/dist/session/idle-evictor.d.ts +18 -0
  64. package/dist/session/idle-evictor.d.ts.map +1 -0
  65. package/dist/session/idle-evictor.js +31 -0
  66. package/dist/session/idle-evictor.js.map +1 -0
  67. package/dist/session/index.d.ts +9 -0
  68. package/dist/session/index.d.ts.map +1 -0
  69. package/dist/session/index.js +8 -0
  70. package/dist/session/index.js.map +1 -0
  71. package/dist/session/session-manager.d.ts +44 -0
  72. package/dist/session/session-manager.d.ts.map +1 -0
  73. package/dist/session/session-manager.js +341 -0
  74. package/dist/session/session-manager.js.map +1 -0
  75. package/dist/session/types.d.ts +124 -0
  76. package/dist/session/types.d.ts.map +1 -0
  77. package/dist/session/types.js +2 -0
  78. package/dist/session/types.js.map +1 -0
  79. package/dist/setup.d.ts +24 -0
  80. package/dist/setup.d.ts.map +1 -0
  81. package/dist/setup.js +135 -0
  82. package/dist/setup.js.map +1 -0
  83. package/dist/shared/index.d.ts +7 -0
  84. package/dist/shared/index.d.ts.map +1 -0
  85. package/dist/shared/index.js +7 -0
  86. package/dist/shared/index.js.map +1 -0
  87. package/dist/shared/scope.d.ts +14 -0
  88. package/dist/shared/scope.d.ts.map +1 -0
  89. package/dist/shared/scope.js +12 -0
  90. package/dist/shared/scope.js.map +1 -0
  91. package/dist/shared/send-helper.d.ts +11 -0
  92. package/dist/shared/send-helper.d.ts.map +1 -0
  93. package/dist/shared/send-helper.js +13 -0
  94. package/dist/shared/send-helper.js.map +1 -0
  95. package/dist/shared/utils.d.ts +19 -0
  96. package/dist/shared/utils.d.ts.map +1 -0
  97. package/dist/shared/utils.js +66 -0
  98. package/dist/shared/utils.js.map +1 -0
  99. package/dist/transport/chunker.d.ts +14 -0
  100. package/dist/transport/chunker.d.ts.map +1 -0
  101. package/dist/transport/chunker.js +78 -0
  102. package/dist/transport/chunker.js.map +1 -0
  103. package/dist/transport/inbound.d.ts +8 -0
  104. package/dist/transport/inbound.d.ts.map +1 -0
  105. package/dist/transport/inbound.js +223 -0
  106. package/dist/transport/inbound.js.map +1 -0
  107. package/dist/transport/index.d.ts +10 -0
  108. package/dist/transport/index.d.ts.map +1 -0
  109. package/dist/transport/index.js +10 -0
  110. package/dist/transport/index.js.map +1 -0
  111. package/dist/transport/outbound-buffer.d.ts +32 -0
  112. package/dist/transport/outbound-buffer.d.ts.map +1 -0
  113. package/dist/transport/outbound-buffer.js +65 -0
  114. package/dist/transport/outbound-buffer.js.map +1 -0
  115. package/dist/transport/outbound.d.ts +26 -0
  116. package/dist/transport/outbound.d.ts.map +1 -0
  117. package/dist/transport/outbound.js +92 -0
  118. package/dist/transport/outbound.js.map +1 -0
  119. package/dist/types.d.ts +34 -0
  120. package/dist/types.d.ts.map +1 -0
  121. package/dist/types.js +5 -0
  122. package/dist/types.js.map +1 -0
  123. package/install.sh +108 -0
  124. package/package.json +75 -0
  125. package/pnpm-workspace.yaml +16 -0
  126. package/scripts/prepare-test-pkg.js +23 -0
@@ -0,0 +1,341 @@
1
+ /**
2
+ * SessionManager — 管理 QQ peer → dsh Agent 的映射和生命周期
3
+ *
4
+ * sessionKey 格式: `qqbot:${appId}:${kind}:${peerId}`
5
+ * - c2c: peerId = senderId (用户 openid)
6
+ * - group: peerId = groupOpenid
7
+ *
8
+ * SessionId 由 sessionKey 确定性派生(SHA-256),
9
+ * 保证同一个用户/群的消息始终路由到同一个会话,
10
+ * 重启后可根据 key 恢复 session。
11
+ *
12
+ * 支持 agent-presets 系统:通过 setup hook 在 create/resume 时
13
+ * 挂载 preset(工具集、prompt sections 等),实现场景化配置。
14
+ */
15
+ import { createHash, randomUUID } from 'node:crypto';
16
+ import { SessionId } from '@deepseek-ai/dsh-session';
17
+ import { ModelResolver } from '../model/model-resolver.js';
18
+ import { IdleEvictor } from './idle-evictor.js';
19
+ export class SessionManager {
20
+ ctx;
21
+ agents;
22
+ config;
23
+ logger;
24
+ sessions = new Map();
25
+ evictor;
26
+ modelResolver;
27
+ constructor(ctx, agents, config, logger) {
28
+ this.ctx = ctx;
29
+ this.agents = agents;
30
+ this.config = config;
31
+ this.logger = logger;
32
+ this.modelResolver = new ModelResolver(ctx, config, logger);
33
+ this.evictor = new IdleEvictor(this.sessions, config.sessionIdleTimeout, (key, record) => {
34
+ this.logger.info(`evicting idle session: key=${key}`);
35
+ this.sessions.delete(key);
36
+ record.agent.cancel({ kind: 'user' });
37
+ void record.handle.dispose().catch(() => { });
38
+ });
39
+ }
40
+ /**
41
+ * 动态获取 sessions 服务(fork 能力,可选)
42
+ */
43
+ getSessionsService() {
44
+ try {
45
+ return this.ctx.get('sessions');
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ }
51
+ // ── 模型相关(委托给 ModelResolver) ──
52
+ getEffectiveModel(scope, peerId) {
53
+ return this.modelResolver.getEffectiveRoute(this.sessionKey(scope, peerId));
54
+ }
55
+ /**
56
+ * 切换模型(fork + 重建,对齐 dsh-TUI 的 switchModel)
57
+ */
58
+ async setModelOverride(scope, peerId, route) {
59
+ const key = this.sessionKey(scope, peerId);
60
+ this.modelResolver.setOverride(key, route);
61
+ const record = this.sessions.get(key);
62
+ if (!record) {
63
+ this.logger.info(`model pref saved (no active session): key=${key} → ${route.provider}/${route.model}`);
64
+ return;
65
+ }
66
+ const sessionsService = this.getSessionsService();
67
+ if (!sessionsService) {
68
+ this.logger.warn(`fork unavailable, fallback to dispose: key=${key}`);
69
+ this.sessions.delete(key);
70
+ record.agent.cancel({ kind: 'user' });
71
+ await record.handle.dispose().catch(() => { });
72
+ return;
73
+ }
74
+ let seed;
75
+ try {
76
+ seed = sessionsService.fork(record.agent.session).events;
77
+ }
78
+ catch (err) {
79
+ this.logger.warn(`fork failed, fallback to dispose: key=${key} err=${err instanceof Error ? err.message : String(err)}`);
80
+ this.sessions.delete(key);
81
+ record.agent.cancel({ kind: 'user' });
82
+ await record.handle.dispose().catch(() => { });
83
+ return;
84
+ }
85
+ const childId = SessionId(randomUUID());
86
+ const composed = await this.composePreset(this.config.preset);
87
+ const created = await this.agents.create({
88
+ sessionId: childId,
89
+ seed,
90
+ meta: {
91
+ cwd: this.config.cwd || process.cwd(),
92
+ parentSession: record.sessionId,
93
+ seedLength: seed.length,
94
+ ...(composed.agentPreset ? { agentPreset: composed.agentPreset } : {}),
95
+ },
96
+ agentOptions: route,
97
+ ...(composed.setup ? { setup: composed.setup } : {}),
98
+ });
99
+ this.modelResolver.setSessionId(key, childId);
100
+ const oldHandle = record.handle;
101
+ record.sessionId = childId;
102
+ record.agent = created.agent;
103
+ record.handle = created;
104
+ record.agentPreset = composed.agentPreset;
105
+ record.lastActivity = Date.now();
106
+ void oldHandle.dispose().catch(() => { });
107
+ this.logger.info(`model switched via fork: key=${key} → ${route.provider}/${route.model} sessionId=${childId}`);
108
+ }
109
+ clearModelOverride(scope, peerId) {
110
+ const key = this.sessionKey(scope, peerId);
111
+ this.modelResolver.clearOverride(key);
112
+ this.modelResolver.clearSessionId(key);
113
+ }
114
+ listAvailableModels() {
115
+ return this.modelResolver.listModels();
116
+ }
117
+ listProviders() {
118
+ return this.modelResolver.listProviders();
119
+ }
120
+ // ── 会话状态 / 统计 ──
121
+ getSessionRecord(scope, peerId) {
122
+ return this.sessions.get(this.sessionKey(scope, peerId));
123
+ }
124
+ getStatus(scope, peerId) {
125
+ const record = this.getSessionRecord(scope, peerId);
126
+ const route = this.getEffectiveModel(scope, peerId);
127
+ return {
128
+ active: !!record,
129
+ sessionId: record?.sessionId,
130
+ provider: route?.provider,
131
+ model: route?.model,
132
+ preset: record?.agentPreset,
133
+ lastActivity: record?.lastActivity,
134
+ messageCount: this.countMessages(record),
135
+ };
136
+ }
137
+ getTokenUsage(scope, peerId) {
138
+ const record = this.getSessionRecord(scope, peerId);
139
+ const stats = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
140
+ const events = record?.agent.session.events;
141
+ if (!events)
142
+ return stats;
143
+ for (const event of events) {
144
+ if (event.type !== 'assistant/message' || !event.usage)
145
+ continue;
146
+ stats.input += event.usage.input ?? 0;
147
+ stats.output += event.usage.output ?? 0;
148
+ stats.cacheRead += event.usage.cacheRead ?? 0;
149
+ stats.cacheWrite += event.usage.cacheWrite ?? 0;
150
+ }
151
+ return stats;
152
+ }
153
+ exportMarkdown(scope, peerId) {
154
+ const record = this.getSessionRecord(scope, peerId);
155
+ if (!record)
156
+ return '';
157
+ const events = record.agent.session.events;
158
+ if (!events || events.length === 0)
159
+ return '';
160
+ const lines = [`# QQ 会话导出\n`, `> session: ${record.sessionId}\n`];
161
+ for (const event of events) {
162
+ if (event.type === 'user/message') {
163
+ const text = extractMessageText(event.message);
164
+ if (text)
165
+ lines.push(`## 用户\n\n${text}\n`);
166
+ }
167
+ else if (event.type === 'assistant/message') {
168
+ const text = extractMessageText(event.message);
169
+ if (text)
170
+ lines.push(`## 助手\n\n${text}\n`);
171
+ }
172
+ }
173
+ return lines.join('\n');
174
+ }
175
+ countMessages(record) {
176
+ const events = record?.agent.session.events;
177
+ if (!events)
178
+ return 0;
179
+ let count = 0;
180
+ for (const event of events) {
181
+ if (event.type === 'user/message' || event.type === 'assistant/message') {
182
+ count += 1;
183
+ }
184
+ }
185
+ return count;
186
+ }
187
+ // ── Session 生命周期管理 ──
188
+ sessionKey(scope, peerId) {
189
+ return `qqbot:${this.config.appId}:${scope}:${peerId}`;
190
+ }
191
+ deriveSessionId(sessionKey) {
192
+ const hash = createHash('sha256').update(sessionKey).digest('hex');
193
+ return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`;
194
+ }
195
+ currentSessionId(sessionKey) {
196
+ return this.modelResolver.getSessionId(sessionKey) ?? this.deriveSessionId(sessionKey);
197
+ }
198
+ async composePreset(presetId) {
199
+ let presets;
200
+ try {
201
+ presets = this.ctx.agentPresets;
202
+ }
203
+ catch {
204
+ // agentPresets 服务未注入,降级跳过
205
+ }
206
+ if (!presets)
207
+ return {};
208
+ try {
209
+ const resolved = await presets.resolve(presetId);
210
+ const resolvedId = resolved.id;
211
+ return {
212
+ agentPreset: resolvedId,
213
+ setup: async (agentCtx) => {
214
+ await presets.mount(agentCtx, resolvedId);
215
+ },
216
+ };
217
+ }
218
+ catch (err) {
219
+ this.logger.warn(`im-qqbot: preset ${presetId ?? '(default)'} unavailable: ${err instanceof Error ? err.message : String(err)} — using host composition`);
220
+ return {};
221
+ }
222
+ }
223
+ /** 获取或恢复或创建会话(get → resume → create) */
224
+ async getOrCreate(scope, peerId, senderId, replyTarget) {
225
+ const key = this.sessionKey(scope, peerId);
226
+ const existing = this.sessions.get(key);
227
+ if (existing) {
228
+ existing.replyTarget = replyTarget;
229
+ existing.lastActivity = Date.now();
230
+ return existing;
231
+ }
232
+ const route = this.modelResolver.getEffectiveRoute(key);
233
+ const sessionId = SessionId(this.currentSessionId(key));
234
+ this.logger.info(`getOrCreate: key=${key} route=${route ? `${route.provider}/${route.model}` : 'host-default'} sessionId=${sessionId}`);
235
+ let agent;
236
+ let handle;
237
+ let agentPreset;
238
+ const live = this.agents.get(sessionId);
239
+ if (live) {
240
+ agent = live;
241
+ this.logger.info(`reusing live agent: key=${key}`);
242
+ }
243
+ else {
244
+ try {
245
+ const composed = await this.composePreset(this.config.preset);
246
+ agentPreset = composed.agentPreset;
247
+ const resumeRoute = this.modelResolver.getResumeRoute(key);
248
+ const resumed = await this.agents.resume({
249
+ resumeSessionId: sessionId,
250
+ ...(resumeRoute ? { agentOptions: resumeRoute } : {}),
251
+ ...(composed.setup ? { setup: composed.setup } : {}),
252
+ });
253
+ agent = resumed.agent;
254
+ handle = resumed;
255
+ this.logger.info(`resumed session: key=${key} preset=${agentPreset ?? 'none'} route=${resumeRoute ? `${resumeRoute.provider}/${resumeRoute.model}` : 'session-own'}`);
256
+ }
257
+ catch {
258
+ const composed = await this.composePreset(this.config.preset);
259
+ agentPreset = composed.agentPreset;
260
+ const created = await this.agents.create({
261
+ sessionId,
262
+ meta: {
263
+ cwd: this.config.cwd || process.cwd(),
264
+ ...(agentPreset ? { agentPreset } : {}),
265
+ },
266
+ ...(route ? { agentOptions: route } : {}),
267
+ ...(composed.setup ? { setup: composed.setup } : {}),
268
+ });
269
+ agent = created.agent;
270
+ handle = created;
271
+ this.logger.info(`created new session: key=${key} preset=${agentPreset ?? 'none'}`);
272
+ }
273
+ }
274
+ const record = {
275
+ sessionKey: key,
276
+ sessionId,
277
+ agent,
278
+ handle: handle ?? { agent, dispose: async () => { } },
279
+ replyTarget,
280
+ scope,
281
+ peerId,
282
+ senderId,
283
+ lastActivity: Date.now(),
284
+ agentPreset,
285
+ };
286
+ this.sessions.set(key, record);
287
+ return record;
288
+ }
289
+ findBySessionId(sessionId) {
290
+ for (const record of this.sessions.values()) {
291
+ if (record.sessionId === sessionId)
292
+ return record;
293
+ }
294
+ return undefined;
295
+ }
296
+ findByAgent(agent) {
297
+ for (const record of this.sessions.values()) {
298
+ if (record.agent === agent)
299
+ return record;
300
+ }
301
+ return undefined;
302
+ }
303
+ async remove(scope, peerId) {
304
+ const key = this.sessionKey(scope, peerId);
305
+ const record = this.sessions.get(key);
306
+ if (!record)
307
+ return;
308
+ this.sessions.delete(key);
309
+ this.modelResolver.clearSessionId(key);
310
+ record.agent.cancel({ kind: 'user' });
311
+ await record.handle.dispose().catch(() => { });
312
+ this.logger.info(`session removed: key=${key}`);
313
+ }
314
+ async disposeAll() {
315
+ this.evictor.dispose();
316
+ const records = [...this.sessions.values()];
317
+ this.sessions.clear();
318
+ for (const record of records) {
319
+ record.agent.cancel({ kind: 'user' });
320
+ }
321
+ await Promise.allSettled(records.map((r) => r.handle.dispose()));
322
+ this.logger.info(`all sessions disposed (count=${records.length})`);
323
+ }
324
+ get size() {
325
+ return this.sessions.size;
326
+ }
327
+ }
328
+ /** 从消息对象中提取纯文本(用于导出/统计) */
329
+ function extractMessageText(message) {
330
+ const blocks = message?.content;
331
+ if (!blocks || !Array.isArray(blocks))
332
+ return '';
333
+ const parts = [];
334
+ for (const block of blocks) {
335
+ if (block.type === 'text' && block.text) {
336
+ parts.push(block.text);
337
+ }
338
+ }
339
+ return parts.join('\n').trim();
340
+ }
341
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * 会话管理层类型定义
3
+ */
4
+ import type { Context } from '@deepseek-ai/cordis';
5
+ import type { ChatScope, ReplyTarget } from '../types.js';
6
+ /** AgentSetup hook 类型 */
7
+ export type AgentSetup = (agentCtx: Context) => Promise<void> | void;
8
+ /** dsh SessionEvent 简化类型(用于统计 token 用量 / 导出) */
9
+ export interface SessionEventLike {
10
+ type: string;
11
+ seq?: number;
12
+ usage?: {
13
+ input?: number;
14
+ output?: number;
15
+ cacheRead?: number;
16
+ cacheWrite?: number;
17
+ };
18
+ message?: {
19
+ content?: Array<{
20
+ type: string;
21
+ text?: string;
22
+ }>;
23
+ [key: string]: unknown;
24
+ };
25
+ [key: string]: unknown;
26
+ }
27
+ /** dsh Agent 简化接口 */
28
+ export interface DshAgent {
29
+ readonly id: string;
30
+ readonly ctx: Context;
31
+ /** 底层 session(fork 时作为 source,events 用于统计/导出) */
32
+ readonly session: {
33
+ readonly id: string;
34
+ readonly events?: readonly SessionEventLike[];
35
+ };
36
+ cancel(cause: {
37
+ kind: string;
38
+ }): void;
39
+ followup(message: unknown): void;
40
+ whenIdle(): Promise<void>;
41
+ }
42
+ export interface DshAgentHandle {
43
+ agent: DshAgent;
44
+ dispose(): Promise<void>;
45
+ }
46
+ /** sessions 服务(fork 能力) */
47
+ export interface SessionsService {
48
+ fork(source: unknown, boundary?: number): {
49
+ events: readonly unknown[];
50
+ };
51
+ }
52
+ export interface DshAgentRegistry {
53
+ /** 获取进程内已存活的 agent */
54
+ get(sessionId: string): DshAgent | undefined;
55
+ /** 从持久化存储恢复 session */
56
+ resume(options: {
57
+ resumeSessionId: string;
58
+ agentOptions?: {
59
+ provider?: string;
60
+ model?: string;
61
+ };
62
+ setup?: AgentSetup;
63
+ }): Promise<DshAgentHandle>;
64
+ /** 创建全新 session */
65
+ create(options: {
66
+ sessionId: string;
67
+ meta?: {
68
+ cwd?: string;
69
+ parentSession?: string;
70
+ seedLength?: number;
71
+ agentPreset?: string;
72
+ };
73
+ seed?: readonly unknown[];
74
+ agentOptions?: {
75
+ provider?: string;
76
+ model?: string;
77
+ };
78
+ setup?: AgentSetup;
79
+ }): Promise<DshAgentHandle>;
80
+ }
81
+ /** agent-presets 服务接口(可选,部署中可能没有) */
82
+ export interface AgentPresetsLike {
83
+ readonly defaultId: string;
84
+ resolve(id?: string): Promise<{
85
+ id: string;
86
+ }>;
87
+ mount(agentCtx: Context, id?: string): Promise<unknown>;
88
+ }
89
+ /** preset 组合结果 */
90
+ export interface PresetComposition {
91
+ agentPreset?: string;
92
+ setup?: AgentSetup;
93
+ }
94
+ /** 单个会话记录 */
95
+ export interface SessionRecord {
96
+ sessionKey: string;
97
+ sessionId: string;
98
+ agent: DshAgent;
99
+ handle: DshAgentHandle;
100
+ replyTarget: ReplyTarget;
101
+ scope: ChatScope;
102
+ peerId: string;
103
+ senderId: string;
104
+ lastActivity: number;
105
+ agentPreset?: string;
106
+ }
107
+ /** 会话状态信息(/status 用) */
108
+ export interface SessionStatus {
109
+ active: boolean;
110
+ sessionId?: string;
111
+ provider?: string;
112
+ model?: string;
113
+ preset?: string;
114
+ lastActivity?: number;
115
+ messageCount?: number;
116
+ }
117
+ /** token 用量统计(/cost 用) */
118
+ export interface TokenUsageStats {
119
+ input: number;
120
+ output: number;
121
+ cacheRead: number;
122
+ cacheWrite: number;
123
+ }
124
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/session/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/session/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ /** 凭据结果 */
2
+ export interface SetupCredentials {
3
+ appId: string;
4
+ appSecret: string;
5
+ }
6
+ /**
7
+ * 执行 QR 扫码绑定,获取 QQ Bot 凭据
8
+ *
9
+ * 使用动态 import 加载 qqbot-connector(可能未安装),
10
+ * 在终端打印二维码等待用户扫码。
11
+ */
12
+ export declare function runQrSetup(source?: string): Promise<SetupCredentials | null>;
13
+ /**
14
+ * 将凭据写入 dsh profile 的 cordis.patch.yml
15
+ *
16
+ * 用 js-yaml 解析现有文件后更新/追加 im-qqbot 条目,再 dump 写回,
17
+ * 保证输出始终是合法 YAML。兼容空数组 `[]`、条目列表,以及
18
+ * `[]` 与条目混合导致解析失败等异常情况(失败时重建)。
19
+ */
20
+ export declare function persistCredentialsToProfile(credentials: SetupCredentials, profileDir?: string, logger?: {
21
+ info(msg: string, ...args: unknown[]): void;
22
+ warn(msg: string, ...args: unknown[]): void;
23
+ }): boolean;
24
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAWA,WAAW;AACX,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AASD;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,MAAM,SAAc,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAwCvF;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,gBAAgB,EAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE;IAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAAE,GACpG,OAAO,CAiDT"}
package/dist/setup.js ADDED
@@ -0,0 +1,135 @@
1
+ /**
2
+ * QQ Bot 凭据初始化 — 扫码绑定
3
+ *
4
+ * 当 appId/appSecret 未配置时,通过 @tencent-connect/qqbot-connector
5
+ * 唤起终端扫码流程获取凭据,并写入 dsh profile 配置。
6
+ */
7
+ import { resolve } from 'node:path';
8
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
9
+ import yaml from 'js-yaml';
10
+ import { qrConnect } from '@tencent-connect/qqbot-connector';
11
+ /**
12
+ * 执行 QR 扫码绑定,获取 QQ Bot 凭据
13
+ *
14
+ * 使用动态 import 加载 qqbot-connector(可能未安装),
15
+ * 在终端打印二维码等待用户扫码。
16
+ */
17
+ export async function runQrSetup(source = 'dsh-qqbot') {
18
+ console.log('\n══════════════════════════════════════════════════════');
19
+ console.log(' QQ Bot 凭据未配置,启动扫码绑定');
20
+ console.log('══════════════════════════════════════════════════════\n');
21
+ try {
22
+ console.log('请使用手机 QQ 扫描下方二维码完成绑定...\n');
23
+ const credentials = await qrConnect({ source });
24
+ if (!credentials || credentials.length === 0) {
25
+ console.error('[im-qqbot] 扫码未返回凭据');
26
+ return null;
27
+ }
28
+ const cred = credentials[0];
29
+ if (!cred) {
30
+ console.error('[im-qqbot] 扫码未返回有效凭据');
31
+ return null;
32
+ }
33
+ console.log(`\n✔ 绑定成功!AppID: ${cred.appId}\n`);
34
+ return {
35
+ appId: cred.appId,
36
+ appSecret: cred.appSecret,
37
+ };
38
+ }
39
+ catch (err) {
40
+ const msg = err instanceof Error ? err.message : String(err);
41
+ if (msg.includes('Cannot find') || msg.includes('ERR_MODULE_NOT_FOUND')) {
42
+ console.error('[im-qqbot] @tencent-connect/qqbot-connector 未安装,无法扫码绑定');
43
+ console.error('[im-qqbot] 请通过环境变量配置:');
44
+ console.error(' export QQBOT_APPID="你的AppID"');
45
+ console.error(' export QQBOT_SECRET="你的AppSecret"');
46
+ }
47
+ else {
48
+ console.error(`[im-qqbot] 扫码绑定失败: ${msg}`);
49
+ }
50
+ return null;
51
+ }
52
+ }
53
+ /**
54
+ * 将凭据写入 dsh profile 的 cordis.patch.yml
55
+ *
56
+ * 用 js-yaml 解析现有文件后更新/追加 im-qqbot 条目,再 dump 写回,
57
+ * 保证输出始终是合法 YAML。兼容空数组 `[]`、条目列表,以及
58
+ * `[]` 与条目混合导致解析失败等异常情况(失败时重建)。
59
+ */
60
+ export function persistCredentialsToProfile(credentials, profileDir, logger) {
61
+ const log = logger ?? console;
62
+ const dir = profileDir;
63
+ if (!dir) {
64
+ printManualInstructions(credentials, log);
65
+ return false;
66
+ }
67
+ const patchPath = resolve(dir, 'cordis.patch.yml');
68
+ try {
69
+ // 1. 解析现有条目(容错处理)
70
+ let entries = [];
71
+ if (existsSync(patchPath)) {
72
+ entries = parsePatchEntries(readFileSync(patchPath, 'utf8'), log);
73
+ }
74
+ // 2. 查找已有 im-qqbot 条目
75
+ const existing = entries.find((e) => e.id === 'im-qqbot');
76
+ if (existing) {
77
+ // 更新已有条目的 config
78
+ existing.config = {
79
+ ...(existing.config ?? {}),
80
+ appId: credentials.appId,
81
+ appSecret: credentials.appSecret,
82
+ };
83
+ }
84
+ else {
85
+ // 追加新条目
86
+ entries.push({
87
+ id: 'im-qqbot',
88
+ config: {
89
+ appId: credentials.appId,
90
+ appSecret: credentials.appSecret,
91
+ },
92
+ });
93
+ }
94
+ // 3. dump 写回(保证合法 YAML)
95
+ const output = `# QQ Bot 凭据(扫码绑定自动生成)\n${yaml.dump(entries)}`;
96
+ writeFileSync(patchPath, output, 'utf8');
97
+ log.info(`✔ 凭据已写入: ${patchPath}`);
98
+ log.info(` 下次启动将自动使用保存的凭据`);
99
+ return true;
100
+ }
101
+ catch (err) {
102
+ log.warn(`写入配置失败: ${err instanceof Error ? err.message : String(err)}`);
103
+ printManualInstructions(credentials, log);
104
+ return false;
105
+ }
106
+ }
107
+ /**
108
+ * 解析 cordis.patch.yml 为条目数组
109
+ *
110
+ * 容错处理:
111
+ * - 空内容 / 空数组 `[]` → 空数组
112
+ * - 条目列表 → 过滤出含 id 的对象
113
+ * - 解析失败(如 `[]` 与条目混合的多文档)→ 返回空数组(重建)
114
+ */
115
+ function parsePatchEntries(content, log) {
116
+ if (!content.trim())
117
+ return [];
118
+ try {
119
+ const parsed = yaml.load(content);
120
+ if (Array.isArray(parsed)) {
121
+ return parsed.filter((e) => typeof e === 'object' && e !== null && typeof e.id === 'string');
122
+ }
123
+ return [];
124
+ }
125
+ catch (err) {
126
+ log.warn(`cordis.patch.yml 解析失败,将重建: ${err instanceof Error ? err.message : String(err)}`);
127
+ return [];
128
+ }
129
+ }
130
+ function printManualInstructions(credentials, log) {
131
+ log.warn('无法自动保存凭据,请手动设置环境变量:');
132
+ log.warn(` export QQBOT_APPID="${credentials.appId}"`);
133
+ log.warn(` export QQBOT_SECRET="${credentials.appSecret}"`);
134
+ }
135
+ //# sourceMappingURL=setup.js.map