@openclaw/qqbot 2026.6.11-beta.2 → 2026.7.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +5 -5
- package/dist/{channel-DvWrqcZB.js → channel-Bh0MrYvU.js} +34 -100
- package/dist/{channel-entry-BGXFRmbg.js → channel-entry-LMtNY-J6.js} +3 -3
- package/dist/channel-entry-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/doctor-contract-api.js +168 -2
- package/dist/{gateway-CCkrdgaK.js → gateway-BgfQAYxB.js} +11 -162
- package/dist/{group-CvVXke_k.js → group-DQQsZ6Y0.js} +2 -2
- package/dist/{handler-runtime--OTMkFWa.js → handler-runtime-BQ72YPsH.js} +2 -2
- package/dist/{outbound-BQcPCo-z.js → outbound-Dfa2uOEp.js} +216 -4
- package/dist/{runtime-D1hn91-s.js → runtime-BL0xZzWe.js} +1 -1
- package/dist/runtime-api.js +1 -1
- package/dist/{sender-CRZ2af7P.js → sender-BHWpE_yH.js} +2 -2
- package/dist/{doctor-contract-BYTS8-ia.js → state-keys-CQKlAFyo.js} +7 -1
- package/dist/target-parser-DagYRQkP.js +71 -0
- package/dist/{tools-CeUI9pG-.js → tools-BvXe7bTq.js} +58 -13
- package/dist/tools-api.js +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
- package/skills/qqbot-channel/SKILL.md +54 -41
- package/skills/qqbot-channel/references/api_references.md +16 -8
- package/skills/qqbot-media/SKILL.md +6 -3
- package/skills/qqbot-remind/SKILL.md +15 -14
- package/dist/target-parser-BdCUmxK7.js +0 -285
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qqbot-remind
|
|
3
|
-
description: QQBot scheduled reminders.
|
|
3
|
+
description: QQBot scheduled reminders. Use only for explicit user requests to create, list, or cancel one-time or recurring QQ reminders; ask for missing time, content, or timezone before scheduling.
|
|
4
4
|
metadata: { "openclaw": { "emoji": "⏰", "requires": { "config": ["channels.qqbot"] } } }
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# QQ Bot 定时提醒
|
|
8
8
|
|
|
9
|
-
## ⚠️
|
|
9
|
+
## ⚠️ 意图规则
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
只有当用户明确要求创建、查询或取消提醒/闹钟/定时任务时,才调用工具。闲聊、假设、解释提醒功能、讨论将来计划但未要求创建提醒时,不要调用工具。
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
如果用户确实要求提醒,你没有内存或后台线程,口头承诺"到时候提醒"是无效的——必须调用工具才能真正注册定时任务。时间、提醒内容、目标会话或时区不清楚时先追问;不要替用户猜测。
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -18,13 +18,14 @@ metadata: { "openclaw": { "emoji": "⏰", "requires": { "config": ["channels.qqb
|
|
|
18
18
|
|
|
19
19
|
**第一步**:调用 `qqbot_remind` 工具,传入简单参数:
|
|
20
20
|
|
|
21
|
-
| 参数
|
|
22
|
-
|
|
|
23
|
-
| `action`
|
|
24
|
-
| `content`
|
|
25
|
-
| `to`
|
|
26
|
-
| `time`
|
|
27
|
-
| `
|
|
21
|
+
| 参数 | 说明 | 示例 |
|
|
22
|
+
| ---------- | -------------------------------------------- | ------------------------------------------- |
|
|
23
|
+
| `action` | 操作类型 | `"add"` / `"list"` / `"remove"` |
|
|
24
|
+
| `content` | 提醒内容 | `"喝水"` |
|
|
25
|
+
| `to` | 目标地址(可选,系统自动获取,通常无需填写) | — |
|
|
26
|
+
| `time` | 时间(相对时间或 cron 表达式) | `"5m"` / `"1h30m"` / `"0 8 * * *"` |
|
|
27
|
+
| `timezone` | IANA 时区(周期提醒建议明确传入) | `"Asia/Shanghai"` / `"America/Los_Angeles"` |
|
|
28
|
+
| `jobId` | 任务 ID(仅 remove) | `"xxx"` |
|
|
28
29
|
|
|
29
30
|
**第二步**:根据 `qqbot_remind` 的返回结果,回复用户。`qqbot_remind` 会直接创建、查询或取消 Gateway cron 任务;成功后不要再调用 `cron` 工具。
|
|
30
31
|
|
|
@@ -92,7 +93,7 @@ metadata: { "openclaw": { "emoji": "⏰", "requires": { "config": ["channels.qqb
|
|
|
92
93
|
"action": "add",
|
|
93
94
|
"job": {
|
|
94
95
|
"name": "{任务名}",
|
|
95
|
-
"schedule": { "kind": "cron", "expr": "0 8 * * *", "tz": "
|
|
96
|
+
"schedule": { "kind": "cron", "expr": "0 8 * * *", "tz": "{用户确认的 IANA 时区}" },
|
|
96
97
|
"sessionTarget": "isolated",
|
|
97
98
|
"wakeMode": "now",
|
|
98
99
|
"payload": {
|
|
@@ -124,7 +125,7 @@ metadata: { "openclaw": { "emoji": "⏰", "requires": { "config": ["channels.qqb
|
|
|
124
125
|
| 每周末上午10点 | `"0 10 * * 0,6"` |
|
|
125
126
|
| 每小时整点 | `"0 * * * *"` |
|
|
126
127
|
|
|
127
|
-
>
|
|
128
|
+
> 周期提醒应使用用户明确提供、用户资料/会话中可信可得,或用户确认过的 IANA 时区。无法判断时先追问;不要把所有用户都假定在同一时区。
|
|
128
129
|
|
|
129
130
|
---
|
|
130
131
|
|
|
@@ -141,7 +142,7 @@ metadata: { "openclaw": { "emoji": "⏰", "requires": { "config": ["channels.qqb
|
|
|
141
142
|
| "修改提醒时间" | `remove` → `add` | — |
|
|
142
143
|
| "提醒我"(无时间) | **需追问** | — |
|
|
143
144
|
|
|
144
|
-
纯相对时间("5分钟后"、"1小时后"
|
|
145
|
+
纯相对时间("5分钟后"、"1小时后")可直接计算,无需确认。时间、日期、周期、内容或时区模糊/缺失时需追问。周期提醒在回复中说明解释后的本地时间和时区。
|
|
145
146
|
|
|
146
147
|
---
|
|
147
148
|
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
import { c as getPlatformAdapter } from "./string-normalize-R_0cKO7Q.js";
|
|
2
|
-
import { a as formatErrorMessage, n as debugLog, r as debugWarn } from "./log-SDfMMBWe.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 OS 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
|
-
* This is the *operating-system* home and intentionally ignores
|
|
23
|
-
* `OPENCLAW_HOME`. QQ Bot still checks this tree for legacy state imports and
|
|
24
|
-
* media-path remaps from older releases.
|
|
25
|
-
*/
|
|
26
|
-
function getHomeDir() {
|
|
27
|
-
try {
|
|
28
|
-
const home = os$1.homedir();
|
|
29
|
-
if (home && fs$1.existsSync(home)) return home;
|
|
30
|
-
} catch {}
|
|
31
|
-
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
32
|
-
if (envHome && fs$1.existsSync(envHome)) return envHome;
|
|
33
|
-
return getPlatformAdapter().getTempDir();
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Resolve the effective OpenClaw home directory.
|
|
37
|
-
*
|
|
38
|
-
* Mirrors the contract from core (`src/infra/home-dir.ts::resolveEffectiveHomeDir`)
|
|
39
|
-
* so QQ Bot media roots live under the same tree the rest of OpenClaw treats as
|
|
40
|
-
* `~`. The extension cannot import the core helper directly (it is a separate
|
|
41
|
-
* package with `openclaw` as a peer dependency), so this re-implements the
|
|
42
|
-
* minimal contract:
|
|
43
|
-
*
|
|
44
|
-
* 1. `OPENCLAW_HOME` when set (with `~` / `~/...` expanded against the OS home).
|
|
45
|
-
* 2. Otherwise fall back to {@link getHomeDir} so existing single-home
|
|
46
|
-
* deployments are unaffected.
|
|
47
|
-
*
|
|
48
|
-
* Empty / `"undefined"` / `"null"` strings are treated as unset to match how
|
|
49
|
-
* core normalizes the variable.
|
|
50
|
-
*/
|
|
51
|
-
function resolveOpenClawHome() {
|
|
52
|
-
const raw = process.env.OPENCLAW_HOME?.trim();
|
|
53
|
-
if (!raw || raw === "undefined" || raw === "null") return getHomeDir();
|
|
54
|
-
if (raw === "~" || raw.startsWith("~/") || raw.startsWith("~\\")) {
|
|
55
|
-
const osHome = getHomeDir();
|
|
56
|
-
if (raw === "~") return osHome;
|
|
57
|
-
return path$1.join(osHome, raw.slice(2));
|
|
58
|
-
}
|
|
59
|
-
return raw;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Return a legacy path under `~/.openclaw/qqbot` without creating it.
|
|
63
|
-
*
|
|
64
|
-
* Current QQ Bot runtime state lives in plugin SQLite KV. This path remains for
|
|
65
|
-
* legacy imports and media-path remaps from older releases.
|
|
66
|
-
*/
|
|
67
|
-
function getQQBotDataPath(...subPaths) {
|
|
68
|
-
return path$1.join(getHomeDir(), ".openclaw", "qqbot", ...subPaths);
|
|
69
|
-
}
|
|
70
|
-
/** Return a path under `~/.openclaw/qqbot`, creating it on demand. */
|
|
71
|
-
function getQQBotDataDir(...subPaths) {
|
|
72
|
-
const dir = getQQBotDataPath(...subPaths);
|
|
73
|
-
if (!fs$1.existsSync(dir)) fs$1.mkdirSync(dir, { recursive: true });
|
|
74
|
-
return dir;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Return a path under `<openclaw-home>/.openclaw/media/qqbot` without creating it.
|
|
78
|
-
*
|
|
79
|
-
* Unlike `getQQBotDataPath`, this lives under OpenClaw's core media allowlist
|
|
80
|
-
* so downloaded images and audio can be accessed by framework media tooling.
|
|
81
|
-
* The base honors `OPENCLAW_HOME` (when set) so files written by agents into
|
|
82
|
-
* the OpenClaw-managed media tree are reachable by this plugin even when
|
|
83
|
-
* `HOME` and `OPENCLAW_HOME` differ (Docker, multi-user hosts). Fixes #83562.
|
|
84
|
-
*/
|
|
85
|
-
function getQQBotMediaPath(...subPaths) {
|
|
86
|
-
return path$1.join(resolveOpenClawHome(), ".openclaw", "media", "qqbot", ...subPaths);
|
|
87
|
-
}
|
|
88
|
-
/** Return a path under `<openclaw-home>/.openclaw/media/qqbot`, creating it on demand. */
|
|
89
|
-
function getQQBotMediaDir(...subPaths) {
|
|
90
|
-
const dir = getQQBotMediaPath(...subPaths);
|
|
91
|
-
if (!fs$1.existsSync(dir)) fs$1.mkdirSync(dir, { recursive: true });
|
|
92
|
-
return dir;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Return `<openclaw-home>/.openclaw/media`, OpenClaw's shared media root.
|
|
96
|
-
*
|
|
97
|
-
* This mirrors the directory that core's `buildMediaLocalRoots` exposes as an
|
|
98
|
-
* allowlisted location (see `openclaw/src/media/local-roots.ts`). Using it as a
|
|
99
|
-
* QQ Bot payload root lets the plugin trust framework-produced files that live
|
|
100
|
-
* in sibling subdirectories such as `outbound/` (written by
|
|
101
|
-
* `saveMediaBuffer(..., "outbound", ...)`) or `inbound/`, while still keeping
|
|
102
|
-
* the check anchored to a single, well-known directory. Like
|
|
103
|
-
* {@link getQQBotMediaPath}, the base honors `OPENCLAW_HOME`.
|
|
104
|
-
*/
|
|
105
|
-
function getOpenClawMediaDir() {
|
|
106
|
-
return path$1.join(resolveOpenClawHome(), ".openclaw", "media");
|
|
107
|
-
}
|
|
108
|
-
function isWindows() {
|
|
109
|
-
return process.platform === "win32";
|
|
110
|
-
}
|
|
111
|
-
/** Return the preferred temporary directory. */
|
|
112
|
-
function getTempDir() {
|
|
113
|
-
return getPlatformAdapter().getTempDir();
|
|
114
|
-
}
|
|
115
|
-
let silkWasmAvailable = null;
|
|
116
|
-
/** Check whether silk-wasm can run in the current environment. */
|
|
117
|
-
async function checkSilkWasmAvailable() {
|
|
118
|
-
if (silkWasmAvailable !== null) return silkWasmAvailable;
|
|
119
|
-
try {
|
|
120
|
-
const { isSilk } = await import("silk-wasm");
|
|
121
|
-
isSilk(new Uint8Array(0));
|
|
122
|
-
silkWasmAvailable = true;
|
|
123
|
-
debugLog("[platform] silk-wasm: available");
|
|
124
|
-
} catch (err) {
|
|
125
|
-
silkWasmAvailable = false;
|
|
126
|
-
debugWarn(`[platform] silk-wasm: NOT available (${formatErrorMessage(err)})`);
|
|
127
|
-
}
|
|
128
|
-
return silkWasmAvailable;
|
|
129
|
-
}
|
|
130
|
-
/** Expand `~` to the current user's home directory. */
|
|
131
|
-
function expandTilde(p) {
|
|
132
|
-
if (!p) return p;
|
|
133
|
-
if (p === "~") return getHomeDir();
|
|
134
|
-
if (p.startsWith("~/") || p.startsWith("~\\")) return path$1.join(getHomeDir(), p.slice(2));
|
|
135
|
-
return p;
|
|
136
|
-
}
|
|
137
|
-
/** Normalize a user-provided path by trimming, stripping `file://`, and expanding `~`. */
|
|
138
|
-
function normalizePath(p) {
|
|
139
|
-
let result = p.trim();
|
|
140
|
-
if (result.startsWith("file://")) {
|
|
141
|
-
result = result.slice(7);
|
|
142
|
-
try {
|
|
143
|
-
result = decodeURIComponent(result);
|
|
144
|
-
} catch {}
|
|
145
|
-
}
|
|
146
|
-
return expandTilde(result);
|
|
147
|
-
}
|
|
148
|
-
/** Return true when the string looks like a local filesystem path rather than a URL. */
|
|
149
|
-
function isLocalPath(p) {
|
|
150
|
-
if (!p) return false;
|
|
151
|
-
if (p.startsWith("file://")) return true;
|
|
152
|
-
if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) return true;
|
|
153
|
-
if (p.startsWith("/")) return true;
|
|
154
|
-
if (/^[a-zA-Z]:[\\/]/.test(p)) return true;
|
|
155
|
-
if (p.startsWith("\\\\")) return true;
|
|
156
|
-
if (p.startsWith("./") || p.startsWith("../")) return true;
|
|
157
|
-
if (p.startsWith(".\\") || p.startsWith("..\\")) return true;
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
function isPathWithinRoot(candidate, root) {
|
|
161
|
-
const relative = path$1.relative(root, candidate);
|
|
162
|
-
return relative === "" || !relative.startsWith("..") && !path$1.isAbsolute(relative);
|
|
163
|
-
}
|
|
164
|
-
/** Remap legacy or hallucinated QQ Bot local media paths to real files when possible. */
|
|
165
|
-
function resolveQQBotLocalMediaPath(p) {
|
|
166
|
-
const normalized = normalizePath(p);
|
|
167
|
-
if (!isLocalPath(normalized) || fs$1.existsSync(normalized)) return normalized;
|
|
168
|
-
const osHomeDir = getHomeDir();
|
|
169
|
-
const openclawHomeDir = resolveOpenClawHome();
|
|
170
|
-
const mediaRoot = getQQBotMediaPath();
|
|
171
|
-
const dataRoot = getQQBotDataPath();
|
|
172
|
-
const candidateRoots = [
|
|
173
|
-
...Array.from(new Set([path$1.join(osHomeDir, ".openclaw", "workspace", "qqbot"), path$1.join(openclawHomeDir, ".openclaw", "workspace", "qqbot")])).map((from) => ({
|
|
174
|
-
from,
|
|
175
|
-
to: mediaRoot
|
|
176
|
-
})),
|
|
177
|
-
{
|
|
178
|
-
from: dataRoot,
|
|
179
|
-
to: mediaRoot
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
from: mediaRoot,
|
|
183
|
-
to: dataRoot
|
|
184
|
-
}
|
|
185
|
-
];
|
|
186
|
-
for (const { from, to } of candidateRoots) {
|
|
187
|
-
if (!isPathWithinRoot(normalized, from)) continue;
|
|
188
|
-
const relative = path$1.relative(from, normalized);
|
|
189
|
-
const candidate = path$1.join(to, relative);
|
|
190
|
-
if (fs$1.existsSync(candidate)) {
|
|
191
|
-
debugWarn(`[platform] Remapped missing QQBot media path ${normalized} -> ${candidate}`);
|
|
192
|
-
return candidate;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return normalized;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Resolve a structured-payload local file path and enforce that it stays within
|
|
199
|
-
* QQ Bot-owned storage roots.
|
|
200
|
-
*/
|
|
201
|
-
function resolveQQBotPayloadLocalFilePath(p) {
|
|
202
|
-
const candidate = resolveQQBotLocalMediaPath(p);
|
|
203
|
-
if (!candidate.trim()) return null;
|
|
204
|
-
const resolvedCandidate = path$1.resolve(candidate);
|
|
205
|
-
if (!fs$1.existsSync(resolvedCandidate)) return null;
|
|
206
|
-
const canonicalCandidate = fs$1.realpathSync(resolvedCandidate);
|
|
207
|
-
const allowedRoots = [getOpenClawMediaDir(), getQQBotMediaPath()];
|
|
208
|
-
for (const root of allowedRoots) {
|
|
209
|
-
const resolvedRoot = path$1.resolve(root);
|
|
210
|
-
if (isPathWithinRoot(canonicalCandidate, fs$1.existsSync(resolvedRoot) ? fs$1.realpathSync(resolvedRoot) : resolvedRoot)) return canonicalCandidate;
|
|
211
|
-
}
|
|
212
|
-
return null;
|
|
213
|
-
}
|
|
214
|
-
//#endregion
|
|
215
|
-
//#region extensions/qqbot/src/engine/messaging/target-parser.ts
|
|
216
|
-
/**
|
|
217
|
-
* Parse a qqbot target string into a structured delivery target.
|
|
218
|
-
*
|
|
219
|
-
* Supported formats:
|
|
220
|
-
* - `qqbot:c2c:openid` → C2C direct message
|
|
221
|
-
* - `qqbot:group:groupid` → Group message
|
|
222
|
-
* - `qqbot:channel:channelid` → Channel message
|
|
223
|
-
* - `c2c:openid` → C2C (without qqbot: prefix)
|
|
224
|
-
* - `group:groupid` → Group (without qqbot: prefix)
|
|
225
|
-
* - `channel:channelid` → Channel (without qqbot: prefix)
|
|
226
|
-
* - `openid` → C2C (bare openid, default)
|
|
227
|
-
*
|
|
228
|
-
* @param to - Raw target string.
|
|
229
|
-
* @returns Parsed target with type and id.
|
|
230
|
-
* @throws {Error} When the target format is invalid.
|
|
231
|
-
*/
|
|
232
|
-
function parseTarget(to) {
|
|
233
|
-
const id = to.replace(/^qqbot:/i, "");
|
|
234
|
-
if (id.startsWith("c2c:")) {
|
|
235
|
-
const userId = id.slice(4);
|
|
236
|
-
if (!userId) throw new Error(`Invalid c2c target format: ${to} - missing user ID`);
|
|
237
|
-
return {
|
|
238
|
-
type: "c2c",
|
|
239
|
-
id: userId
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
if (id.startsWith("group:")) {
|
|
243
|
-
const groupId = id.slice(6);
|
|
244
|
-
if (!groupId) throw new Error(`Invalid group target format: ${to} - missing group ID`);
|
|
245
|
-
return {
|
|
246
|
-
type: "group",
|
|
247
|
-
id: groupId
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
if (id.startsWith("channel:")) {
|
|
251
|
-
const channelId = id.slice(8);
|
|
252
|
-
if (!channelId) throw new Error(`Invalid channel target format: ${to} - missing channel ID`);
|
|
253
|
-
return {
|
|
254
|
-
type: "channel",
|
|
255
|
-
id: channelId
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
if (!id) throw new Error(`Invalid target format: ${to} - empty ID after removing qqbot: prefix`);
|
|
259
|
-
return {
|
|
260
|
-
type: "c2c",
|
|
261
|
-
id
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Normalize a QQ Bot target string into the canonical `qqbot:...` form.
|
|
266
|
-
*
|
|
267
|
-
* Returns `undefined` when the target does not look like a QQ Bot address.
|
|
268
|
-
*/
|
|
269
|
-
function normalizeTarget(target) {
|
|
270
|
-
const id = target.replace(/^qqbot:/i, "");
|
|
271
|
-
if (id.startsWith("c2c:") || id.startsWith("group:") || id.startsWith("channel:")) return `qqbot:${id}`;
|
|
272
|
-
if (/^[0-9a-fA-F]{32}$/.test(id)) return `qqbot:c2c:${id}`;
|
|
273
|
-
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}`;
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Return true when the string looks like a QQ Bot target ID.
|
|
277
|
-
*/
|
|
278
|
-
function looksLikeQQBotTarget(id) {
|
|
279
|
-
if (/^qqbot:(c2c|group|channel):/i.test(id)) return true;
|
|
280
|
-
if (/^(c2c|group|channel):/i.test(id)) return true;
|
|
281
|
-
if (/^[0-9a-fA-F]{32}$/.test(id)) return true;
|
|
282
|
-
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);
|
|
283
|
-
}
|
|
284
|
-
//#endregion
|
|
285
|
-
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 };
|