@tencent-connect/openclaw-qqbot 1.7.2 → 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 (291) hide show
  1. package/README.md +25 -8
  2. package/README.zh.md +24 -8
  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 -19
  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 +42 -11
  13. package/scripts/upgrade-via-source.sh +4 -4
  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 +46 -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 +2 -0
  85. package/src/types-augment.d.ts +54 -0
  86. package/src/types.ts +51 -9
  87. package/src/utils/mention.ts +52 -0
  88. package/src/utils/pkg-version.ts +84 -47
  89. package/src/utils/platform.ts +31 -7
  90. package/src/utils/plugin-logger.ts +104 -0
  91. package/src/utils/ssrf-guard.ts +32 -2
  92. package/src/utils/stt.ts +137 -0
  93. package/src/utils/voice-text.ts +61 -0
  94. package/tsconfig.json +2 -1
  95. package/tsup.config.ts +57 -0
  96. package/dist/index.d.ts +0 -18
  97. package/dist/index.js +0 -27
  98. package/dist/src/admin-resolver.d.ts +0 -33
  99. package/dist/src/admin-resolver.js +0 -157
  100. package/dist/src/api.d.ts +0 -309
  101. package/dist/src/api.js +0 -923
  102. package/dist/src/approval-handler.d.ts +0 -47
  103. package/dist/src/approval-handler.js +0 -372
  104. package/dist/src/channel.d.ts +0 -29
  105. package/dist/src/channel.js +0 -528
  106. package/dist/src/config.d.ts +0 -60
  107. package/dist/src/config.js +0 -288
  108. package/dist/src/credential-backup.d.ts +0 -31
  109. package/dist/src/credential-backup.js +0 -66
  110. package/dist/src/deliver-debounce.d.ts +0 -74
  111. package/dist/src/deliver-debounce.js +0 -174
  112. package/dist/src/gateway.d.ts +0 -18
  113. package/dist/src/gateway.js +0 -2025
  114. package/dist/src/group-history.d.ts +0 -136
  115. package/dist/src/group-history.js +0 -226
  116. package/dist/src/image-server.d.ts +0 -87
  117. package/dist/src/image-server.js +0 -570
  118. package/dist/src/inbound-attachments.d.ts +0 -60
  119. package/dist/src/inbound-attachments.js +0 -248
  120. package/dist/src/known-users.d.ts +0 -100
  121. package/dist/src/known-users.js +0 -263
  122. package/dist/src/message-gating.d.ts +0 -53
  123. package/dist/src/message-gating.js +0 -107
  124. package/dist/src/message-queue.d.ts +0 -91
  125. package/dist/src/message-queue.js +0 -257
  126. package/dist/src/onboarding.d.ts +0 -10
  127. package/dist/src/onboarding.js +0 -203
  128. package/dist/src/outbound-deliver.d.ts +0 -48
  129. package/dist/src/outbound-deliver.js +0 -392
  130. package/dist/src/outbound.d.ts +0 -220
  131. package/dist/src/outbound.js +0 -975
  132. package/dist/src/proactive.d.ts +0 -170
  133. package/dist/src/proactive.js +0 -399
  134. package/dist/src/ref-index-store.d.ts +0 -101
  135. package/dist/src/ref-index-store.js +0 -298
  136. package/dist/src/reply-dispatcher.d.ts +0 -35
  137. package/dist/src/reply-dispatcher.js +0 -311
  138. package/dist/src/request-context.d.ts +0 -25
  139. package/dist/src/request-context.js +0 -37
  140. package/dist/src/runtime.d.ts +0 -3
  141. package/dist/src/runtime.js +0 -13
  142. package/dist/src/session-store.d.ts +0 -52
  143. package/dist/src/session-store.js +0 -254
  144. package/dist/src/slash-commands.d.ts +0 -82
  145. package/dist/src/slash-commands.js +0 -2233
  146. package/dist/src/startup-greeting.d.ts +0 -30
  147. package/dist/src/startup-greeting.js +0 -97
  148. package/dist/src/streaming.d.ts +0 -247
  149. package/dist/src/streaming.js +0 -899
  150. package/dist/src/stt.d.ts +0 -21
  151. package/dist/src/stt.js +0 -70
  152. package/dist/src/tools/channel.d.ts +0 -16
  153. package/dist/src/tools/channel.js +0 -231
  154. package/dist/src/tools/remind.d.ts +0 -2
  155. package/dist/src/tools/remind.js +0 -255
  156. package/dist/src/transport/index.d.ts +0 -10
  157. package/dist/src/transport/index.js +0 -9
  158. package/dist/src/transport/webhook-transport.d.ts +0 -67
  159. package/dist/src/transport/webhook-transport.js +0 -245
  160. package/dist/src/transport/webhook-verify.d.ts +0 -48
  161. package/dist/src/transport/webhook-verify.js +0 -98
  162. package/dist/src/types.d.ts +0 -462
  163. package/dist/src/types.js +0 -22
  164. package/dist/src/typing-keepalive.d.ts +0 -27
  165. package/dist/src/typing-keepalive.js +0 -64
  166. package/dist/src/update-checker.d.ts +0 -36
  167. package/dist/src/update-checker.js +0 -171
  168. package/dist/src/utils/audio-convert.d.ts +0 -98
  169. package/dist/src/utils/audio-convert.js +0 -783
  170. package/dist/src/utils/chunked-upload.d.ts +0 -68
  171. package/dist/src/utils/chunked-upload.js +0 -341
  172. package/dist/src/utils/file-utils.d.ts +0 -61
  173. package/dist/src/utils/file-utils.js +0 -172
  174. package/dist/src/utils/image-size.d.ts +0 -51
  175. package/dist/src/utils/image-size.js +0 -234
  176. package/dist/src/utils/media-send.d.ts +0 -158
  177. package/dist/src/utils/media-send.js +0 -502
  178. package/dist/src/utils/media-tags.d.ts +0 -14
  179. package/dist/src/utils/media-tags.js +0 -165
  180. package/dist/src/utils/payload.d.ts +0 -112
  181. package/dist/src/utils/payload.js +0 -186
  182. package/dist/src/utils/pkg-version.d.ts +0 -5
  183. package/dist/src/utils/pkg-version.js +0 -61
  184. package/dist/src/utils/platform.d.ts +0 -137
  185. package/dist/src/utils/platform.js +0 -390
  186. package/dist/src/utils/ssrf-guard.d.ts +0 -25
  187. package/dist/src/utils/ssrf-guard.js +0 -91
  188. package/dist/src/utils/text-parsing.d.ts +0 -31
  189. package/dist/src/utils/text-parsing.js +0 -74
  190. package/dist/src/utils/upload-cache.d.ts +0 -34
  191. package/dist/src/utils/upload-cache.js +0 -93
  192. package/node_modules/@eshaz/web-worker/LICENSE +0 -201
  193. package/node_modules/@eshaz/web-worker/README.md +0 -134
  194. package/node_modules/@eshaz/web-worker/browser.js +0 -17
  195. package/node_modules/@eshaz/web-worker/cjs/browser.js +0 -16
  196. package/node_modules/@eshaz/web-worker/cjs/node.js +0 -219
  197. package/node_modules/@eshaz/web-worker/index.d.ts +0 -4
  198. package/node_modules/@eshaz/web-worker/node.js +0 -223
  199. package/node_modules/@eshaz/web-worker/package.json +0 -54
  200. package/node_modules/@wasm-audio-decoders/common/index.js +0 -5
  201. package/node_modules/@wasm-audio-decoders/common/package.json +0 -36
  202. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderCommon.js +0 -231
  203. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderWorker.js +0 -129
  204. package/node_modules/@wasm-audio-decoders/common/src/puff/README +0 -67
  205. package/node_modules/@wasm-audio-decoders/common/src/puff/build_puff.js +0 -31
  206. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.c +0 -863
  207. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.h +0 -35
  208. package/node_modules/@wasm-audio-decoders/common/src/utilities.js +0 -3
  209. package/node_modules/@wasm-audio-decoders/common/types.d.ts +0 -7
  210. package/node_modules/mpg123-decoder/README.md +0 -265
  211. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js +0 -185
  212. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js.map +0 -1
  213. package/node_modules/mpg123-decoder/index.js +0 -8
  214. package/node_modules/mpg123-decoder/package.json +0 -58
  215. package/node_modules/mpg123-decoder/src/EmscriptenWasm.js +0 -464
  216. package/node_modules/mpg123-decoder/src/MPEGDecoder.js +0 -200
  217. package/node_modules/mpg123-decoder/src/MPEGDecoderWebWorker.js +0 -21
  218. package/node_modules/mpg123-decoder/types.d.ts +0 -30
  219. package/node_modules/silk-wasm/LICENSE +0 -21
  220. package/node_modules/silk-wasm/README.md +0 -85
  221. package/node_modules/silk-wasm/lib/index.cjs +0 -16
  222. package/node_modules/silk-wasm/lib/index.d.ts +0 -70
  223. package/node_modules/silk-wasm/lib/index.mjs +0 -16
  224. package/node_modules/silk-wasm/lib/silk.wasm +0 -0
  225. package/node_modules/silk-wasm/lib/utils.d.ts +0 -4
  226. package/node_modules/silk-wasm/package.json +0 -39
  227. package/node_modules/simple-yenc/.github/FUNDING.yml +0 -1
  228. package/node_modules/simple-yenc/.prettierignore +0 -1
  229. package/node_modules/simple-yenc/LICENSE +0 -7
  230. package/node_modules/simple-yenc/README.md +0 -163
  231. package/node_modules/simple-yenc/dist/esm.js +0 -1
  232. package/node_modules/simple-yenc/dist/index.js +0 -1
  233. package/node_modules/simple-yenc/package.json +0 -50
  234. package/node_modules/simple-yenc/rollup.config.js +0 -27
  235. package/node_modules/simple-yenc/src/simple-yenc.js +0 -302
  236. package/node_modules/ws/LICENSE +0 -20
  237. package/node_modules/ws/README.md +0 -548
  238. package/node_modules/ws/browser.js +0 -8
  239. package/node_modules/ws/index.js +0 -13
  240. package/node_modules/ws/lib/buffer-util.js +0 -131
  241. package/node_modules/ws/lib/constants.js +0 -19
  242. package/node_modules/ws/lib/event-target.js +0 -292
  243. package/node_modules/ws/lib/extension.js +0 -203
  244. package/node_modules/ws/lib/limiter.js +0 -55
  245. package/node_modules/ws/lib/permessage-deflate.js +0 -528
  246. package/node_modules/ws/lib/receiver.js +0 -706
  247. package/node_modules/ws/lib/sender.js +0 -602
  248. package/node_modules/ws/lib/stream.js +0 -161
  249. package/node_modules/ws/lib/subprotocol.js +0 -62
  250. package/node_modules/ws/lib/validation.js +0 -152
  251. package/node_modules/ws/lib/websocket-server.js +0 -554
  252. package/node_modules/ws/lib/websocket.js +0 -1393
  253. package/node_modules/ws/package.json +0 -69
  254. package/node_modules/ws/wrapper.mjs +0 -8
  255. package/scripts/postinstall-link-sdk.js +0 -170
  256. package/skills/qqbot-media/SKILL.md +0 -60
  257. package/src/admin-resolver.ts +0 -181
  258. package/src/api.ts +0 -1333
  259. package/src/credential-backup.ts +0 -72
  260. package/src/deliver-debounce.ts +0 -229
  261. package/src/gateway.ts +0 -2272
  262. package/src/group-history.ts +0 -328
  263. package/src/image-server.ts +0 -675
  264. package/src/inbound-attachments.ts +0 -321
  265. package/src/known-users.ts +0 -353
  266. package/src/message-gating.ts +0 -190
  267. package/src/message-queue.ts +0 -354
  268. package/src/onboarding.ts +0 -282
  269. package/src/outbound-deliver.ts +0 -486
  270. package/src/outbound.ts +0 -1179
  271. package/src/ref-index-store.ts +0 -412
  272. package/src/reply-dispatcher.ts +0 -334
  273. package/src/session-store.ts +0 -303
  274. package/src/slash-commands.ts +0 -2431
  275. package/src/startup-greeting.ts +0 -120
  276. package/src/streaming.ts +0 -1077
  277. package/src/stt.ts +0 -86
  278. package/src/tools/channel.ts +0 -275
  279. package/src/transport/index.ts +0 -11
  280. package/src/transport/webhook-transport.ts +0 -332
  281. package/src/transport/webhook-verify.ts +0 -119
  282. package/src/typing-keepalive.ts +0 -59
  283. package/src/utils/audio-convert.ts +0 -887
  284. package/src/utils/chunked-upload.ts +0 -483
  285. package/src/utils/file-utils.ts +0 -193
  286. package/src/utils/image-size.ts +0 -266
  287. package/src/utils/media-send.ts +0 -636
  288. package/src/utils/media-tags.ts +0 -183
  289. package/src/utils/payload.ts +0 -265
  290. package/src/utils/text-parsing.ts +0 -85
  291. package/src/utils/upload-cache.ts +0 -128
