@tencent-connect/openclaw-qqbot 1.7.1 → 2.0.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 (283) hide show
  1. package/README.md +206 -4
  2. package/README.zh.md +207 -4
  3. package/bin/qqbot-cli.js +5 -2
  4. package/dist/index.cjs +15549 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.cts +890 -0
  7. package/index.ts +56 -18
  8. package/openclaw.plugin.json +19 -3
  9. package/package.json +14 -23
  10. package/preload.cjs +17 -14
  11. package/scripts/link-sdk-core.cjs +133 -50
  12. package/scripts/upgrade-via-npm.sh +400 -73
  13. package/scripts/upgrade-via-source.sh +126 -89
  14. package/skills/qqbot-channel/SKILL.md +34 -12
  15. package/src/adapter/contract.ts +69 -0
  16. package/src/adapter/gateway.ts +61 -0
  17. package/src/adapter/index.ts +15 -0
  18. package/src/adapter/lint.ts +144 -0
  19. package/src/adapter/media.ts +112 -0
  20. package/src/adapter/pairing.ts +99 -0
  21. package/src/adapter/resolve.ts +333 -0
  22. package/src/adapter/setup.ts +55 -0
  23. package/src/adapter/webhook.ts +248 -0
  24. package/src/adapter/workspace.ts +29 -0
  25. package/src/bot-instance.ts +60 -0
  26. package/src/channel.ts +202 -413
  27. package/src/commands/bot-approve.ts +143 -0
  28. package/src/commands/bot-clear-storage.ts +114 -0
  29. package/src/commands/bot-group-always.ts +62 -0
  30. package/src/commands/bot-help.ts +40 -0
  31. package/src/commands/bot-logs.ts +248 -0
  32. package/src/commands/bot-me.ts +18 -0
  33. package/src/commands/bot-pairing.ts +57 -0
  34. package/src/commands/bot-ping.ts +33 -0
  35. package/src/commands/bot-streaming.ts +55 -0
  36. package/src/commands/bot-upgrade.ts +56 -0
  37. package/src/commands/bot-version.ts +41 -0
  38. package/src/commands/config-util.ts +96 -0
  39. package/src/commands/index.ts +49 -0
  40. package/src/config.ts +59 -19
  41. package/src/dispatch/body-assembler.ts +356 -0
  42. package/src/dispatch/ctx-builder.ts +110 -0
  43. package/src/dispatch/dispatch.ts +352 -0
  44. package/src/dispatch/envelope-builder.ts +112 -0
  45. package/src/dispatch/index.ts +2 -0
  46. package/src/{approval-handler.ts → features/approval-handler.ts} +40 -94
  47. package/src/features/approval-utils.ts +41 -0
  48. package/src/features/credential-backup.ts +82 -0
  49. package/src/features/history-store.ts +19 -0
  50. package/src/features/msgid-cache.ts +55 -0
  51. package/src/features/onboarding.ts +38 -0
  52. package/src/{proactive.ts → features/proactive.ts} +68 -49
  53. package/src/features/ref-index-store.ts +282 -0
  54. package/src/{update-checker.ts → features/update-checker.ts} +15 -35
  55. package/src/gateway/event-handlers.ts +241 -0
  56. package/src/gateway/index.ts +3 -0
  57. package/src/gateway/lifecycle.ts +221 -0
  58. package/src/gateway/middleware-setup.ts +139 -0
  59. package/src/gateway/qqbot-gateway.ts +342 -0
  60. package/src/middleware/access-control.ts +130 -0
  61. package/src/middleware/attachment.ts +314 -0
  62. package/src/middleware/policy-injector.ts +66 -0
  63. package/src/openclaw-plugin-sdk.d.ts +81 -10
  64. package/src/outbound/cron-scheduler.ts +130 -0
  65. package/src/outbound/debounce.ts +102 -0
  66. package/src/outbound/deliver-pipeline.ts +235 -0
  67. package/src/outbound/image-size.ts +123 -0
  68. package/src/outbound/index.ts +3 -0
  69. package/src/outbound/local-file-router.ts +145 -0
  70. package/src/outbound/media-send.ts +377 -0
  71. package/src/outbound/outbound-service.ts +222 -0
  72. package/src/outbound/reply-limiter.ts +128 -0
  73. package/src/outbound/sanitize.ts +32 -0
  74. package/src/outbound/streaming-controller.ts +228 -0
  75. package/src/outbound/target.ts +63 -0
  76. package/src/outbound/tts-provider.ts +84 -0
  77. package/src/request-context.ts +9 -8
  78. package/src/runtime.ts +31 -6
  79. package/src/setup/account-key.ts +41 -0
  80. package/src/setup/finalize.ts +110 -0
  81. package/src/setup/login.ts +197 -0
  82. package/src/setup/surface.ts +40 -0
  83. package/src/tools/platform.ts +149 -0
  84. package/src/tools/remind.ts +1 -1
  85. package/src/types-augment.d.ts +54 -0
  86. package/src/types.ts +71 -8
  87. package/src/typings/openclaw-webhook-ingress.d.ts +66 -0
  88. package/src/utils/mention.ts +52 -0
  89. package/src/utils/pkg-version.ts +84 -47
  90. package/src/utils/platform.ts +31 -7
  91. package/src/utils/plugin-logger.ts +104 -0
  92. package/src/utils/ssrf-guard.ts +32 -2
  93. package/src/utils/stt.ts +137 -0
  94. package/src/utils/voice-text.ts +61 -0
  95. package/tsconfig.json +2 -1
  96. package/tsup.config.ts +57 -0
  97. package/dist/index.d.ts +0 -17
  98. package/dist/index.js +0 -26
  99. package/dist/src/admin-resolver.d.ts +0 -33
  100. package/dist/src/admin-resolver.js +0 -157
  101. package/dist/src/api.d.ts +0 -307
  102. package/dist/src/api.js +0 -910
  103. package/dist/src/approval-handler.d.ts +0 -47
  104. package/dist/src/approval-handler.js +0 -372
  105. package/dist/src/channel.d.ts +0 -29
  106. package/dist/src/channel.js +0 -528
  107. package/dist/src/config.d.ts +0 -56
  108. package/dist/src/config.js +0 -278
  109. package/dist/src/credential-backup.d.ts +0 -31
  110. package/dist/src/credential-backup.js +0 -66
  111. package/dist/src/deliver-debounce.d.ts +0 -74
  112. package/dist/src/deliver-debounce.js +0 -174
  113. package/dist/src/gateway.d.ts +0 -18
  114. package/dist/src/gateway.js +0 -2063
  115. package/dist/src/group-history.d.ts +0 -136
  116. package/dist/src/group-history.js +0 -226
  117. package/dist/src/image-server.d.ts +0 -87
  118. package/dist/src/image-server.js +0 -570
  119. package/dist/src/inbound-attachments.d.ts +0 -60
  120. package/dist/src/inbound-attachments.js +0 -248
  121. package/dist/src/known-users.d.ts +0 -100
  122. package/dist/src/known-users.js +0 -263
  123. package/dist/src/message-gating.d.ts +0 -53
  124. package/dist/src/message-gating.js +0 -107
  125. package/dist/src/message-queue.d.ts +0 -91
  126. package/dist/src/message-queue.js +0 -257
  127. package/dist/src/onboarding.d.ts +0 -10
  128. package/dist/src/onboarding.js +0 -203
  129. package/dist/src/outbound-deliver.d.ts +0 -48
  130. package/dist/src/outbound-deliver.js +0 -392
  131. package/dist/src/outbound.d.ts +0 -220
  132. package/dist/src/outbound.js +0 -975
  133. package/dist/src/proactive.d.ts +0 -170
  134. package/dist/src/proactive.js +0 -399
  135. package/dist/src/ref-index-store.d.ts +0 -101
  136. package/dist/src/ref-index-store.js +0 -298
  137. package/dist/src/reply-dispatcher.d.ts +0 -35
  138. package/dist/src/reply-dispatcher.js +0 -311
  139. package/dist/src/request-context.d.ts +0 -25
  140. package/dist/src/request-context.js +0 -37
  141. package/dist/src/runtime.d.ts +0 -3
  142. package/dist/src/runtime.js +0 -13
  143. package/dist/src/session-store.d.ts +0 -52
  144. package/dist/src/session-store.js +0 -254
  145. package/dist/src/slash-commands.d.ts +0 -82
  146. package/dist/src/slash-commands.js +0 -2117
  147. package/dist/src/startup-greeting.d.ts +0 -30
  148. package/dist/src/startup-greeting.js +0 -97
  149. package/dist/src/streaming.d.ts +0 -247
  150. package/dist/src/streaming.js +0 -899
  151. package/dist/src/stt.d.ts +0 -21
  152. package/dist/src/stt.js +0 -70
  153. package/dist/src/tools/channel.d.ts +0 -16
  154. package/dist/src/tools/channel.js +0 -234
  155. package/dist/src/tools/remind.d.ts +0 -2
  156. package/dist/src/tools/remind.js +0 -256
  157. package/dist/src/types.d.ts +0 -443
  158. package/dist/src/types.js +0 -22
  159. package/dist/src/typing-keepalive.d.ts +0 -27
  160. package/dist/src/typing-keepalive.js +0 -64
  161. package/dist/src/update-checker.d.ts +0 -36
  162. package/dist/src/update-checker.js +0 -171
  163. package/dist/src/utils/audio-convert.d.ts +0 -98
  164. package/dist/src/utils/audio-convert.js +0 -755
  165. package/dist/src/utils/chunked-upload.d.ts +0 -68
  166. package/dist/src/utils/chunked-upload.js +0 -341
  167. package/dist/src/utils/file-utils.d.ts +0 -61
  168. package/dist/src/utils/file-utils.js +0 -172
  169. package/dist/src/utils/image-size.d.ts +0 -51
  170. package/dist/src/utils/image-size.js +0 -234
  171. package/dist/src/utils/media-send.d.ts +0 -158
  172. package/dist/src/utils/media-send.js +0 -502
  173. package/dist/src/utils/media-tags.d.ts +0 -14
  174. package/dist/src/utils/media-tags.js +0 -165
  175. package/dist/src/utils/payload.d.ts +0 -112
  176. package/dist/src/utils/payload.js +0 -186
  177. package/dist/src/utils/pkg-version.d.ts +0 -5
  178. package/dist/src/utils/pkg-version.js +0 -61
  179. package/dist/src/utils/platform.d.ts +0 -137
  180. package/dist/src/utils/platform.js +0 -390
  181. package/dist/src/utils/ssrf-guard.d.ts +0 -25
  182. package/dist/src/utils/ssrf-guard.js +0 -91
  183. package/dist/src/utils/text-parsing.d.ts +0 -31
  184. package/dist/src/utils/text-parsing.js +0 -74
  185. package/dist/src/utils/upload-cache.d.ts +0 -34
  186. package/dist/src/utils/upload-cache.js +0 -93
  187. package/node_modules/@eshaz/web-worker/LICENSE +0 -201
  188. package/node_modules/@eshaz/web-worker/README.md +0 -134
  189. package/node_modules/@eshaz/web-worker/browser.js +0 -17
  190. package/node_modules/@eshaz/web-worker/cjs/browser.js +0 -16
  191. package/node_modules/@eshaz/web-worker/cjs/node.js +0 -219
  192. package/node_modules/@eshaz/web-worker/index.d.ts +0 -4
  193. package/node_modules/@eshaz/web-worker/node.js +0 -223
  194. package/node_modules/@eshaz/web-worker/package.json +0 -54
  195. package/node_modules/@wasm-audio-decoders/common/index.js +0 -5
  196. package/node_modules/@wasm-audio-decoders/common/package.json +0 -36
  197. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderCommon.js +0 -231
  198. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderWorker.js +0 -129
  199. package/node_modules/@wasm-audio-decoders/common/src/puff/README +0 -67
  200. package/node_modules/@wasm-audio-decoders/common/src/puff/build_puff.js +0 -31
  201. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.c +0 -863
  202. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.h +0 -35
  203. package/node_modules/@wasm-audio-decoders/common/src/utilities.js +0 -3
  204. package/node_modules/@wasm-audio-decoders/common/types.d.ts +0 -7
  205. package/node_modules/mpg123-decoder/README.md +0 -265
  206. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js +0 -185
  207. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js.map +0 -1
  208. package/node_modules/mpg123-decoder/index.js +0 -8
  209. package/node_modules/mpg123-decoder/package.json +0 -58
  210. package/node_modules/mpg123-decoder/src/EmscriptenWasm.js +0 -464
  211. package/node_modules/mpg123-decoder/src/MPEGDecoder.js +0 -200
  212. package/node_modules/mpg123-decoder/src/MPEGDecoderWebWorker.js +0 -21
  213. package/node_modules/mpg123-decoder/types.d.ts +0 -30
  214. package/node_modules/silk-wasm/LICENSE +0 -21
  215. package/node_modules/silk-wasm/README.md +0 -85
  216. package/node_modules/silk-wasm/lib/index.cjs +0 -16
  217. package/node_modules/silk-wasm/lib/index.d.ts +0 -70
  218. package/node_modules/silk-wasm/lib/index.mjs +0 -16
  219. package/node_modules/silk-wasm/lib/silk.wasm +0 -0
  220. package/node_modules/silk-wasm/lib/utils.d.ts +0 -4
  221. package/node_modules/silk-wasm/package.json +0 -39
  222. package/node_modules/simple-yenc/.github/FUNDING.yml +0 -1
  223. package/node_modules/simple-yenc/.prettierignore +0 -1
  224. package/node_modules/simple-yenc/LICENSE +0 -7
  225. package/node_modules/simple-yenc/README.md +0 -163
  226. package/node_modules/simple-yenc/dist/esm.js +0 -1
  227. package/node_modules/simple-yenc/dist/index.js +0 -1
  228. package/node_modules/simple-yenc/package.json +0 -50
  229. package/node_modules/simple-yenc/rollup.config.js +0 -27
  230. package/node_modules/simple-yenc/src/simple-yenc.js +0 -302
  231. package/node_modules/ws/LICENSE +0 -20
  232. package/node_modules/ws/README.md +0 -548
  233. package/node_modules/ws/browser.js +0 -8
  234. package/node_modules/ws/index.js +0 -13
  235. package/node_modules/ws/lib/buffer-util.js +0 -131
  236. package/node_modules/ws/lib/constants.js +0 -19
  237. package/node_modules/ws/lib/event-target.js +0 -292
  238. package/node_modules/ws/lib/extension.js +0 -203
  239. package/node_modules/ws/lib/limiter.js +0 -55
  240. package/node_modules/ws/lib/permessage-deflate.js +0 -528
  241. package/node_modules/ws/lib/receiver.js +0 -706
  242. package/node_modules/ws/lib/sender.js +0 -602
  243. package/node_modules/ws/lib/stream.js +0 -161
  244. package/node_modules/ws/lib/subprotocol.js +0 -62
  245. package/node_modules/ws/lib/validation.js +0 -152
  246. package/node_modules/ws/lib/websocket-server.js +0 -554
  247. package/node_modules/ws/lib/websocket.js +0 -1393
  248. package/node_modules/ws/package.json +0 -69
  249. package/node_modules/ws/wrapper.mjs +0 -8
  250. package/scripts/postinstall-link-sdk.js +0 -126
  251. package/skills/qqbot-media/SKILL.md +0 -60
  252. package/src/admin-resolver.ts +0 -181
  253. package/src/api.ts +0 -1319
  254. package/src/credential-backup.ts +0 -72
  255. package/src/deliver-debounce.ts +0 -229
  256. package/src/gateway.ts +0 -2304
  257. package/src/group-history.ts +0 -328
  258. package/src/image-server.ts +0 -675
  259. package/src/inbound-attachments.ts +0 -321
  260. package/src/known-users.ts +0 -353
  261. package/src/message-gating.ts +0 -190
  262. package/src/message-queue.ts +0 -354
  263. package/src/onboarding.ts +0 -274
  264. package/src/outbound-deliver.ts +0 -486
  265. package/src/outbound.ts +0 -1179
  266. package/src/ref-index-store.ts +0 -412
  267. package/src/reply-dispatcher.ts +0 -334
  268. package/src/session-store.ts +0 -303
  269. package/src/slash-commands.ts +0 -2297
  270. package/src/startup-greeting.ts +0 -120
  271. package/src/streaming.ts +0 -1077
  272. package/src/stt.ts +0 -86
  273. package/src/tools/channel.ts +0 -281
  274. package/src/typing-keepalive.ts +0 -59
  275. package/src/utils/audio-convert.ts +0 -859
  276. package/src/utils/chunked-upload.ts +0 -483
  277. package/src/utils/file-utils.ts +0 -193
  278. package/src/utils/image-size.ts +0 -266
  279. package/src/utils/media-send.ts +0 -636
  280. package/src/utils/media-tags.ts +0 -183
  281. package/src/utils/payload.ts +0 -265
  282. package/src/utils/text-parsing.ts +0 -85
  283. package/src/utils/upload-cache.ts +0 -128
