@jerryliang122/openclaw-qqbot 1.0.7 → 1.0.9
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/README.md +4 -4
- package/README.zh.md +4 -4
- package/dist/index.cjs +216 -169
- package/dist/index.cjs.map +1 -1
- package/package.json +3 -3
- package/src/adapter/pairing.ts +1 -1
- package/src/adapter/resolve.ts +2 -2
- package/src/adapter/setup.ts +1 -1
- package/src/dispatch/dispatch.ts +1 -1
- package/src/features/question-helpers.ts +1 -1
- package/src/openclaw-plugin-sdk.d.ts +39 -3
- package/src/tools/platform.ts +86 -72
- package/src/tools/remind.ts +53 -42
- package/src/tools/secret-input.ts +112 -80
- package/src/tools/tool-session.ts +74 -0
- package/src/utils/pkg-version.ts +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
[](./LICENSE)
|
|
14
14
|
[](https://bot.q.qq.com/wiki/)
|
|
15
|
-
[](https://github.com/jerryliang122/qqbot-openclaw)
|
|
16
16
|
[](https://nodejs.org/)
|
|
17
17
|
[](https://www.typescriptlang.org/)
|
|
18
18
|
[](https://github.com/jerryliang122/qqbot-openclaw)
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
> This is an **independently maintained fork** with its own versioning (v1.x, decoupled from the upstream 2.x line). Upstream: [tencent-connect/openclaw-qqbot](https://github.com/tencent-connect/openclaw-qqbot).
|
|
25
25
|
>
|
|
26
|
-
> **Requirements**: OpenClaw `>= 2026.9.
|
|
26
|
+
> **Requirements**: OpenClaw `>= 2026.9.1` · Published to npm as [`@jerryliang122/openclaw-qqbot`](https://www.npmjs.com/package/@jerryliang122/openclaw-qqbot). See [CHANGELOG](CHANGELOG.md) for differences vs the old version and the upgrade guide.
|
|
27
27
|
|
|
28
28
|
Scan to join the QQ group chat
|
|
29
29
|
|
|
@@ -179,7 +179,7 @@ Measures end-to-end latency from QQ server push to plugin response, broken down
|
|
|
179
179
|
|
|
180
180
|
> **You**: `/bot-version`
|
|
181
181
|
>
|
|
182
|
-
> **QQBot**: 🦞 Framework: OpenClaw 2026.9.
|
|
182
|
+
> **QQBot**: 🦞 Framework: OpenClaw 2026.9.1 / 🤖 Plugin: v1.0.0 / 🌟 GitHub repo
|
|
183
183
|
|
|
184
184
|
Shows framework version, plugin version, and a direct link to the official repository.
|
|
185
185
|
|
|
@@ -282,7 +282,7 @@ Answers "why does this group have no context" diagnostics: the push mode is chos
|
|
|
282
282
|
|
|
283
283
|
### Step 2 — Install / Upgrade the Plugin
|
|
284
284
|
|
|
285
|
-
> **Note**: The unscoped npm name `openclaw-qqbot` belongs to the original upstream project — this fork publishes as the scoped package `@jerryliang122/openclaw-qqbot`. Requires OpenClaw >= 2026.9.
|
|
285
|
+
> **Note**: The unscoped npm name `openclaw-qqbot` belongs to the original upstream project — this fork publishes as the scoped package `@jerryliang122/openclaw-qqbot`. Requires OpenClaw >= 2026.9.1.
|
|
286
286
|
|
|
287
287
|
**Option A: Install from npm (Recommended)**
|
|
288
288
|
|
package/README.zh.md
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
**让你的 AI 助手接入 QQ — 私聊、群聊、富媒体,一个插件全搞定。**
|
|
11
11
|
|
|
12
12
|
> 本仓库为**独立维护的 fork**,自 v1.0.0 起独立发版(与上游 2.x 版本线完全脱钩)。
|
|
13
|
-
> 运行要求:OpenClaw `>= 2026.9.
|
|
13
|
+
> 运行要求:OpenClaw `>= 2026.9.1`;npm 包名 [`@jerryliang122/openclaw-qqbot`](https://www.npmjs.com/package/@jerryliang122/openclaw-qqbot)。
|
|
14
14
|
> 与旧版本的差异及升级指南见 [CHANGELOG](CHANGELOG.md)。上游仓库:[tencent-connect/openclaw-qqbot](https://github.com/tencent-connect/openclaw-qqbot)。
|
|
15
15
|
|
|
16
16
|
### 🚀 当前版本: `v1.0.0`
|
|
17
17
|
|
|
18
18
|
[](./LICENSE)
|
|
19
19
|
[](https://bot.q.qq.com/wiki/)
|
|
20
|
-
[](https://github.com/jerryliang122/qqbot-openclaw)
|
|
21
21
|
[](https://nodejs.org/)
|
|
22
22
|
[](https://www.typescriptlang.org/)
|
|
23
23
|
|
|
@@ -177,7 +177,7 @@ AI 可直接发送视频,支持本地文件和公网 URL。
|
|
|
177
177
|
|
|
178
178
|
> **你**:`/bot-version`
|
|
179
179
|
>
|
|
180
|
-
> **QQBot**:🦞框架版本:OpenClaw 2026.9.
|
|
180
|
+
> **QQBot**:🦞框架版本:OpenClaw 2026.9.1 / 🤖QQBot 插件版本:v1.0.0 / 🌟GitHub 仓库
|
|
181
181
|
|
|
182
182
|
一目了然查看框架版本、插件版本,并可直接跳转官方仓库。
|
|
183
183
|
|
|
@@ -282,7 +282,7 @@ AI 可直接发送视频,支持本地文件和公网 URL。
|
|
|
282
282
|
|
|
283
283
|
### 第二步 — 安装 / 升级插件
|
|
284
284
|
|
|
285
|
-
> 无 scope 的 npm 包名 `openclaw-qqbot` 属于上游原项目——本 fork 以 `@jerryliang122/openclaw-qqbot` 发布。要求 OpenClaw >= 2026.9.
|
|
285
|
+
> 无 scope 的 npm 包名 `openclaw-qqbot` 属于上游原项目——本 fork 以 `@jerryliang122/openclaw-qqbot` 发布。要求 OpenClaw >= 2026.9.1。
|
|
286
286
|
|
|
287
287
|
**方式 A:从 npm 安装(推荐)**
|
|
288
288
|
|
package/dist/index.cjs
CHANGED
|
@@ -8259,7 +8259,7 @@ var init_outbound_service = __esm({
|
|
|
8259
8259
|
|
|
8260
8260
|
// src/utils/pkg-version.ts
|
|
8261
8261
|
function getPackageVersion() {
|
|
8262
|
-
return true ? "1.0.
|
|
8262
|
+
return true ? "1.0.9" : "unknown";
|
|
8263
8263
|
}
|
|
8264
8264
|
function getOpenclawVersion(runtimeVersion) {
|
|
8265
8265
|
return runtimeVersion && runtimeVersion !== "unknown" ? runtimeVersion : "unknown";
|
|
@@ -10454,7 +10454,7 @@ function getAdapters(rt, log5) {
|
|
|
10454
10454
|
async function persistAuthConfig(runtime2, cfg, afterWrite = "restart") {
|
|
10455
10455
|
const config = runtime2.config;
|
|
10456
10456
|
if (typeof config?.mutateConfigFile !== "function") {
|
|
10457
|
-
throw new Error("persistAuthConfig: runtime.config.mutateConfigFile is unavailable (requires openclaw >= 2026.9.
|
|
10457
|
+
throw new Error("persistAuthConfig: runtime.config.mutateConfigFile is unavailable (requires openclaw >= 2026.9.1)");
|
|
10458
10458
|
}
|
|
10459
10459
|
await config.mutateConfigFile({
|
|
10460
10460
|
mutate: () => cfg,
|
|
@@ -15131,7 +15131,7 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log5) {
|
|
|
15131
15131
|
const envelope = buildEnvelope2(ctx, msg, account);
|
|
15132
15132
|
dlog?.debug(`received sender=${envelope.senderId} scope=${envelope.chatScope} msgId=${envelope.messageId}`);
|
|
15133
15133
|
if (!adapters.inboundRun || !adapters.dispatchReply) {
|
|
15134
|
-
dlog?.error(`runtime adapter inboundRun/dispatchReply not available (openclaw=${adapters.version}, requires >=2026.9.
|
|
15134
|
+
dlog?.error(`runtime adapter inboundRun/dispatchReply not available (openclaw=${adapters.version}, requires >=2026.9.1)`);
|
|
15135
15135
|
return;
|
|
15136
15136
|
}
|
|
15137
15137
|
const assembled = ctx.state.assembledBody ?? assembleBody(ctx, msg, account);
|
|
@@ -17478,9 +17478,33 @@ init_runtime();
|
|
|
17478
17478
|
|
|
17479
17479
|
// src/tools/platform.ts
|
|
17480
17480
|
init_config();
|
|
17481
|
-
|
|
17482
|
-
init_request_context();
|
|
17481
|
+
init_outbound_service();
|
|
17483
17482
|
init_plugin_logger();
|
|
17483
|
+
|
|
17484
|
+
// src/tools/tool-session.ts
|
|
17485
|
+
init_request_context();
|
|
17486
|
+
function resolveToolSessionRoute(delivery) {
|
|
17487
|
+
const alsTarget = getRequestTarget();
|
|
17488
|
+
if (alsTarget) {
|
|
17489
|
+
return {
|
|
17490
|
+
target: alsTarget,
|
|
17491
|
+
accountId: getRequestAccountId(),
|
|
17492
|
+
source: "request-context"
|
|
17493
|
+
};
|
|
17494
|
+
}
|
|
17495
|
+
const to = typeof delivery?.to === "string" ? delivery.to.trim() : "";
|
|
17496
|
+
if (!to) return void 0;
|
|
17497
|
+
const channel = typeof delivery?.channel === "string" ? delivery.channel.trim() : "";
|
|
17498
|
+
if (channel && channel !== "qqbot") return void 0;
|
|
17499
|
+
if (!/^qqbot:(c2c|group|channel):/i.test(to)) return void 0;
|
|
17500
|
+
return {
|
|
17501
|
+
target: to,
|
|
17502
|
+
accountId: delivery?.accountId,
|
|
17503
|
+
source: "delivery-context"
|
|
17504
|
+
};
|
|
17505
|
+
}
|
|
17506
|
+
|
|
17507
|
+
// src/tools/platform.ts
|
|
17484
17508
|
var toolLog = createPluginLogger({ prefix: "[tool:platform]" });
|
|
17485
17509
|
var PlatformApiSchema = {
|
|
17486
17510
|
type: "object",
|
|
@@ -17526,68 +17550,76 @@ function registerPlatformTool(api) {
|
|
|
17526
17550
|
const accountIds = listQQBotAccountIds(cfg);
|
|
17527
17551
|
if (accountIds.length === 0) return;
|
|
17528
17552
|
api.registerTool(
|
|
17529
|
-
{
|
|
17530
|
-
|
|
17531
|
-
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
|
|
17538
|
-
|
|
17539
|
-
|
|
17540
|
-
|
|
17541
|
-
|
|
17542
|
-
|
|
17543
|
-
|
|
17544
|
-
|
|
17545
|
-
|
|
17546
|
-
|
|
17547
|
-
|
|
17548
|
-
|
|
17549
|
-
|
|
17550
|
-
|
|
17551
|
-
|
|
17552
|
-
|
|
17553
|
-
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17553
|
+
(factoryCtx) => {
|
|
17554
|
+
const delivery = factoryCtx.deliveryContext;
|
|
17555
|
+
return {
|
|
17556
|
+
name: "qqbot_platform_api",
|
|
17557
|
+
label: "QQBot Platform API Gateway",
|
|
17558
|
+
description: "QQ \u5F00\u653E\u5E73\u53F0\u7EDF\u4E00 HTTP API \u7F51\u5173\uFF0C\u81EA\u52A8\u586B\u5145\u9274\u6743 Token\u3002\u5E38\u7528\u63A5\u53E3\u901F\u67E5\uFF1A\u3010\u9891\u9053\u3011GET /users/@me/guilds | /guilds/{guild_id}/channels | /channels/{channel_id} | \u3010\u7FA4\u3011GET /v2/groups/{group_id}/bot_state | /v2/groups/{group_id}/members/{member_id} | /v2/groups/{group_id}/info\u3002\u66F4\u591A\u63A5\u53E3\u548C\u53C2\u6570\u8BE6\u60C5\u8BF7\u9605\u8BFB qqbot-channel \u548C qqbot-group skill\u3002",
|
|
17559
|
+
parameters: PlatformApiSchema,
|
|
17560
|
+
async execute(_toolCallId, params) {
|
|
17561
|
+
const p2 = params;
|
|
17562
|
+
if (!p2.method) return json({ error: "method \u4E3A\u5FC5\u586B\u53C2\u6570" });
|
|
17563
|
+
if (!p2.path) return json({ error: "path \u4E3A\u5FC5\u586B\u53C2\u6570" });
|
|
17564
|
+
const method = p2.method.toUpperCase();
|
|
17565
|
+
if (!["GET", "POST", "PUT", "PATCH", "DELETE"].includes(method)) {
|
|
17566
|
+
return json({ error: `\u4E0D\u652F\u6301\u7684 HTTP \u65B9\u6CD5: ${method}` });
|
|
17567
|
+
}
|
|
17568
|
+
const pathError = validatePath(p2.path);
|
|
17569
|
+
if (pathError) return json({ error: pathError });
|
|
17570
|
+
const route = resolveToolSessionRoute(delivery);
|
|
17571
|
+
if (!route) {
|
|
17572
|
+
return json({
|
|
17573
|
+
error: "\u5F53\u524D\u8FD0\u884C\u6CA1\u6709 QQ \u4F1A\u8BDD\u6765\u6E90\uFF08\u53EF\u80FD\u7531\u5B9A\u65F6\u4EFB\u52A1\u6216\u6846\u67B6\u5185\u90E8\u89E6\u53D1\u7684 run\uFF09\uFF0C\u65E0\u6CD5\u786E\u5B9A\u8C03\u7528\u54EA\u4E2A QQ Bot \u8D26\u6237\u3002\u8BF7\u5728 QQ \u6D88\u606F\u4F1A\u8BDD\u4E2D\u4F7F\u7528\u672C\u5DE5\u5177\u3002"
|
|
17574
|
+
});
|
|
17575
|
+
}
|
|
17576
|
+
try {
|
|
17577
|
+
const resolvedGateway = resolveGatewayForSend(route.accountId ?? "default");
|
|
17578
|
+
if (!resolvedGateway) {
|
|
17579
|
+
return json({ error: `\u8D26\u6237 ${route.accountId ?? "default"} \u7684 gateway \u5C1A\u672A\u542F\u52A8` });
|
|
17580
|
+
}
|
|
17581
|
+
const bot = resolvedGateway.gw.bot;
|
|
17582
|
+
const apiGateway = bot.api;
|
|
17583
|
+
const startedAt = Date.now();
|
|
17584
|
+
let data;
|
|
17585
|
+
switch (method) {
|
|
17586
|
+
case "GET":
|
|
17587
|
+
data = await apiGateway.get(p2.path, p2.query);
|
|
17588
|
+
break;
|
|
17589
|
+
case "POST":
|
|
17590
|
+
data = await apiGateway.post(p2.path, p2.body);
|
|
17591
|
+
break;
|
|
17592
|
+
case "PUT":
|
|
17593
|
+
data = await apiGateway.put(p2.path, p2.body);
|
|
17594
|
+
break;
|
|
17595
|
+
case "PATCH":
|
|
17596
|
+
data = await apiGateway.patch(p2.path, p2.body);
|
|
17597
|
+
break;
|
|
17598
|
+
case "DELETE":
|
|
17599
|
+
data = await apiGateway.delete(p2.path);
|
|
17600
|
+
break;
|
|
17601
|
+
}
|
|
17602
|
+
toolLog.info(`${method} ${p2.path} ok (${Date.now() - startedAt}ms)`, { accountId: resolvedGateway.accountId });
|
|
17603
|
+
return json(data);
|
|
17604
|
+
} catch (err) {
|
|
17605
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
17606
|
+
const apiErr = err;
|
|
17607
|
+
toolLog.warn(`${method} ${p2.path} failed status=${apiErr.httpStatus ?? "?"} code=${apiErr.bizCode ?? "?"}: ${errMsg}`, { accountId: route.accountId ?? "default" });
|
|
17608
|
+
return json({
|
|
17609
|
+
error: errMsg,
|
|
17610
|
+
status: apiErr.httpStatus,
|
|
17611
|
+
code: apiErr.bizCode,
|
|
17612
|
+
path: p2.path
|
|
17613
|
+
});
|
|
17569
17614
|
}
|
|
17570
|
-
toolLog.info(`${method} ${p2.path} ok (${Date.now() - startedAt}ms)`, { accountId });
|
|
17571
|
-
return json(data);
|
|
17572
|
-
} catch (err) {
|
|
17573
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
17574
|
-
const apiErr = err;
|
|
17575
|
-
toolLog.warn(`${method} ${p2.path} failed status=${apiErr.httpStatus ?? "?"} code=${apiErr.bizCode ?? "?"}: ${errMsg}`, { accountId });
|
|
17576
|
-
return json({
|
|
17577
|
-
error: errMsg,
|
|
17578
|
-
status: apiErr.httpStatus,
|
|
17579
|
-
code: apiErr.bizCode,
|
|
17580
|
-
path: p2.path
|
|
17581
|
-
});
|
|
17582
17615
|
}
|
|
17583
|
-
}
|
|
17616
|
+
};
|
|
17584
17617
|
},
|
|
17585
17618
|
{ name: "qqbot_platform_api" }
|
|
17586
17619
|
);
|
|
17587
17620
|
}
|
|
17588
17621
|
|
|
17589
17622
|
// src/tools/remind.ts
|
|
17590
|
-
init_request_context();
|
|
17591
17623
|
var RemindSchema = {
|
|
17592
17624
|
type: "object",
|
|
17593
17625
|
properties: {
|
|
@@ -17732,71 +17764,76 @@ function formatDelay(ms) {
|
|
|
17732
17764
|
}
|
|
17733
17765
|
function registerRemindTool(api) {
|
|
17734
17766
|
api.registerTool(
|
|
17735
|
-
{
|
|
17736
|
-
|
|
17737
|
-
|
|
17738
|
-
|
|
17739
|
-
|
|
17740
|
-
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17748
|
-
|
|
17749
|
-
if (!p2.jobId) {
|
|
17750
|
-
return json2({ error: "action=remove \u65F6 jobId \u4E3A\u5FC5\u586B\u53C2\u6570\u3002\u8BF7\u5148\u7528 action=list \u83B7\u53D6 jobId\u3002" });
|
|
17767
|
+
(factoryCtx) => {
|
|
17768
|
+
const delivery = factoryCtx.deliveryContext;
|
|
17769
|
+
return {
|
|
17770
|
+
name: "qqbot_remind",
|
|
17771
|
+
label: "QQBot \u5B9A\u65F6\u63D0\u9192",
|
|
17772
|
+
description: '\u521B\u5EFA\u3001\u67E5\u8BE2\u3001\u5220\u9664 QQ \u5B9A\u65F6\u63D0\u9192\u3002\u4F7F\u7528\u7B80\u5355\u53C2\u6570\u5373\u53EF\uFF0C\u65E0\u9700\u624B\u52A8\u6784\u9020 cron JSON\u3002\n\u521B\u5EFA\u63D0\u9192\uFF1Aaction=add, content=\u63D0\u9192\u5185\u5BB9, to=\u76EE\u6807\u5730\u5740, time=\u65F6\u95F4\n\u67E5\u770B\u63D0\u9192\uFF1Aaction=list\n\u5220\u9664\u63D0\u9192\uFF1Aaction=remove, jobId=\u4EFB\u52A1ID\uFF08\u5148 list \u83B7\u53D6\uFF09\n\u65F6\u95F4\u683C\u5F0F\u793A\u4F8B\uFF1A"5m"(5\u5206\u949F\u540E) "1h"(1\u5C0F\u65F6\u540E) "0 8 * * *"(\u6BCF\u59298\u70B9)',
|
|
17773
|
+
parameters: RemindSchema,
|
|
17774
|
+
async execute(_toolCallId, params) {
|
|
17775
|
+
const p2 = params;
|
|
17776
|
+
if (p2.action === "list") {
|
|
17777
|
+
return json2({
|
|
17778
|
+
_instruction: "\u8BF7\u7ACB\u5373\u4F7F\u7528 cron \u5DE5\u5177\u6267\u884C\u4EE5\u4E0B\u53C2\u6570",
|
|
17779
|
+
cronParams: { action: "list" }
|
|
17780
|
+
});
|
|
17751
17781
|
}
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
|
|
17757
|
-
|
|
17758
|
-
|
|
17759
|
-
|
|
17760
|
-
|
|
17761
|
-
|
|
17762
|
-
|
|
17763
|
-
|
|
17764
|
-
|
|
17765
|
-
|
|
17766
|
-
|
|
17767
|
-
|
|
17768
|
-
|
|
17769
|
-
|
|
17782
|
+
if (p2.action === "remove") {
|
|
17783
|
+
if (!p2.jobId) {
|
|
17784
|
+
return json2({ error: "action=remove \u65F6 jobId \u4E3A\u5FC5\u586B\u53C2\u6570\u3002\u8BF7\u5148\u7528 action=list \u83B7\u53D6 jobId\u3002" });
|
|
17785
|
+
}
|
|
17786
|
+
return json2({
|
|
17787
|
+
_instruction: "\u8BF7\u7ACB\u5373\u4F7F\u7528 cron \u5DE5\u5177\u6267\u884C\u4EE5\u4E0B\u53C2\u6570",
|
|
17788
|
+
cronParams: { action: "remove", jobId: p2.jobId }
|
|
17789
|
+
});
|
|
17790
|
+
}
|
|
17791
|
+
if (!p2.content) {
|
|
17792
|
+
return json2({ error: "action=add \u65F6 content\uFF08\u63D0\u9192\u5185\u5BB9\uFF09\u4E3A\u5FC5\u586B\u53C2\u6570" });
|
|
17793
|
+
}
|
|
17794
|
+
const route = resolveToolSessionRoute(delivery);
|
|
17795
|
+
const resolvedTo = p2.to || route?.target;
|
|
17796
|
+
if (!resolvedTo) {
|
|
17797
|
+
return json2({
|
|
17798
|
+
error: "action=add \u65F6\u65E0\u6CD5\u786E\u5B9A\u6295\u9012\u76EE\u6807\u5730\u5740\uFF08\u5F53\u524D run \u65E0 QQ \u4F1A\u8BDD\u6765\u6E90\uFF09\u3002\u8BF7\u663E\u5F0F\u4F20\u5165 to\uFF08\u683C\u5F0F\uFF1Aqqbot:c2c:user_openid \u6216 qqbot:group:group_openid\uFF09\u540E\u91CD\u8BD5\u3002"
|
|
17799
|
+
});
|
|
17800
|
+
}
|
|
17801
|
+
const resolvedAccountId = route?.accountId || "default";
|
|
17802
|
+
if (!p2.time) {
|
|
17803
|
+
return json2({ error: 'action=add \u65F6 time\uFF08\u65F6\u95F4\uFF09\u4E3A\u5FC5\u586B\u53C2\u6570\u3002\u793A\u4F8B\uFF1A"5m"\u3001"1h30m"\u3001"0 8 * * *"' });
|
|
17804
|
+
}
|
|
17805
|
+
if (isCronExpression(p2.time)) {
|
|
17806
|
+
const cronJob = buildCronJob(p2, resolvedTo, resolvedAccountId);
|
|
17807
|
+
return json2({
|
|
17808
|
+
_instruction: "\u8BF7\u7ACB\u5373\u4F7F\u7528 cron \u5DE5\u5177\uFF0C\u5C06 cronParams \u7684\u503C\u539F\u6837\u4F5C\u4E3A\u53C2\u6570\u4F20\u5165\uFF08\u4E0D\u8981\u4FEE\u6539\u6216\u7701\u7565\u4EFB\u4F55\u5B57\u6BB5\uFF0C\u7279\u522B\u662F delivery.accountId\uFF09\uFF0C\u7136\u540E\u56DE\u590D\u7528\u6237\u63D0\u9192\u5DF2\u8BBE\u7F6E",
|
|
17809
|
+
cronParams: cronJob,
|
|
17810
|
+
summary: `\u23F0 \u5468\u671F\u63D0\u9192: "${p2.content}" (${p2.time}, tz=${p2.timezone || "Asia/Shanghai"})`
|
|
17811
|
+
});
|
|
17812
|
+
}
|
|
17813
|
+
const delayMs = parseRelativeTime(p2.time);
|
|
17814
|
+
if (!delayMs || delayMs <= 0) {
|
|
17815
|
+
return json2({
|
|
17816
|
+
error: `\u65E0\u6CD5\u89E3\u6790\u65F6\u95F4 "${p2.time}"\u3002\u652F\u6301\u683C\u5F0F\uFF1A\u76F8\u5BF9\u65F6\u95F4\u5982 "5m"\u3001"1h"\u3001"1h30m"\u3001"2d"\uFF1Bcron \u8868\u8FBE\u5F0F\u5982 "0 8 * * *"\uFF08\u6BCF\u59298\u70B9\uFF09`
|
|
17817
|
+
});
|
|
17818
|
+
}
|
|
17819
|
+
if (delayMs < 3e4) {
|
|
17820
|
+
return json2({ error: "\u63D0\u9192\u65F6\u95F4\u4E0D\u80FD\u5C11\u4E8E 30 \u79D2" });
|
|
17821
|
+
}
|
|
17822
|
+
const onceJob = buildOnceJob(p2, delayMs, resolvedTo, resolvedAccountId);
|
|
17770
17823
|
return json2({
|
|
17771
17824
|
_instruction: "\u8BF7\u7ACB\u5373\u4F7F\u7528 cron \u5DE5\u5177\uFF0C\u5C06 cronParams \u7684\u503C\u539F\u6837\u4F5C\u4E3A\u53C2\u6570\u4F20\u5165\uFF08\u4E0D\u8981\u4FEE\u6539\u6216\u7701\u7565\u4EFB\u4F55\u5B57\u6BB5\uFF0C\u7279\u522B\u662F delivery.accountId\uFF09\uFF0C\u7136\u540E\u56DE\u590D\u7528\u6237\u63D0\u9192\u5DF2\u8BBE\u7F6E",
|
|
17772
|
-
cronParams:
|
|
17773
|
-
summary: `\u23F0 \
|
|
17825
|
+
cronParams: onceJob,
|
|
17826
|
+
summary: `\u23F0 ${formatDelay(delayMs)}\u540E\u63D0\u9192: "${p2.content}"`
|
|
17774
17827
|
});
|
|
17775
17828
|
}
|
|
17776
|
-
|
|
17777
|
-
if (!delayMs || delayMs <= 0) {
|
|
17778
|
-
return json2({
|
|
17779
|
-
error: `\u65E0\u6CD5\u89E3\u6790\u65F6\u95F4 "${p2.time}"\u3002\u652F\u6301\u683C\u5F0F\uFF1A\u76F8\u5BF9\u65F6\u95F4\u5982 "5m"\u3001"1h"\u3001"1h30m"\u3001"2d"\uFF1Bcron \u8868\u8FBE\u5F0F\u5982 "0 8 * * *"\uFF08\u6BCF\u59298\u70B9\uFF09`
|
|
17780
|
-
});
|
|
17781
|
-
}
|
|
17782
|
-
if (delayMs < 3e4) {
|
|
17783
|
-
return json2({ error: "\u63D0\u9192\u65F6\u95F4\u4E0D\u80FD\u5C11\u4E8E 30 \u79D2" });
|
|
17784
|
-
}
|
|
17785
|
-
const onceJob = buildOnceJob(p2, delayMs, resolvedTo, resolvedAccountId);
|
|
17786
|
-
return json2({
|
|
17787
|
-
_instruction: "\u8BF7\u7ACB\u5373\u4F7F\u7528 cron \u5DE5\u5177\uFF0C\u5C06 cronParams \u7684\u503C\u539F\u6837\u4F5C\u4E3A\u53C2\u6570\u4F20\u5165\uFF08\u4E0D\u8981\u4FEE\u6539\u6216\u7701\u7565\u4EFB\u4F55\u5B57\u6BB5\uFF0C\u7279\u522B\u662F delivery.accountId\uFF09\uFF0C\u7136\u540E\u56DE\u590D\u7528\u6237\u63D0\u9192\u5DF2\u8BBE\u7F6E",
|
|
17788
|
-
cronParams: onceJob,
|
|
17789
|
-
summary: `\u23F0 ${formatDelay(delayMs)}\u540E\u63D0\u9192: "${p2.content}"`
|
|
17790
|
-
});
|
|
17791
|
-
}
|
|
17829
|
+
};
|
|
17792
17830
|
},
|
|
17793
17831
|
{ name: "qqbot_remind" }
|
|
17794
17832
|
);
|
|
17795
17833
|
}
|
|
17796
17834
|
|
|
17797
17835
|
// src/tools/secret-input.ts
|
|
17798
|
-
|
|
17799
|
-
init_request_context();
|
|
17836
|
+
init_outbound_service();
|
|
17800
17837
|
init_target();
|
|
17801
17838
|
init_plugin_logger();
|
|
17802
17839
|
var toolLog2 = createPluginLogger({ prefix: "[tool:secret-input]" });
|
|
@@ -17856,67 +17893,77 @@ function json3(data) {
|
|
|
17856
17893
|
}
|
|
17857
17894
|
function registerSecretInputTool(api) {
|
|
17858
17895
|
api.registerTool(
|
|
17859
|
-
{
|
|
17860
|
-
|
|
17861
|
-
|
|
17862
|
-
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
|
|
17868
|
-
|
|
17869
|
-
return json3({
|
|
17870
|
-
|
|
17871
|
-
|
|
17872
|
-
|
|
17873
|
-
|
|
17874
|
-
|
|
17875
|
-
|
|
17876
|
-
|
|
17877
|
-
|
|
17878
|
-
|
|
17879
|
-
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17896
|
+
(factoryCtx) => {
|
|
17897
|
+
const delivery = factoryCtx.deliveryContext;
|
|
17898
|
+
return {
|
|
17899
|
+
name: "qqbot_secret_input",
|
|
17900
|
+
label: "QQBot Secret Input Card",
|
|
17901
|
+
description: "\u5F53\u7528\u6237\u8981\u4EA4\u4ED8\u4E00\u4E2A\u65B0\u5BC6\u94A5/\u51ED\u636E\uFF08API Key\u3001Token \u7B49\uFF09\u7ED9\u7CFB\u7EDF\u4FDD\u5B58\u65F6\u8C03\u7528\uFF1A\u5411\u7528\u6237\u79C1\u804A\u53D1\u9001\u4E00\u5F20\u5BC6\u94A5\u8F93\u5165\u5361\u7247\uFF0C\u7528\u6237\u628A\u5BC6\u94A5\u7C98\u8D34\u5728\u8F93\u5165\u6846\u53D1\u9001\u540E\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u62E6\u622A\u8BE5\u6D88\u606F\u5E76\u6267\u884C openclaw secrets store set \u5B8C\u6210\u4FDD\u5B58\uFF0C\u7ED3\u679C\u7531\u63D2\u4EF6\u76F4\u63A5\u56DE\u590D\u7528\u6237\u3002\u5BC6\u94A5\u5185\u5BB9\u4E0D\u4F1A\u8FDB\u5165\u5BF9\u8BDD\u3002\u5FC5\u987B\u7531\u7528\u6237\u63D0\u4F9B name \u53C2\u6570\uFF08\u73AF\u5883\u53D8\u91CF\u540D\uFF09\u3002",
|
|
17902
|
+
parameters: SecretInputSchema,
|
|
17903
|
+
async execute(_toolCallId, params) {
|
|
17904
|
+
const p2 = params;
|
|
17905
|
+
const name = (p2.name ?? "").trim();
|
|
17906
|
+
if (!name) return json3({ error: "name \u4E3A\u5FC5\u586B\u53C2\u6570\uFF08\u73AF\u5883\u53D8\u91CF\u540D\uFF09" });
|
|
17907
|
+
if (!isValidSecretName(name)) {
|
|
17908
|
+
return json3({
|
|
17909
|
+
error: `\u73AF\u5883\u53D8\u91CF\u540D\u4E0D\u5408\u6CD5\uFF1A\u5FC5\u987B\u4EE5\u5927\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u4EC5\u542B\u5927\u5199\u5B57\u6BCD/\u6570\u5B57/\u4E0B\u5212\u7EBF\uFF0C\u6700\u957F 128 \u5B57\u7B26\uFF08\u6536\u5230 "${name}"\uFF09\u3002\u793A\u4F8B\uFF1AOPENWEATHER_API_KEY\u3002\u8BF7\u4FEE\u6B63\u540E\u91CD\u8BD5\u3002`
|
|
17910
|
+
});
|
|
17911
|
+
}
|
|
17912
|
+
const kind = "env";
|
|
17913
|
+
const route = resolveToolSessionRoute(delivery);
|
|
17914
|
+
if (!route) {
|
|
17915
|
+
return json3({
|
|
17916
|
+
error: "\u5F53\u524D\u8FD0\u884C\u6CA1\u6709 QQ \u4F1A\u8BDD\u6765\u6E90\uFF08\u53EF\u80FD\u7531\u5B9A\u65F6\u4EFB\u52A1\u6216\u6846\u67B6\u5185\u90E8\u89E6\u53D1\u7684 run\uFF09\uFF0C\u65E0\u6CD5\u5B9A\u4F4D\u8981\u53D1\u5361\u7684\u7528\u6237\u3002\u8BF7\u5F15\u5BFC\u7528\u6237\u5728 QQ \u79C1\u804A\u4E2D\u76F4\u63A5\u53D1\u8D77\u5BC6\u94A5\u8F93\u5165\uFF0C\u4E0D\u8981\u5728\u65E0\u4F1A\u8BDD\u4E0A\u4E0B\u6587\u7684\u4EFB\u52A1\u91CC\u8C03\u7528\u672C\u5DE5\u5177\u3002"
|
|
17917
|
+
});
|
|
17918
|
+
}
|
|
17919
|
+
const scope = QQBOT_PREFIX_RE.exec(route.target)?.[1]?.toLowerCase();
|
|
17920
|
+
const parsed = parseTarget(route.target);
|
|
17921
|
+
if (scope !== "c2c" || !parsed.targetId) {
|
|
17922
|
+
return json3({
|
|
17923
|
+
error: `\u5BC6\u94A5\u8F93\u5165\u5361\u7247\u4EC5\u652F\u6301\u79C1\u804A\uFF08c2c\uFF09\u4F1A\u8BDD\uFF0C\u5F53\u524D\u76EE\u6807 ${route.target} \u4E0D\u9002\u7528\u2014\u2014\u5BC6\u94A5\u4E0D\u5E94\u51FA\u73B0\u5728\u7FA4\u804A\u6216\u9891\u9053\u4E2D\u3002\u8BF7\u5F15\u5BFC\u7528\u6237\u5728\u79C1\u804A\u4E2D\u53D1\u8D77\u3002`
|
|
17924
|
+
});
|
|
17925
|
+
}
|
|
17926
|
+
const requestedAccountId = route.accountId ?? "default";
|
|
17927
|
+
const resolvedGateway = resolveGatewayForSend(requestedAccountId);
|
|
17928
|
+
if (!resolvedGateway) {
|
|
17929
|
+
return json3({ error: `\u8D26\u6237 ${requestedAccountId} \u7684 gateway \u5C1A\u672A\u542F\u52A8\uFF0C\u65E0\u6CD5\u53D1\u9001\u5BC6\u94A5\u8F93\u5165\u5361\u7247` });
|
|
17930
|
+
}
|
|
17931
|
+
const accountId = resolvedGateway.accountId;
|
|
17932
|
+
const bot = resolvedGateway.gw.bot;
|
|
17933
|
+
const description = p2.description?.trim() || void 0;
|
|
17934
|
+
registerPendingSecretInput({
|
|
17935
|
+
accountId,
|
|
17936
|
+
senderOpenid: parsed.targetId,
|
|
17937
|
+
name,
|
|
17938
|
+
kind,
|
|
17939
|
+
description,
|
|
17940
|
+
createdAt: Date.now()
|
|
17883
17941
|
});
|
|
17884
|
-
|
|
17885
|
-
|
|
17886
|
-
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
await bot.sendTextWithKeyboard(
|
|
17900
|
-
{ scope: "c2c", targetId: parsed.targetId },
|
|
17901
|
-
buildSecretInputCard(name, description, DEFAULT_SECRET_INPUT_TTL_MS / 6e4),
|
|
17902
|
-
buildSecretInputKeyboard()
|
|
17942
|
+
try {
|
|
17943
|
+
await bot.sendTextWithKeyboard(
|
|
17944
|
+
{ scope: "c2c", targetId: parsed.targetId },
|
|
17945
|
+
buildSecretInputCard(name, description, DEFAULT_SECRET_INPUT_TTL_MS / 6e4),
|
|
17946
|
+
buildSecretInputKeyboard()
|
|
17947
|
+
);
|
|
17948
|
+
} catch (err) {
|
|
17949
|
+
cancelPendingSecretInput(accountId, parsed.targetId);
|
|
17950
|
+
toolLog2.error(`card send failed: ${err instanceof Error ? err.message : String(err)}`, { name, accountId });
|
|
17951
|
+
return json3({
|
|
17952
|
+
error: `\u5BC6\u94A5\u8F93\u5165\u5361\u7247\u53D1\u9001\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`
|
|
17953
|
+
});
|
|
17954
|
+
}
|
|
17955
|
+
toolLog2.info(
|
|
17956
|
+
`card sent, pending registered name=${name} accountId=${accountId} route=${route.source} ttlMinutes=${DEFAULT_SECRET_INPUT_TTL_MS / 6e4}`
|
|
17903
17957
|
);
|
|
17904
|
-
} catch (err) {
|
|
17905
|
-
cancelPendingSecretInput(accountId, parsed.targetId);
|
|
17906
|
-
toolLog2.error(`card send failed: ${err instanceof Error ? err.message : String(err)}`, { name, accountId });
|
|
17907
17958
|
return json3({
|
|
17908
|
-
|
|
17959
|
+
ok: true,
|
|
17960
|
+
name,
|
|
17961
|
+
kind,
|
|
17962
|
+
command: `openclaw secrets store set ${name} --kind env --value <\u7528\u6237\u8F93\u5165>`,
|
|
17963
|
+
instruction: `\u5361\u7247\u5DF2\u53D1\u9001\u7ED9\u7528\u6237\u3002\u7528\u6237\u4E0B\u4E00\u6761\u79C1\u804A\u6D88\u606F\u5C06\u88AB\u63D2\u4EF6\u81EA\u52A8\u62E6\u622A\uFF08\u4E0D\u4F1A\u8FDB\u5165\u5BF9\u8BDD\uFF09\uFF0C\u6267\u884C\u4E0A\u8FF0\u547D\u4EE4\u4FDD\u5B58\u5BC6\u94A5\uFF0C\u6210\u529F/\u5931\u8D25\u7531\u63D2\u4EF6\u76F4\u63A5\u56DE\u590D\u7528\u6237\u3002\u8BF7\u76F4\u63A5\u7ED3\u675F\u672C\u8F6E\uFF08\u53EF\u544A\u77E5\u7528\u6237\u6309\u5361\u7247\u63D0\u793A\u53D1\u9001\u5BC6\u94A5\uFF09\uFF0C\u4E0D\u8981\u7B49\u5F85\u7528\u6237\u8F93\u5165\uFF0C\u4E5F\u4E0D\u8981\u8BA9\u7528\u6237\u628A\u5BC6\u94A5\u5185\u5BB9\u53D1\u5230\u5BF9\u8BDD\u91CC\u3002`
|
|
17909
17964
|
});
|
|
17910
17965
|
}
|
|
17911
|
-
|
|
17912
|
-
return json3({
|
|
17913
|
-
ok: true,
|
|
17914
|
-
name,
|
|
17915
|
-
kind,
|
|
17916
|
-
command: `openclaw secrets store set ${name} --kind env --value <\u7528\u6237\u8F93\u5165>`,
|
|
17917
|
-
instruction: `\u5361\u7247\u5DF2\u53D1\u9001\u7ED9\u7528\u6237\u3002\u7528\u6237\u4E0B\u4E00\u6761\u79C1\u804A\u6D88\u606F\u5C06\u88AB\u63D2\u4EF6\u81EA\u52A8\u62E6\u622A\uFF08\u4E0D\u4F1A\u8FDB\u5165\u5BF9\u8BDD\uFF09\uFF0C\u6267\u884C\u4E0A\u8FF0\u547D\u4EE4\u4FDD\u5B58\u5BC6\u94A5\uFF0C\u6210\u529F/\u5931\u8D25\u7531\u63D2\u4EF6\u76F4\u63A5\u56DE\u590D\u7528\u6237\u3002\u8BF7\u76F4\u63A5\u7ED3\u675F\u672C\u8F6E\uFF08\u53EF\u544A\u77E5\u7528\u6237\u6309\u5361\u7247\u63D0\u793A\u53D1\u9001\u5BC6\u94A5\uFF09\uFF0C\u4E0D\u8981\u7B49\u5F85\u7528\u6237\u8F93\u5165\uFF0C\u4E5F\u4E0D\u8981\u8BA9\u7528\u6237\u628A\u5BC6\u94A5\u5185\u5BB9\u53D1\u5230\u5BF9\u8BDD\u91CC\u3002`
|
|
17918
|
-
});
|
|
17919
|
-
}
|
|
17966
|
+
};
|
|
17920
17967
|
},
|
|
17921
17968
|
{ name: "qqbot_secret_input" }
|
|
17922
17969
|
);
|