package/index.ts CHANGED
@@ -1,32 +1,69 @@
1
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
- import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
1
+ /**
2
+ * @tencent-connect/openclaw-qqbot
3
+ *
4
+ * 独立版 QQ Bot 通道插件 — 基于 @tencent-connect/qqbot-nodejs SDK 重构。
5
+ *
6
+ * 直接依赖:
7
+ * - openclaw/plugin-sdk:OpenClaw 插件框架
8
+ * - @tencent-connect/qqbot-nodejs:QQ 开放平台 Node.js SDK
9
+ */
10
+ import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
11
+ import { emptyPluginConfigSchema } from 'openclaw/plugin-sdk';
3
12
 
4
- import { qqbotPlugin } from "./src/channel.js";
5
- import { setQQBotRuntime } from "./src/runtime.js";
6
- import { registerChannelTool } from "./src/tools/channel.js";
7
- import { registerRemindTool } from "./src/tools/remind.js";
13
+ import { qqbotPlugin } from './src/channel.js';
14
+ import { setQQBotRuntime } from './src/runtime.js';
15
+ import { registerPlatformTool } from './src/tools/platform.js';
16
+ import { registerRemindTool } from './src/tools/remind.js';
17
+ import { verifyRuntimeContract } from './src/adapter/contract.js';
18
+
19
+ let registered = false;
8
20
 
