openclaw-xiaoyou 1.0.7 → 1.2.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/index.ts +1 -5
- package/package.json +1 -1
- package/src/channel.ts +60 -55
package/index.ts
CHANGED
|
@@ -3,10 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 安装方式:
|
|
5
5
|
* openclaw plugins install openclaw-xiaoyou
|
|
6
|
-
* openclaw plugins enable openclaw-xiaoyou
|
|
7
|
-
*
|
|
8
|
-
* 配置方式:
|
|
9
|
-
* openclaw channels add --channel xiaoyou
|
|
10
6
|
*/
|
|
11
7
|
|
|
12
8
|
import { xiayouPlugin, setRuntime } from "./src/channel.js";
|
|
@@ -19,7 +15,7 @@ const plugin = {
|
|
|
19
15
|
|
|
20
16
|
register(api: any) {
|
|
21
17
|
// 注入 runtime,供 gateway/outbound 内部使用
|
|
22
|
-
setRuntime(api.runtime);
|
|
18
|
+
if (api.runtime) setRuntime(api.runtime);
|
|
23
19
|
|
|
24
20
|
// 注册 channel
|
|
25
21
|
api.registerChannel({ plugin: xiayouPlugin });
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 运行在 OpenClaw Gateway 进程内,通过 gateway adapter 管理
|
|
5
5
|
* 与企业服务的 WebSocket 连接生命周期。
|
|
6
|
-
*
|
|
7
|
-
* 用户通过 OpenClaw 标准 channel 配置来设置企业服务地址等参数。
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
import type { ResolvedAccount } from "./types.js";
|
|
@@ -14,7 +12,6 @@ import { createEnterpriseClient, type EnterpriseClient } from "./enterprise-clie
|
|
|
14
12
|
|
|
15
13
|
let _client: EnterpriseClient | null = null;
|
|
16
14
|
|
|
17
|
-
/** OpenClaw runtime API 引用,由 index.ts register() 注入 */
|
|
18
15
|
let _runtime: any = null;
|
|
19
16
|
export function setRuntime(rt: any) { _runtime = rt; }
|
|
20
17
|
export function getRuntime() { return _runtime; }
|
|
@@ -25,6 +22,12 @@ function getChannelConfig(cfg: any): any {
|
|
|
25
22
|
return cfg?.channels?.xiaoyou ?? {};
|
|
26
23
|
}
|
|
27
24
|
|
|
25
|
+
function listAccountIds(cfg: any): string[] {
|
|
26
|
+
const section = getChannelConfig(cfg);
|
|
27
|
+
if (section?.wsUrl) return ["default"];
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
|
|
28
31
|
function resolveAccount(cfg: any, accountId?: string | null): any {
|
|
29
32
|
const section = getChannelConfig(cfg);
|
|
30
33
|
const id = accountId || "default";
|
|
@@ -35,32 +38,10 @@ function resolveAccount(cfg: any, accountId?: string | null): any {
|
|
|
35
38
|
config: section,
|
|
36
39
|
enabled: section.enabled !== false,
|
|
37
40
|
configured,
|
|
38
|
-
|
|
39
|
-
authToken: section.authToken ?? "",
|
|
40
|
-
allowFrom: section.allowFrom ?? [],
|
|
41
|
-
dmPolicy: section.dmSecurity,
|
|
42
|
-
reconnectIntervalMs: section.reconnectIntervalMs ?? 3000,
|
|
43
|
-
maxReconnectAttempts: section.maxReconnectAttempts ?? 0,
|
|
44
|
-
heartbeatIntervalMs: section.heartbeatIntervalMs ?? 30000,
|
|
45
|
-
heartbeatTimeoutMs: section.heartbeatTimeoutMs ?? 10000,
|
|
41
|
+
name: "Xiaoyou",
|
|
46
42
|
};
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
function inspectAccount(cfg: any) {
|
|
50
|
-
const section = getChannelConfig(cfg);
|
|
51
|
-
return {
|
|
52
|
-
enabled: Boolean(section?.wsUrl),
|
|
53
|
-
configured: Boolean(section?.wsUrl),
|
|
54
|
-
tokenStatus: section?.authToken ? "available" : "missing",
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function listAccountIds(cfg: any): string[] {
|
|
59
|
-
const section = getChannelConfig(cfg);
|
|
60
|
-
if (section?.wsUrl) return ["default"];
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
45
|
// ─── Channel Plugin ──────────────────────────────────
|
|
65
46
|
|
|
66
47
|
export const xiayouPlugin = {
|
|
@@ -89,42 +70,56 @@ export const xiayouPlugin = {
|
|
|
89
70
|
blockStreaming: false,
|
|
90
71
|
},
|
|
91
72
|
|
|
92
|
-
|
|
73
|
+
reload: { configPrefixes: ["channels.xiaoyou"] },
|
|
74
|
+
|
|
93
75
|
config: {
|
|
94
|
-
resolveAccount,
|
|
95
|
-
inspectAccount,
|
|
96
76
|
listAccountIds,
|
|
77
|
+
resolveAccount,
|
|
78
|
+
isConfigured: (account: any): boolean => Boolean(account?.config?.wsUrl),
|
|
79
|
+
describeAccount: (account: any) => ({
|
|
80
|
+
accountId: account?.accountId || "default",
|
|
81
|
+
name: "Xiaoyou",
|
|
82
|
+
enabled: account?.enabled !== false,
|
|
83
|
+
}),
|
|
84
|
+
defaultAccountId: (): string => "default",
|
|
97
85
|
},
|
|
98
86
|
|
|
99
|
-
// ── DM 安全策略 ────────────────────────────────────
|
|
100
87
|
security: {
|
|
101
88
|
dm: {
|
|
102
89
|
channelKey: "xiaoyou",
|
|
103
|
-
resolvePolicy: (account:
|
|
104
|
-
resolveAllowFrom: (account:
|
|
105
|
-
defaultPolicy: "
|
|
90
|
+
resolvePolicy: (account: any) => account?.config?.dmSecurity ?? "open",
|
|
91
|
+
resolveAllowFrom: (account: any) => account?.config?.allowFrom ?? ["*"],
|
|
92
|
+
defaultPolicy: "open",
|
|
106
93
|
},
|
|
107
94
|
},
|
|
108
95
|
|
|
109
|
-
// ── 回复线程模式 ───────────────────────────────────
|
|
110
96
|
threading: { topLevelReplyToMode: "reply" as const },
|
|
111
97
|
|
|
112
98
|
// ── Gateway 生命周期 ───────────────────────────────
|
|
113
99
|
gateway: {
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
100
|
+
startAccount: async (ctx: any) => {
|
|
101
|
+
const { account, cfg, log } = ctx;
|
|
102
|
+
|
|
103
|
+
// 注入 runtime
|
|
104
|
+
if (ctx.runtime) setRuntime(ctx.runtime);
|
|
105
|
+
|
|
106
|
+
const section = account?.config || getChannelConfig(cfg);
|
|
107
|
+
const logger = log || console;
|
|
108
|
+
|
|
109
|
+
if (!section?.wsUrl) {
|
|
110
|
+
throw new Error("xiaoyou: wsUrl is required");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const resolved: ResolvedAccount = {
|
|
114
|
+
wsUrl: section.wsUrl,
|
|
115
|
+
authToken: section.authToken ?? "",
|
|
116
|
+
allowFrom: section.allowFrom ?? [],
|
|
117
|
+
dmPolicy: section.dmSecurity ?? "open",
|
|
118
|
+
reconnectIntervalMs: section.reconnectIntervalMs ?? 3000,
|
|
119
|
+
maxReconnectAttempts: section.maxReconnectAttempts ?? 0,
|
|
120
|
+
heartbeatIntervalMs: section.heartbeatIntervalMs ?? 30000,
|
|
121
|
+
heartbeatTimeoutMs: section.heartbeatTimeoutMs ?? 10000,
|
|
122
|
+
};
|
|
128
123
|
|
|
129
124
|
// 断开已有连接
|
|
130
125
|
if (_client) _client.disconnect();
|
|
@@ -135,7 +130,7 @@ export const xiayouPlugin = {
|
|
|
135
130
|
onMessage: async (msg) => {
|
|
136
131
|
const runtime = getRuntime();
|
|
137
132
|
if (!runtime) {
|
|
138
|
-
logger.error("[xiaoyou] runtime not available");
|
|
133
|
+
logger.error("[xiaoyou] runtime not available, cannot dispatch");
|
|
139
134
|
return;
|
|
140
135
|
}
|
|
141
136
|
await runtime.inbound.dispatch({
|
|
@@ -158,12 +153,22 @@ export const xiayouPlugin = {
|
|
|
158
153
|
client.connect();
|
|
159
154
|
_client = client;
|
|
160
155
|
logger.info("[xiaoyou] gateway started");
|
|
161
|
-
|
|
156
|
+
|
|
157
|
+
// 保持 startAccount 挂起,直到 abortSignal 触发
|
|
158
|
+
return new Promise<void>((resolve) => {
|
|
159
|
+
if (ctx.abortSignal) {
|
|
160
|
+
ctx.abortSignal.addEventListener("abort", () => {
|
|
161
|
+
logger.info("[xiaoyou] abortSignal received, disconnecting");
|
|
162
|
+
client.disconnect();
|
|
163
|
+
if (_client === client) _client = null;
|
|
164
|
+
resolve();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
});
|
|
162
168
|
},
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (_client === client) _client = null;
|
|
170
|
+
stopAccount: async () => {
|
|
171
|
+
if (_client) { _client.disconnect(); _client = null; }
|
|
167
172
|
},
|
|
168
173
|
},
|
|
169
174
|
|
|
@@ -202,8 +207,8 @@ export const xiayouPlugin = {
|
|
|
202
207
|
status: {
|
|
203
208
|
describe: async ({ account }: any) => {
|
|
204
209
|
const issues: Array<{ severity: string; message: string }> = [];
|
|
205
|
-
const wsUrl = account?.
|
|
206
|
-
const authToken = account?.
|
|
210
|
+
const wsUrl = account?.config?.wsUrl;
|
|
211
|
+
const authToken = account?.config?.authToken;
|
|
207
212
|
|
|
208
213
|
if (!wsUrl) issues.push({ severity: "error", message: "wsUrl not configured" });
|
|
209
214
|
if (!authToken) issues.push({ severity: "warning", message: "authToken not set" });
|