@ryantest/openclaw-qqbot 0.0.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.
Files changed (197) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +483 -0
  3. package/README.zh.md +478 -0
  4. package/bin/qqbot-cli.js +243 -0
  5. package/clawdbot.plugin.json +16 -0
  6. package/dist/index.d.ts +17 -0
  7. package/dist/index.js +26 -0
  8. package/dist/src/admin-resolver.d.ts +27 -0
  9. package/dist/src/admin-resolver.js +122 -0
  10. package/dist/src/api.d.ts +156 -0
  11. package/dist/src/api.js +599 -0
  12. package/dist/src/channel.d.ts +11 -0
  13. package/dist/src/channel.js +354 -0
  14. package/dist/src/config.d.ts +25 -0
  15. package/dist/src/config.js +161 -0
  16. package/dist/src/credential-backup.d.ts +31 -0
  17. package/dist/src/credential-backup.js +66 -0
  18. package/dist/src/gateway.d.ts +18 -0
  19. package/dist/src/gateway.js +1265 -0
  20. package/dist/src/image-server.d.ts +68 -0
  21. package/dist/src/image-server.js +462 -0
  22. package/dist/src/inbound-attachments.d.ts +58 -0
  23. package/dist/src/inbound-attachments.js +234 -0
  24. package/dist/src/known-users.d.ts +100 -0
  25. package/dist/src/known-users.js +263 -0
  26. package/dist/src/message-queue.d.ts +50 -0
  27. package/dist/src/message-queue.js +115 -0
  28. package/dist/src/onboarding.d.ts +10 -0
  29. package/dist/src/onboarding.js +203 -0
  30. package/dist/src/outbound-deliver.d.ts +48 -0
  31. package/dist/src/outbound-deliver.js +462 -0
  32. package/dist/src/outbound.d.ts +203 -0
  33. package/dist/src/outbound.js +1102 -0
  34. package/dist/src/proactive.d.ts +170 -0
  35. package/dist/src/proactive.js +399 -0
  36. package/dist/src/ref-index-store.d.ts +70 -0
  37. package/dist/src/ref-index-store.js +273 -0
  38. package/dist/src/reply-dispatcher.d.ts +35 -0
  39. package/dist/src/reply-dispatcher.js +311 -0
  40. package/dist/src/runtime.d.ts +3 -0
  41. package/dist/src/runtime.js +10 -0
  42. package/dist/src/session-store.d.ts +52 -0
  43. package/dist/src/session-store.js +254 -0
  44. package/dist/src/slash-commands.d.ts +71 -0
  45. package/dist/src/slash-commands.js +1179 -0
  46. package/dist/src/startup-greeting.d.ts +30 -0
  47. package/dist/src/startup-greeting.js +78 -0
  48. package/dist/src/stt.d.ts +21 -0
  49. package/dist/src/stt.js +70 -0
  50. package/dist/src/tools/channel.d.ts +16 -0
  51. package/dist/src/tools/channel.js +234 -0
  52. package/dist/src/tools/remind.d.ts +2 -0
  53. package/dist/src/tools/remind.js +247 -0
  54. package/dist/src/types.d.ts +175 -0
  55. package/dist/src/types.js +1 -0
  56. package/dist/src/typing-keepalive.d.ts +27 -0
  57. package/dist/src/typing-keepalive.js +64 -0
  58. package/dist/src/update-checker.d.ts +34 -0
  59. package/dist/src/update-checker.js +166 -0
  60. package/dist/src/user-messages.d.ts +8 -0
  61. package/dist/src/user-messages.js +8 -0
  62. package/dist/src/utils/audio-convert.d.ts +89 -0
  63. package/dist/src/utils/audio-convert.js +704 -0
  64. package/dist/src/utils/file-utils.d.ts +55 -0
  65. package/dist/src/utils/file-utils.js +150 -0
  66. package/dist/src/utils/image-size.d.ts +51 -0
  67. package/dist/src/utils/image-size.js +234 -0
  68. package/dist/src/utils/media-tags.d.ts +14 -0
  69. package/dist/src/utils/media-tags.js +164 -0
  70. package/dist/src/utils/payload.d.ts +112 -0
  71. package/dist/src/utils/payload.js +186 -0
  72. package/dist/src/utils/platform.d.ts +137 -0
  73. package/dist/src/utils/platform.js +390 -0
  74. package/dist/src/utils/text-parsing.d.ts +32 -0
  75. package/dist/src/utils/text-parsing.js +80 -0
  76. package/dist/src/utils/upload-cache.d.ts +34 -0
  77. package/dist/src/utils/upload-cache.js +93 -0
  78. package/index.ts +31 -0
  79. package/moltbot.plugin.json +16 -0
  80. package/node_modules/@eshaz/web-worker/LICENSE +201 -0
  81. package/node_modules/@eshaz/web-worker/README.md +134 -0
  82. package/node_modules/@eshaz/web-worker/browser.js +17 -0
  83. package/node_modules/@eshaz/web-worker/cjs/browser.js +16 -0
  84. package/node_modules/@eshaz/web-worker/cjs/node.js +219 -0
  85. package/node_modules/@eshaz/web-worker/index.d.ts +4 -0
  86. package/node_modules/@eshaz/web-worker/node.js +223 -0
  87. package/node_modules/@eshaz/web-worker/package.json +54 -0
  88. package/node_modules/@wasm-audio-decoders/common/index.js +5 -0
  89. package/node_modules/@wasm-audio-decoders/common/package.json +36 -0
  90. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderCommon.js +231 -0
  91. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderWorker.js +129 -0
  92. package/node_modules/@wasm-audio-decoders/common/src/puff/README +67 -0
  93. package/node_modules/@wasm-audio-decoders/common/src/puff/build_puff.js +31 -0
  94. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.c +863 -0
  95. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.h +35 -0
  96. package/node_modules/@wasm-audio-decoders/common/src/utilities.js +3 -0
  97. package/node_modules/@wasm-audio-decoders/common/types.d.ts +7 -0
  98. package/node_modules/mpg123-decoder/README.md +265 -0
  99. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js +185 -0
  100. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js.map +1 -0
  101. package/node_modules/mpg123-decoder/index.js +8 -0
  102. package/node_modules/mpg123-decoder/package.json +58 -0
  103. package/node_modules/mpg123-decoder/src/EmscriptenWasm.js +464 -0
  104. package/node_modules/mpg123-decoder/src/MPEGDecoder.js +200 -0
  105. package/node_modules/mpg123-decoder/src/MPEGDecoderWebWorker.js +21 -0
  106. package/node_modules/mpg123-decoder/types.d.ts +30 -0
  107. package/node_modules/silk-wasm/LICENSE +21 -0
  108. package/node_modules/silk-wasm/README.md +85 -0
  109. package/node_modules/silk-wasm/lib/index.cjs +16 -0
  110. package/node_modules/silk-wasm/lib/index.d.ts +70 -0
  111. package/node_modules/silk-wasm/lib/index.mjs +16 -0
  112. package/node_modules/silk-wasm/lib/silk.wasm +0 -0
  113. package/node_modules/silk-wasm/lib/utils.d.ts +4 -0
  114. package/node_modules/silk-wasm/package.json +39 -0
  115. package/node_modules/simple-yenc/.github/FUNDING.yml +1 -0
  116. package/node_modules/simple-yenc/.prettierignore +1 -0
  117. package/node_modules/simple-yenc/LICENSE +7 -0
  118. package/node_modules/simple-yenc/README.md +163 -0
  119. package/node_modules/simple-yenc/dist/esm.js +1 -0
  120. package/node_modules/simple-yenc/dist/index.js +1 -0
  121. package/node_modules/simple-yenc/package.json +50 -0
  122. package/node_modules/simple-yenc/rollup.config.js +27 -0
  123. package/node_modules/simple-yenc/src/simple-yenc.js +302 -0
  124. package/node_modules/ws/LICENSE +20 -0
  125. package/node_modules/ws/README.md +548 -0
  126. package/node_modules/ws/browser.js +8 -0
  127. package/node_modules/ws/index.js +13 -0
  128. package/node_modules/ws/lib/buffer-util.js +131 -0
  129. package/node_modules/ws/lib/constants.js +19 -0
  130. package/node_modules/ws/lib/event-target.js +292 -0
  131. package/node_modules/ws/lib/extension.js +203 -0
  132. package/node_modules/ws/lib/limiter.js +55 -0
  133. package/node_modules/ws/lib/permessage-deflate.js +528 -0
  134. package/node_modules/ws/lib/receiver.js +706 -0
  135. package/node_modules/ws/lib/sender.js +602 -0
  136. package/node_modules/ws/lib/stream.js +161 -0
  137. package/node_modules/ws/lib/subprotocol.js +62 -0
  138. package/node_modules/ws/lib/validation.js +152 -0
  139. package/node_modules/ws/lib/websocket-server.js +554 -0
  140. package/node_modules/ws/lib/websocket.js +1393 -0
  141. package/node_modules/ws/package.json +69 -0
  142. package/node_modules/ws/wrapper.mjs +8 -0
  143. package/openclaw.plugin.json +16 -0
  144. package/package.json +76 -0
  145. package/scripts/cleanup-legacy-plugins.sh +124 -0
  146. package/scripts/proactive-api-server.ts +369 -0
  147. package/scripts/send-proactive.ts +293 -0
  148. package/scripts/set-markdown.sh +156 -0
  149. package/scripts/test-sendmedia.ts +116 -0
  150. package/scripts/upgrade-via-alt-pkg.sh +307 -0
  151. package/scripts/upgrade-via-npm.ps1 +296 -0
  152. package/scripts/upgrade-via-npm.sh +301 -0
  153. package/scripts/upgrade-via-source.sh +774 -0
  154. package/skills/qqbot-channel/SKILL.md +263 -0
  155. package/skills/qqbot-channel/references/api_references.md +521 -0
  156. package/skills/qqbot-media/SKILL.md +56 -0
  157. package/skills/qqbot-remind/SKILL.md +149 -0
  158. package/src/admin-resolver.ts +140 -0
  159. package/src/api.ts +819 -0
  160. package/src/bot-logs-2026-03-21T11-21-47(2).txt +46 -0
  161. package/src/channel.ts +381 -0
  162. package/src/config.ts +187 -0
  163. package/src/credential-backup.ts +72 -0
  164. package/src/gateway.log +43 -0
  165. package/src/gateway.ts +1404 -0
  166. package/src/image-server.ts +539 -0
  167. package/src/inbound-attachments.ts +304 -0
  168. package/src/known-users.ts +353 -0
  169. package/src/message-queue.ts +169 -0
  170. package/src/onboarding.ts +274 -0
  171. package/src/openclaw-2026-03-21.log +3729 -0
  172. package/src/openclaw-plugin-sdk.d.ts +522 -0
  173. package/src/outbound-deliver.ts +552 -0
  174. package/src/outbound.ts +1266 -0
  175. package/src/proactive.ts +530 -0
  176. package/src/ref-index-store.ts +357 -0
  177. package/src/reply-dispatcher.ts +334 -0
  178. package/src/runtime.ts +14 -0
  179. package/src/session-store.ts +303 -0
  180. package/src/slash-commands.ts +1305 -0
  181. package/src/startup-greeting.ts +98 -0
  182. package/src/stt.ts +86 -0
  183. package/src/tools/channel.ts +281 -0
  184. package/src/tools/remind.ts +296 -0
  185. package/src/types.ts +183 -0
  186. package/src/typing-keepalive.ts +59 -0
  187. package/src/update-checker.ts +179 -0
  188. package/src/user-messages.ts +7 -0
  189. package/src/utils/audio-convert.ts +803 -0
  190. package/src/utils/file-utils.ts +167 -0
  191. package/src/utils/image-size.ts +266 -0
  192. package/src/utils/media-tags.ts +182 -0
  193. package/src/utils/payload.ts +265 -0
  194. package/src/utils/platform.ts +435 -0
  195. package/src/utils/text-parsing.ts +82 -0
  196. package/src/utils/upload-cache.ts +128 -0
  197. package/tsconfig.json +16 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * QQ Bot 文本解析工具函数
