@tencent-connect/openclaw-qqbot 1.6.5-alpha.0 → 1.6.5-alpha.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.
- package/dist/src/admin-resolver.js +9 -11
- package/openclaw.plugin.json +1 -0
- package/package.json +5 -20
- package/scripts/postinstall-link-sdk.js +113 -0
- package/scripts/upgrade-via-npm.ps1 +41 -0
- package/scripts/upgrade-via-npm.sh +30 -0
- package/src/admin-resolver.ts +10 -11
- package/clawdbot.plugin.json +0 -16
- package/moltbot.plugin.json +0 -16
|
@@ -129,26 +129,24 @@ export function sendStartupGreetings(ctx, trigger) {
|
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
131
|
const upgradeTargetOpenId = loadUpgradeGreetingTargetOpenId(ctx.accountId, ctx.appId, ctx.log);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
// 没有 upgrade-greeting-target 文件 → 不是通过 /bot-upgrade 触发的升级
|
|
133
|
+
// (console 手动重启、脚本升级等场景),静默更新 marker 不发消息
|
|
134
|
+
if (!upgradeTargetOpenId) {
|
|
135
|
+
markStartupGreetingSent(ctx.accountId, ctx.appId, plan.version);
|
|
136
|
+
ctx.log?.info(`[qqbot:${ctx.accountId}] Version changed but no upgrade-greeting-target, silently updating marker (trigger=${trigger})`);
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
138
139
|
try {
|
|
139
|
-
|
|
140
|
-
ctx.log?.info(`[qqbot:${ctx.accountId}] Sending startup greeting to ${receiverType} (trigger=${trigger}): "${plan.greeting}"`);
|
|
140
|
+
ctx.log?.info(`[qqbot:${ctx.accountId}] Sending startup greeting to upgrade-requester (trigger=${trigger}): "${plan.greeting}"`);
|
|
141
141
|
const token = await getAccessToken(ctx.appId, ctx.clientSecret);
|
|
142
142
|
const GREETING_TIMEOUT_MS = 10_000;
|
|
143
143
|
await Promise.race([
|
|
144
|
-
sendProactiveC2CMessage(token,
|
|
144
|
+
sendProactiveC2CMessage(token, upgradeTargetOpenId, plan.greeting),
|
|
145
145
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Startup greeting send timeout (10s)")), GREETING_TIMEOUT_MS)),
|
|
146
146
|
]);
|
|
147
147
|
markStartupGreetingSent(ctx.accountId, ctx.appId, plan.version);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
ctx.log?.info(`[qqbot:${ctx.accountId}] Sent startup greeting to ${receiverType}: ${targetOpenId}`);
|
|
148
|
+
clearUpgradeGreetingTargetOpenId(ctx.accountId, ctx.appId);
|
|
149
|
+
ctx.log?.info(`[qqbot:${ctx.accountId}] Sent startup greeting to upgrade-requester: ${upgradeTargetOpenId}`);
|
|
152
150
|
}
|
|
153
151
|
catch (err) {
|
|
154
152
|
const message = err instanceof Error ? err.message : String(err);
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"name": "OpenClaw QQ Bot",
|
|
4
4
|
"description": "QQ Bot channel plugin with message support, cron jobs, and proactive messaging",
|
|
5
5
|
"channels": ["qqbot"],
|
|
6
|
+
"extensions": ["./dist/index.js"],
|
|
6
7
|
"skills": ["skills/qqbot-channel", "skills/qqbot-remind", "skills/qqbot-media"],
|
|
7
8
|
"capabilities": {
|
|
8
9
|
"proactiveMessaging": true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tencent-connect/openclaw-qqbot",
|
|
3
|
-
"version": "1.6.5-alpha.
|
|
3
|
+
"version": "1.6.5-alpha.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,32 +16,19 @@
|
|
|
16
16
|
"scripts",
|
|
17
17
|
"index.ts",
|
|
18
18
|
"tsconfig.json",
|
|
19
|
-
"openclaw.plugin.json"
|
|
20
|
-
"clawdbot.plugin.json",
|
|
21
|
-
"moltbot.plugin.json"
|
|
19
|
+
"openclaw.plugin.json"
|
|
22
20
|
],
|
|
23
|
-
"clawdbot": {
|
|
24
|
-
"id": "openclaw-qqbot",
|
|
25
|
-
"extensions": [
|
|
26
|
-
"./index.ts"
|
|
27
|
-
]
|
|
28
|
-
},
|
|
29
|
-
"moltbot": {
|
|
30
|
-
"id": "openclaw-qqbot",
|
|
31
|
-
"extensions": [
|
|
32
|
-
"./index.ts"
|
|
33
|
-
]
|
|
34
|
-
},
|
|
35
21
|
"openclaw": {
|
|
36
22
|
"id": "openclaw-qqbot",
|
|
37
23
|
"extensions": [
|
|
38
|
-
"./index.
|
|
24
|
+
"./dist/index.js"
|
|
39
25
|
]
|
|
40
26
|
},
|
|
41
27
|
"scripts": {
|
|
42
28
|
"build": "tsc || true",
|
|
43
29
|
"dev": "tsc --watch",
|
|
44
|
-
"prepack": "npm install --omit=dev"
|
|
30
|
+
"prepack": "npm install --omit=dev",
|
|
31
|
+
"postinstall": "node scripts/postinstall-link-sdk.js 2>/dev/null || true"
|
|
45
32
|
},
|
|
46
33
|
"dependencies": {
|
|
47
34
|
"mpg123-decoder": "^1.0.3",
|
|
@@ -59,8 +46,6 @@
|
|
|
59
46
|
"typescript": "^5.9.3"
|
|
60
47
|
},
|
|
61
48
|
"peerDependencies": {
|
|
62
|
-
"clawdbot": "*",
|
|
63
|
-
"moltbot": "*",
|
|
64
49
|
"openclaw": "*"
|
|
65
50
|
},
|
|
66
51
|
"homepage": "https://github.com/tencent-connect/openclaw-qqbot",
|
|
@@ -0,0 +1,113 @@
|
|
|
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, symlinkSync, 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
|
+
// Only run when installed under an openclaw-like extensions directory
|
|
22
|
+
// (supports openclaw, clawdbot, moltbot, etc.)
|
|
23
|
+
if (!pluginRoot.includes("extensions")) {
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const linkTarget = join(pluginRoot, "node_modules", "openclaw");
|
|
28
|
+
|
|
29
|
+
// Already linked or exists
|
|
30
|
+
if (existsSync(linkTarget)) {
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// CLI names to try (openclaw and its aliases)
|
|
35
|
+
const CLI_NAMES = ["openclaw", "clawdbot", "moltbot"];
|
|
36
|
+
|
|
37
|
+
// Find the global openclaw installation
|
|
38
|
+
let openclawRoot = null;
|
|
39
|
+
|
|
40
|
+
// Strategy 1: npm root -g → look for any known CLI package name
|
|
41
|
+
if (!openclawRoot) {
|
|
42
|
+
try {
|
|
43
|
+
const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
|
|
44
|
+
for (const name of CLI_NAMES) {
|
|
45
|
+
const candidate = join(globalRoot, name);
|
|
46
|
+
if (existsSync(join(candidate, "package.json"))) {
|
|
47
|
+
openclawRoot = candidate;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Strategy 2: resolve from the CLI binary (which openclaw / clawdbot / moltbot)
|
|
55
|
+
if (!openclawRoot) {
|
|
56
|
+
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
57
|
+
for (const name of CLI_NAMES) {
|
|
58
|
+
try {
|
|
59
|
+
const bin = execSync(`${whichCmd} ${name}`, { encoding: "utf-8" }).trim().split("\n")[0];
|
|
60
|
+
if (!bin) continue;
|
|
61
|
+
// Resolve symlinks to get actual binary location
|
|
62
|
+
const realBin = realpathSync(bin);
|
|
63
|
+
// bin is typically <prefix>/bin/<name> -> ../lib/node_modules/<name>/...
|
|
64
|
+
const candidate = resolve(dirname(realBin), "..", "lib", "node_modules", name);
|
|
65
|
+
if (existsSync(join(candidate, "package.json"))) {
|
|
66
|
+
openclawRoot = candidate;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
// Also try: binary might be inside the package itself (e.g. .../node_modules/<name>/bin/<name>)
|
|
70
|
+
const candidate2 = resolve(dirname(realBin), "..");
|
|
71
|
+
if (existsSync(join(candidate2, "package.json")) && existsSync(join(candidate2, "plugin-sdk"))) {
|
|
72
|
+
openclawRoot = candidate2;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
} catch {}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Strategy 3: walk up from the extensions directory to find the CLI's data root,
|
|
80
|
+
// then look for a global node_modules sibling
|
|
81
|
+
if (!openclawRoot) {
|
|
82
|
+
// pluginRoot is like /home/user/.openclaw/extensions/openclaw-qqbot
|
|
83
|
+
// The CLI data dir is /home/user/.openclaw (or .clawdbot, .moltbot)
|
|
84
|
+
const extensionsDir = dirname(pluginRoot);
|
|
85
|
+
const dataDir = dirname(extensionsDir);
|
|
86
|
+
const dataDirName = dataDir.split("/").pop() || dataDir.split("\\").pop() || "";
|
|
87
|
+
// dataDirName is like ".openclaw" → strip the dot to get "openclaw"
|
|
88
|
+
const cliName = dataDirName.replace(/^\./, "");
|
|
89
|
+
if (cliName) {
|
|
90
|
+
try {
|
|
91
|
+
const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
|
|
92
|
+
const candidate = join(globalRoot, cliName);
|
|
93
|
+
if (existsSync(join(candidate, "package.json"))) {
|
|
94
|
+
openclawRoot = candidate;
|
|
95
|
+
}
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!openclawRoot) {
|
|
101
|
+
// Not fatal — plugin may work if openclaw loads it with proper alias resolution
|
|
102
|
+
// But log a warning so upgrade scripts can detect the failure
|
|
103
|
+
console.error("[postinstall-link-sdk] WARNING: could not find openclaw/clawdbot/moltbot global installation, symlink not created");
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
mkdirSync(join(pluginRoot, "node_modules"), { recursive: true });
|
|
109
|
+
symlinkSync(openclawRoot, linkTarget, "junction");
|
|
110
|
+
console.log(`[postinstall-link-sdk] symlink created: node_modules/openclaw -> ${openclawRoot}`);
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.error(`[postinstall-link-sdk] WARNING: symlink creation failed: ${e.message}`);
|
|
113
|
+
}
|
|
@@ -315,6 +315,47 @@ foreach ($legacyName in @("qqbot", "openclaw-qq")) {
|
|
|
315
315
|
}
|
|
316
316
|
Write-Host " Installed to: $TARGET_DIR"
|
|
317
317
|
|
|
318
|
+
# Execute postinstall script to create openclaw SDK symlink
|
|
319
|
+
# (upgrade-via-npm is pure file operation, npm install is not run, so postinstall won't trigger automatically)
|
|
320
|
+
$PostinstallScript = Join-Path $TARGET_DIR "scripts" "postinstall-link-sdk.js"
|
|
321
|
+
if (Test-Path $PostinstallScript) {
|
|
322
|
+
Write-Host " Running postinstall: creating openclaw SDK symlink..."
|
|
323
|
+
try {
|
|
324
|
+
Push-Location $TARGET_DIR
|
|
325
|
+
$postOutput = & node $PostinstallScript 2>&1
|
|
326
|
+
Pop-Location
|
|
327
|
+
if ($postOutput) { Write-Host " $postOutput" }
|
|
328
|
+
} catch {
|
|
329
|
+
Write-Host " [WARN] postinstall script failed (non-fatal)" -ForegroundColor Yellow
|
|
330
|
+
try { Pop-Location } catch {}
|
|
331
|
+
}
|
|
332
|
+
# Verify symlink creation
|
|
333
|
+
$symlinkPath = Join-Path $TARGET_DIR "node_modules" "openclaw"
|
|
334
|
+
if (Test-Path $symlinkPath) {
|
|
335
|
+
Write-Host " [OK] openclaw SDK symlink ready"
|
|
336
|
+
} else {
|
|
337
|
+
Write-Host " [WARN] openclaw SDK symlink not created, attempting manual fallback..." -ForegroundColor Yellow
|
|
338
|
+
$cliDataDir = Split-Path $EXTENSIONS_DIR -Parent
|
|
339
|
+
$cliName = (Split-Path $cliDataDir -Leaf) -replace '^\.',''
|
|
340
|
+
try {
|
|
341
|
+
$globalRoot = (& npm root -g 2>$null).Trim()
|
|
342
|
+
$globalPkg = Join-Path $globalRoot $cliName
|
|
343
|
+
if ($globalRoot -and (Test-Path $globalPkg)) {
|
|
344
|
+
$nmDir = Join-Path $TARGET_DIR "node_modules"
|
|
345
|
+
if (-not (Test-Path $nmDir)) { New-Item -ItemType Directory -Path $nmDir -Force | Out-Null }
|
|
346
|
+
New-Item -ItemType Junction -Path $symlinkPath -Target $globalPkg -Force | Out-Null
|
|
347
|
+
Write-Host " [OK] Manual symlink created: -> $globalPkg"
|
|
348
|
+
} else {
|
|
349
|
+
Write-Host " [ERROR] Cannot locate global $cliName installation (npm root -g: $globalRoot)" -ForegroundColor Red
|
|
350
|
+
}
|
|
351
|
+
} catch {
|
|
352
|
+
Write-Host " [ERROR] Manual symlink creation also failed: $($_.Exception.Message)" -ForegroundColor Red
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
Write-Host " [WARN] postinstall script not found, skipping symlink creation" -ForegroundColor Yellow
|
|
357
|
+
}
|
|
358
|
+
|
|
318
359
|
# [4/5] Verify installation
|
|
319
360
|
Write-Host ""
|
|
320
361
|
Write-Host "[4/5] Verifying installation..."
|
|
@@ -297,6 +297,36 @@ for dir_name in qqbot openclaw-qq; do
|
|
|
297
297
|
done
|
|
298
298
|
echo " 已安装到: $TARGET_DIR"
|
|
299
299
|
|
|
300
|
+
# 执行 postinstall 脚本创建 openclaw SDK symlink
|
|
301
|
+
# (upgrade-via-npm 是纯文件操作,不走 npm install,所以 postinstall 不会自动触发)
|
|
302
|
+
POSTINSTALL_SCRIPT="$TARGET_DIR/scripts/postinstall-link-sdk.js"
|
|
303
|
+
if [ -f "$POSTINSTALL_SCRIPT" ]; then
|
|
304
|
+
echo " 执行 postinstall: 创建 openclaw SDK symlink..."
|
|
305
|
+
POSTINSTALL_OUTPUT="$(cd "$TARGET_DIR" && node "$POSTINSTALL_SCRIPT" 2>&1)" || true
|
|
306
|
+
[ -n "$POSTINSTALL_OUTPUT" ] && echo " $POSTINSTALL_OUTPUT"
|
|
307
|
+
# 验证 symlink 是否创建成功
|
|
308
|
+
if [ -d "$TARGET_DIR/node_modules/openclaw" ]; then
|
|
309
|
+
echo " ✅ openclaw SDK symlink 已就绪"
|
|
310
|
+
else
|
|
311
|
+
echo " ⚠️ openclaw SDK symlink 未创建,插件可能无法加载"
|
|
312
|
+
echo " 尝试手动创建 symlink..."
|
|
313
|
+
# 手动 fallback:尝试从 CLI 数据目录名推断全局包名
|
|
314
|
+
_CLI_DATA_DIR="$(dirname "$EXTENSIONS_DIR")"
|
|
315
|
+
_CLI_NAME="$(basename "$_CLI_DATA_DIR" | sed 's/^\.//')"
|
|
316
|
+
_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"
|
|
317
|
+
if [ -n "$_GLOBAL_ROOT" ] && [ -n "$_CLI_NAME" ] && [ -d "$_GLOBAL_ROOT/$_CLI_NAME" ]; then
|
|
318
|
+
mkdir -p "$TARGET_DIR/node_modules"
|
|
319
|
+
ln -sf "$_GLOBAL_ROOT/$_CLI_NAME" "$TARGET_DIR/node_modules/openclaw" 2>/dev/null && \
|
|
320
|
+
echo " ✅ 手动 symlink 创建成功: -> $_GLOBAL_ROOT/$_CLI_NAME" || \
|
|
321
|
+
echo " ❌ 手动 symlink 创建也失败了"
|
|
322
|
+
else
|
|
323
|
+
echo " ❌ 无法定位全局 $_CLI_NAME 安装路径(npm root -g: $_GLOBAL_ROOT)"
|
|
324
|
+
fi
|
|
325
|
+
fi
|
|
326
|
+
else
|
|
327
|
+
echo " ⚠️ 未找到 postinstall 脚本,跳过 symlink 创建"
|
|
328
|
+
fi
|
|
329
|
+
|
|
300
330
|
# [4/5] 输出新版本号和升级报告(供调用方解析)
|
|
301
331
|
echo ""
|
|
302
332
|
echo "[4/5] 验证安装..."
|
package/src/admin-resolver.ts
CHANGED
|
@@ -152,27 +152,26 @@ export function sendStartupGreetings(ctx: AdminResolverContext, trigger: "READY"
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
const upgradeTargetOpenId = loadUpgradeGreetingTargetOpenId(ctx.accountId, ctx.appId, ctx.log);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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})`);
|
|
159
161
|
return;
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
try {
|
|
163
|
-
|
|
164
|
-
ctx.log?.info(`[qqbot:${ctx.accountId}] Sending startup greeting to ${receiverType} (trigger=${trigger}): "${plan.greeting}"`);
|
|
165
|
+
ctx.log?.info(`[qqbot:${ctx.accountId}] Sending startup greeting to upgrade-requester (trigger=${trigger}): "${plan.greeting}"`);
|
|
165
166
|
const token = await getAccessToken(ctx.appId, ctx.clientSecret);
|
|
166
167
|
const GREETING_TIMEOUT_MS = 10_000;
|
|
167
168
|
await Promise.race([
|
|
168
|
-
sendProactiveC2CMessage(token,
|
|
169
|
+
sendProactiveC2CMessage(token, upgradeTargetOpenId, plan.greeting),
|
|
169
170
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Startup greeting send timeout (10s)")), GREETING_TIMEOUT_MS)),
|
|
170
171
|
]);
|
|
171
172
|
markStartupGreetingSent(ctx.accountId, ctx.appId, plan.version);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
ctx.log?.info(`[qqbot:${ctx.accountId}] Sent startup greeting to ${receiverType}: ${targetOpenId}`);
|
|
173
|
+
clearUpgradeGreetingTargetOpenId(ctx.accountId, ctx.appId);
|
|
174
|
+
ctx.log?.info(`[qqbot:${ctx.accountId}] Sent startup greeting to upgrade-requester: ${upgradeTargetOpenId}`);
|
|
176
175
|
} catch (err) {
|
|
177
176
|
const message = err instanceof Error ? err.message : String(err);
|
|
178
177
|
markStartupGreetingFailed(ctx.accountId, ctx.appId, plan.version, message);
|
package/clawdbot.plugin.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "openclaw-qqbot",
|
|
3
|
-
"name": "OpenClaw QQ Bot",
|
|
4
|
-
"description": "QQ Bot channel plugin with message support, cron jobs, and proactive messaging",
|
|
5
|
-
"channels": ["qqbot"],
|
|
6
|
-
"skills": ["skills/qqbot-channel", "skills/qqbot-remind", "skills/qqbot-media"],
|
|
7
|
-
"capabilities": {
|
|
8
|
-
"proactiveMessaging": true,
|
|
9
|
-
"cronJobs": true
|
|
10
|
-
},
|
|
11
|
-
"configSchema": {
|
|
12
|
-
"type": "object",
|
|
13
|
-
"additionalProperties": false,
|
|
14
|
-
"properties": {}
|
|
15
|
-
}
|
|
16
|
-
}
|
package/moltbot.plugin.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "openclaw-qqbot",
|
|
3
|
-
"name": "OpenClaw QQ Bot",
|
|
4
|
-
"description": "QQ Bot channel plugin with message support, cron jobs, and proactive messaging",
|
|
5
|
-
"channels": ["qqbot"],
|
|
6
|
-
"skills": ["skills/qqbot-channel", "skills/qqbot-remind", "skills/qqbot-media"],
|
|
7
|
-
"capabilities": {
|
|
8
|
-
"proactiveMessaging": true,
|
|
9
|
-
"cronJobs": true
|
|
10
|
-
},
|
|
11
|
-
"configSchema": {
|
|
12
|
-
"type": "object",
|
|
13
|
-
"additionalProperties": false,
|
|
14
|
-
"properties": {}
|
|
15
|
-
}
|
|
16
|
-
}
|