@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
@@ -1,69 +0,0 @@
1
- {
2
- "name": "ws",
3
- "version": "8.19.0",
4
- "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
5
- "keywords": [
6
- "HyBi",
7
- "Push",
8
- "RFC-6455",
9
- "WebSocket",
10
- "WebSockets",
11
- "real-time"
12
- ],
13
- "homepage": "https://github.com/websockets/ws",
14
- "bugs": "https://github.com/websockets/ws/issues",
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/websockets/ws.git"
18
- },
19
- "author": "Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)",
20
- "license": "MIT",
21
- "main": "index.js",
22
- "exports": {
23
- ".": {
24
- "browser": "./browser.js",
25
- "import": "./wrapper.mjs",
26
- "require": "./index.js"
27
- },
28
- "./package.json": "./package.json"
29
- },
30
- "browser": "browser.js",
31
- "engines": {
32
- "node": ">=10.0.0"
33
- },
34
- "files": [
35
- "browser.js",
36
- "index.js",
37
- "lib/*.js",
38
- "wrapper.mjs"
39
- ],
40
- "scripts": {
41
- "test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js",
42
- "integration": "mocha --throw-deprecation test/*.integration.js",
43
- "lint": "eslint . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\""
44
- },
45
- "peerDependencies": {
46
- "bufferutil": "^4.0.1",
47
- "utf-8-validate": ">=5.0.2"
48
- },
49
- "peerDependenciesMeta": {
50
- "bufferutil": {
51
- "optional": true
52
- },
53
- "utf-8-validate": {
54
- "optional": true
55
- }
56
- },
57
- "devDependencies": {
58
- "benchmark": "^2.1.4",
59
- "bufferutil": "^4.0.1",
60
- "eslint": "^9.0.0",
61
- "eslint-config-prettier": "^10.0.1",
62
- "eslint-plugin-prettier": "^5.0.0",
63
- "globals": "^16.0.0",
64
- "mocha": "^8.4.0",
65
- "nyc": "^15.0.0",
66
- "prettier": "^3.0.0",
67
- "utf-8-validate": "^6.0.0"
68
- }
69
- }
@@ -1,8 +0,0 @@
1
- import createWebSocketStream from './lib/stream.js';
2
- import Receiver from './lib/receiver.js';
3
- import Sender from './lib/sender.js';
4
- import WebSocket from './lib/websocket.js';
5
- import WebSocketServer from './lib/websocket-server.js';
6
-
7
- export { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };
8
- export default WebSocket;
@@ -1,170 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // When installed as an openclaw extension under ~/.openclaw/extensions/,
4
- // the plugin needs access to `openclaw/plugin-sdk` at runtime.
5
- // openclaw's jiti loader resolves this via alias by walking up from the plugin
6
- // path to find the openclaw package root — but ~/.openclaw/extensions/ is not
7
- // under the openclaw package tree, so the alias lookup fails.
8
- //
9
- // This script creates a symlink from the plugin's node_modules/openclaw to the
10
- // globally installed openclaw package, allowing Node's native ESM resolver
11
- // (used by jiti with tryNative:true for .js files) to find `openclaw/plugin-sdk`.
12
-
13
- import { existsSync, lstatSync, symlinkSync, unlinkSync, rmSync, mkdirSync, realpathSync } from "node:fs";
14
- import { dirname, join, resolve } from "node:path";
15
- import { fileURLToPath } from "node:url";
16
- import { execSync } from "node:child_process";
17
-
18
- const __dirname = dirname(fileURLToPath(import.meta.url));
19
- const pluginRoot = resolve(__dirname, "..");
20
-
21
- const linkTarget = join(pluginRoot, "node_modules", "openclaw");
22
-
23
- // Check if already a valid symlink pointing to a directory with plugin-sdk/core
24
- if (existsSync(linkTarget)) {
25
- try {
26
- const stat = lstatSync(linkTarget);
27
- if (stat.isSymbolicLink()) {
28
- // Symlink exists — verify it has plugin-sdk/core
29
- if (existsSync(join(linkTarget, "plugin-sdk", "core.js"))) {
30
- process.exit(0);
31
- }
32
- // Symlink is stale or points to wrong target, remove and re-create
33
- unlinkSync(linkTarget);
34
- } else if (existsSync(join(linkTarget, "plugin-sdk", "core.js"))) {
35
- // Real directory with correct structure (e.g. npm installed a good version)
36
- process.exit(0);
37
- } else {
38
- // Real directory from npm install but missing plugin-sdk/core — replace with symlink
39
- rmSync(linkTarget, { recursive: true, force: true });
40
- }
41
- } catch {
42
- // If stat fails, try to remove and re-create
43
- try { rmSync(linkTarget, { recursive: true, force: true }); } catch {}
44
- }
45
- }
46
-
47
- // CLI names to try (openclaw and its aliases)
48
- const CLI_NAMES = ["openclaw", "clawdbot", "moltbot"];
49
-
50
- // Find the global openclaw installation
51
- let openclawRoot = null;
52
-
53
- // Strategy 1: npm root -g → look for any known CLI package name
54
- if (!openclawRoot) {
55
- try {
56
- const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
57
- for (const name of CLI_NAMES) {
58
- const candidate = join(globalRoot, name);
59
- if (existsSync(join(candidate, "package.json"))) {
60
- openclawRoot = candidate;
61
- break;
62
- }
63
- }
64
- } catch {}
65
- }
66
-
67
- // Strategy 2: resolve from the CLI binary (which openclaw / clawdbot / moltbot)
68
- if (!openclawRoot) {
69
- const whichCmd = process.platform === "win32" ? "where" : "which";
70
- for (const name of CLI_NAMES) {
71
- try {
72
- const bin = execSync(`${whichCmd} ${name}`, { encoding: "utf-8" }).trim().split("\n")[0];
73
- if (!bin) continue;
74
- // Resolve symlinks to get actual binary location
75
- const realBin = realpathSync(bin);
76
- // bin is typically <prefix>/bin/<name> -> ../lib/node_modules/<name>/...
77
- const candidate = resolve(dirname(realBin), "..", "lib", "node_modules", name);
78
- if (existsSync(join(candidate, "package.json"))) {
79
- openclawRoot = candidate;
80
- break;
81
- }
82
- // Also try: binary might be inside the package itself (e.g. .../node_modules/<name>/bin/<name>)
83
- const candidate2 = resolve(dirname(realBin), "..");
84
- if (existsSync(join(candidate2, "package.json")) && existsSync(join(candidate2, "plugin-sdk"))) {
85
- openclawRoot = candidate2;
86
- break;
87
- }
88
- } catch {}
89
- }
90
- }
91
-
92
- // Strategy 3: walk up from the extensions directory to find the CLI's data root,
93
- // then look for a global node_modules sibling
94
- if (!openclawRoot) {
95
- // pluginRoot is like /home/user/.openclaw/extensions/openclaw-qqbot
96
- // The CLI data dir is /home/user/.openclaw (or .clawdbot, .moltbot)
97
- const extensionsDir = dirname(pluginRoot);
98
- const dataDir = dirname(extensionsDir);
99
- const dataDirName = dataDir.split("/").pop() || dataDir.split("\\").pop() || "";
100
- // dataDirName is like ".openclaw" → strip the dot to get "openclaw"
101
- const cliName = dataDirName.replace(/^\./, "");
102
- if (cliName) {
103
- try {
104
- const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
105
- const candidate = join(globalRoot, cliName);
106
- if (existsSync(join(candidate, "package.json"))) {
107
- openclawRoot = candidate;
108
- }
109
- } catch {}
110
- }
111
- }
112
-
113
- // Strategy 4: pnpm global installation
114
- // pnpm stores globals in ~/Library/pnpm/global/<ver>/.pnpm/<pkg>@<version>.../node_modules/<pkg>
115
- // or resolves via `pnpm root -g`
116
- if (!openclawRoot) {
117
- // 4a: try `pnpm root -g`
118
- try {
119
- const pnpmGlobalRoot = execSync("pnpm root -g", { encoding: "utf-8" }).trim();
120
- for (const name of CLI_NAMES) {
121
- const candidate = join(pnpmGlobalRoot, name);
122
- if (existsSync(join(candidate, "package.json"))) {
123
- openclawRoot = candidate;
124
- break;
125
- }
126
- }
127
- } catch {}
128
-
129
- // 4b: resolve from the real binary path into .pnpm store
130
- if (!openclawRoot) {
131
- const whichCmd = process.platform === "win32" ? "where" : "which";
132
- for (const name of CLI_NAMES) {
133
- try {
134
- const bin = execSync(`${whichCmd} ${name}`, { encoding: "utf-8" }).trim().split("\n")[0];
135
- if (!bin) continue;
136
- const realBin = realpathSync(bin);
137
- // pnpm bin layout: .../node_modules/.pnpm/<pkg>@<ver>.../node_modules/<pkg>/dist/bin.js
138
- // or .../node_modules/<pkg>/dist/bin.js (hoisted)
139
- // Walk up to find node_modules/<name>/package.json
140
- let dir = dirname(realBin);
141
- for (let i = 0; i < 8; i++) {
142
- const candidate = join(dir, "node_modules", name);
143
- if (existsSync(join(candidate, "package.json"))) {
144
- openclawRoot = candidate;
145
- break;
146
- }
147
- const parent = dirname(dir);
148
- if (parent === dir) break;
149
- dir = parent;
150
- }
151
- if (openclawRoot) break;
152
- } catch {}
153
- }
154
- }
155
- }
156
-
157
- if (!openclawRoot) {
158
- // Not fatal — plugin may work if openclaw loads it with proper alias resolution
159
- // But log a warning so upgrade scripts can detect the failure
160
- console.error("[postinstall-link-sdk] WARNING: could not find openclaw/clawdbot/moltbot global installation, symlink not created");
161
- process.exit(0);
162
- }
163
-
164
- try {
165
- mkdirSync(join(pluginRoot, "node_modules"), { recursive: true });
166
- symlinkSync(openclawRoot, linkTarget, "junction");
167
- console.log(`[postinstall-link-sdk] symlink created: node_modules/openclaw -> ${openclawRoot}`);
168
- } catch (e) {
169
- console.error(`[postinstall-link-sdk] WARNING: symlink creation failed: ${e.message}`);
170
- }
@@ -1,60 +0,0 @@
1
- ---
2
- name: qqbot-media
3
- description: QQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
4
- metadata: {"openclaw":{"emoji":"📸","requires":{"config":["channels.qqbot"]}}}
5
- ---
6
-
7
- # QQBot 富媒体收发
8
-
9
- ## 用法
10
-
11
- ```
12
- <qqmedia>路径或URL</qqmedia>
13
- ```
14
-
15
- 系统根据文件扩展名自动识别类型并路由:
16
- - `.jpg/.png/.gif/.webp/.bmp` → 图片
17
- - `.silk/.wav/.mp3/.ogg/.aac/.flac` 等 → 语音
18
- - `.mp4/.mov/.avi/.mkv/.webm` 等 → 视频
19
- - 其他扩展名 → 文件
20
- - 无扩展名的 URL → 默认按图片处理
21
-
22
- ## 接收媒体
23
-
24
- - 用户发来的**图片**自动下载到本地,路径在上下文【附件】中,可直接用 `<qqmedia>路径</qqmedia>` 回发
25
- - 用户发来的**语音**路径在上下文中;若有 STT 能力则优先转写
26
-
27
- ## 规则
28
-
29
- 1. **路径必须是绝对路径**(以 `/` 或 `http` 开头)
30
- 2. **标签必须用开闭标签包裹路径**:`<qqmedia>路径</qqmedia>`
31
- 3. **你有能力发送本地图片/文件**——直接用标签包裹路径即可,**不要说"无法发送"**
32
- 4. 发送语音时不要重复语音中已朗读的文字
33
- 5. 多个媒体用多个标签
34
- 6. 以会话上下文中的能力说明为准(如未启用语音则不要发语音)
35
- 7. **发送前需检查文件大小**,当文件超限时告知用户文件太大,QQBot 发送文件大小规则如下:
36
- - 图片:最大 **30MB**
37
- - 语音:最大 **20MB**
38
- - 视频:最大 **100MB**
39
- - 文件:最大 **100MB**
40
-
41
- ## 示例
42
-
43
- ```
44
- 这是你要的图片:
45
- <qqmedia>/Users/xxx/photo.jpg</qqmedia>
46
- ```
47
-
48
- ```
49
- <qqmedia>/tmp/tts/output.mp3</qqmedia>
50
- ```
51
-
52
- ```
53
- 视频在这里:
54
- <qqmedia>https://example.com/video.mp4</qqmedia>
55
- ```
56
-
57
- ```
58
- 文件已准备好:
59
- <qqmedia>/tmp/report.pdf</qqmedia>
60
- ```
@@ -1,181 +0,0 @@
1
- /**
2
- * 管理员解析器模块
3
- * - 管理员 openid 持久化读写
4
- * - 升级问候目标读写
5
- * - 启动问候语发送
6
- */
7
-
8
- import path from "node:path";
9
- import * as fs from "node:fs";
10
- import { getQQBotDataDir } from "./utils/platform.js";
11
- import { listKnownUsers } from "./known-users.js";
12
- import { getAccessToken, sendProactiveC2CMessage } from "./api.js";
13
- import { getStartupGreetingPlan, markStartupGreetingSent, markStartupGreetingFailed } from "./startup-greeting.js";
14
-
15
- // ---- 类型 ----
16
-
17
- export interface AdminResolverContext {
18
- accountId: string;
19
- appId: string;
20
- clientSecret: string;
21
- log?: {
22
- info: (msg: string) => void;
23
- error: (msg: string) => void;
24
- };
25
- }
26
-
27
- // ---- 文件路径 ----
28
-
29
- function safeName(id: string): string {
30
- return id.replace(/[^a-zA-Z0-9._-]/g, "_");
31
- }
32
-
33
- /** 新版 admin 文件路径(按 accountId + appId 区分) */
34
- function getAdminMarkerFile(accountId: string, appId: string): string {
35
- return path.join(getQQBotDataDir("data"), `admin-${safeName(accountId)}-${safeName(appId)}.json`);
36
- }
37
-
38
- /** 旧版 admin 文件路径(仅按 accountId 区分,用于迁移兼容) */
39
- function getLegacyAdminMarkerFile(accountId: string): string {
40
- return path.join(getQQBotDataDir("data"), `admin-${accountId}.json`);
41
- }
42
-
43
- function getUpgradeGreetingTargetFile(accountId: string, appId: string): string {
44
- return path.join(getQQBotDataDir("data"), `upgrade-greeting-target-${safeName(accountId)}-${safeName(appId)}.json`);
45
- }
46
-
47
- // ---- 管理员 openid 持久化 ----
48
-
49
- /**
50
- * 读取 admin openid(按 accountId + appId 区分)
51
- * 兼容策略:新路径优先 → fallback 旧路径 → 自动迁移
52
- */
53
- export function loadAdminOpenId(accountId: string, appId: string): string | undefined {
54
- try {
55
- // 1. 先尝试新版路径
56
- const newFile = getAdminMarkerFile(accountId, appId);
57
- if (fs.existsSync(newFile)) {
58
- const data = JSON.parse(fs.readFileSync(newFile, "utf8"));
59
- if (data.openid) return data.openid;
60
- }
61
-
62
- // 2. fallback 旧版路径(仅按 accountId)
63
- const legacyFile = getLegacyAdminMarkerFile(accountId);
64
- if (fs.existsSync(legacyFile)) {
65
- const data = JSON.parse(fs.readFileSync(legacyFile, "utf8"));
66
- if (data.openid) {
67
- // 自动迁移:写到新路径,删除旧文件
68
- saveAdminOpenId(accountId, appId, data.openid);
69
- try { fs.unlinkSync(legacyFile); } catch { /* ignore */ }
70
- return data.openid;
71
- }
72
- }
73
- } catch { /* 文件损坏视为无 */ }
74
- return undefined;
75
- }
76
-
77
- export function saveAdminOpenId(accountId: string, appId: string, openid: string): void {
78
- try {
79
- fs.writeFileSync(
80
- getAdminMarkerFile(accountId, appId),
81
- JSON.stringify({ accountId, appId, openid, savedAt: new Date().toISOString() }),
82
- );
83
- } catch { /* ignore */ }
84
- }
85
-
86
- // ---- 升级问候目标 ----
87
-
88
- export function loadUpgradeGreetingTargetOpenId(accountId: string, appId: string, log?: { info: (msg: string) => void }): string | undefined {
89
- try {
90
- const file = getUpgradeGreetingTargetFile(accountId, appId);
91
- if (fs.existsSync(file)) {
92
- const data = JSON.parse(fs.readFileSync(file, "utf8")) as { accountId?: string; appId?: string; openid?: string };
93
- if (!data.openid) {
94
- log?.info(`[qqbot:${accountId}] upgrade-greeting-target file found but openid is empty`);
95
- return undefined;
96
- }
97
- if (data.appId && data.appId !== appId) {
98
- log?.info(`[qqbot:${accountId}] upgrade-greeting-target appId mismatch: file=${data.appId}, current=${appId}`);
99
- return undefined;
100
- }
101
- if (data.accountId && data.accountId !== accountId) {
102
- log?.info(`[qqbot:${accountId}] upgrade-greeting-target accountId mismatch: file=${data.accountId}, current=${accountId}`);
103
- return undefined;
104
- }
105
- log?.info(`[qqbot:${accountId}] upgrade-greeting-target loaded: openid=${data.openid}`);
106
- return data.openid;
107
- } else {
108
- log?.info(`[qqbot:${accountId}] upgrade-greeting-target file not found: ${file}`);
109
- }
110
- } catch (err) {
111
- log?.info(`[qqbot:${accountId}] upgrade-greeting-target file read error: ${err}`);
112
- }
113
- return undefined;
114
- }
115
-
116
- export function clearUpgradeGreetingTargetOpenId(accountId: string, appId: string): void {
117
- try {
118
- const file = getUpgradeGreetingTargetFile(accountId, appId);
119
- if (fs.existsSync(file)) {
120
- fs.unlinkSync(file);
121
- }
122
- } catch { /* ignore */ }
123
- }
124
-
125
- // ---- 解析管理员 ----
126
-
127
- /**
128
- * 解析管理员 openid:
129
- * 1. 优先读持久化文件(按 accountId + appId 区分)
130
- * 2. fallback 取第一个私聊用户,并写入文件锁定
131
- */
132
- export function resolveAdminOpenId(ctx: Pick<AdminResolverContext, "accountId" | "appId" | "log">): string | undefined {
133
- const saved = loadAdminOpenId(ctx.accountId, ctx.appId);
134
- if (saved) return saved;
135
- const first = listKnownUsers({ accountId: ctx.accountId, type: "c2c", sortBy: "firstSeenAt", sortOrder: "asc", limit: 1 })[0]?.openid;
136
- if (first) {
137
- saveAdminOpenId(ctx.accountId, ctx.appId, first);
138
- ctx.log?.info(`[qqbot:${ctx.accountId}] Auto-detected admin openid: ${first} (persisted)`);
139
- }
140
- return first;
141
- }
142
-
143
- // ---- 启动问候语 ----
144
-
145
- /** 异步发送启动问候语(优先发给升级触发者,fallback 发给管理员) */
146
- export function sendStartupGreetings(ctx: AdminResolverContext, trigger: "READY" | "RESUMED"): void {
147
- (async () => {
148
- const plan = getStartupGreetingPlan(ctx.accountId, ctx.appId);
149
- if (!plan.shouldSend || !plan.greeting) {
150
- ctx.log?.info(`[qqbot:${ctx.accountId}] Skipping startup greeting (${plan.reason ?? "debounced"}, trigger=${trigger})`);
151
- return;
152
- }
153
-
154
- const upgradeTargetOpenId = loadUpgradeGreetingTargetOpenId(ctx.accountId, ctx.appId, ctx.log);
155
-
156
- // 没有 upgrade-greeting-target 文件 → 不是通过 /bot-upgrade 触发的升级
157
- // (console 手动重启、脚本升级等场景),静默更新 marker 不发消息
158
- if (!upgradeTargetOpenId) {
159
- markStartupGreetingSent(ctx.accountId, ctx.appId, plan.version);
160
- ctx.log?.info(`[qqbot:${ctx.accountId}] Version changed but no upgrade-greeting-target, silently updating marker (trigger=${trigger})`);
161
- return;
162
- }
163
-
164
- try {
165
- ctx.log?.info(`[qqbot:${ctx.accountId}] Sending startup greeting to upgrade-requester (trigger=${trigger}): "${plan.greeting}"`);
166
- const token = await getAccessToken(ctx.appId, ctx.clientSecret);
167
- const GREETING_TIMEOUT_MS = 10_000;
168
- await Promise.race([
169
- sendProactiveC2CMessage(token, upgradeTargetOpenId, plan.greeting),
170
- new Promise((_, reject) => setTimeout(() => reject(new Error("Startup greeting send timeout (10s)")), GREETING_TIMEOUT_MS)),
171
- ]);
172
- markStartupGreetingSent(ctx.accountId, ctx.appId, plan.version);
173
- clearUpgradeGreetingTargetOpenId(ctx.accountId, ctx.appId);
174
- ctx.log?.info(`[qqbot:${ctx.accountId}] Sent startup greeting to upgrade-requester: ${upgradeTargetOpenId}`);
175
- } catch (err) {
176
- const message = err instanceof Error ? err.message : String(err);
177
- markStartupGreetingFailed(ctx.accountId, ctx.appId, plan.version, message);
178
- ctx.log?.error(`[qqbot:${ctx.accountId}] Failed to send startup greeting: ${message}`);
179
- }
180
- })();
181
- }