9
21
  const plugin = {
10
- id: "openclaw-qqbot",
11
- name: "QQ Bot",
12
- description: "QQ Bot channel plugin",
22
+ id: 'openclaw-qqbot',
23
+ name: 'QQ Bot',
24
+ description: 'QQ Bot channel plugin',
13
25
  configSchema: emptyPluginConfigSchema(),
14
26
  register(api: OpenClawPluginApi) {
15
27
  setQQBotRuntime(api.runtime);
28
+
29
+ if (!registered) {
30
+ registered = true;
31
+ const contract = verifyRuntimeContract(api.runtime);
32
+ if (!contract.ok) {
33
+ throw new Error(
34
+ `openclaw-qqbot incompatible with openclaw ${contract.version}: ` +
35
+ `missing required APIs: ${contract.missing.join(', ')}. ` +
36
+ `Please upgrade openclaw or downgrade the plugin.`,
37
+ );
38
+ }
39
+ }
40
+
16
41
  api.registerChannel({ plugin: qqbotPlugin as any });
17
- registerChannelTool(api);
42
+ registerPlatformTool(api);
18
43
  registerRemindTool(api);
19
44
  },
20
45
  };
21
46
 
22
47
  export default plugin;
23
48
 
24
- export { qqbotPlugin } from "./src/channel.js";
25
- export { setQQBotRuntime, getQQBotRuntime } from "./src/runtime.js";
26
- export { qqbotOnboardingAdapter } from "./src/onboarding.js";
27
- export * from "./src/types.js";
28
- export * from "./src/api.js";
29
- export * from "./src/config.js";
30
- export * from "./src/gateway.js";
31
- export * from "./src/outbound.js";
32
- export * from "./src/transport/index.js";
49
+ // ── Public API exports ──
50
+
51
+ export { qqbotPlugin } from './src/channel.js';
52
+ export { setQQBotRuntime, getQQBotRuntime } from './src/runtime.js';
53
+ export { getBotForAccount, tryGetBotForAccount, buildUserAgent } from './src/bot-instance.js';
54
+ export { qqbotOnboardingAdapter } from './src/features/onboarding.js';
55
+ export { QQBotGateway } from './src/gateway/index.js';
56
+ export { sendText, sendMedia } from './src/outbound/outbound-service.js';
57
+ export { parseTarget } from './src/outbound/target.js';
58
+ export { dispatchToOpenClaw } from './src/dispatch/index.js';
59
+ export {
60
+ PersistedRefIndexStore,
61
+ getPersistedRefIndexStore,
62
+ flushAllRefIndexStores,
63
+ } from './src/features/ref-index-store.js';
64
+ export {
65
+ StreamingController,
66
+ shouldUseStreaming,
67
+ } from './src/outbound/streaming-controller.js';
68
+ export * from './src/types.js';
69
+ export * from './src/config.js';
@@ -4,18 +4,34 @@
4
4
  "description": "QQ Bot channel plugin with message support, cron jobs, and proactive messaging",
5
5
  "channels": ["qqbot"],
6
6
  "extensions": ["./preload.cjs"],