3
+ */
4
+
5
+ import type { RefAttachmentSummary } from "../ref-index-store.js";
6
+
7
+ /**
8
+ * 解析 QQ 表情标签,将 <faceType=1,faceId="13",ext="base64..."> 格式
9
+ * 替换为 【表情: 中文名】 格式
10
+ * ext 字段为 Base64 编码的 JSON,格式如 {"text":"呲牙"}
11
+ */
12
+ export function parseFaceTags(text: string): string {
13
+ if (!text) return text;
14
+
15
+ return text.replace(/<faceType=\d+,faceId="[^"]*",ext="([^"]*)">/g, (_match, ext: string) => {
16
+ try {
17
+ const decoded = Buffer.from(ext, "base64").toString("utf-8");
18
+ const parsed = JSON.parse(decoded);
19
+ const faceName = parsed.text || "未知表情";
20
+ return `【表情: ${faceName}】`;
21
+ } catch {
22
+ return _match;
23
+ }
24
+ });
25
+ }
26
+
27
+ /**
28
+ * 过滤内部标记(如 [[reply_to: xxx]])
29
+ * 这些标记可能被 AI 错误地学习并输出,需要在发送前移除
30
+ */
31
+ export function filterInternalMarkers(text: string): string {
32
+ if (!text) return text;
33
+
34
+ let result = text.replace(/\[\[[a-z_]+:\s*[^\]]*\]\]/gi, "");
35
+ // 过滤框架内部图片引用标记:@image:image_xxx.png、@voice:voice_xxx.silk 等
36
+ result = result.replace(/@(?:image|voice|video|file):[a-zA-Z0-9_.-]+/g, "");
37
+ result = result.replace(/\n{3,}/g, "\n\n").trim();
38
+
39
+ return result;
40
+ }
41
+
42
+ /**
43
+ * 从 message_scene.ext 数组中解析引用索引
44
+ * ext 格式示例: ["", "ref_msg_idx=REFIDX_xxx", "msg_idx=REFIDX_yyy"]
45
+ */
46
+ export function parseRefIndices(ext?: string[]): { refMsgIdx?: string; msgIdx?: string } {
47
+ if (!ext || ext.length === 0) return {};
48
+ let refMsgIdx: string | undefined;
49
+ let msgIdx: string | undefined;
50
+ for (const item of ext) {
51
+ if (item.startsWith("ref_msg_idx=")) {
52
+ refMsgIdx = item.slice("ref_msg_idx=".length);
53
+ } else if (item.startsWith("msg_idx=")) {
54
+ msgIdx = item.slice("msg_idx=".length);
55
+ }
56
+ }
57
+ return { refMsgIdx, msgIdx };
58
+ }
59
+
60
+ /**
61
+ * 从附件列表中构建附件摘要(用于引用索引缓存)
62
+ */
63
+ export function buildAttachmentSummaries(
64
+ attachments?: Array<{ content_type: string; url: string; filename?: string; voice_wav_url?: string }>,
65
+ localPaths?: Array<string | null>,
66
+ ): RefAttachmentSummary[] | undefined {
67
+ if (!attachments || attachments.length === 0) return undefined;
68
+ return attachments.map((att, idx) => {
69
+ const ct = att.content_type?.toLowerCase() ?? "";
70
+ let type: RefAttachmentSummary["type"] = "unknown";
71
+ if (ct.startsWith("image/")) type = "image";
72
+ else if (ct === "voice" || ct.startsWith("audio/") || ct.includes("silk") || ct.includes("amr")) type = "voice";
73
+ else if (ct.startsWith("video/")) type = "video";
74
+ else if (ct.startsWith("application/") || ct.startsWith("text/")) type = "file";
75
+ return {
76
+ type,
77
+ filename: att.filename,
78
+ contentType: att.content_type,
79
+ localPath: localPaths?.[idx] ?? undefined,
80
+ };
81
+ });
82
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * file_info 缓存 — 借鉴 Telegram file_id 机制
3
+ *
4
+ * QQ Bot API 上传文件后返回 file_info + ttl,在 TTL 内相同文件可直接复用 file_info
5
+ * 避免重复上传同一文件,节省带宽和时间。
6
+ *
7
+ * 缓存 key = md5(fileContent) + targetType(c2c/group) + targetId + fileType
8
+ */
9
+
10
+ import * as crypto from "node:crypto";
11
+ import * as fs from "node:fs";
12
+
13
+ interface CacheEntry {
14
+ fileInfo: string;
15
+ fileUuid: string;
16
+ /** 过期时间戳(ms),比 API 返回的 TTL 提前 60 秒失效 */
17
+ expiresAt: number;
18
+ }
19
+
20
+ // 内存缓存,key 格式:`${contentHash}:${scope}:${targetId}:${fileType}`
21
+ const cache = new Map<string, CacheEntry>();
22
+
23
+ // 最大缓存条目数,防止内存泄漏
24
+ const MAX_CACHE_SIZE = 500;
25
+
26
+ /**
27
+ * 计算文件内容的 MD5 hash(用于缓存 key)
28
+ * 对于 Base64 数据直接 hash,对于文件路径读取后 hash
29
+ */
30
+ export function computeFileHash(data: string | Buffer): string {
31
+ const content = typeof data === "string" ? data : data;
32
+ return crypto.createHash("md5").update(content).digest("hex");
33
+ }
34
+
35
+ /**
36
+ * 构建缓存 key
37
+ * @param contentHash - 文件内容 hash
38
+ * @param scope - "c2c" | "group"
39
+ * @param targetId - 用户 openid 或群 openid
40
+ * @param fileType - 1=IMAGE, 2=VIDEO, 3=VOICE, 4=FILE
41
+ */
42
+ function buildCacheKey(contentHash: string, scope: string, targetId: string, fileType: number): string {
43
+ return `${contentHash}:${scope}:${targetId}:${fileType}`;
44
+ }
45
+
46
+ /**
47
+ * 从缓存获取 file_info
48
+ * @returns file_info 字符串,未命中或已过期返回 null
49
+ */
50
+ export function getCachedFileInfo(
51
+ contentHash: string,
52
+ scope: "c2c" | "group",
53
+ targetId: string,
54
+ fileType: number,
55
+ ): string | null {
56
+ const key = buildCacheKey(contentHash, scope, targetId, fileType);
57
+ const entry = cache.get(key);
58
+
59
+ if (!entry) return null;
60
+
61
+ // 检查是否过期
62
+ if (Date.now() >= entry.expiresAt) {
63
+ cache.delete(key);
64
+ return null;
65
+ }
66
+
67
+ console.log(`[upload-cache] Cache HIT: key=${key.slice(0, 40)}..., fileUuid=${entry.fileUuid}`);
68
+ return entry.fileInfo;
69
+ }
70
+
71
+ /**
72
+ * 将上传结果写入缓存
73
+ * @param ttl - API 返回的 TTL(秒),缓存会提前 60 秒失效
74
+ */
75
+ export function setCachedFileInfo(
76
+ contentHash: string,
77
+ scope: "c2c" | "group",
78
+ targetId: string,
79
+ fileType: number,
80
+ fileInfo: string,
81
+ fileUuid: string,
82
+ ttl: number,
83
+ ): void {
84
+ // 清理过期条目(惰性清理)
85
+ if (cache.size >= MAX_CACHE_SIZE) {
86
+ const now = Date.now();
87
+ for (const [k, v] of cache) {
88
+ if (now >= v.expiresAt) {
89
+ cache.delete(k);
90
+ }
91
+ }
92
+ // 如果清理后仍然超限,删除最早的一半
93
+ if (cache.size >= MAX_CACHE_SIZE) {
94
+ const keys = Array.from(cache.keys());
95
+ for (let i = 0; i < keys.length / 2; i++) {
96
+ cache.delete(keys[i]!);
97
+ }
98
+ }
99
+ }
100
+
101
+ const key = buildCacheKey(contentHash, scope, targetId, fileType);
102
+ // 提前 60 秒失效,避免临界点过期
103
+ const safetyMargin = 60;
104
+ const effectiveTtl = Math.max(ttl - safetyMargin, 10);
105
+
106
+ cache.set(key, {
107
+ fileInfo,
108
+ fileUuid,
109
+ expiresAt: Date.now() + effectiveTtl * 1000,
110
+ });
111
+
112
+ console.log(`[upload-cache] Cache SET: key=${key.slice(0, 40)}..., ttl=${effectiveTtl}s, uuid=${fileUuid}`);
113
+ }
114
+
115
+ /**
116
+ * 获取缓存统计
117
+ */
118
+ export function getUploadCacheStats(): { size: number; maxSize: number } {
119
+ return { size: cache.size, maxSize: MAX_CACHE_SIZE };
120
+ }
121
+
122
+ /**
123
+ * 清除所有缓存
124
+ */
125
+ export function clearUploadCache(): void {
126
+ cache.clear();
127
+ console.log(`[upload-cache] Cache cleared`);
128
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "rootDir": ".",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["index.ts", "src/**/*.ts"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }