@openclaw/qqbot 2026.5.12 → 2026.5.14-beta.2

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.
@@ -1,284 +0,0 @@
1
- import { a as normalizeStringifiedOptionalString, c as getPlatformAdapter, d as registerPlatformAdapterFactory, l as hasPlatformAdapter, o as readStringField, r as normalizeOptionalLowercaseString, t as asOptionalObjectRecord, u as registerPlatformAdapter } from "./string-normalize-C46CS-F1.js";
2
- import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
3
- import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
4
- //#region extensions/qqbot/src/bridge/logger.ts
5
- let _logger = null;
6
- /** Register the framework logger. Called once in startGateway(). */
7
- function setBridgeLogger(logger) {
8
- _logger = logger;
9
- }
10
- /** Get the bridge logger. Falls back to console if not yet registered. */
11
- function getBridgeLogger() {
12
- return _logger ?? {
13
- info: (msg) => console.log(msg),
14
- error: (msg) => console.error(msg),
15
- debug: (msg) => console.log(msg)
16
- };
17
- }
18
- //#endregion
19
- //#region extensions/qqbot/src/bridge/bootstrap.ts
20
- /**
21
- * Bootstrap the PlatformAdapter for the built-in version.
22
- *
23
- * ## Design
24
- *
25
- * The adapter is registered via two complementary mechanisms:
26
- *
27
- * 1. **Factory registration** (`registerPlatformAdapterFactory`) — a lightweight
28
- * callback stored in `adapter/index.ts` that is invoked lazily by
29
- * `getPlatformAdapter()` on first access. This guarantees the adapter is
30
- * available regardless of module evaluation order or bundler chunk splitting.
31
- *
32
- * 2. **Eager side-effect** (`ensurePlatformAdapter()`) — called at module
33
- * evaluation time when `channel.ts` imports this file. Provides the adapter
34
- * immediately for code that runs synchronously during startup.
35
- *
36
- * Heavy async-only dependencies (`media-runtime`, `config-runtime`,
37
- * `approval-gateway-runtime`) are lazy-imported inside each async method body
38
- * so that this module evaluates with minimal overhead.
39
- *
40
- * Synchronous dependencies (`secret-input`, `temp-path`) are imported
41
- * statically at the top level so they work reliably in both production and
42
- * vitest (which resolves bare specifiers via `resolve.alias`, not Node CJS).
43
- */
44
- function createBuiltinAdapter() {
45
- return {
46
- async validateRemoteUrl(_url, _options) {},
47
- async resolveSecret(value) {
48
- if (typeof value === "string") return value || void 0;
49
- },
50
- async downloadFile(url, destDir, filename) {
51
- const { fetchRemoteMedia } = await import("openclaw/plugin-sdk/media-runtime");
52
- const result = await fetchRemoteMedia({
53
- url,
54
- filePathHint: filename
55
- });
56
- const fs = await import("node:fs");
57
- const path = await import("node:path");
58
- if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
59
- const destPath = path.join(destDir, filename ?? "download");
60
- fs.writeFileSync(destPath, result.buffer);
61
- return destPath;
62
- },
63
- async fetchMedia(options) {
64
- const { fetchRemoteMedia } = await import("openclaw/plugin-sdk/media-runtime");
65
- const result = await fetchRemoteMedia({
66
- url: options.url,
67
- filePathHint: options.filePathHint,
68
- maxBytes: options.maxBytes,
69
- maxRedirects: options.maxRedirects,
70
- ssrfPolicy: options.ssrfPolicy,
71
- requestInit: options.requestInit
72
- });
73
- return {
74
- buffer: result.buffer,
75
- fileName: result.fileName
76
- };
77
- },
78
- getTempDir() {
79
- return resolvePreferredOpenClawTmpDir();
80
- },
81
- hasConfiguredSecret(value) {
82
- return hasConfiguredSecretInput(value);
83
- },
84
- normalizeSecretInputString(value) {
85
- return normalizeSecretInputString(value) ?? void 0;
86
- },
87
- resolveSecretInputString(params) {
88
- return normalizeResolvedSecretInputString(params) ?? void 0;
89
- },
90
- async resolveApproval(approvalId, decision) {
91
- try {
92
- const { getRuntimeConfig } = await import("openclaw/plugin-sdk/runtime-config-snapshot");
93
- const { resolveApprovalOverGateway } = await import("openclaw/plugin-sdk/approval-gateway-runtime");
94
- await resolveApprovalOverGateway({
95
- cfg: getRuntimeConfig(),
96
- approvalId,
97
- decision,
98
- clientDisplayName: "QQBot Approval Handler"
99
- });
100
- return true;
101
- } catch (err) {
102
- getBridgeLogger().error(`[qqbot] resolveApproval failed: ${String(err)}`);
103
- return false;
104
- }
105
- }
106
- };
107
- }
108
- /**
109
- * Ensure the built-in PlatformAdapter is registered.
110
- *
111
- * Safe to call multiple times — only registers on the first invocation.
112
- * Exported for backward compatibility with code that calls it explicitly.
113
- */
114
- function ensurePlatformAdapter() {
115
- if (!hasPlatformAdapter()) registerPlatformAdapter(createBuiltinAdapter());
116
- }
117
- registerPlatformAdapterFactory(createBuiltinAdapter);
118
- ensurePlatformAdapter();
119
- //#endregion
120
- //#region extensions/qqbot/src/engine/config/resolve.ts
121
- /**
122
- * QQBot config resolution (pure logic layer).
123
- * QQBot 配置解析(纯逻辑层)。
124
- *
125
- * Resolves account IDs, default account selection, and base account
126
- * info from raw config objects. Secret/credential resolution is
127
- * intentionally left to the outer layer (src/bridge/config.ts) so that
128
- * this module stays framework-agnostic and self-contained.
129
- */
130
- /**
131
- * Default account ID, used for the unnamed top-level account.
132
- * 默认账号 ID,用于顶层配置中未命名的账号。
133
- */
134
- const DEFAULT_ACCOUNT_ID = "default";
135
- function normalizeAppId(raw) {
136
- if (typeof raw === "string") return raw.trim();
137
- if (typeof raw === "number") return String(raw);
138
- return "";
139
- }
140
- function normalizeAccountConfig(account) {
141
- if (!account) return {};
142
- const audioPolicy = asOptionalObjectRecord(account.audioFormatPolicy);
143
- return {
144
- ...account,
145
- ...audioPolicy ? { audioFormatPolicy: { ...audioPolicy } } : {}
146
- };
147
- }
148
- function readQQBotSection(cfg) {
149
- return asOptionalObjectRecord(asOptionalObjectRecord(cfg.channels)?.qqbot);
150
- }
151
- /**
152
- * List all configured QQBot account IDs.
153
- * 列出所有已配置的 QQBot 账号 ID。
154
- */
155
- function listAccountIds(cfg) {
156
- const ids = /* @__PURE__ */ new Set();
157
- const qqbot = readQQBotSection(cfg);
158
- if (qqbot?.appId || process.env.QQBOT_APP_ID) ids.add(DEFAULT_ACCOUNT_ID);
159
- if (qqbot?.accounts) {
160
- for (const accountId of Object.keys(qqbot.accounts)) if (qqbot.accounts[accountId]?.appId) ids.add(accountId);
161
- }
162
- return Array.from(ids);
163
- }
164
- /**
165
- * Resolve the default QQBot account ID.
166
- * 解析默认 QQBot 账号 ID(优先级:defaultAccount > 顶层 appId > 第一个命名账号)。
167
- */
168
- function resolveDefaultAccountId(cfg) {
169
- const qqbot = readQQBotSection(cfg);
170
- const configuredDefaultAccountId = normalizeOptionalLowercaseString(qqbot?.defaultAccount);
171
- if (configuredDefaultAccountId && (configuredDefaultAccountId === "default" || Boolean(qqbot?.accounts?.[configuredDefaultAccountId]?.appId))) return configuredDefaultAccountId;
172
- if (qqbot?.appId || process.env.QQBOT_APP_ID) return DEFAULT_ACCOUNT_ID;
173
- if (qqbot?.accounts) {
174
- const ids = Object.keys(qqbot.accounts);
175
- if (ids.length > 0) return ids[0];
176
- }
177
- return DEFAULT_ACCOUNT_ID;
178
- }
179
- /**
180
- * Resolve base account info (without credentials).
181
- * 解析账号基础信息(不含凭证)。
182
- *
183
- * Resolves everything except Secret/credential fields. The outer
184
- * config.ts layer calls this and adds Secret handling on top.
185
- */
186
- function resolveAccountBase(cfg, accountId) {
187
- const resolvedAccountId = accountId ?? resolveDefaultAccountId(cfg);
188
- const qqbot = readQQBotSection(cfg);
189
- let accountConfig = {};
190
- let appId = "";
191
- if (resolvedAccountId === "default") {
192
- accountConfig = normalizeAccountConfig(asOptionalObjectRecord(qqbot));
193
- appId = normalizeAppId(qqbot?.appId);
194
- } else {
195
- const account = qqbot?.accounts?.[resolvedAccountId];
196
- accountConfig = normalizeAccountConfig(asOptionalObjectRecord(account));
197
- appId = normalizeAppId(asOptionalObjectRecord(account)?.appId);
198
- }
199
- if (!appId && process.env.QQBOT_APP_ID && resolvedAccountId === "default") appId = normalizeAppId(process.env.QQBOT_APP_ID);
200
- return {
201
- accountId: resolvedAccountId,
202
- name: readStringField(accountConfig, "name"),
203
- enabled: accountConfig.enabled !== false,
204
- appId,
205
- systemPrompt: readStringField(accountConfig, "systemPrompt"),
206
- markdownSupport: accountConfig.markdownSupport !== false,
207
- config: accountConfig
208
- };
209
- }
210
- /** Apply account config updates into a raw config object. */
211
- function applyAccountConfig(cfg, accountId, input) {
212
- const next = { ...cfg };
213
- const channels = asOptionalObjectRecord(cfg.channels) ?? {};
214
- const existingQQBot = asOptionalObjectRecord(channels.qqbot) ?? {};
215
- if (accountId === "default") {
216
- const allowFrom = existingQQBot.allowFrom ?? ["*"];
217
- next.channels = {
218
- ...channels,
219
- qqbot: {
220
- ...existingQQBot,
221
- enabled: true,
222
- allowFrom,
223
- ...input.appId ? { appId: input.appId } : {},
224
- ...input.clientSecret ? {
225
- clientSecret: input.clientSecret,
226
- clientSecretFile: void 0
227
- } : input.clientSecretFile ? {
228
- clientSecretFile: input.clientSecretFile,
229
- clientSecret: void 0
230
- } : {},
231
- ...input.name ? { name: input.name } : {}
232
- }
233
- };
234
- } else {
235
- const accounts = existingQQBot.accounts ?? {};
236
- const existingAccount = accounts[accountId] ?? {};
237
- const allowFrom = existingAccount.allowFrom ?? ["*"];
238
- next.channels = {
239
- ...channels,
240
- qqbot: {
241
- ...existingQQBot,
242
- enabled: true,
243
- accounts: {
244
- ...accounts,
245
- [accountId]: {
246
- ...existingAccount,
247
- enabled: true,
248
- allowFrom,
249
- ...input.appId ? { appId: input.appId } : {},
250
- ...input.clientSecret ? {
251
- clientSecret: input.clientSecret,
252
- clientSecretFile: void 0
253
- } : input.clientSecretFile ? {
254
- clientSecretFile: input.clientSecretFile,
255
- clientSecret: void 0
256
- } : {},
257
- ...input.name ? { name: input.name } : {}
258
- }
259
- }
260
- }
261
- };
262
- }
263
- return next;
264
- }
265
- /** Check whether a QQBot account has been fully configured. */
266
- function isAccountConfigured(account) {
267
- return Boolean(account?.appId && (Boolean(account?.clientSecret) || getPlatformAdapter().hasConfiguredSecret(account?.config?.clientSecret) || Boolean(account?.config?.clientSecretFile?.trim())));
268
- }
269
- /** Build a summary description of an account. */
270
- function describeAccount(account) {
271
- return {
272
- accountId: account?.accountId ?? "default",
273
- name: account?.name,
274
- enabled: account?.enabled ?? false,
275
- configured: isAccountConfigured(account),
276
- tokenSource: account?.secretSource
277
- };
278
- }
279
- /** Normalize allowFrom entries into uppercase strings without the qqbot: prefix. */
280
- function formatAllowFrom(allowFrom) {
281
- return (allowFrom ?? []).map((entry) => normalizeStringifiedOptionalString(entry)).filter((entry) => Boolean(entry)).map((entry) => entry.replace(/^qqbot:/i, "")).map((entry) => entry.toUpperCase());
282
- }
283
- //#endregion
284
- export { isAccountConfigured as a, resolveDefaultAccountId as c, setBridgeLogger as d, formatAllowFrom as i, ensurePlatformAdapter as l, applyAccountConfig as n, listAccountIds as o, describeAccount as r, resolveAccountBase as s, DEFAULT_ACCOUNT_ID as t, getBridgeLogger as u };
@@ -1,18 +0,0 @@
1
- import { _ as setOpenClawVersion } from "./sender-BrpzCcXA.js";
2
- import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
3
- //#region extensions/qqbot/src/bridge/runtime.ts
4
- const { setRuntime: _setRuntime, getRuntime: getQQBotRuntime } = createPluginRuntimeStore({
5
- pluginId: "qqbot",
6
- errorMessage: "QQBot runtime not initialized"
7
- });
8
- /** Set the QQBot runtime and inject the framework version into the User-Agent. */
9
- function setQQBotRuntime(runtime) {
10
- _setRuntime(runtime);
11
- setOpenClawVersion(runtime.version);
12
- }
13
- /** Type-narrowed getter for engine/ modules that need GatewayPluginRuntime. */
14
- function getQQBotRuntimeForEngine() {
15
- return getQQBotRuntime();
16
- }
17
- //#endregion
18
- export { getQQBotRuntimeForEngine as n, setQQBotRuntime as r, getQQBotRuntime as t };
@@ -1,245 +0,0 @@
1
- import { c as getPlatformAdapter } from "./string-normalize-C46CS-F1.js";
2
- import { C as debugWarn, L as formatErrorMessage, S as debugLog } from "./sender-BrpzCcXA.js";
3
- import * as fs$1 from "node:fs";
4
- import * as os$1 from "node:os";
5
- import * as path$1 from "node:path";
6
- //#region extensions/qqbot/src/engine/utils/platform.ts
7
- /**
8
- * Cross-platform path and detection helpers for core/ modules.
9
- *
10
- * Provides home/data/media directory helpers, platform detection,
11
- * silk-wasm availability checks — all without importing `openclaw/plugin-sdk`.
12
- * The temp-directory fallback is delegated to the PlatformAdapter.
13
- */
14
- /**
15
- * Resolve the current user's home directory safely across platforms.
16
- *
17
- * Priority:
18
- * 1. `os.homedir()`
19
- * 2. `$HOME` or `%USERPROFILE%`
20
- * 3. PlatformAdapter.getTempDir() as a last resort
21
- */
22
- function getHomeDir() {
23
- try {
24
- const home = os$1.homedir();
25
- if (home && fs$1.existsSync(home)) return home;
26
- } catch {}
27
- const envHome = process.env.HOME || process.env.USERPROFILE;
28
- if (envHome && fs$1.existsSync(envHome)) return envHome;
29
- return getPlatformAdapter().getTempDir();
30
- }
31
- /** Return a path under `~/.openclaw/qqbot` without creating it. */
32
- function getQQBotDataPath(...subPaths) {
33
- return path$1.join(getHomeDir(), ".openclaw", "qqbot", ...subPaths);
34
- }
35
- /** Return a path under `~/.openclaw/qqbot`, creating it on demand. */
36
- function getQQBotDataDir(...subPaths) {
37
- const dir = getQQBotDataPath(...subPaths);
38
- if (!fs$1.existsSync(dir)) fs$1.mkdirSync(dir, { recursive: true });
39
- return dir;
40
- }
41
- /**
42
- * Return a path under `~/.openclaw/media/qqbot` without creating it.
43
- *
44
- * Unlike `getQQBotDataPath`, this lives under OpenClaw's core media allowlist so
45
- * downloaded images and audio can be accessed by framework media tooling.
46
- */
47
- function getQQBotMediaPath(...subPaths) {
48
- return path$1.join(getHomeDir(), ".openclaw", "media", "qqbot", ...subPaths);
49
- }
50
- /** Return a path under `~/.openclaw/media/qqbot`, creating it on demand. */
51
- function getQQBotMediaDir(...subPaths) {
52
- const dir = getQQBotMediaPath(...subPaths);
53
- if (!fs$1.existsSync(dir)) fs$1.mkdirSync(dir, { recursive: true });
54
- return dir;
55
- }
56
- /**
57
- * Return `~/.openclaw/media`, OpenClaw's shared media root.
58
- *
59
- * This mirrors the directory that core's `buildMediaLocalRoots` exposes as an
60
- * allowlisted location (see `openclaw/src/media/local-roots.ts`). Using it as a
61
- * QQ Bot payload root lets the plugin trust framework-produced files that live
62
- * in sibling subdirectories such as `outbound/` (written by
63
- * `saveMediaBuffer(..., "outbound", ...)`) or `inbound/`, while still keeping
64
- * the check anchored to a single, well-known directory.
65
- */
66
- function getOpenClawMediaDir() {
67
- return path$1.join(getHomeDir(), ".openclaw", "media");
68
- }
69
- function isWindows() {
70
- return process.platform === "win32";
71
- }
72
- /** Return the preferred temporary directory. */
73
- function getTempDir() {
74
- return getPlatformAdapter().getTempDir();
75
- }
76
- let _silkWasmAvailable = null;
77
- /** Check whether silk-wasm can run in the current environment. */
78
- async function checkSilkWasmAvailable() {
79
- if (_silkWasmAvailable !== null) return _silkWasmAvailable;
80
- try {
81
- const { isSilk } = await import("silk-wasm");
82
- isSilk(new Uint8Array(0));
83
- _silkWasmAvailable = true;
84
- debugLog("[platform] silk-wasm: available");
85
- } catch (err) {
86
- _silkWasmAvailable = false;
87
- debugWarn(`[platform] silk-wasm: NOT available (${formatErrorMessage(err)})`);
88
- }
89
- return _silkWasmAvailable;
90
- }
91
- /** Expand `~` to the current user's home directory. */
92
- function expandTilde(p) {
93
- if (!p) return p;
94
- if (p === "~") return getHomeDir();
95
- if (p.startsWith("~/") || p.startsWith("~\\")) return path$1.join(getHomeDir(), p.slice(2));
96
- return p;
97
- }
98
- /** Normalize a user-provided path by trimming, stripping `file://`, and expanding `~`. */
99
- function normalizePath(p) {
100
- let result = p.trim();
101
- if (result.startsWith("file://")) {
102
- result = result.slice(7);
103
- try {
104
- result = decodeURIComponent(result);
105
- } catch {}
106
- }
107
- return expandTilde(result);
108
- }
109
- /** Return true when the string looks like a local filesystem path rather than a URL. */
110
- function isLocalPath(p) {
111
- if (!p) return false;
112
- if (p.startsWith("file://")) return true;
113
- if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) return true;
114
- if (p.startsWith("/")) return true;
115
- if (/^[a-zA-Z]:[\\/]/.test(p)) return true;
116
- if (p.startsWith("\\\\")) return true;
117
- if (p.startsWith("./") || p.startsWith("../")) return true;
118
- if (p.startsWith(".\\") || p.startsWith("..\\")) return true;
119
- return false;
120
- }
121
- function isPathWithinRoot(candidate, root) {
122
- const relative = path$1.relative(root, candidate);
123
- return relative === "" || !relative.startsWith("..") && !path$1.isAbsolute(relative);
124
- }
125
- /** Remap legacy or hallucinated QQ Bot local media paths to real files when possible. */
126
- function resolveQQBotLocalMediaPath(p) {
127
- const normalized = normalizePath(p);
128
- if (!isLocalPath(normalized) || fs$1.existsSync(normalized)) return normalized;
129
- const homeDir = getHomeDir();
130
- const mediaRoot = getQQBotMediaPath();
131
- const dataRoot = getQQBotDataPath();
132
- const candidateRoots = [
133
- {
134
- from: path$1.join(homeDir, ".openclaw", "workspace", "qqbot"),
135
- to: mediaRoot
136
- },
137
- {
138
- from: dataRoot,
139
- to: mediaRoot
140
- },
141
- {
142
- from: mediaRoot,
143
- to: dataRoot
144
- }
145
- ];
146
- for (const { from, to } of candidateRoots) {
147
- if (!isPathWithinRoot(normalized, from)) continue;
148
- const relative = path$1.relative(from, normalized);
149
- const candidate = path$1.join(to, relative);
150
- if (fs$1.existsSync(candidate)) {
151
- debugWarn(`[platform] Remapped missing QQBot media path ${normalized} -> ${candidate}`);
152
- return candidate;
153
- }
154
- }
155
- return normalized;
156
- }
157
- /**
158
- * Resolve a structured-payload local file path and enforce that it stays within
159
- * QQ Bot-owned storage roots.
160
- */
161
- function resolveQQBotPayloadLocalFilePath(p) {
162
- const candidate = resolveQQBotLocalMediaPath(p);
163
- if (!candidate.trim()) return null;
164
- const resolvedCandidate = path$1.resolve(candidate);
165
- if (!fs$1.existsSync(resolvedCandidate)) return null;
166
- const canonicalCandidate = fs$1.realpathSync(resolvedCandidate);
167
- const allowedRoots = [getOpenClawMediaDir(), getQQBotMediaPath()];
168
- for (const root of allowedRoots) {
169
- const resolvedRoot = path$1.resolve(root);
170
- if (isPathWithinRoot(canonicalCandidate, fs$1.existsSync(resolvedRoot) ? fs$1.realpathSync(resolvedRoot) : resolvedRoot)) return canonicalCandidate;
171
- }
172
- return null;
173
- }
174
- //#endregion
175
- //#region extensions/qqbot/src/engine/messaging/target-parser.ts
176
- /**
177
- * Parse a qqbot target string into a structured delivery target.
178
- *
179
- * Supported formats:
180
- * - `qqbot:c2c:openid` → C2C direct message
181
- * - `qqbot:group:groupid` → Group message
182
- * - `qqbot:channel:channelid` → Channel message
183
- * - `c2c:openid` → C2C (without qqbot: prefix)
184
- * - `group:groupid` → Group (without qqbot: prefix)
185
- * - `channel:channelid` → Channel (without qqbot: prefix)
186
- * - `openid` → C2C (bare openid, default)
187
- *
188
- * @param to - Raw target string.
189
- * @returns Parsed target with type and id.
190
- * @throws {Error} When the target format is invalid.
191
- */
192
- function parseTarget(to) {
193
- let id = to.replace(/^qqbot:/i, "");
194
- if (id.startsWith("c2c:")) {
195
- const userId = id.slice(4);
196
- if (!userId) throw new Error(`Invalid c2c target format: ${to} - missing user ID`);
197
- return {
198
- type: "c2c",
199
- id: userId
200
- };
201
- }
202
- if (id.startsWith("group:")) {
203
- const groupId = id.slice(6);
204
- if (!groupId) throw new Error(`Invalid group target format: ${to} - missing group ID`);
205
- return {
206
- type: "group",
207
- id: groupId
208
- };
209
- }
210
- if (id.startsWith("channel:")) {
211
- const channelId = id.slice(8);
212
- if (!channelId) throw new Error(`Invalid channel target format: ${to} - missing channel ID`);
213
- return {
214
- type: "channel",
215
- id: channelId
216
- };
217
- }
218
- if (!id) throw new Error(`Invalid target format: ${to} - empty ID after removing qqbot: prefix`);
219
- return {
220
- type: "c2c",
221
- id
222
- };
223
- }
224
- /**
225
- * Normalize a QQ Bot target string into the canonical `qqbot:...` form.
226
- *
227
- * Returns `undefined` when the target does not look like a QQ Bot address.
228
- */
229
- function normalizeTarget(target) {
230
- const id = target.replace(/^qqbot:/i, "");
231
- if (id.startsWith("c2c:") || id.startsWith("group:") || id.startsWith("channel:")) return `qqbot:${id}`;
232
- if (/^[0-9a-fA-F]{32}$/.test(id)) return `qqbot:c2c:${id}`;
233
- if (/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(id)) return `qqbot:c2c:${id}`;
234
- }
235
- /**
236
- * Return true when the string looks like a QQ Bot target ID.
237
- */
238
- function looksLikeQQBotTarget(id) {
239
- if (/^qqbot:(c2c|group|channel):/i.test(id)) return true;
240
- if (/^(c2c|group|channel):/i.test(id)) return true;
241
- if (/^[0-9a-fA-F]{32}$/.test(id)) return true;
242
- return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(id);
243
- }
244
- //#endregion
245
- export { getHomeDir as a, getQQBotMediaDir as c, isLocalPath as d, isWindows as f, checkSilkWasmAvailable as i, getQQBotMediaPath as l, resolveQQBotPayloadLocalFilePath as m, normalizeTarget as n, getQQBotDataDir as o, normalizePath as p, parseTarget as r, getQQBotDataPath as s, looksLikeQQBotTarget as t, getTempDir as u };