openclaw-xiaoyou 1.1.0 → 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 +44 -48
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,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
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",
|
|
41
|
+
name: "Xiaoyou",
|
|
55
42
|
};
|
|
56
43
|
}
|
|
57
44
|
|
|
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,11 +70,11 @@ 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,
|
|
97
78
|
isConfigured: (account: any): boolean => Boolean(account?.config?.wsUrl),
|
|
98
79
|
describeAccount: (account: any) => ({
|
|
99
80
|
accountId: account?.accountId || "default",
|
|
@@ -103,37 +84,41 @@ export const xiayouPlugin = {
|
|
|
103
84
|
defaultAccountId: (): string => "default",
|
|
104
85
|
},
|
|
105
86
|
|
|
106
|
-
// ── DM 安全策略 ────────────────────────────────────
|
|
107
87
|
security: {
|
|
108
88
|
dm: {
|
|
109
89
|
channelKey: "xiaoyou",
|
|
110
|
-
resolvePolicy: (account:
|
|
111
|
-
resolveAllowFrom: (account:
|
|
112
|
-
defaultPolicy: "
|
|
90
|
+
resolvePolicy: (account: any) => account?.config?.dmSecurity ?? "open",
|
|
91
|
+
resolveAllowFrom: (account: any) => account?.config?.allowFrom ?? ["*"],
|
|
92
|
+
defaultPolicy: "open",
|
|
113
93
|
},
|
|
114
94
|
},
|
|
115
95
|
|
|
116
|
-
// ── 回复线程模式 ───────────────────────────────────
|
|
117
96
|
threading: { topLevelReplyToMode: "reply" as const },
|
|
118
97
|
|
|
119
98
|
// ── Gateway 生命周期 ───────────────────────────────
|
|
120
|
-
reload: { configPrefixes: ["channels.xiaoyou"] },
|
|
121
|
-
|
|
122
99
|
gateway: {
|
|
123
100
|
startAccount: async (ctx: any) => {
|
|
124
101
|
const { account, cfg, log } = ctx;
|
|
102
|
+
|
|
103
|
+
// 注入 runtime
|
|
104
|
+
if (ctx.runtime) setRuntime(ctx.runtime);
|
|
105
|
+
|
|
125
106
|
const section = account?.config || getChannelConfig(cfg);
|
|
126
107
|
const logger = log || console;
|
|
127
108
|
|
|
109
|
+
if (!section?.wsUrl) {
|
|
110
|
+
throw new Error("xiaoyou: wsUrl is required");
|
|
111
|
+
}
|
|
112
|
+
|
|
128
113
|
const resolved: ResolvedAccount = {
|
|
129
|
-
wsUrl: section
|
|
130
|
-
authToken: section
|
|
131
|
-
allowFrom: section
|
|
132
|
-
dmPolicy: section
|
|
133
|
-
reconnectIntervalMs: section
|
|
134
|
-
maxReconnectAttempts: section
|
|
135
|
-
heartbeatIntervalMs: section
|
|
136
|
-
heartbeatTimeoutMs: section
|
|
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,
|
|
137
122
|
};
|
|
138
123
|
|
|
139
124
|
// 断开已有连接
|
|
@@ -145,7 +130,7 @@ export const xiayouPlugin = {
|
|
|
145
130
|
onMessage: async (msg) => {
|
|
146
131
|
const runtime = getRuntime();
|
|
147
132
|
if (!runtime) {
|
|
148
|
-
logger.error("[xiaoyou] runtime not available");
|
|
133
|
+
logger.error("[xiaoyou] runtime not available, cannot dispatch");
|
|
149
134
|
return;
|
|
150
135
|
}
|
|
151
136
|
await runtime.inbound.dispatch({
|
|
@@ -168,7 +153,18 @@ export const xiayouPlugin = {
|
|
|
168
153
|
client.connect();
|
|
169
154
|
_client = client;
|
|
170
155
|
logger.info("[xiaoyou] gateway started");
|
|
171
|
-
|
|
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
|
+
});
|
|
172
168
|
},
|
|
173
169
|
|
|
174
170
|
stopAccount: async () => {
|
|
@@ -211,8 +207,8 @@ export const xiayouPlugin = {
|
|
|
211
207
|
status: {
|
|
212
208
|
describe: async ({ account }: any) => {
|
|
213
209
|
const issues: Array<{ severity: string; message: string }> = [];
|
|
214
|
-
const wsUrl = account?.
|
|
215
|
-
const authToken = account?.
|
|
210
|
+
const wsUrl = account?.config?.wsUrl;
|
|
211
|
+
const authToken = account?.config?.authToken;
|
|
216
212
|
|
|
217
213
|
if (!wsUrl) issues.push({ severity: "error", message: "wsUrl not configured" });
|
|
218
214
|
if (!authToken) issues.push({ severity: "warning", message: "authToken not set" });
|