qidao-openclaw-plugin 1.0.9 → 1.1.3
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/package.json +1 -1
- package/src/index.js +93 -86
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 栖岛聊天 OpenClaw Channel 插件
|
|
3
|
+
* 严格按照官方文档实现: https://docs.openclaw.ai/tools/plugin
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
6
|
import { QidaoChannel } from './qidao-channel.js';
|
|
@@ -7,6 +8,7 @@ import { QidaoChannel } from './qidao-channel.js';
|
|
|
7
8
|
// 存储所有账户的连接实例
|
|
8
9
|
const accountConnections = new Map();
|
|
9
10
|
|
|
11
|
+
// Channel 定义
|
|
10
12
|
const qidaoChannel = {
|
|
11
13
|
id: 'qidao',
|
|
12
14
|
|
|
@@ -19,19 +21,14 @@ const qidaoChannel = {
|
|
|
19
21
|
|
|
20
22
|
capabilities: {
|
|
21
23
|
chatTypes: ['direct', 'group'],
|
|
22
|
-
supportsMedia: true,
|
|
23
|
-
supportsReactions: false,
|
|
24
|
-
supportsThreads: false,
|
|
25
24
|
},
|
|
26
25
|
|
|
27
26
|
config: {
|
|
28
|
-
// 列出所有配置的账户ID
|
|
29
27
|
listAccountIds: (cfg) => {
|
|
30
28
|
const accounts = cfg.channels?.qidao?.accounts ?? {};
|
|
31
29
|
return Object.keys(accounts);
|
|
32
30
|
},
|
|
33
31
|
|
|
34
|
-
// 解析指定账户的配置
|
|
35
32
|
resolveAccount: (cfg, accountId) => {
|
|
36
33
|
const accounts = cfg.channels?.qidao?.accounts ?? {};
|
|
37
34
|
const account = accounts[accountId ?? 'default'];
|
|
@@ -50,40 +47,52 @@ const qidaoChannel = {
|
|
|
50
47
|
},
|
|
51
48
|
},
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const connection = accountConnections.get(accountId ?? 'default');
|
|
50
|
+
// 添加 setup 配置向导
|
|
51
|
+
setup: {
|
|
52
|
+
configure: async ({ cfg, prompter }) => {
|
|
53
|
+
const accounts = cfg.channels?.qidao?.accounts ?? {};
|
|
54
|
+
const defaultAccount = accounts.default ?? {};
|
|
59
55
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
}
|
|
56
|
+
const chatId = await prompter.text({
|
|
57
|
+
message: '请输入栖岛 Chat ID:',
|
|
58
|
+
default: defaultAccount.chatId?.toString(),
|
|
59
|
+
});
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
}
|
|
61
|
+
const userId = await prompter.text({
|
|
62
|
+
message: '请输入栖岛 User ID (可选):',
|
|
63
|
+
default: defaultAccount.userId?.toString() || '',
|
|
64
|
+
});
|
|
73
65
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
const serverUrl = await prompter.text({
|
|
67
|
+
message: '请输入服务器地址:',
|
|
68
|
+
default: defaultAccount.serverUrl || 'wss://oc.qidao.chat/ws',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const newCfg = {
|
|
72
|
+
...cfg,
|
|
73
|
+
channels: {
|
|
74
|
+
...cfg.channels,
|
|
75
|
+
qidao: {
|
|
76
|
+
accounts: {
|
|
77
|
+
default: {
|
|
78
|
+
enabled: true,
|
|
79
|
+
chatId: parseInt(chatId),
|
|
80
|
+
userId: userId ? parseInt(userId) : undefined,
|
|
81
|
+
serverUrl,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return { cfg: newCfg, accountId: 'default' };
|
|
83
89
|
},
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
outbound: {
|
|
93
|
+
deliveryMode: 'direct',
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
sendMedia: async ({ url, accountId, chatId }) => {
|
|
95
|
+
sendText: async ({ text, accountId, chatId }) => {
|
|
87
96
|
const connection = accountConnections.get(accountId ?? 'default');
|
|
88
97
|
|
|
89
98
|
if (!connection || !connection.isConnected()) {
|
|
@@ -101,7 +110,7 @@ const qidaoChannel = {
|
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
try {
|
|
104
|
-
await connection.
|
|
113
|
+
await connection.sendMessage(parseInt(chatId), text);
|
|
105
114
|
return { ok: true };
|
|
106
115
|
} catch (error) {
|
|
107
116
|
return {
|
|
@@ -113,81 +122,79 @@ const qidaoChannel = {
|
|
|
113
122
|
},
|
|
114
123
|
};
|
|
115
124
|
|
|
125
|
+
// 插件注册函数
|
|
116
126
|
export default function register(api) {
|
|
117
127
|
api.logger.info('栖岛聊天插件加载中...');
|
|
118
128
|
|
|
119
|
-
// 注册Channel
|
|
129
|
+
// 注册 Channel
|
|
120
130
|
api.registerChannel({ plugin: qidaoChannel });
|
|
121
131
|
|
|
122
|
-
//
|
|
132
|
+
// 异步初始化连接
|
|
123
133
|
setImmediate(async () => {
|
|
124
134
|
try {
|
|
125
135
|
const cfg = api.getGatewayConfig?.() || {};
|
|
126
136
|
const accounts = cfg.channels?.qidao?.accounts ?? {};
|
|
127
137
|
|
|
128
|
-
|
|
129
|
-
Object.entries(accounts).forEach(([accountId, accountConfig]) => {
|
|
138
|
+
for (const [accountId, accountConfig] of Object.entries(accounts)) {
|
|
130
139
|
if (accountConfig.enabled === false) {
|
|
131
140
|
api.logger.info(`栖岛账户 ${accountId} 已禁用`);
|
|
132
|
-
|
|
141
|
+
continue;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
if (!accountConfig.chatId) {
|
|
136
145
|
api.logger.warn(`栖岛账户 ${accountId} 缺少chatId配置`);
|
|
137
|
-
|
|
146
|
+
continue;
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
const serverUrl = accountConfig.serverUrl ?? 'wss://oc.qidao.chat/ws';
|
|
141
150
|
|
|
142
151
|
api.logger.info(`连接栖岛账户: ${accountId} (chatId: ${accountConfig.chatId})`);
|
|
143
152
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// 监听连接事件
|
|
152
|
-
connection.on('connect', () => {
|
|
153
|
-
api.logger.info(`栖岛账户 ${accountId} 已连接`);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
connection.on('disconnect', () => {
|
|
157
|
-
api.logger.warn(`栖岛账户 ${accountId} 已断开`);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
connection.on('error', (error) => {
|
|
161
|
-
api.logger.error(`栖岛账户 ${accountId} 错误: ${error.message}`);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// 监听栖岛消息,转发给OpenClaw
|
|
165
|
-
connection.on('message', (message) => {
|
|
166
|
-
api.logger.debug(`栖岛账户 ${accountId} 收到消息:`, message);
|
|
153
|
+
try {
|
|
154
|
+
const connection = new QidaoChannel({
|
|
155
|
+
serverUrl,
|
|
156
|
+
chatId: accountConfig.chatId,
|
|
157
|
+
userId: accountConfig.userId,
|
|
158
|
+
});
|
|
167
159
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
api.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
160
|
+
// 监听连接事件
|
|
161
|
+
connection.on('connect', () => {
|
|
162
|
+
api.logger.info(`栖岛账户 ${accountId} 已连接`);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
connection.on('disconnect', () => {
|
|
166
|
+
api.logger.warn(`栖岛账户 ${accountId} 已断开`);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
connection.on('error', (error) => {
|
|
170
|
+
api.logger.error(`栖岛账户 ${accountId} 错误: ${error.message}`);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// 监听栖岛消息,转发给OpenClaw
|
|
174
|
+
connection.on('message', (message) => {
|
|
175
|
+
api.logger.debug(`栖岛账户 ${accountId} 收到消息:`, message);
|
|
176
|
+
|
|
177
|
+
if (message.type === 'new_message') {
|
|
178
|
+
api.ingestMessage({
|
|
179
|
+
channelId: 'qidao',
|
|
180
|
+
accountId: accountId,
|
|
181
|
+
senderId: message.senderId.toString(),
|
|
182
|
+
senderName: message.senderName,
|
|
183
|
+
text: message.messageText,
|
|
184
|
+
timestamp: message.timestamp,
|
|
185
|
+
chatType: message.chatType === 0 ? 'direct' : 'group',
|
|
186
|
+
chatId: message.chatId.toString(),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await connection.connect();
|
|
192
|
+
accountConnections.set(accountId, connection);
|
|
193
|
+
|
|
194
|
+
} catch (error) {
|
|
185
195
|
api.logger.error(`栖岛账户 ${accountId} 连接失败: ${error.message}`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// 保存连接实例
|
|
189
|
-
accountConnections.set(accountId, connection);
|
|
190
|
-
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
191
198
|
} catch (error) {
|
|
192
199
|
api.logger.error(`栖岛聊天插件初始化失败: ${error.message}`);
|
|
193
200
|
}
|