7
- "skills": ["skills/qqbot-channel", "skills/qqbot-remind", "skills/qqbot-media", "skills/qqbot-upgrade"],
7
+ "skills": ["skills/qqbot-channel", "skills/qqbot-remind", "skills/qqbot-upgrade"],
8
+ "contracts": {
9
+ "tools": ["qqbot_platform_api", "qqbot_remind"]
10
+ },
8
11
  "capabilities": {
9
12
  "proactiveMessaging": true,
10
13
  "cronJobs": true
11
14
  },
12
15
  "configSchema": {
13
16
  "type": "object",
14
- "additionalProperties": false,
15
- "properties": {}
17
+ "additionalProperties": true,
18
+ "properties": {
19
+ "appId": { "type": "string", "description": "QQ Bot AppID" },
20
+ "clientSecret": { "type": "string", "description": "QQ Bot AppSecret" }
21
+ }
16
22
  },
17
23
  "channelConfigs": {
18
24
  "qqbot": {
25
+ "schema": {
26
+ "type": "object",
27
+ "additionalProperties": true,
28
+ "properties": {
29
+ "appId": { "type": "string", "description": "QQ Bot AppID" },
30
+ "clientSecret": { "type": "string", "description": "QQ Bot AppSecret" }
31
+ }
32
+ },
33
+ "label": "QQ Bot",
34
+ "description": "QQ Bot channel configuration with message support, cron jobs, and proactive messaging.",
19
35
  "preferOver": ["qqbot"]
20
36
  }
21
37
  }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@tencent-connect/openclaw-qqbot",
3
- "version": "1.7.2",
3
+ "version": "2.0.0",
4
+ "description": "QQ Bot channel plugin for OpenClaw",
4
5
  "publishConfig": {
5
6
  "access": "public"
6
7
  },
7
8
  "type": "module",
8
- "main": "dist/index.js",
9
+ "main": "dist/index.cjs",
9
10
  "types": "dist/index.d.ts",
10
11
  "bin": {
11
12
  "openclaw-qqbot": "./bin/qqbot-cli.js",
@@ -20,6 +21,7 @@
20
21
  "index.ts",
21
22
  "preload.cjs",
22
23
  "tsconfig.json",
24
+ "tsup.config.ts",
23
25
  "openclaw.plugin.json"
24
26
  ],
25
27
  "openclaw": {
@@ -33,38 +35,27 @@
33
35
  }
34
36
  },
35
37
  "scripts": {
36
- "build": "tsc || true",
37
- "postbuild": "node -e \"const fs=require('fs'),p=require('path'),ext=p.join(require('os').homedir(),'.openclaw/extensions/openclaw-qqbot');if(fs.existsSync(ext)&&!fs.lstatSync(ext).isSymbolicLink()){const d=p.join(ext,'dist'),pr=p.join(ext,'preload.cjs');fs.cpSync('dist',d,{recursive:true});fs.copyFileSync('preload.cjs',pr);console.log('[postbuild] synced to',ext)}\"",
38
- "dev": "tsc --watch",
39
- "prepack": "npm install --omit=dev",
40
- "postinstall": "node scripts/postinstall-link-sdk.js 2>/dev/null || true"
38
+ "build": "tsup",
39
+ "dev": "tsup --watch",
40
+ "typecheck": "tsc --noEmit",
41
+ "lint:runtime": "npx tsx src/runtime-adapter/lint-runtime-access.ts"
41
42
  },
42
43
  "dependencies": {
43
- "mpg123-decoder": "^1.0.3",
44
- "silk-wasm": "^3.7.1",
45
- "ws": "^8.18.0"
44
+ "@tencent-connect/qqbot-connector": "1.2.0",
45
+ "@tencent-connect/qqbot-nodejs": "^1.0.4"
46
46
  },
47
- "bundledDependencies": [
48
- "mpg123-decoder",
49
- "silk-wasm",
50
- "ws"
51
- ],
52
47
  "devDependencies": {
53
- "@types/node": "^20.0.0",
54
- "@types/ws": "^8.5.0",
48
+ "@types/node": "^20.19.43",
49
+ "tsup": "^8.5.1",
55
50
  "typescript": "^5.9.3"
56
51
  },
57
52
  "peerDependencies": {
53
+ "@tencent-connect/qqbot-connector": "1.2.0",
58
54
  "openclaw": "*"
59
55
  },
60
56
  "homepage": "https://github.com/tencent-connect/openclaw-qqbot",
61
57
  "repository": {
62
58
  "type": "git",
63
59
  "url": "git+https://github.com/tencent-connect/openclaw-qqbot.git"
64
- },
65
- "bundleDependencies": [
66
- "mpg123-decoder",
67
- "silk-wasm",
68
- "ws"
69
- ]
60
+ }
70
61
  }
package/preload.cjs CHANGED
@@ -9,25 +9,28 @@
9
9
  */
10
10
  "use strict";
11
11
 
12
+ const path = require("node:path");
13
+ const fs = require("node:fs");
12
14
  const { ensurePluginSdkSymlink } = require("./scripts/link-sdk-core.cjs");
13
15
 
14
- // 1) 同步创建 symlink
16
+ // 1) 同步创建 symlink(确保 openclaw/plugin-sdk 可解析)
15
17
  ensurePluginSdkSymlink(__dirname, "[preload]");
16
18
 
17
- // 2) Node 22 原生支持 CJS require() 加载 ESM 模块
18
- // 同步加载插件入口,确保框架同步检查 register/activate 时能找到
19
- const _pluginModule = require("./dist/index.js");
19
+ // 2) 加载编译产物(向后兼容:优先 .cjs,fallback .js)
20
+ const cjsPath = path.join(__dirname, "dist", "index.cjs");
21
+ const jsPath = path.join(__dirname, "dist", "index.js");
20
22
 