@@ -1,112 +0,0 @@
1
- /**
2
- * QQBot 结构化消息载荷工具
3
- *
4
- * 用于处理 AI 输出的结构化消息载荷,包括:
5
- * - 定时提醒载荷 (cron_reminder)
6
- * - 媒体消息载荷 (media)
7
- */
8
- /**
9
- * 定时提醒载荷
10
- */
11
- export interface CronReminderPayload {
12
- type: 'cron_reminder';
13
- /** 提醒内容 */
14
- content: string;
15
- /** 目标类型:c2c (私聊) 或 group (群聊) */
16
- targetType: 'c2c' | 'group';
17
- /** 目标地址:user_openid 或 group_openid */
18
- targetAddress: string;
19
- /** 原始消息 ID(可选) */
20
- originalMessageId?: string;
21
- }
22
- /**
23
- * 媒体消息载荷
24
- */
25
- export interface MediaPayload {
26
- type: 'media';
27
- /** 媒体类型:image, audio, video, file */
28
- mediaType: 'image' | 'audio' | 'video' | 'file';
29
- /** 来源类型:url 或 file */
30
- source: 'url' | 'file';
31
- /** 媒体路径或 URL */
32
- path: string;
33
- /** 媒体描述(可选) */
34
- caption?: string;
35
- }
36
- /**
37
- * QQBot 载荷联合类型
38
- */
39
- export type QQBotPayload = CronReminderPayload | MediaPayload;
40
- /**
41
- * 解析结果
42
- */
43
- export interface ParseResult {
44
- /** 是否为结构化载荷 */
45
- isPayload: boolean;
46
- /** 解析后的载荷对象(如果是结构化载荷) */
47
- payload?: QQBotPayload;
48
- /** 原始文本(如果不是结构化载荷) */
49
- text?: string;
50
- /** 解析错误信息(如果解析失败) */
51
- error?: string;
52
- }
53
- /**
54
- * 解析 AI 输出的结构化载荷
55
- *
56
- * 检测消息是否以 QQBOT_PAYLOAD: 前缀开头,如果是则提取并解析 JSON
57
- *
58
- * @param text AI 输出的原始文本
59
- * @returns 解析结果
60
- *
61
- * @example
62
- * const result = parseQQBotPayload('QQBOT_PAYLOAD:\n{"type": "media", "mediaType": "image", ...}');
63
- * if (result.isPayload && result.payload) {
64
- * // 处理结构化载荷
65
- * }
66
- */
67
- export declare function parseQQBotPayload(text: string): ParseResult;
68
- /**
69
- * 将定时提醒载荷编码为 Cron 消息格式
70
- *
71
- * 将 JSON 编码为 Base64,并添加 QQBOT_CRON: 前缀
72
- *
73
- * @param payload 定时提醒载荷
74
- * @returns 编码后的消息字符串,格式为 QQBOT_CRON:{base64}
75
- *
76
- * @example
77
- * const message = encodePayloadForCron({
78
- * type: 'cron_reminder',
79
- * content: '喝水时间到!',
80
- * targetType: 'c2c',
81
- * targetAddress: 'user_openid_xxx'
82
- * });
83
- * // 返回: QQBOT_CRON:eyJ0eXBlIjoiY3Jvbl9yZW1pbmRlciIs...
84
- */
85
- export declare function encodePayloadForCron(payload: CronReminderPayload): string;
86
- /**
87
- * 解码 Cron 消息中的载荷
88
- *
89
- * 检测 QQBOT_CRON: 前缀,解码 Base64 并解析 JSON
90
- *
91
- * @param message Cron 触发时收到的消息
92
- * @returns 解码结果,包含是否为 Cron 载荷、解析后的载荷对象或错误信息
93
- *
94
- * @example
95
- * const result = decodeCronPayload('QQBOT_CRON:eyJ0eXBlIjoiY3Jvbl9yZW1pbmRlciIs...');
96
- * if (result.isCronPayload && result.payload) {
97
- * // 处理定时提醒
98
- * }
99
- */
100
- export declare function decodeCronPayload(message: string): {
101
- isCronPayload: boolean;
102
- payload?: CronReminderPayload;
103
- error?: string;
104
- };
105
- /**
106
- * 判断载荷是否为定时提醒类型
107
- */
108
- export declare function isCronReminderPayload(payload: QQBotPayload): payload is CronReminderPayload;
109
- /**
110
- * 判断载荷是否为媒体消息类型
111
- */
112
- export declare function isMediaPayload(payload: QQBotPayload): payload is MediaPayload;
@@ -1,186 +0,0 @@
1
- /**
2
- * QQBot 结构化消息载荷工具
3
- *
4
- * 用于处理 AI 输出的结构化消息载荷,包括:
5
- * - 定时提醒载荷 (cron_reminder)
6
- * - 媒体消息载荷 (media)
7
- */
8
- // ============================================
9
- // 常量定义
10
- // ============================================
11
- /** AI 输出的结构化载荷前缀 */
12
- const PAYLOAD_PREFIX = 'QQBOT_PAYLOAD:';
13
- /** Cron 消息存储的前缀 */
14
- const CRON_PREFIX = 'QQBOT_CRON:';
15
- // ============================================
16
- // 解析函数
17
- // ============================================
18
- /**
19
- * 解析 AI 输出的结构化载荷
20
- *
21
- * 检测消息是否以 QQBOT_PAYLOAD: 前缀开头,如果是则提取并解析 JSON
22
- *
23
- * @param text AI 输出的原始文本
24
- * @returns 解析结果
25
- *
26
- * @example
27
- * const result = parseQQBotPayload('QQBOT_PAYLOAD:\n{"type": "media", "mediaType": "image", ...}');
28
- * if (result.isPayload && result.payload) {
29
- * // 处理结构化载荷
30
- * }
31
- */
32
- export function parseQQBotPayload(text) {
33
- const trimmedText = text.trim();
34
- // 检查是否以 QQBOT_PAYLOAD: 开头
35
- if (!trimmedText.startsWith(PAYLOAD_PREFIX)) {
36
- return {
37
- isPayload: false,
38
- text: text
39
- };
40
- }
41
- // 提取 JSON 内容(去掉前缀)
42
- const jsonContent = trimmedText.slice(PAYLOAD_PREFIX.length).trim();
43
- if (!jsonContent) {
44
- return {
45
- isPayload: true,
46
- error: '载荷内容为空'
47
- };
48
- }
49
- try {
50
- const payload = JSON.parse(jsonContent);
51
- // 验证必要字段
52
- if (!payload.type) {
53
- return {
54
- isPayload: true,
55
- error: '载荷缺少 type 字段'
56
- };
57
- }
58
- // 根据 type 进行额外验证
59
- if (payload.type === 'cron_reminder') {
60
- if (!payload.content || !payload.targetType || !payload.targetAddress) {
61
- return {
62
- isPayload: true,
63
- error: 'cron_reminder 载荷缺少必要字段 (content, targetType, targetAddress)'
64
- };
65
- }
66
- }
67
- else if (payload.type === 'media') {
68
- if (!payload.mediaType || !payload.source || !payload.path) {
69
- return {
70
- isPayload: true,
71
- error: 'media 载荷缺少必要字段 (mediaType, source, path)'
72
- };
73
- }
74
- }
75
- return {
76
- isPayload: true,
77
- payload
78
- };
79
- }
80
- catch (e) {
81
- return {
82
- isPayload: true,
83
- error: `JSON 解析失败: ${e instanceof Error ? e.message : String(e)}`
84
- };
85
- }
86
- }
87
- // ============================================
88
- // Cron 编码/解码函数
89
- // ============================================
90
- /**
91
- * 将定时提醒载荷编码为 Cron 消息格式
92
- *
93
- * 将 JSON 编码为 Base64,并添加 QQBOT_CRON: 前缀
94
- *
95
- * @param payload 定时提醒载荷
96
- * @returns 编码后的消息字符串,格式为 QQBOT_CRON:{base64}
97
- *
98
- * @example
99
- * const message = encodePayloadForCron({
100
- * type: 'cron_reminder',
101
- * content: '喝水时间到!',
102
- * targetType: 'c2c',
103
- * targetAddress: 'user_openid_xxx'
104
- * });
105
- * // 返回: QQBOT_CRON:eyJ0eXBlIjoiY3Jvbl9yZW1pbmRlciIs...
106
- */
107
- export function encodePayloadForCron(payload) {
108
- const jsonString = JSON.stringify(payload);
109
- const base64 = Buffer.from(jsonString, 'utf-8').toString('base64');
110
- return `${CRON_PREFIX}${base64}`;
111
- }
112
- /**
113
- * 解码 Cron 消息中的载荷
114
- *
115
- * 检测 QQBOT_CRON: 前缀,解码 Base64 并解析 JSON
116
- *
117
- * @param message Cron 触发时收到的消息
118
- * @returns 解码结果,包含是否为 Cron 载荷、解析后的载荷对象或错误信息
119
- *
120
- * @example
121
- * const result = decodeCronPayload('QQBOT_CRON:eyJ0eXBlIjoiY3Jvbl9yZW1pbmRlciIs...');
122
- * if (result.isCronPayload && result.payload) {
123
- * // 处理定时提醒
124
- * }
125
- */
126
- export function decodeCronPayload(message) {
127
- const trimmedMessage = message.trim();
128
- // 检查是否以 QQBOT_CRON: 开头
129
- if (!trimmedMessage.startsWith(CRON_PREFIX)) {
130
- return {
131
- isCronPayload: false
132
- };
133
- }
134
- // 提取 Base64 内容
135
- const base64Content = trimmedMessage.slice(CRON_PREFIX.length);
136
- if (!base64Content) {
137
- return {
138
- isCronPayload: true,
139
- error: 'Cron 载荷内容为空'
140
- };
141
- }
142
- try {
143
- // Base64 解码
144
- const jsonString = Buffer.from(base64Content, 'base64').toString('utf-8');
145
- const payload = JSON.parse(jsonString);
146
- // 验证类型
147
- if (payload.type !== 'cron_reminder') {
148
- return {
149
- isCronPayload: true,
150
- error: `期望 type 为 cron_reminder,实际为 ${payload.type}`
151
- };
152
- }
153
- // 验证必要字段
154
- if (!payload.content || !payload.targetType || !payload.targetAddress) {
155
- return {
156
- isCronPayload: true,
157
- error: 'Cron 载荷缺少必要字段'
158
- };
159
- }
160
- return {
161
- isCronPayload: true,
162
- payload
163
- };
164
- }
165
- catch (e) {
166
- return {
167
- isCronPayload: true,
168
- error: `Cron 载荷解码失败: ${e instanceof Error ? e.message : String(e)}`
169
- };
170
- }
171
- }
172
- // ============================================
173
- // 辅助函数
174
- // ============================================
175
- /**
176
- * 判断载荷是否为定时提醒类型
177
- */
178
- export function isCronReminderPayload(payload) {
179
- return payload.type === 'cron_reminder';
180
- }
181
- /**
182
- * 判断载荷是否为媒体消息类型
183
- */
184
- export function isMediaPayload(payload) {
185
- return payload.type === 'media';
186
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * 从 import.meta.url 向上遍历目录树查找 package.json 并读取 version。
3
- * 不依赖硬编码的 "../" 层级,无论编译输出结构如何变化都能可靠找到。
4
- */
5
- export declare function getPackageVersion(metaUrl?: string): string;
@@ -1,61 +0,0 @@
1
- /**
2
- * 从 import.meta.url 向上遍历目录树查找 package.json 并读取 version。
3
- * 不依赖硬编码的 "../" 层级,无论编译输出结构如何变化都能可靠找到。
4
- */
5
- import { fileURLToPath } from "node:url";
6
- import { createRequire } from "node:module";
7
- import path from "node:path";
8
- import fs from "node:fs";
9
- /** 已定位到的 package.json 路径,避免重复遍历目录树 */
10
- let _resolvedPkgPath = null;
11
- export function getPackageVersion(metaUrl) {
12
- // 如果之前已定位到 package.json 路径,直接重新读取(快速路径)
13
- if (_resolvedPkgPath) {
14
- try {
15
- const pkg = JSON.parse(fs.readFileSync(_resolvedPkgPath, "utf8"));
16
- if (pkg.name === "@tencent-connect/openclaw-qqbot" && pkg.version) {
17
- return pkg.version;
18
- }
19
- }
20
- catch {
21
- // 文件可能已被删除(升级过程中),清除路径缓存,走完整查找
22
- _resolvedPkgPath = null;
23
- }
24
- }
25
- // Strategy 1: 从调用者的 import.meta.url(或本模块)向上遍历找 package.json
26
- const startFile = metaUrl ? fileURLToPath(metaUrl) : fileURLToPath(import.meta.url);
27
- let dir = path.dirname(startFile);
28
- const root = path.parse(dir).root;
29
- while (dir !== root) {
30
- const candidate = path.join(dir, "package.json");
31
- try {
32
- if (fs.existsSync(candidate)) {
33
- const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
34
- // 确认是我们自己的包(避免找到其他 package.json)
35
- if (pkg.name === "@tencent-connect/openclaw-qqbot" && pkg.version) {
36
- _resolvedPkgPath = candidate;
37
- return pkg.version;
38
- }
39
- }
40
- }
41
- catch {
42
- // ignore and try parent
43
- }
44
- dir = path.dirname(dir);
45
- }
46
- // Strategy 2: fallback 用 createRequire 尝试常见相对路径
47
- try {
48
- const require = createRequire(metaUrl ?? import.meta.url);
49
- for (const rel of ["../../package.json", "../package.json", "./package.json"]) {
50
- try {
51
- const pkg = require(rel);
52
- if (pkg?.version) {
53
- return pkg.version;
54
- }
55
- }
56
- catch { /* next */ }
57
- }
58
- }
59
- catch { /* fallback */ }
60
- return "unknown";
61
- }
@@ -1,137 +0,0 @@
1
- /**
2
- * 跨平台兼容工具
3
- *
4
- * 统一 Mac / Linux / Windows 三大系统的:
5
- * - 用户主目录获取
6
- * - 临时目录获取
7
- * - 本地路径判断
8
- * - ffmpeg / ffprobe 可执行文件路径
9
- * - silk-wasm 原生模块兼容性检测
10
- * - 启动诊断报告
11
- */
12
- export type PlatformType = "darwin" | "linux" | "win32" | "other";
13
- export declare function getPlatform(): PlatformType;
14
- export declare function isWindows(): boolean;
15
- /**
16
- * 安全获取用户主目录
17
- *
18
- * 优先级:
19
- * 1. os.homedir()(Node 原生,所有平台)
20
- * 2. $HOME(Mac/Linux)或 %USERPROFILE%(Windows)
21
- * 3. 降级到 /tmp(Linux/Mac)或 os.tmpdir()(Windows)
22
- *
23
- * 与之前 `process.env.HOME || "/home/ubuntu"` 的硬编码相比,
24
- * 现在能正确处理 Windows 和非 ubuntu 用户。
25
- */
26
- export declare function getHomeDir(): string;
27
- /**
28
- * 获取 .openclaw/qqbot 下的子目录路径,并自动创建
29
- * 替代各文件中分散的 path.join(HOME, ".openclaw", "qqbot", ...)
30
- */
31
- export declare function getQQBotDataDir(...subPaths: string[]): string;
32
- /**
33
- * 获取 .openclaw/media/qqbot 下的子目录路径,并自动创建
34
- *
35
- * 与 getQQBotDataDir 不同,此目录位于 OpenClaw 核心的媒体安全白名单
36
- * (~/.openclaw/media) 之下,下载到这里的文件可以被框架的 image/media
37
- * 工具直接访问,不会触发 "Local media path is not under an allowed directory" 错误。
38
- *
39
- * 用于存放从 QQ 下载的图片、语音等需要被框架处理的媒体文件。
40
- */
41
- export declare function getQQBotMediaDir(...subPaths: string[]): string;
42
- /**
43
- * 获取系统临时目录(跨平台安全)
44
- * Mac: /var/folders/... 或 /tmp
45
- * Linux: /tmp
46
- * Windows: %TEMP% 或 C:\Users\xxx\AppData\Local\Temp
47
- */
48
- export declare function getTempDir(): string;
49
- /**
50
- * 展开路径中的波浪线(~)为用户主目录
51
- *
52
- * Mac/Linux 用户经常使用 `~/Desktop/file.png` 这样的路径,
53
- * 但 Node.js 的 fs 模块不会像 shell 一样自动展开 `~`。
54
- *
55
- * 支持:
56
- * - `~/xxx` → `/Users/you/xxx`(Mac)或 `/home/you/xxx`(Linux)
57
- * - `~` → `/Users/you`
58
- * - 非 `~` 开头的路径原样返回
59
- *
60
- * 注意: 不支持 `~otheruser/xxx` 语法(极少使用,且需要系统调用获取其他用户信息)
61
- */
62
- export declare function expandTilde(p: string): string;
63
- /**
64
- * 对路径进行完整的规范化处理:剥离 file:// 前缀 + 展开波浪线 + 去除首尾空白
65
- * 所有文件操作前应通过此函数处理用户输入的路径
66
- */
67
- export declare function normalizePath(p: string): string;
68
- /**
69
- * 规范化文件名为 QQ Bot API 要求的 UTF-8 编码格式
70
- *
71
- * 问题场景:
72
- * - macOS HFS+/APFS 文件系统使用 NFD(Unicode 分解形式)存储文件名,
73
- * 例如「中文.txt」被分解为多个码点,QQ Bot API 可能拒绝
74
- * - 文件名可能包含 API 不接受的特殊控制字符
75
- * - URL 路径中可能包含 percent-encoded 的文件名需要解码
76
- *
77
- * 处理:
78
- * 1. Unicode NFC 规范化(将 NFD 分解形式合并为 NFC 组合形式)
79
- * 2. 去除 ASCII 控制字符(0x00-0x1F, 0x7F)
80
- * 3. 去除首尾空白
81
- * 4. 对 percent-encoded 的文件名尝试 URI 解码
82
- */
83
- export declare function sanitizeFileName(name: string): string;
84
- /**
85
- * 判断字符串是否为本地文件路径(非 URL)
86
- *
87
- * 覆盖:
88
- * - Unix 绝对路径: /Users/..., /home/..., /tmp/...
89
- * - Windows 绝对路径: C:\..., D:/..., \\server\share
90
- * - 相对路径: ./file, ../file
91
- * - 波浪线路径: ~/Desktop/file.png
92
- * - file:// 协议: file:///Users/..., file:///home/...
93
- *
94
- * 不匹配:
95
- * - http:// / https:// URL
96
- * - data: URL
97
- */
98
- export declare function isLocalPath(p: string): boolean;
99
- /**
100
- * 判断 markdown 中提取的路径是否像本地路径
101
- * 比 isLocalPath 更宽松,用于从 markdown ![](path) 中检测误用
102
- */
103
- export declare function looksLikeLocalPath(p: string): boolean;
104
- /**
105
- * 检测 ffmpeg 是否可用,返回可执行路径
106
- *
107
- * Windows 上检测 ffmpeg.exe,Mac/Linux 检测 ffmpeg
108
- * 支持通过环境变量 FFMPEG_PATH 指定自定义路径
109
- *
110
- * @returns ffmpeg 可执行文件路径,不可用返回 null
111
- */
112
- export declare function detectFfmpeg(): Promise<string | null>;
113
- /** 重置 ffmpeg 缓存(用于测试) */
114
- export declare function resetFfmpegCache(): void;
115
- /**
116
- * 检测 silk-wasm 是否可用
117
- *
118
- * silk-wasm 依赖 WASM 运行时,在某些环境(如老版本 Node、某些容器)可能不可用。
119
- * 提前检测避免运行时崩溃。
120
- */
121
- export declare function checkSilkWasmAvailable(): Promise<boolean>;
122
- export interface DiagnosticReport {
123
- platform: string;
124
- arch: string;
125
- nodeVersion: string;
126
- homeDir: string;
127
- tempDir: string;
128
- dataDir: string;
129
- ffmpeg: string | null;
130
- silkWasm: boolean;
131
- warnings: string[];
132
- }
133
- /**
134
- * 运行启动诊断,返回环境报告
135
- * 在 gateway 启动时调用,打印环境信息并给出警告
136
- */
137
- export declare function runDiagnostics(): Promise<DiagnosticReport>;