@youdu/openclaw-youdu 2026.3.25
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 +21 -0
- package/README.md +83 -0
- package/dist/cert/cacert-2026-03-19.pem +3669 -0
- package/dist/index.cjs.js +27125 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.esm.js +27096 -0
- package/dist/src/channel.d.ts +3 -0
- package/dist/src/const.d.ts +29 -0
- package/dist/src/dm-policy.d.ts +24 -0
- package/dist/src/group-policy.d.ts +25 -0
- package/dist/src/media.d.ts +64 -0
- package/dist/src/message-sender.d.ts +18 -0
- package/dist/src/monitor.d.ts +44 -0
- package/dist/src/onboarding.d.ts +4 -0
- package/dist/src/openclaw-compat.d.ts +44 -0
- package/dist/src/runtime.d.ts +6 -0
- package/dist/src/sdk/types.d.ts +46 -0
- package/dist/src/sdk/ws-client.d.ts +20 -0
- package/dist/src/sdk/ws-manager.d.ts +63 -0
- package/dist/src/sdk/ws-utils.d.ts +38 -0
- package/dist/src/state-manager.d.ts +48 -0
- package/dist/src/utils.d.ts +60 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +67 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as https from "node:https";
|
|
2
|
+
/** 渠道 ID */
|
|
3
|
+
export declare const CHANNEL_ID: "youdu";
|
|
4
|
+
export declare const DEFAULT_DM_POLICY = "pairing";
|
|
5
|
+
export declare const WEBSOCKET_SCHEME = "wss://";
|
|
6
|
+
export declare const HTTP_SCHEME = "https://";
|
|
7
|
+
export declare const PORT = 7443;
|
|
8
|
+
export declare const WS_URL = "/cgi/bot/wss";
|
|
9
|
+
export declare const DOWNLOAD_MEDIA_URL = "/cgi/bot/file/download";
|
|
10
|
+
export declare const UPLOAD_MEDIA_URL = "/cgi/bot/file/upload";
|
|
11
|
+
export declare const agent: https.Agent;
|
|
12
|
+
/** 文本分块大小上限 */
|
|
13
|
+
export declare const TEXT_CHUNK_LIMIT = 4000;
|
|
14
|
+
/** WebSocket 心跳间隔(毫秒) */
|
|
15
|
+
export declare const WS_HEARTBEAT_INTERVAL_MS = 30000;
|
|
16
|
+
/** WebSocket 最大重连次数 */
|
|
17
|
+
export declare const WS_MAX_RECONNECT_ATTEMPTS = 10;
|
|
18
|
+
/** 消息处理总超时时间(毫秒) */
|
|
19
|
+
export declare const MESSAGE_PROCESS_TIMEOUT_MS: number;
|
|
20
|
+
/** "思考中"流式消息占位内容 */
|
|
21
|
+
export declare const THINKING_MESSAGE = "<think></think>";
|
|
22
|
+
/** 消息状态清理间隔(毫秒) */
|
|
23
|
+
export declare const MESSAGE_STATE_CLEANUP_INTERVAL_MS = 60000;
|
|
24
|
+
/** 仅包含图片时的消息占位符 */
|
|
25
|
+
export declare const MEDIA_IMAGE_PLACEHOLDER = "<media:image>";
|
|
26
|
+
/** 仅包含文件时的消息占位符 */
|
|
27
|
+
export declare const MEDIA_DOCUMENT_PLACEHOLDER = "<media:document>";
|
|
28
|
+
/** 最大的媒体传输大小 */
|
|
29
|
+
export declare const DEFAULT_MEDIA_MAX_SIZE: number;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
|
2
|
+
import type { ResolvedYouDuAccount } from "./utils.js";
|
|
3
|
+
import { WSClient, WsFrame } from "./sdk/ws-client";
|
|
4
|
+
/**
|
|
5
|
+
* DM Policy 检查结果
|
|
6
|
+
*/
|
|
7
|
+
export interface DmPolicyCheckResult {
|
|
8
|
+
/** 是否允许继续处理消息 */
|
|
9
|
+
allowed: boolean;
|
|
10
|
+
/** 是否已发送配对消息(仅在 pairing 模式下) */
|
|
11
|
+
pairingSent?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 检查 DM Policy 访问控制
|
|
15
|
+
* @returns 检查结果,包含是否允许继续处理
|
|
16
|
+
*/
|
|
17
|
+
export declare function checkDmPolicy(params: {
|
|
18
|
+
senderId: string;
|
|
19
|
+
isGroup: boolean;
|
|
20
|
+
account: ResolvedYouDuAccount;
|
|
21
|
+
wsClient: WSClient;
|
|
22
|
+
frame: WsFrame;
|
|
23
|
+
runtime: RuntimeEnv;
|
|
24
|
+
}): Promise<DmPolicyCheckResult>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
|
3
|
+
import type { ResolvedYouDuAccount } from "./utils";
|
|
4
|
+
/**
|
|
5
|
+
* 群组策略检查结果
|
|
6
|
+
*/
|
|
7
|
+
export interface GroupPolicyCheckResult {
|
|
8
|
+
/** 是否允许继续处理消息 */
|
|
9
|
+
allowed: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 检查群组策略访问控制
|
|
13
|
+
* @returns 检查结果,包含是否允许继续处理
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkGroupPolicy(params: {
|
|
16
|
+
chatId: string;
|
|
17
|
+
senderId: string;
|
|
18
|
+
account: ResolvedYouDuAccount;
|
|
19
|
+
config: OpenClawConfig;
|
|
20
|
+
runtime: RuntimeEnv;
|
|
21
|
+
}): GroupPolicyCheckResult;
|
|
22
|
+
/**
|
|
23
|
+
* 检查发送者是否在允许列表中(通用)
|
|
24
|
+
*/
|
|
25
|
+
export declare function isSenderAllowed(senderId: string, allowFrom: string[]): boolean;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ResolvedYouDuAccount, YouDuConfig } from './utils.js';
|
|
2
|
+
import { WSClient, WsFrame } from "./sdk/ws-client";
|
|
3
|
+
import { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
|
4
|
+
export interface YouDuMediaBody {
|
|
5
|
+
mediaId?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
size?: number;
|
|
8
|
+
width?: number;
|
|
9
|
+
height?: number;
|
|
10
|
+
duration?: number;
|
|
11
|
+
contentType?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface InboundMediaAttachment extends YouDuMediaBody {
|
|
14
|
+
kind: 'image' | 'file' | 'audio' | 'video';
|
|
15
|
+
}
|
|
16
|
+
export interface DownloadedInboundMedia {
|
|
17
|
+
path: string;
|
|
18
|
+
contentType?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface UploadAndSendMediaOptions {
|
|
21
|
+
wsClient: WSClient;
|
|
22
|
+
account: ResolvedYouDuAccount;
|
|
23
|
+
mediaUrl: string;
|
|
24
|
+
frame: WsFrame;
|
|
25
|
+
mediaLocalRoots?: readonly string[];
|
|
26
|
+
runtime: RuntimeEnv;
|
|
27
|
+
}
|
|
28
|
+
export declare function inferInboundMessageText(body: {
|
|
29
|
+
text?: {
|
|
30
|
+
content?: string;
|
|
31
|
+
};
|
|
32
|
+
media?: Array<YouDuMediaBody & {
|
|
33
|
+
kind?: string;
|
|
34
|
+
}>;
|
|
35
|
+
image?: YouDuMediaBody;
|
|
36
|
+
file?: YouDuMediaBody;
|
|
37
|
+
audio?: YouDuMediaBody;
|
|
38
|
+
video?: YouDuMediaBody;
|
|
39
|
+
}): string;
|
|
40
|
+
export declare function extractInboundMedia(body: {
|
|
41
|
+
media?: Array<YouDuMediaBody & {
|
|
42
|
+
kind?: string;
|
|
43
|
+
}>;
|
|
44
|
+
image?: YouDuMediaBody;
|
|
45
|
+
file?: YouDuMediaBody;
|
|
46
|
+
audio?: YouDuMediaBody;
|
|
47
|
+
video?: YouDuMediaBody;
|
|
48
|
+
}): InboundMediaAttachment[];
|
|
49
|
+
export declare function uploadAndSendMedia(options: UploadAndSendMediaOptions): Promise<void>;
|
|
50
|
+
export declare function uploadOutboundMedia(params: {
|
|
51
|
+
account: ResolvedYouDuAccount;
|
|
52
|
+
mediaUrl: string;
|
|
53
|
+
mediaLocalRoots?: readonly string[];
|
|
54
|
+
preferredKind?: InboundMediaAttachment['kind'];
|
|
55
|
+
token?: string;
|
|
56
|
+
}): Promise<InboundMediaAttachment>;
|
|
57
|
+
export declare function buildYouDuMediaMessageBody(media: InboundMediaAttachment): Record<string, unknown>;
|
|
58
|
+
export declare function downloadInboundMedia(params: {
|
|
59
|
+
account: ResolvedYouDuAccount;
|
|
60
|
+
attachments: InboundMediaAttachment[];
|
|
61
|
+
messageId: string;
|
|
62
|
+
config: YouDuConfig;
|
|
63
|
+
token?: string;
|
|
64
|
+
}): Promise<Array<DownloadedInboundMedia>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RuntimeEnv } from 'openclaw/plugin-sdk/runtime-env';
|
|
2
|
+
import { WSClient, WsFrame } from './sdk/ws-client';
|
|
3
|
+
import { InboundMediaAttachment } from "./media";
|
|
4
|
+
/**
|
|
5
|
+
* 发送 YouDu 回复
|
|
6
|
+
*/
|
|
7
|
+
export declare function sendYouDuReply(params: {
|
|
8
|
+
wsClient: WSClient;
|
|
9
|
+
frame: WsFrame;
|
|
10
|
+
text: string;
|
|
11
|
+
runtime: RuntimeEnv;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
export declare function sendYouDuMediaReply(params: {
|
|
14
|
+
wsClient: WSClient;
|
|
15
|
+
frame: WsFrame;
|
|
16
|
+
mediaAttachment: InboundMediaAttachment;
|
|
17
|
+
runtime: RuntimeEnv;
|
|
18
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
|
3
|
+
import { ResolvedYouDuAccount } from './utils.js';
|
|
4
|
+
import { type YouDuMediaBody } from './media.js';
|
|
5
|
+
/**
|
|
6
|
+
* 消息体类型(待用户完善)
|
|
7
|
+
*/
|
|
8
|
+
export interface YouDuMessageBody {
|
|
9
|
+
msgid: string;
|
|
10
|
+
chattype: 'single' | 'group';
|
|
11
|
+
chatid: string;
|
|
12
|
+
from: {
|
|
13
|
+
userid: string;
|
|
14
|
+
account: string;
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
create_time?: number;
|
|
18
|
+
response_url?: string;
|
|
19
|
+
msgtype: string;
|
|
20
|
+
text?: {
|
|
21
|
+
content: string;
|
|
22
|
+
};
|
|
23
|
+
image?: YouDuMediaBody;
|
|
24
|
+
file?: YouDuMediaBody;
|
|
25
|
+
audio?: YouDuMediaBody;
|
|
26
|
+
video?: YouDuMediaBody;
|
|
27
|
+
media?: Array<YouDuMediaBody & {
|
|
28
|
+
kind?: string;
|
|
29
|
+
}>;
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 监控器选项
|
|
34
|
+
*/
|
|
35
|
+
export interface YouDuMonitorOptions {
|
|
36
|
+
account: ResolvedYouDuAccount;
|
|
37
|
+
config: OpenClawConfig;
|
|
38
|
+
runtime: RuntimeEnv;
|
|
39
|
+
abortSignal?: AbortSignal;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 监听 YouDu WebSocket 连接(主函数)
|
|
43
|
+
*/
|
|
44
|
+
export declare function monitorYouDuProvider(options: YouDuMonitorOptions): Promise<void>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const DEFAULT_ACCOUNT_ID = "default";
|
|
2
|
+
/** 与 openclaw plugin-sdk 中 WebMediaResult 兼容的类型 */
|
|
3
|
+
export type WebMediaResult = {
|
|
4
|
+
buffer: Buffer;
|
|
5
|
+
contentType?: string;
|
|
6
|
+
kind?: string;
|
|
7
|
+
fileName?: string;
|
|
8
|
+
};
|
|
9
|
+
export type OutboundMediaLoadOptions = {
|
|
10
|
+
maxBytes?: number;
|
|
11
|
+
mediaLocalRoots?: readonly string[];
|
|
12
|
+
};
|
|
13
|
+
export type DetectMimeOptions = {
|
|
14
|
+
buffer?: Buffer;
|
|
15
|
+
headerMime?: string | null;
|
|
16
|
+
filePath?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* 从 URL 或本地路径加载媒体文件(兼容入口)
|
|
20
|
+
*
|
|
21
|
+
* 优先使用 SDK 版本,不可用时使用 fallback。
|
|
22
|
+
* SDK 版本抛出的业务异常(如 LocalMediaAccessError)会直接透传。
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadOutboundMediaFromUrl(mediaUrl: string, options?: OutboundMediaLoadOptions): Promise<WebMediaResult>;
|
|
25
|
+
/**
|
|
26
|
+
* 向 allowFrom 列表添加通配符 "*"(兼容入口)
|
|
27
|
+
*
|
|
28
|
+
* 当 dmPolicy 为 "open" 时,需要确保 allowFrom 中包含 "*" 以允许所有来源。
|
|
29
|
+
* 优先使用 SDK 版本(plugin-sdk/setup 或 plugin-sdk/core),不可用时使用 fallback。
|
|
30
|
+
*
|
|
31
|
+
* 注意:此函数为同步函数,与 SDK 原始签名一致。
|
|
32
|
+
* SDK 引用在模块加载时异步探测并缓存,调用时同步读取缓存。
|
|
33
|
+
*/
|
|
34
|
+
export declare function addWildcardAllowFrom(allowFrom: string[]): string[];
|
|
35
|
+
export declare function emptyPluginConfigSchema(): Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* 格式化配对审批提示信息(参考 moltbot 实现)
|
|
38
|
+
* @param channelId 频道ID
|
|
39
|
+
* @returns 配对审批提示字符串
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatPairingApproveHint(channelId: string): string;
|
|
42
|
+
/** 解析 openclaw 状态目录 */
|
|
43
|
+
export declare function resolveStateDir(): string;
|
|
44
|
+
export declare function getDefaultMediaLocalRoots(): Promise<readonly string[]>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日志接口
|
|
3
|
+
*/
|
|
4
|
+
export interface Logger {
|
|
5
|
+
debug(message: string, ...args: any[]): void;
|
|
6
|
+
info(message: string, ...args: any[]): void;
|
|
7
|
+
warn(message: string, ...args: any[]): void;
|
|
8
|
+
error(message: string, ...args: any[]): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* WebSocket 帧结构
|
|
12
|
+
*/
|
|
13
|
+
export interface WsFrame<T = any> {
|
|
14
|
+
cmd?: string;
|
|
15
|
+
headers: {
|
|
16
|
+
reqId: string;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
};
|
|
19
|
+
body?: T;
|
|
20
|
+
errCode?: number;
|
|
21
|
+
errMsg?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 客户端配置选项
|
|
25
|
+
*/
|
|
26
|
+
export interface WSClientOptions {
|
|
27
|
+
botId: string;
|
|
28
|
+
secret: string;
|
|
29
|
+
reconnectInterval?: number;
|
|
30
|
+
maxReconnectAttempts?: number;
|
|
31
|
+
heartbeatInterval?: number;
|
|
32
|
+
requestTimeout?: number;
|
|
33
|
+
wsUrl?: string;
|
|
34
|
+
logger?: Logger;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 客户端事件映射
|
|
38
|
+
*/
|
|
39
|
+
export interface WSClientEventMap {
|
|
40
|
+
connected: () => void;
|
|
41
|
+
authenticated: () => void;
|
|
42
|
+
disconnected: (reason: string) => void;
|
|
43
|
+
reconnecting: (attempt: number) => void;
|
|
44
|
+
error: (error: Error) => void;
|
|
45
|
+
message: (frame: WsFrame) => void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { WsCmd, DefaultLogger } from "./ws-utils";
|
|
3
|
+
import type { WsFrame, WSClientOptions } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* YouDu WebSocket 客户端
|
|
6
|
+
*/
|
|
7
|
+
export declare class WSClient extends EventEmitter {
|
|
8
|
+
private options;
|
|
9
|
+
private wsManager;
|
|
10
|
+
private logger;
|
|
11
|
+
private started;
|
|
12
|
+
constructor(options: WSClientOptions);
|
|
13
|
+
private setupWsEvents;
|
|
14
|
+
connect(): this;
|
|
15
|
+
disconnect(): void;
|
|
16
|
+
reply(frame: WsFrame, body: any, cmd?: string): Promise<WsFrame>;
|
|
17
|
+
getToken(): string;
|
|
18
|
+
}
|
|
19
|
+
export type { Logger, WsFrame, WSClientOptions, WSClientEventMap, } from "./types";
|
|
20
|
+
export { DefaultLogger, WsCmd };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import type { Logger, WsFrame } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* WebSocket 长连接管理器
|
|
5
|
+
*/
|
|
6
|
+
export declare class WsConnectionManager extends EventEmitter {
|
|
7
|
+
private ws;
|
|
8
|
+
private logger;
|
|
9
|
+
private wsUrl;
|
|
10
|
+
private heartbeatInterval;
|
|
11
|
+
private heartbeatTimer;
|
|
12
|
+
private maxReconnectAttempts;
|
|
13
|
+
private reconnectAttempts;
|
|
14
|
+
private isManualClose;
|
|
15
|
+
/** 认证凭证 */
|
|
16
|
+
private botId;
|
|
17
|
+
private botSecret;
|
|
18
|
+
private token;
|
|
19
|
+
private hasAuthenticated;
|
|
20
|
+
/** 连续未收到心跳响应的次数 */
|
|
21
|
+
private missedPongCount;
|
|
22
|
+
private readonly maxMissedPong;
|
|
23
|
+
private reconnectBaseDelay;
|
|
24
|
+
private readonly reconnectMaxDelay;
|
|
25
|
+
/** 回复队列 */
|
|
26
|
+
private replyQueues;
|
|
27
|
+
private pendingAcks;
|
|
28
|
+
private readonly replyAckTimeout;
|
|
29
|
+
private readonly maxReplyQueueSize;
|
|
30
|
+
constructor(logger: Logger, heartbeatInterval?: number, reconnectBaseDelay?: number, maxReconnectAttempts?: number, wsUrl?: string);
|
|
31
|
+
setCredentials(botId: string, botSecret: string): void;
|
|
32
|
+
getToken(): string;
|
|
33
|
+
connect(): void;
|
|
34
|
+
private setupEventHandlers;
|
|
35
|
+
private sendAuth;
|
|
36
|
+
private handleFrame;
|
|
37
|
+
private startHeartbeat;
|
|
38
|
+
private stopHeartbeat;
|
|
39
|
+
private sendHeartbeat;
|
|
40
|
+
private scheduleReconnect;
|
|
41
|
+
send(frame: WsFrame): void;
|
|
42
|
+
sendReply(reqId: string, body: any, cmd?: string): Promise<WsFrame>;
|
|
43
|
+
private processReplyQueue;
|
|
44
|
+
private handleReplyAck;
|
|
45
|
+
private clearPendingMessages;
|
|
46
|
+
/**
|
|
47
|
+
* 断开 WebSocket 连接(主动断开)
|
|
48
|
+
*
|
|
49
|
+
* 此方法会清除 token 和认证状态,下次连接时将使用 bot_id + secret 重新认证。
|
|
50
|
+
*
|
|
51
|
+
* 注意:被动断线(网络问题、服务端断开)不会调用此方法,会保留 token 并使用 reconnect 快速恢复。
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // 主动断开,下次使用 bot_id + secret 重新认证
|
|
55
|
+
* wsClient.disconnect();
|
|
56
|
+
*
|
|
57
|
+
* // 如果想保留 token(不推荐,因为 disconnect 已自动清除)
|
|
58
|
+
* // 被动断线会自动保留 token,无需额外操作
|
|
59
|
+
*/
|
|
60
|
+
disconnect(): void;
|
|
61
|
+
/** 清除认证状态,强制下次连接使用 bot_id + secret 重新认证 */
|
|
62
|
+
clearAuth(): void;
|
|
63
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Logger } from "./types";
|
|
2
|
+
/** WebSocket 命令常量 */
|
|
3
|
+
export declare enum WsCmd {
|
|
4
|
+
/** 认证订阅(首次认证) */
|
|
5
|
+
SUBSCRIBE = "subscribe",
|
|
6
|
+
/** 断线重连认证 */
|
|
7
|
+
RECONNECT = "reconnect",
|
|
8
|
+
/** 心跳 */
|
|
9
|
+
HEARTBEAT = "ping",
|
|
10
|
+
/** 消息回调 */
|
|
11
|
+
CALLBACK = "msg_callback",
|
|
12
|
+
/** 事件回调 */
|
|
13
|
+
EVENT_CALLBACK = "event_callback",
|
|
14
|
+
/** 回复消息 */
|
|
15
|
+
RESPONSE = "respond_msg",
|
|
16
|
+
/** 主动发送消息 */
|
|
17
|
+
SEND_MSG = "send_msg"
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 生成随机字符串
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateRandomString(length?: number): string;
|
|
23
|
+
/**
|
|
24
|
+
* 生成唯一请求 ID
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateReqId(prefix: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* 默认日志实现
|
|
29
|
+
*/
|
|
30
|
+
export declare class DefaultLogger implements Logger {
|
|
31
|
+
private prefix;
|
|
32
|
+
constructor(prefix?: string);
|
|
33
|
+
private formatTime;
|
|
34
|
+
debug(message: string, ...args: any[]): void;
|
|
35
|
+
info(message: string, ...args: any[]): void;
|
|
36
|
+
warn(message: string, ...args: any[]): void;
|
|
37
|
+
error(message: string, ...args: any[]): void;
|
|
38
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 状态管理器
|
|
3
|
+
* 管理 WebSocket 连接和消息状态
|
|
4
|
+
*/
|
|
5
|
+
import type { WSClient } from './sdk/ws-client.js';
|
|
6
|
+
/** 消息状态 */
|
|
7
|
+
export interface MessageState {
|
|
8
|
+
accumulatedText: string;
|
|
9
|
+
streamId: string;
|
|
10
|
+
mediaUrls?: string[];
|
|
11
|
+
hasText?: boolean;
|
|
12
|
+
hasMedia?: boolean;
|
|
13
|
+
hasMediaFailed?: boolean;
|
|
14
|
+
deliverCalled?: boolean;
|
|
15
|
+
mediaErrorSummary?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 设置账户的 WebSocket 客户端
|
|
19
|
+
*/
|
|
20
|
+
export declare function setYouDuWebSocket(accountId: string, wsClient: WSClient): void;
|
|
21
|
+
/**
|
|
22
|
+
* 获取账户的 WebSocket 客户端
|
|
23
|
+
*/
|
|
24
|
+
export declare function getYouDuWebSocket(accountId: string): WSClient | null;
|
|
25
|
+
/**
|
|
26
|
+
* 设置消息状态
|
|
27
|
+
*/
|
|
28
|
+
export declare function setMessageState(messageId: string, state: MessageState): void;
|
|
29
|
+
/**
|
|
30
|
+
* 获取消息状态
|
|
31
|
+
*/
|
|
32
|
+
export declare function getMessageState(messageId: string): MessageState | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* 删除消息状态
|
|
35
|
+
*/
|
|
36
|
+
export declare function deleteMessageState(messageId: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* 启动消息状态定期清理
|
|
39
|
+
*/
|
|
40
|
+
export declare function startMessageStateCleanup(): void;
|
|
41
|
+
/**
|
|
42
|
+
* 停止消息状态清理
|
|
43
|
+
*/
|
|
44
|
+
export declare function stopMessageStateCleanup(): void;
|
|
45
|
+
/**
|
|
46
|
+
* 清理账户相关状态
|
|
47
|
+
*/
|
|
48
|
+
export declare function cleanupAccount(accountId: string): Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置和工具函数
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
5
|
+
/**
|
|
6
|
+
* 有度渠道配置
|
|
7
|
+
*/
|
|
8
|
+
export interface YouDuConfig {
|
|
9
|
+
botId?: string;
|
|
10
|
+
secret?: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
url?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 控制谁可以向 bot 发消息
|
|
16
|
+
* "pairing"(默认):未知发送者会收到一次性配对码以供批准
|
|
17
|
+
* "allowlist":仅允许 allowFrom(或已配对允许存储)中的发送者
|
|
18
|
+
* "open":允许所有入站私信(需要 allowFrom: ["*"])
|
|
19
|
+
* "disabled":忽略所有私信
|
|
20
|
+
*/
|
|
21
|
+
dmPolicy?: 'pairing' | 'open' | 'allowlist' | 'disabled';
|
|
22
|
+
allowFrom?: string[];
|
|
23
|
+
/** 群组访问策略:"open" = 允许所有群组(默认),"allowlist" = 仅允许 groupAllowFrom 中的群组,"disabled" = 禁用群组消息 */
|
|
24
|
+
groupPolicy?: 'open' | 'allowlist' | 'disabled';
|
|
25
|
+
/** 群组白名单(仅 groupPolicy="allowlist" 时生效) */
|
|
26
|
+
groupAllowFrom?: string[];
|
|
27
|
+
/** 是否发送"思考中"消息,默认为 true */
|
|
28
|
+
sendThinkingMessage?: boolean;
|
|
29
|
+
/** 每个群组的详细配置(如群组内发送者白名单) */
|
|
30
|
+
groups?: Record<string, YouDuGroupConfig>;
|
|
31
|
+
/** Maximum inbound media file size in MB */
|
|
32
|
+
mediaMaxMb?: number;
|
|
33
|
+
/** 额外允许访问的本地媒体路径白名单(支持 ~ 表示 home 目录),如 ["~/Downloads", "~/Documents"] */
|
|
34
|
+
mediaLocalRoots?: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 解析后的有度账户配置
|
|
38
|
+
*/
|
|
39
|
+
export interface ResolvedYouDuAccount {
|
|
40
|
+
accountId: string;
|
|
41
|
+
name: string;
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
botId: string;
|
|
44
|
+
secret: string;
|
|
45
|
+
url: string;
|
|
46
|
+
sendThinkingMessage: boolean;
|
|
47
|
+
config: YouDuConfig;
|
|
48
|
+
}
|
|
49
|
+
export interface YouDuGroupConfig {
|
|
50
|
+
/** 群组内发送者白名单(仅列表中的成员消息会被处理) */
|
|
51
|
+
allowFrom?: Array<string | number>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 解析有度账户配置
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveYouDuAccount(cfg: OpenClawConfig): ResolvedYouDuAccount;
|
|
57
|
+
/**
|
|
58
|
+
* 设置有度账户配置
|
|
59
|
+
*/
|
|
60
|
+
export declare function setYouDuAccount(cfg: OpenClawConfig, account: Partial<YouDuConfig>): OpenClawConfig;
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@youdu/openclaw-youdu",
|
|
3
|
+
"version": "2026.3.25",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"openclaw.plugin.json",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "rollup -c",
|
|
15
|
+
"dev": "rollup -c -w",
|
|
16
|
+
"clean": "rmdir /s /q dist",
|
|
17
|
+
"prebuild": "npm run clean"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"youdu",
|
|
21
|
+
"openclaw",
|
|
22
|
+
"openclaw-youdu"
|
|
23
|
+
],
|
|
24
|
+
"author": "",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/youdu/openclaw-youdu.git"
|
|
29
|
+
},
|
|
30
|
+
"openclaw": {
|
|
31
|
+
"extensions": [
|
|
32
|
+
"./dist/index.esm.js"
|
|
33
|
+
],
|
|
34
|
+
"channel": {
|
|
35
|
+
"id": "youdu",
|
|
36
|
+
"label": "有度",
|
|
37
|
+
"selectionLabel": "有度 (YouDu)",
|
|
38
|
+
"docsPath": "/channels/youdu",
|
|
39
|
+
"docsLabel": "openclaw-youdu",
|
|
40
|
+
"blurb": "有度机器人接入插件",
|
|
41
|
+
"order": 80,
|
|
42
|
+
"quickstartAllowFrom": true
|
|
43
|
+
},
|
|
44
|
+
"install": {
|
|
45
|
+
"npmSpec": "@youdu/openclaw-youdu",
|
|
46
|
+
"localPath": "extensions/openclaw-youdu",
|
|
47
|
+
"defaultChoice": "npm"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"axios": "1.14.0",
|
|
52
|
+
"form-data": "^4.0.5",
|
|
53
|
+
"ws": "^8.14.2"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
57
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
58
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
59
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
60
|
+
"openclaw": "2026.3.22",
|
|
61
|
+
"rollup": "^4.9.6",
|
|
62
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
63
|
+
"rollup-plugin-dts": "^6.1.0",
|
|
64
|
+
"tslib": "^2.6.2",
|
|
65
|
+
"typescript": "^5.3.3"
|
|
66
|
+
}
|
|
67
|
+
}
|