21
- // 3) 展平 default export:框架检查 register/activate 在顶级属性
22
- // ESM export default 在 require() 后变成 { default: plugin, ... }
23
- const _default = _pluginModule.default;
24
- const merged = Object.assign({}, _pluginModule);
25
- if (_default && typeof _default === "object") {
26
- for (const key of Object.keys(_default)) {
27
- if (!(key in merged)) {
28
- merged[key] = _default[key];
23
+ if (fs.existsSync(cjsPath)) {
24
+ module.exports = require(cjsPath);
25
+ } else {
26
+ // 兼容旧版 tsc 编译产物(ESM .js),需展平 default export
27
+ const _mod = require(jsPath);
28
+ const _default = _mod.default;
29
+ const merged = Object.assign({}, _mod);
30
+ if (_default && typeof _default === "object") {
31
+ for (const key of Object.keys(_default)) {
32
+ if (!(key in merged)) merged[key] = _default[key];
29
33
  }
30
34
  }
35
+ module.exports = merged;
31
36
  }
32
-
33
- module.exports = merged;
@@ -3,12 +3,14 @@
3
3
  *
4
4
  * 被 preload.cjs 和 postinstall-link-sdk.js 共同使用,避免代码重复。
5
5
  * 必须是 CJS 格式,因为 preload.cjs 需要同步 require()。
6
+ *
7
+ * 注意:本模块不使用 child_process,避免被 openclaw 安全检查拦截。
6
8
  */
7
9
  "use strict";
8
10
 
9
11
  const path = require("node:path");
10
12
  const fs = require("node:fs");
11
- const { execSync } = require("node:child_process");
13
+ const os = require("node:os");
12
14
 
13
15
  const CLI_NAMES = ["openclaw", "clawdbot", "moltbot"];
14
16
 
@@ -27,6 +29,104 @@ function compareVersionGte(version, target) {
27
29
  return true;
28
30
  }
29
31
 
32
+ /**
33
+ * 获取全局 node_modules 候选目录列表(按优先级排序)。
34
+ * 不依赖 npm/child_process,通过常用路径推导。
35
+ */
36
+ function getGlobalNodeModulesDirs() {
37
+ const dirs = [];
38
+ const npmPrefix = process.env.npm_config_prefix || process.env.PREFIX;
39
+ if (npmPrefix) {
40
+ // macOS: prefix/lib/node_modules; Windows: prefix/node_modules
41
+ dirs.push(path.join(npmPrefix, "lib", "node_modules"));
42
+ dirs.push(path.join(npmPrefix, "node_modules"));
43
+ }
44
+
45
+ // nvm / fnm / volta 等版本管理器
46
+ // process.execPath = .../versions/node/vX.Y.Z/bin/node
47
+ const execBase = path.dirname(path.dirname(process.execPath));
48
+ dirs.push(path.join(execBase, "lib", "node_modules"));
49
+ dirs.push(path.join(execBase, "node_modules"));
50
+
51
+ // Homebrew (macOS Intel)
52
+ dirs.push("/usr/local/lib/node_modules");
53
+ // Homebrew (macOS Apple Silicon)
54
+ dirs.push("/opt/homebrew/lib/node_modules");
55
+ // Linux / macOS 标准路径
56
+ dirs.push("/usr/lib/node_modules");
57
+ // pnpm global (XDG)
58
+ const xdgData = process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share");
59
+ dirs.push(path.join(xdgData, "pnpm", "global", "5", "node_modules"));
60
+ dirs.push(path.join(xdgData, "npm", "lib", "node_modules"));
61
+
62
+ return dirs;
63
+ }
64
+
65
+ /**
66
+ * 在全局 node_modules 目录中查找指定包的 package.json。
67
+ */
68
+ function findPackageInGlobalDirs(packageName) {
69
+ for (const dir of getGlobalNodeModulesDirs()) {
70
+ const pkgPath = path.join(dir, packageName, "package.json");
71
+ try {
72
+ if (fs.existsSync(pkgPath)) return pkgPath;
73
+ } catch {}
74
+ }
75
+ return null;
76
+ }
77
+
78
+ /**
79
+ * 在 $PATH 中查找 CLI 可执行文件。
80
+ */
81
+ function findCliInPath(cliName) {
82
+ const pathEnv = process.env.PATH || "";
83
+ const ext = process.platform === "win32" ? ".cmd" : "";
84
+ const dirs = pathEnv.split(path.delimiter);
85
+
86
+ for (const dir of dirs) {
87
+ const binPath = path.join(dir, cliName + ext);
88
+ try {
89
+ if (fs.existsSync(binPath)) return fs.realpathSync(binPath);
90
+ } catch {}
91
+ }
92
+ return null;
93
+ }
94
+
95
+ /**
96
+ * 从 CLI 二进制路径反查全局 node_modules 中的 package.json。
97
+ */
98
+ function resolveGlobalRootFromBin(binPath, cliName) {
99
+ // 方式 A: bin -> ../lib/node_modules/<cli>/package.json
100
+ const binDir = path.dirname(binPath);
101
+ const c1 = path.resolve(binDir, "..", "lib", "node_modules", cliName, "package.json");
102
+ try { if (fs.existsSync(c1)) return c1; } catch {}
103
+
104
+ // 方式 B: bin -> ../package.json (如果在 node_modules/.bin 下)
105
+ const c2 = path.resolve(binDir, "..", "package.json");
106
+ try {
107
+ if (fs.existsSync(c2)) {
108
+ const parentDir = path.dirname(c2);
109
+ if (fs.existsSync(path.join(parentDir, "plugin-sdk")) || fs.existsSync(path.join(parentDir, "dist", "plugin-sdk"))) {
110
+ return c2;
111
+ }
112
+ }
113
+ } catch {}
114
+
115
+ return null;
116
+ }
117
+
118
+ /**
119
+ * 读取 package.json 中的版本号。
120
+ */
121
+ function readPkgVersion(pkgPath) {
122
+ try {
123
+ const v = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
124
+ return v || null;
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+
30
130
  /**
31
131
  * 检查 openclaw 版本是否 >= 2026.3.22(需要 symlink 的最低版本)。
32
132
  * 如果无法检测版本,返回 true(保守策略:宁可多创建也不遗漏)。
@@ -34,29 +134,25 @@ function compareVersionGte(version, target) {
34
134
  function isOpenclawVersionRequiresSymlink() {
35
135
  const REQUIRED = [2026, 3, 22];
36
136
 
37
- // Strategy 1: 从全局 openclaw package.json 读取版本
38
- try {
39
- const globalRoot = execSync("npm root -g", { encoding: "utf-8", timeout: 5000 }).trim();
40
- for (const name of CLI_NAMES) {
41
- const pkgPath = path.join(globalRoot, name, "package.json");
42
- if (fs.existsSync(pkgPath)) {
43
- const v = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
44
- if (v) return compareVersionGte(v, REQUIRED);
45
- }
137
+ // Strategy 1: 从全局 node_modules 读取 package.json 版本
138
+ for (const name of CLI_NAMES) {
139
+ const pkgPath = findPackageInGlobalDirs(name);
140
+ if (pkgPath) {
141
+ const v = readPkgVersion(pkgPath);
142
+ if (v) return compareVersionGte(v, REQUIRED);
46
143
  }
47
- } catch {}
144
+ }
48
145
 
49
- // Strategy 2: 从 CLI 命令获取版本
146
+ // Strategy 2: 从 CLI 二进制反查到 package.json
50
147
  for (const name of CLI_NAMES) {
51
- try {
52
- const out = execSync(`${name} --version`, {
53
- encoding: "utf-8",
54
- timeout: 5000,
55
- stdio: ["pipe", "pipe", "pipe"],
56
- }).trim();
57
- const m = out.match(/(\d+\.\d+\.\d+)/);
58
- if (m) return compareVersionGte(m[1], REQUIRED);
59
- } catch {}
148
+ const binPath = findCliInPath(name);
149
+ if (binPath) {
150
+ const pkgPath = resolveGlobalRootFromBin(binPath, name);
151
+ if (pkgPath) {
152
+ const v = readPkgVersion(pkgPath);
153
+ if (v) return compareVersionGte(v, REQUIRED);
154
+ }
155
+ }
60
156
  }
61
157
 
62
158
  return true;
@@ -64,34 +160,22 @@ function isOpenclawVersionRequiresSymlink() {
64
160
 
65
161
  /**
66
162
  * 查找全局 openclaw 安装路径。
67
- * 三种策略依次尝试:npm root -g、which <cli>、从 extensions 目录推断。
163
+ * 三种策略依次尝试:全局 node_modules、$PATH 反查、extensions 目录推断。
68
164
  */
69
165
  function findOpenclawRoot(pluginRoot) {
70
- // Strategy 1: npm root -g
71
- try {
72
- const globalRoot = execSync("npm root -g", { encoding: "utf-8", timeout: 5000 }).trim();
73
- for (const name of CLI_NAMES) {
74
- const candidate = path.join(globalRoot, name);
75
- if (fs.existsSync(path.join(candidate, "package.json"))) return candidate;
76
- }
77
- } catch {}
166
+ // Strategy 1: 从全局 node_modules 查找
167
+ for (const name of CLI_NAMES) {
168
+ const pkgPath = findPackageInGlobalDirs(name);
169
+ if (pkgPath) return path.dirname(pkgPath);
170
+ }
78
171
 
79
- // Strategy 2: which <cli>
80
- const whichCmd = process.platform === "win32" ? "where" : "which";
172
+ // Strategy 2: $PATH 反查
81
173
  for (const name of CLI_NAMES) {
82
- try {
83
- const bin = execSync(`${whichCmd} ${name}`, {
84
- encoding: "utf-8",
85
- timeout: 5000,
86
- stdio: ["pipe", "pipe", "pipe"],
87
- }).trim().split("\n")[0];
88
- if (!bin) continue;
89
- const realBin = fs.realpathSync(bin);
90
- const c1 = path.resolve(path.dirname(realBin), "..", "lib", "node_modules", name);
91
- if (fs.existsSync(path.join(c1, "package.json"))) return c1;
92
- const c2 = path.resolve(path.dirname(realBin), "..");
93
- if (fs.existsSync(path.join(c2, "package.json")) && fs.existsSync(path.join(c2, "plugin-sdk"))) return c2;
94
- } catch {}
174
+ const binPath = findCliInPath(name);
175
+ if (binPath) {
176
+ const pkgPath = resolveGlobalRootFromBin(binPath, name);
177
+ if (pkgPath) return path.dirname(pkgPath);
178
+ }
95
179
  }
96
180
 
97
181
  // Strategy 3: 从 extensions 目录推断
@@ -100,11 +184,10 @@ function findOpenclawRoot(pluginRoot) {
100
184
  const dataDirName = path.basename(dataDir);
101
185
  const cliName = dataDirName.replace(/^\./, "");
102
186
  if (cliName) {
103
- try {
104
- const globalRoot = execSync("npm root -g", { encoding: "utf-8", timeout: 5000 }).trim();
105
- const candidate = path.join(globalRoot, cliName);
106
- if (fs.existsSync(path.join(candidate, "package.json"))) return candidate;
107
- } catch {}
187
+ for (const dir of getGlobalNodeModulesDirs()) {
188
+ const pkgPath = path.join(dir, cliName, "package.json");
189
+ try { if (fs.existsSync(pkgPath)) return path.dirname(pkgPath); } catch {}
190
+ }
108
191
  }
109
192
 
110
193
  return null;
@@ -929,22 +929,53 @@ NEW_VERSION=""; [ -f "$TARGET_DIR/package.json" ] && NEW_VERSION="$(read_pkg_ver
929
929
  PREFLIGHT_OK=true
930
930
  [ -z "$NEW_VERSION" ] && echo " ❌ 无法读取版本号" && PREFLIGHT_OK=false || echo " ✅ 版本: $NEW_VERSION"
931
931
 
932
- ENTRY=""; for f in "dist/index.js" "index.js"; do [ -f "$TARGET_DIR/$f" ] && ENTRY="$f" && break; done
932
+ ENTRY=""; for f in "dist/index.cjs" "dist/index.js" "index.js"; do [ -f "$TARGET_DIR/$f" ] && ENTRY="$f" && break; done
933
933
  [ -z "$ENTRY" ] && echo " ❌ 缺少入口文件" && PREFLIGHT_OK=false || echo " ✅ 入口: $ENTRY"
934
934
 
935
+ # 检测构建模式:bundled (tsup dist/index.cjs) vs unbundled (dist/src/ 独立文件)
936
+ # 优先看 dist/src/ 是否存在;存在 → unbundled;否则依赖入口文件大小判断
937
+ IS_BUNDLED=false
935
938
  if [ -d "$TARGET_DIR/dist/src" ]; then
936
- JS_COUNT=$(find "$TARGET_DIR/dist/src" -name "*.js" -type f 2>/dev/null | wc -l | tr -d ' ')
937
- echo " ✅ dist/src/ ${JS_COUNT} JS"
938
- [ "$JS_COUNT" -lt 5 ] && echo " ❌ JS 数量异常偏少" && PREFLIGHT_OK=false
939
- else
940
- echo " 缺少 dist/src/"; PREFLIGHT_OK=false
939
+ IS_BUNDLED=false
940
+ elif [ -f "$TARGET_DIR/$ENTRY" ]; then
941
+ BUNDLE_SIZE=$(wc -c < "$TARGET_DIR/$ENTRY" 2>/dev/null || echo "0")
942
+ # bundled 输出通常 > 200KB,unbundled 入口 < 50KB
943
+ [ "$BUNDLE_SIZE" -gt 200000 ] 2>/dev/null && IS_BUNDLED=true
941
944
  fi
942
945
 
943
- MISS=""
944
- for m in "dist/src/gateway.js" "dist/src/api.js" "dist/src/admin-resolver.js"; do
945
- [ ! -f "$TARGET_DIR/$m" ] && MISS="$MISS $m"
946
- done
947
- [ -n "$MISS" ] && echo " ❌ 缺少:$MISS" && PREFLIGHT_OK=false || echo " ✅ 关键模块完整"
946
+ if [ "$IS_BUNDLED" = "true" ]; then
947
+ echo " ✅ bundled 构建 (${BUNDLE_SIZE} bytes)"
948
+
949
+ # 内联验证:bundle 中 grep 关键导出
950
+ BUNDLE_MISS=""
951
+ for sig in "GatewayConnection" "dispatchToOpenClaw" "qqbotPlugin" "sendText" "sendMedia"; do
952
+ if ! grep -qF "$sig" "$TARGET_DIR/$ENTRY" 2>/dev/null; then
953
+ BUNDLE_MISS="$BUNDLE_MISS $sig"
954
+ fi
955
+ done
956
+ [ -n "$BUNDLE_MISS" ] && echo " ❌ bundle 缺少签名:$BUNDLE_MISS" && PREFLIGHT_OK=false || echo " ✅ 关键模块签名完整"
957
+
958
+ # ws 依赖应该被 tsup noExternal 打包进 bundle
959
+ if grep -qF "ws" "$TARGET_DIR/$ENTRY" 2>/dev/null; then
960
+ echo " ✅ ws bundled"
961
+ else
962
+ echo " ⚠️ ws 未打包"
963
+ fi
964
+ else
965
+ if [ -d "$TARGET_DIR/dist/src" ]; then
966
+ JS_COUNT=$(find "$TARGET_DIR/dist/src" -name "*.js" -type f 2>/dev/null | wc -l | tr -d ' ')
967
+ echo " ✅ dist/src/ 含 ${JS_COUNT} 个 JS"
968
+ [ "$JS_COUNT" -lt 5 ] && echo " ❌ JS 数量异常偏少" && PREFLIGHT_OK=false
969
+ else
970
+ echo " ❌ 缺少 dist/src/"; PREFLIGHT_OK=false
971
+ fi
972
+
973
+ MISS=""
974
+ for m in "dist/src/gateway.js" "dist/src/api.js" "dist/src/admin-resolver.js"; do
975
+ [ ! -f "$TARGET_DIR/$m" ] && MISS="$MISS $m"
976
+ done
977
+ [ -n "$MISS" ] && echo " ❌ 缺少:$MISS" && PREFLIGHT_OK=false || echo " ✅ 关键模块完整"
978
+ fi
948
979
 
949
980
  if [ -d "$TARGET_DIR/node_modules" ]; then
950
981
  BOK=true
@@ -319,14 +319,14 @@ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-qqbot-nm-bak-*" -exec rm -rf
319
319
  # 导致新增的模块(如 streaming.js)缺失。
320
320
  echo " 清空 dist/ 确保全量重新构建..."
321
321
  rm -rf "$PROJ_DIR/dist"
322
- if [ ! -f "$PROJ_DIR/dist/index.js" ]; then
322
+ if [ ! -f "$PROJ_DIR/dist/index.cjs" ] && [ ! -f "$PROJ_DIR/dist/index.js" ]; then
323
323
  echo " dist/ 不存在,先执行构建..."
324
324
  if [ ! -d "$PROJ_DIR/node_modules" ]; then
325
325
  npm install --prefix "$PROJ_DIR" 2>&1 || true
326
326
  fi
327
327
  npm run --prefix "$PROJ_DIR" build 2>&1 || true
328
- if [ ! -f "$PROJ_DIR/dist/index.js" ]; then
329
- echo " ❌ 构建失败:dist/index.js 未生成"
328
+ if [ ! -f "$PROJ_DIR/dist/index.cjs" ] && [ ! -f "$PROJ_DIR/dist/index.js" ]; then
329
+ echo " ❌ 构建失败:dist/index.cjs 未生成"
330
330
  echo " 请手动执行: cd $PROJ_DIR && npm install && npm run build"
331
331
  exit 1
332
332
  fi
@@ -360,7 +360,7 @@ if [ -n "$_NM_BACKUP" ] && [ -d "$_NM_BACKUP" ]; then
360
360
  mv "$_NM_BACKUP" "$PROJ_DIR/node_modules"
361
361
  echo " 已恢复源码目录 node_modules"
362
362
  fi
363
- if [ ! -f "$_INSTALL_DIR/dist/index.js" ] || [ ! -f "$_INSTALL_DIR/preload.cjs" ]; then
363
+ if { [ ! -f "$_INSTALL_DIR/dist/index.cjs" ] && [ ! -f "$_INSTALL_DIR/dist/index.js" ]; } || [ ! -f "$_INSTALL_DIR/preload.cjs" ]; then
364
364
  echo ""
365
365
  echo "❌ 插件安装失败!"
366
366
  echo "========================================="
@@ -1,12 +1,33 @@
1
1
  ---
2
2
  name: qqbot-channel
3
- description: QQ 频道管理技能。查询频道列表、子频道、成员、发帖、公告、日程等操作。使用 qqbot_channel_api 工具代理 QQ 开放平台 HTTP 接口,自动处理 Token 鉴权。当用户需要查看频道、管理子频道、查询成员、发布帖子/公告/日程时使用此技能。
3
+ description: QQ 频道管理技能(非QQ群)。查询频道列表、子频道、成员、发帖、公告、日程等操作。使用 qqbot_platform_api 工具代理 QQ 开放平台 HTTP 接口,自动处理 Token 鉴权。仅用于 QQ 频道(Guild/Channel)。触发条件:用户提到「频道」「子频道」「guild」「channel」「帖子」「日程」「公告」。
4
4
  metadata: {"openclaw":{"emoji":"📡","requires":{"config":["channels.qqbot"]}}}
5
5
  ---
6
6
 
7
7
  # QQ 频道 API 请求指导
8
8
 
9
- `qqbot_channel_api` 是一个 QQ 开放平台 HTTP 代理工具,**自动填充鉴权 Token**。你只需要指定 HTTP 方法、API 路径、请求体和查询参数。
9
+ > **本 Skill 仅处理 QQ 频道(Guild/Channel)操作。** 频道 ID 为纯数字,API 路径为 `/guilds/...` 和 `/channels/...`。
10
+
11
+ `qqbot_platform_api` 是 QQ 开放平台统一 HTTP API 网关,**自动填充鉴权 Token**。你只需要指定 HTTP 方法、API 路径、请求体和查询参数即可调用频道相关接口。
12
+
13
+ ---
14
+
15
+ ## 🔀 适用范围(必读)
16
+
17
+ QQ 频道是类似 Discord 的社区产品,层级结构为 **频道(Guild) → 子频道(Channel)**:
18
+
19
+ | 层级 | 中文名 | 英文 | API 路径 | ID 格式 |
20
+ |------|--------|------|----------|---------|
21
+ | 顶层 | 频道 | Guild | `/guilds/{guild_id}` | 纯数字(如 `123456`) |
22
+ | 次级 | 子频道 | Channel | `/channels/{channel_id}` | 纯数字(如 `789012`) |
23
+
24
+ **核心特征**:
25
+ - 频道内可以创建多个子频道(文字、语音、论坛、直播等)
26
+ - 支持发帖、公告、日程等功能
27
+ - 频道成员通过 `/guilds/{guild_id}/members` 管理
28
+ - ID 为纯数字格式,API 路径以 `/guilds/` 或 `/channels/` 开头
29
+
30
+ **触发关键词**:频道、子频道、guild、channel、帖子、日程、公告、论坛、频道成员
10
31
 
11
32
  ## 📚 详细参考文档
12
33
 
@@ -251,13 +272,14 @@ metadata: {"openclaw":{"emoji":"📡","requires":{"config":["channels.qqbot"]}}}
251
272
 
252
273
  ## ⚠️ 注意事项
253
274
 
254
- 1. **路径中的占位符**(如 `{guild_id}`、`{channel_id}`)必须替换为实际值
255
- 2. **query 参数的值必须为字符串类型**,如 `{ "limit": "100" }` 而非 `{ "limit": 100 }`
256
- 3. **成员列表翻页**时可能返回重复成员,需按 `user.id` 去重
257
- 4. **公告**的两种类型(消息公告和推荐子频道公告)会互相顶替
258
- 5. **日程**的时间戳为毫秒级字符串
259
- 6. **删除操作不可逆**,请谨慎使用
260
- 7. **论坛操作**仅私域机器人可用
261
- 8. **子频道分组**(type=4)的 `position` 必须 >= 2
262
- 9. **日程操作**有频率限制:单个管理员每天 10 次,单个频道每天 100
263
- 10. **头像/图标展示**:成员 `user.avatar` 和频道 `icon` 等图片 URL 必须使用 Markdown 图片语法 `![描述](URL)` 展示,禁止作为纯文本或超链接展示
275
+ 1. **适用范围**:本 Skill 仅处理 QQ 频道(Guild/Channel)操作,API 路径以 `/guilds/` 或 `/channels/` 开头,ID 为纯数字
276
+ 2. **路径中的占位符**(如 `{guild_id}`、`{channel_id}`)必须替换为实际的纯数字 ID
277
+ 3. **query 参数的值必须为字符串类型**,如 `{ "limit": "100" }` 而非 `{ "limit": 100 }`
278
+ 4. **成员列表翻页**时可能返回重复成员,需按 `user.id` 去重
279
+ 5. **公告**的两种类型(消息公告和推荐子频道公告)会互相顶替
280
+ 6. **日程**的时间戳为毫秒级字符串
281
+ 7. **删除操作不可逆**,请谨慎使用
282
+ 8. **论坛操作**仅私域机器人可用
283
+ 9. **子频道分组**(type=4)的 `position` 必须 >= 2
284
+ 10. **日程操作**有频率限制:单个管理员每天 10 次,单个频道每天 100
285
+ 11. **头像/图标展示**:成员 `user.avatar` 和频道 `icon` 等图片 URL 必须使用 Markdown 图片语法 `![描述](URL)` 展示,禁止作为纯文本或超链接展示