@jerryliang122/openclaw-qqbot 1.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.
- package/LICENSE +22 -0
- package/README.md +967 -0
- package/README.zh.md +790 -0
- package/dist/index.cjs +18072 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1222 -0
- package/index.ts +92 -0
- package/openclaw.plugin.json +38 -0
- package/package.json +69 -0
- package/preload.cjs +19 -0
- package/scripts/link-sdk-core.cjs +268 -0
- package/scripts/proactive-api-server.ts +369 -0
- package/scripts/send-proactive.ts +293 -0
- package/scripts/test-sendmedia.ts +116 -0
- package/skills/qqbot-channel/SKILL.md +285 -0
- package/skills/qqbot-channel/references/api_references.md +521 -0
- package/skills/qqbot-remind/SKILL.md +159 -0
- package/skills/qqbot-upgrade/SKILL.md +56 -0
- package/src/adapter/contract.ts +63 -0
- package/src/adapter/lint.ts +144 -0
- package/src/adapter/media.ts +40 -0
- package/src/adapter/pairing.ts +95 -0
- package/src/adapter/resolve.ts +255 -0
- package/src/adapter/setup.ts +13 -0
- package/src/adapter/webhook.ts +248 -0
- package/src/adapter/workspace.ts +21 -0
- package/src/agent-prompt-adapter.ts +26 -0
- package/src/bot-instance.ts +60 -0
- package/src/channel.ts +230 -0
- package/src/commands/bot-approve.ts +143 -0
- package/src/commands/bot-clear-storage.ts +114 -0
- package/src/commands/bot-group-always.ts +62 -0
- package/src/commands/bot-group-info.ts +48 -0
- package/src/commands/bot-help.ts +40 -0
- package/src/commands/bot-logs.ts +248 -0
- package/src/commands/bot-me.ts +18 -0
- package/src/commands/bot-pairing.ts +50 -0
- package/src/commands/bot-ping.ts +33 -0
- package/src/commands/bot-streaming.ts +55 -0
- package/src/commands/bot-upgrade.ts +56 -0
- package/src/commands/bot-version.ts +41 -0
- package/src/commands/config-util.ts +96 -0
- package/src/commands/index.ts +51 -0
- package/src/config.ts +403 -0
- package/src/constants.ts +6 -0
- package/src/dispatch/body-assembler.ts +308 -0
- package/src/dispatch/ctx-builder.ts +127 -0
- package/src/dispatch/dispatch.ts +667 -0
- package/src/dispatch/envelope-builder.ts +112 -0
- package/src/dispatch/index.ts +2 -0
- package/src/features/approval-capability.ts +302 -0
- package/src/features/approval-helpers.ts +271 -0
- package/src/features/approval-utils.ts +21 -0
- package/src/features/command-panel.ts +301 -0
- package/src/features/credential-backup.ts +74 -0
- package/src/features/group-mode-store.ts +79 -0
- package/src/features/history-store.ts +75 -0
- package/src/features/msgid-cache.ts +55 -0
- package/src/features/outbound-echo-store.ts +46 -0
- package/src/features/proactive-budget.ts +57 -0
- package/src/features/proactive.ts +549 -0
- package/src/features/question-helpers.ts +771 -0
- package/src/features/quota-manager.ts +173 -0
- package/src/features/ref-index-store.ts +289 -0
- package/src/features/secret-input-store.ts +118 -0
- package/src/features/secret-store-cli.ts +324 -0
- package/src/features/typing-refresh.ts +51 -0
- package/src/features/update-checker.ts +166 -0
- package/src/gateway/event-handlers.ts +456 -0
- package/src/gateway/index.ts +3 -0
- package/src/gateway/lifecycle.ts +236 -0
- package/src/gateway/middleware-setup.ts +173 -0
- package/src/gateway/qqbot-gateway.ts +458 -0
- package/src/gateway-adapter.ts +44 -0
- package/src/heartbeat-adapter.ts +57 -0
- package/src/message-adapter.ts +40 -0
- package/src/messaging-adapter.ts +78 -0
- package/src/middleware/access-control.ts +125 -0
- package/src/middleware/attachment.ts +373 -0
- package/src/middleware/inbound-guard.ts +102 -0
- package/src/middleware/policy-injector.ts +71 -0
- package/src/middleware/secret-capture.ts +161 -0
- package/src/middleware/typing.ts +110 -0
- package/src/openclaw-plugin-sdk.d.ts +543 -0
- package/src/outbound/chunker.ts +80 -0
- package/src/outbound/debounce.ts +102 -0
- package/src/outbound/deliver-pipeline.ts +235 -0
- package/src/outbound/index.ts +3 -0
- package/src/outbound/local-file-router.ts +145 -0
- package/src/outbound/media-send.ts +408 -0
- package/src/outbound/outbound-service.ts +298 -0
- package/src/outbound/reply-limiter.ts +139 -0
- package/src/outbound/sanitize.ts +32 -0
- package/src/outbound/streaming-controller.ts +332 -0
- package/src/outbound/target.ts +109 -0
- package/src/outbound-adapter.ts +323 -0
- package/src/plugin-base.ts +42 -0
- package/src/request-context.ts +50 -0
- package/src/runtime.ts +42 -0
- package/src/setup/account-key.ts +41 -0
- package/src/setup/finalize.ts +110 -0
- package/src/setup/login.ts +197 -0
- package/src/setup/surface.ts +40 -0
- package/src/status-adapter.ts +56 -0
- package/src/tools/platform.ts +149 -0
- package/src/tools/remind.ts +308 -0
- package/src/tools/secret-input.ts +185 -0
- package/src/types-augment.d.ts +54 -0
- package/src/types-plugin.ts +82 -0
- package/src/types.ts +620 -0
- package/src/typing-lifecycle.ts +182 -0
- package/src/utils/mention.ts +52 -0
- package/src/utils/pkg-version.ts +23 -0
- package/src/utils/platform.ts +459 -0
- package/src/utils/plugin-logger.ts +104 -0
- package/src/utils/ssrf-guard.ts +132 -0
- package/src/utils/stt.ts +150 -0
- package/src/utils/voice-text.ts +61 -0
- package/tsconfig.json +17 -0
- package/tsup.config.ts +64 -0
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Plugin SDK 类型声明
|
|
3
|
+
*
|
|
4
|
+
* 此文件为 openclaw/plugin-sdk 模块提供 TypeScript 类型声明
|
|
5
|
+
* 仅包含本项目实际使用的类型和函数
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare module "openclaw/plugin-sdk" {
|
|
9
|
+
// ============ 配置类型 ============
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* OpenClaw 主配置对象
|
|
13
|
+
*/
|
|
14
|
+
export interface OpenClawConfig {
|
|
15
|
+
/** 频道配置 */
|
|
16
|
+
channels?: import('./types.channels-2ARZmGtj.js').ChannelsConfig;
|
|
17
|
+
/** 其他配置字段 */
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ============ 插件运行时 ============
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 插件运行时接口
|
|
25
|
+
* 注意:channel 属性设为 any 是因为 SDK 内部类型非常复杂,
|
|
26
|
+
* 且会随 SDK 版本变化。实际使用时 SDK 会提供正确的运行时类型。
|
|
27
|
+
*/
|
|
28
|
+
export interface PluginRuntime {
|
|
29
|
+
/** OpenClaw 框架版本号,如 "2026.3.31" */
|
|
30
|
+
version: string;
|
|
31
|
+
/** 配置访问(运行时 config 在 config.current(),非顶层 getConfig()) */
|
|
32
|
+
config?: {
|
|
33
|
+
/** 获取当前运行时配置快照(只读) */
|
|
34
|
+
current(): OpenClawConfig;
|
|
35
|
+
};
|
|
36
|
+
/** Channel 接口 */
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
channel?: any;
|
|
39
|
+
/** 结构化日志(框架自动追加 channel 前缀) */
|
|
40
|
+
logging: {
|
|
41
|
+
shouldLogVerbose: () => boolean;
|
|
42
|
+
getChildLogger: (
|
|
43
|
+
bindings?: Record<string, unknown>,
|
|
44
|
+
opts?: { level?: string },
|
|
45
|
+
) => RuntimeLogger;
|
|
46
|
+
};
|
|
47
|
+
/** 其他运行时方法(不要假设 getConfig/getDataDir/setConfig 可用) */
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 结构化日志器 */
|
|
52
|
+
export interface RuntimeLogger {
|
|
53
|
+
debug?: (message: string, meta?: Record<string, unknown>) => void;
|
|
54
|
+
info: (message: string, meta?: Record<string, unknown>) => void;
|
|
55
|
+
warn: (message: string, meta?: Record<string, unknown>) => void;
|
|
56
|
+
error: (message: string, meta?: Record<string, unknown>) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ============ 插件 API ============
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Agent Tool 执行结果
|
|
63
|
+
*/
|
|
64
|
+
export interface AgentToolResult {
|
|
65
|
+
content: Array<{ type: "text"; text: string }>;
|
|
66
|
+
details?: unknown;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Agent Tool 定义
|
|
71
|
+
*/
|
|
72
|
+
export interface AnyAgentTool {
|
|
73
|
+
name: string;
|
|
74
|
+
label?: string;
|
|
75
|
+
description: string;
|
|
76
|
+
parameters: unknown;
|
|
77
|
+
execute: (toolCallId: string, params: unknown) => Promise<AgentToolResult> | AgentToolResult;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Tool 注册选项
|
|
82
|
+
*/
|
|
83
|
+
export interface ToolRegistrationOptions {
|
|
84
|
+
name?: string;
|
|
85
|
+
names?: string[];
|
|
86
|
+
optional?: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* OpenClaw 插件 API
|
|
91
|
+
*/
|
|
92
|
+
export interface OpenClawPluginApi {
|
|
93
|
+
/** 运行时实例 */
|
|
94
|
+
runtime: PluginRuntime;
|
|
95
|
+
/** 当前配置 */
|
|
96
|
+
config: OpenClawConfig;
|
|
97
|
+
/** 日志 */
|
|
98
|
+
logger: {
|
|
99
|
+
info?: (msg: string) => void;
|
|
100
|
+
warn?: (msg: string) => void;
|
|
101
|
+
error?: (msg: string) => void;
|
|
102
|
+
debug?: (msg: string) => void;
|
|
103
|
+
};
|
|
104
|
+
/** 注册频道 */
|
|
105
|
+
registerChannel<TAccount = unknown>(options: { plugin: ChannelPlugin<TAccount> }): void;
|
|
106
|
+
/** 注册工具 */
|
|
107
|
+
registerTool(tool: AnyAgentTool, opts?: ToolRegistrationOptions): void;
|
|
108
|
+
/** 其他 API 方法 */
|
|
109
|
+
[key: string]: unknown;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ============ 插件配置 Schema ============
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 空的插件配置 Schema
|
|
116
|
+
*/
|
|
117
|
+
export function emptyPluginConfigSchema(): unknown;
|
|
118
|
+
|
|
119
|
+
// ============ 频道插件 ============
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 频道插件 Meta 信息
|
|
123
|
+
*/
|
|
124
|
+
export interface ChannelPluginMeta {
|
|
125
|
+
id: string;
|
|
126
|
+
label: string;
|
|
127
|
+
selectionLabel?: string;
|
|
128
|
+
docsPath?: string;
|
|
129
|
+
blurb?: string;
|
|
130
|
+
order?: number;
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 频道插件能力配置
|
|
136
|
+
*/
|
|
137
|
+
export interface ChannelPluginCapabilities {
|
|
138
|
+
chatTypes?: ("direct" | "group" | "channel")[];
|
|
139
|
+
media?: boolean;
|
|
140
|
+
reactions?: boolean;
|
|
141
|
+
threads?: boolean;
|
|
142
|
+
blockStreaming?: boolean;
|
|
143
|
+
[key: string]: unknown;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 账户描述
|
|
148
|
+
*/
|
|
149
|
+
export interface AccountDescription {
|
|
150
|
+
accountId: string;
|
|
151
|
+
name?: string;
|
|
152
|
+
enabled: boolean;
|
|
153
|
+
configured: boolean;
|
|
154
|
+
tokenSource?: string;
|
|
155
|
+
[key: string]: unknown;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 频道插件配置接口(泛型)
|
|
160
|
+
*/
|
|
161
|
+
export interface ChannelPluginConfig<TAccount> {
|
|
162
|
+
listAccountIds: (cfg: OpenClawConfig) => string[];
|
|
163
|
+
resolveAccount: (cfg: OpenClawConfig, accountId?: string | null) => TAccount;
|
|
164
|
+
defaultAccountId: (cfg: OpenClawConfig) => string;
|
|
165
|
+
setAccountEnabled?: (ctx: { cfg: OpenClawConfig; accountId: string; enabled: boolean }) => OpenClawConfig;
|
|
166
|
+
deleteAccount?: (ctx: { cfg: OpenClawConfig; accountId: string }) => OpenClawConfig;
|
|
167
|
+
isConfigured?: (account: TAccount | undefined) => boolean;
|
|
168
|
+
describeAccount?: (account: TAccount | undefined) => AccountDescription;
|
|
169
|
+
[key: string]: unknown;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Setup 输入参数(扩展类型以支持 QQBot 特定字段)
|
|
174
|
+
*/
|
|
175
|
+
export interface SetupInput {
|
|
176
|
+
token?: string;
|
|
177
|
+
tokenFile?: string;
|
|
178
|
+
useEnv?: boolean;
|
|
179
|
+
name?: string;
|
|
180
|
+
[key: string]: unknown;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 频道插件 Setup 接口
|
|
185
|
+
*/
|
|
186
|
+
export interface ChannelPluginSetup {
|
|
187
|
+
resolveAccountId?: (ctx: { accountId?: string }) => string;
|
|
188
|
+
applyAccountName?: (ctx: { cfg: OpenClawConfig; accountId: string; name: string }) => OpenClawConfig;
|
|
189
|
+
validateInput?: (ctx: { input: SetupInput }) => string | null;
|
|
190
|
+
applyConfig?: (ctx: { cfg: OpenClawConfig; accountId: string; input: SetupInput }) => OpenClawConfig;
|
|
191
|
+
applyAccountConfig?: (ctx: { cfg: OpenClawConfig; accountId: string; input: SetupInput }) => OpenClawConfig;
|
|
192
|
+
[key: string]: unknown;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 消息目标解析结果
|
|
197
|
+
*/
|
|
198
|
+
export interface NormalizeTargetResult {
|
|
199
|
+
ok: boolean;
|
|
200
|
+
to?: string;
|
|
201
|
+
error?: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 目标解析器
|
|
206
|
+
*/
|
|
207
|
+
export interface TargetResolver {
|
|
208
|
+
looksLikeId?: (id: string) => boolean;
|
|
209
|
+
hint?: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 频道插件 Messaging 接口
|
|
214
|
+
*/
|
|
215
|
+
export interface ChannelPluginMessaging {
|
|
216
|
+
normalizeTarget?: (target: string) => string | undefined;
|
|
217
|
+
targetResolver?: TargetResolver;
|
|
218
|
+
[key: string]: unknown;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 发送文本结果
|
|
223
|
+
*/
|
|
224
|
+
export interface SendTextResult {
|
|
225
|
+
channel: string;
|
|
226
|
+
messageId?: string;
|
|
227
|
+
error?: Error;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 发送文本上下文
|
|
232
|
+
*/
|
|
233
|
+
export interface SendTextContext {
|
|
234
|
+
to: string;
|
|
235
|
+
text: string;
|
|
236
|
+
accountId?: string;
|
|
237
|
+
replyToId?: string;
|
|
238
|
+
cfg: OpenClawConfig;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* 发送媒体上下文
|
|
243
|
+
*/
|
|
244
|
+
export interface SendMediaContext {
|
|
245
|
+
to: string;
|
|
246
|
+
text?: string;
|
|
247
|
+
mediaUrl?: string;
|
|
248
|
+
accountId?: string;
|
|
249
|
+
replyToId?: string;
|
|
250
|
+
cfg: OpenClawConfig;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* 频道插件 Outbound 接口
|
|
255
|
+
*/
|
|
256
|
+
export interface ChannelPluginOutbound {
|
|
257
|
+
deliveryMode?: "direct" | "queued";
|
|
258
|
+
chunker?: (text: string, limit: number) => string[];
|
|
259
|
+
chunkerMode?: "markdown" | "plain";
|
|
260
|
+
textChunkLimit?: number;
|
|
261
|
+
sendText?: (ctx: SendTextContext) => Promise<SendTextResult>;
|
|
262
|
+
sendMedia?: (ctx: SendMediaContext) => Promise<SendTextResult>;
|
|
263
|
+
[key: string]: unknown;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 账户状态
|
|
268
|
+
*/
|
|
269
|
+
export interface AccountStatus {
|
|
270
|
+
running?: boolean;
|
|
271
|
+
connected?: boolean;
|
|
272
|
+
lastConnectedAt?: number;
|
|
273
|
+
lastError?: string;
|
|
274
|
+
[key: string]: unknown;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Gateway 启动上下文
|
|
279
|
+
*/
|
|
280
|
+
export interface GatewayStartContext<TAccount = unknown> {
|
|
281
|
+
account: TAccount;
|
|
282
|
+
accountId: string;
|
|
283
|
+
abortSignal: AbortSignal;
|
|
284
|
+
cfg: OpenClawConfig;
|
|
285
|
+
log?: {
|
|
286
|
+
info: (msg: string) => void;
|
|
287
|
+
warn: (msg: string) => void;
|
|
288
|
+
error: (msg: string) => void;
|
|
289
|
+
debug: (msg: string) => void;
|
|
290
|
+
};
|
|
291
|
+
getStatus: () => AccountStatus;
|
|
292
|
+
setStatus: (status: AccountStatus) => void;
|
|
293
|
+
[key: string]: unknown;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Gateway 登出上下文
|
|
298
|
+
*/
|
|
299
|
+
export interface GatewayLogoutContext {
|
|
300
|
+
accountId: string;
|
|
301
|
+
cfg: OpenClawConfig;
|
|
302
|
+
[key: string]: unknown;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Gateway 登出结果
|
|
307
|
+
*/
|
|
308
|
+
export interface GatewayLogoutResult {
|
|
309
|
+
ok: boolean;
|
|
310
|
+
cleared: boolean;
|
|
311
|
+
updatedConfig?: OpenClawConfig;
|
|
312
|
+
error?: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 频道插件 Gateway 接口
|
|
317
|
+
*/
|
|
318
|
+
export interface ChannelPluginGateway<TAccount = unknown> {
|
|
319
|
+
startAccount?: (ctx: GatewayStartContext<TAccount>) => Promise<void>;
|
|
320
|
+
logoutAccount?: (ctx: GatewayLogoutContext) => Promise<GatewayLogoutResult>;
|
|
321
|
+
[key: string]: unknown;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ============ 群消息适配器 ============
|
|
325
|
+
|
|
326
|
+
/** 群消息策略适配器(resolveRequireMention / resolveToolPolicy / resolveGroupIntroHint) */
|
|
327
|
+
export interface ChannelGroupAdapter {
|
|
328
|
+
/** 是否需要 @机器人才响应 */
|
|
329
|
+
resolveRequireMention?: (ctx: { cfg: OpenClawConfig; accountId?: string; groupId: string }) => boolean | undefined;
|
|
330
|
+
/** 群聊 AI 工具使用范围 */
|
|
331
|
+
resolveToolPolicy?: (
|
|
332
|
+
ctx: { cfg: OpenClawConfig; accountId?: string; groupId: string; senderId?: string }
|
|
333
|
+
) =>
|
|
334
|
+
| "full"
|
|
335
|
+
| "restricted"
|
|
336
|
+
| "none"
|
|
337
|
+
| GroupToolPolicyConfig
|
|
338
|
+
| undefined;
|
|
339
|
+
/** 平台特有的群聊行为提示 */
|
|
340
|
+
resolveGroupIntroHint?: (ctx: { cfg: OpenClawConfig; accountId?: string; groupId: string }) => string | undefined;
|
|
341
|
+
/** 其他适配器方法 */
|
|
342
|
+
[key: string]: unknown;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** 工具策略配置(用于把 none/restricted/full 映射为 allow/deny) */
|
|
346
|
+
export type GroupToolPolicyConfig = {
|
|
347
|
+
allow: string[];
|
|
348
|
+
deny?: string[];
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
/** @mention 检测与清理适配器(stripMentionText / detectWasMentioned) */
|
|
352
|
+
export interface ChannelMentionAdapter {
|
|
353
|
+
/** 清理 @mention 文本:平台格式→可读格式,去除 @机器人自身 */
|
|
354
|
+
stripMentionText?: (text: string, mentions?: Array<{ member_openid?: string; nickname?: string; is_you?: boolean }>) => string;
|
|
355
|
+
/** stripMentions:框架回调型(一次性拿到 text + ctx) */
|
|
356
|
+
stripMentions?: (params: { text: string; ctx: unknown }) => string;
|
|
357
|
+
/** 检测当前消息是否 @了机器人 */
|
|
358
|
+
detectWasMentioned?: (ctx: {
|
|
359
|
+
eventType?: string;
|
|
360
|
+
mentions?: Array<{ is_you?: boolean; bot?: boolean }>;
|
|
361
|
+
content?: string;
|
|
362
|
+
mentionPatterns?: string[];
|
|
363
|
+
}) => boolean;
|
|
364
|
+
/** 其他适配器方法 */
|
|
365
|
+
[key: string]: unknown;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** 状态摘要构建(仅覆盖当前项目用到的字段) */
|
|
369
|
+
export interface ChannelPluginStatus {
|
|
370
|
+
defaultRuntime: Record<string, unknown>;
|
|
371
|
+
buildChannelSummary?: (ctx: { snapshot: any }) => Record<string, unknown>;
|
|
372
|
+
buildAccountSnapshot?: (ctx: { account: any; runtime: any }) => Record<string, unknown>;
|
|
373
|
+
[key: string]: unknown;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* 频道插件接口(泛型)
|
|
378
|
+
*/
|
|
379
|
+
export interface ChannelPlugin<TAccount = unknown> {
|
|
380
|
+
/** 插件 ID */
|
|
381
|
+
id: string;
|
|
382
|
+
/** 插件 Meta 信息 */
|
|
383
|
+
meta?: ChannelPluginMeta;
|
|
384
|
+
/** 插件版本 */
|
|
385
|
+
version?: string;
|
|
386
|
+
/** 插件能力 */
|
|
387
|
+
capabilities?: ChannelPluginCapabilities;
|
|
388
|
+
/** 重载配置 */
|
|
389
|
+
reload?: { configPrefixes?: string[] };
|
|
390
|
+
/** 配置方法 */
|
|
391
|
+
config?: ChannelPluginConfig<TAccount>;
|
|
392
|
+
/** Setup 方法 */
|
|
393
|
+
setup?: ChannelPluginSetup;
|
|
394
|
+
/** Messaging 配置 */
|
|
395
|
+
messaging?: ChannelPluginMessaging;
|
|
396
|
+
/** Outbound 配置 */
|
|
397
|
+
outbound?: ChannelPluginOutbound;
|
|
398
|
+
/** Gateway 配置 */
|
|
399
|
+
gateway?: ChannelPluginGateway<TAccount>;
|
|
400
|
+
/** 群消息策略适配器 */
|
|
401
|
+
groups?: ChannelGroupAdapter;
|
|
402
|
+
/** @mention 检测与清理适配器 */
|
|
403
|
+
mentions?: ChannelMentionAdapter;
|
|
404
|
+
/** 状态摘要构建(可选) */
|
|
405
|
+
status?: ChannelPluginStatus;
|
|
406
|
+
/** 启动函数 */
|
|
407
|
+
start?: (runtime: PluginRuntime) => void | Promise<void>;
|
|
408
|
+
/** 停止函数 */
|
|
409
|
+
stop?: () => void | Promise<void>;
|
|
410
|
+
/** deliver 函数 - 发送消息 */
|
|
411
|
+
deliver?: (ctx: unknown) => Promise<unknown>;
|
|
412
|
+
/** 其他插件属性 */
|
|
413
|
+
[key: string]: unknown;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ============ 配置辅助函数 ============
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* 将账户名称应用到频道配置段
|
|
420
|
+
*/
|
|
421
|
+
export function applyAccountNameToChannelSection(ctx: {
|
|
422
|
+
cfg: OpenClawConfig;
|
|
423
|
+
channelKey: string;
|
|
424
|
+
accountId: string;
|
|
425
|
+
name?: string;
|
|
426
|
+
}): OpenClawConfig;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* 从配置段删除账户
|
|
430
|
+
*/
|
|
431
|
+
export function deleteAccountFromConfigSection(ctx: {
|
|
432
|
+
cfg: OpenClawConfig;
|
|
433
|
+
sectionKey: string;
|
|
434
|
+
accountId: string;
|
|
435
|
+
clearBaseFields?: string[];
|
|
436
|
+
}): OpenClawConfig;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* 设置账户启用状态
|
|
440
|
+
*/
|
|
441
|
+
export function setAccountEnabledInConfigSection(ctx: {
|
|
442
|
+
cfg: OpenClawConfig;
|
|
443
|
+
sectionKey: string;
|
|
444
|
+
accountId: string;
|
|
445
|
+
enabled: boolean;
|
|
446
|
+
allowTopLevel?: boolean;
|
|
447
|
+
}): OpenClawConfig;
|
|
448
|
+
|
|
449
|
+
// ============ 群访问策略引擎(核心框架标准) ============
|
|
450
|
+
|
|
451
|
+
/** 群组访问策略类型:"open" | "disabled" | "allowlist" */
|
|
452
|
+
export type GroupPolicy = "open" | "disabled" | "allowlist";
|
|
453
|
+
|
|
454
|
+
/** 基于白名单匹配的群访问决策原因 */
|
|
455
|
+
export type MatchedGroupAccessReason =
|
|
456
|
+
| "allowed"
|
|
457
|
+
| "disabled"
|
|
458
|
+
| "missing_match_input"
|
|
459
|
+
| "empty_allowlist"
|
|
460
|
+
| "not_allowlisted";
|
|
461
|
+
|
|
462
|
+
/** 基于白名单匹配的群访问决策结果 */
|
|
463
|
+
export type MatchedGroupAccessDecision = {
|
|
464
|
+
allowed: boolean;
|
|
465
|
+
groupPolicy: GroupPolicy;
|
|
466
|
+
reason: MatchedGroupAccessReason;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* 核心框架标准群访问策略评估引擎(基于 policy + allowlist 匹配)
|
|
471
|
+
* @see openclaw/src/plugin-sdk/group-access.ts
|
|
472
|
+
*/
|
|
473
|
+
export function evaluateMatchedGroupAccessForPolicy(params: {
|
|
474
|
+
groupPolicy: GroupPolicy;
|
|
475
|
+
allowlistConfigured: boolean;
|
|
476
|
+
allowlistMatched: boolean;
|
|
477
|
+
requireMatchInput?: boolean;
|
|
478
|
+
hasMatchInput?: boolean;
|
|
479
|
+
}): MatchedGroupAccessDecision;
|
|
480
|
+
|
|
481
|
+
// ============ 审批运行时类型(minimal) ============
|
|
482
|
+
// 这些类型只覆盖本项目真实使用到的字段,
|
|
483
|
+
// 用来消除 strict/noImplicitAny 下的连锁报错。
|
|
484
|
+
|
|
485
|
+
export interface ExecApprovalRequest {
|
|
486
|
+
id: string;
|
|
487
|
+
expiresAtMs: number;
|
|
488
|
+
request: {
|
|
489
|
+
commandPreview?: string;
|
|
490
|
+
command?: string;
|
|
491
|
+
cwd?: string;
|
|
492
|
+
agentId?: string;
|
|
493
|
+
turnSourceAccountId?: string;
|
|
494
|
+
sessionKey?: string;
|
|
495
|
+
turnSourceTo?: string;
|
|
496
|
+
[key: string]: unknown;
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export interface ExecApprovalResolved {
|
|
501
|
+
id: string;
|
|
502
|
+
decision: string;
|
|
503
|
+
[key: string]: unknown;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export interface PluginApprovalRequest {
|
|
507
|
+
id: string;
|
|
508
|
+
request: {
|
|
509
|
+
timeoutMs?: number;
|
|
510
|
+
severity?: "critical" | "info" | string;
|
|
511
|
+
title: string;
|
|
512
|
+
description?: string;
|
|
513
|
+
toolName?: string;
|
|
514
|
+
pluginId?: string;
|
|
515
|
+
agentId?: string;
|
|
516
|
+
turnSourceAccountId?: string;
|
|
517
|
+
sessionKey?: string;
|
|
518
|
+
turnSourceTo?: string;
|
|
519
|
+
[key: string]: unknown;
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export interface PluginApprovalResolved {
|
|
524
|
+
id: string;
|
|
525
|
+
decision: string;
|
|
526
|
+
[key: string]: unknown;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// ============ 其他导出 ============
|
|
530
|
+
|
|
531
|
+
/** 默认账户 ID 常量 */
|
|
532
|
+
export const DEFAULT_ACCOUNT_ID: string;
|
|
533
|
+
|
|
534
|
+
/** 规范化账户 ID */
|
|
535
|
+
export function normalizeAccountId(accountId: string | undefined | null): string;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// 2026.8.1-beta 起 openclaw 发布包明确排除该子路径的 .d.ts(files 列表
|
|
539
|
+
// "!dist/plugin-sdk/text-utility-runtime.d.ts"),2026.9.2 仍未恢复,运行时导出仍在。
|
|
540
|
+
// 仅声明本项目实际使用的函数(签名对齐 dist/utf16-slice-*.js)。
|
|
541
|
+
declare module "openclaw/plugin-sdk/text-utility-runtime" {
|
|
542
|
+
export function truncateUtf16Safe(input: string, maxLen: number): string;
|
|
543
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQBot Markdown 文本分块
|
|
3
|
+
*
|
|
4
|
+
* 优先使用框架 runtime 提供的 chunkMarkdownText(高版本);
|
|
5
|
+
* 不可用时回退到本地 GFM 表格感知 chunker —— 保证不在表格内部切分。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getAdapters } from '../adapter/resolve.js';
|
|
9
|
+
import { tryGetQQBotRuntime } from '../runtime.js';
|
|
10
|
+
|
|
11
|
+
// ── GFM 表格检测 ──
|
|
12
|
+
|
|
13
|
+
/** GFM 表格数据行: | col1 | col2 | */
|
|
14
|
+
const GFM_TABLE_DATA_RE = /^\|.+\|.*\|/;
|
|
15
|
+
/** GFM 表格分隔行: |---|:---:|---| (1 个或多于 1 个破折号,支持对齐冒号) */
|
|
16
|
+
const GFM_TABLE_SEP_RE = /^\|[\s:-]+\|/;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 判断一行是否为 GFM 表格行(数据行或分隔行)。
|
|
20
|
+
* 保障 table-aware chunker 不会在表格内部切分。
|
|
21
|
+
*/
|
|
22
|
+
function isGfmTableLine(line: string): boolean {
|
|
23
|
+
return GFM_TABLE_DATA_RE.test(line) || GFM_TABLE_SEP_RE.test(line);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 表格感知 fallback chunker:按换行边界切分,整块缓冲表格行。
|
|
28
|
+
*/
|
|
29
|
+
export function chunkMarkdownPreservingTables(text: string, limit: number): string[] {
|
|
30
|
+
const lines = text.split('\n');
|
|
31
|
+
const chunks: string[] = [];
|
|
32
|
+
let current = '';
|
|
33
|
+
let tableBuffer: string[] = [];
|
|
34
|
+
|
|
35
|
+
const flushTable = () => {
|
|
36
|
+
if (tableBuffer.length === 0) return;
|
|
37
|
+
const tableBlock = tableBuffer.join('\n');
|
|
38
|
+
const candidate = current ? `${current}\n${tableBlock}` : tableBlock;
|
|
39
|
+
if (candidate.length > limit && current) {
|
|
40
|
+
chunks.push(current);
|
|
41
|
+
current = tableBlock;
|
|
42
|
+
} else {
|
|
43
|
+
current = candidate;
|
|
44
|
+
}
|
|
45
|
+
tableBuffer = [];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
if (isGfmTableLine(line)) {
|
|
50
|
+
tableBuffer.push(line);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 遇到非表格行,先刷新缓冲的表格
|
|
55
|
+
flushTable();
|
|
56
|
+
|
|
57
|
+
const candidate = current ? `${current}\n${line}` : line;
|
|
58
|
+
if (candidate.length > limit && current) {
|
|
59
|
+
chunks.push(current);
|
|
60
|
+
current = line;
|
|
61
|
+
} else {
|
|
62
|
+
current = candidate;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// 处理末尾的表格缓冲
|
|
66
|
+
flushTable();
|
|
67
|
+
if (current) chunks.push(current);
|
|
68
|
+
return chunks.length > 0 ? chunks : [text];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* chunker 入口(框架 ChannelOutboundAdapter.chunker 契约):
|
|
73
|
+
* runtime adapter 的 chunkMarkdownText 优先,低版本降级到本地实现。
|
|
74
|
+
*/
|
|
75
|
+
export function chunkQQBotMarkdown(text: string, limit: number): string[] {
|
|
76
|
+
const rt = tryGetQQBotRuntime();
|
|
77
|
+
const adapterChunker = rt ? getAdapters(rt).chunkMarkdownText : null;
|
|
78
|
+
if (adapterChunker) return adapterChunker(text, limit);
|
|
79
|
+
return chunkMarkdownPreservingTables(text, limit);
|
|
80
|
+
}
|