qidao-openclaw-plugin 1.2.8 → 1.3.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +129 -38
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qidao-openclaw-plugin",
3
- "version": "1.2.8",
3
+ "version": "1.3.2",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "description": "OpenClaw 栖岛聊天 Channel 插件 - 连接到栖岛聊天服务",
package/src/index.js CHANGED
@@ -6,6 +6,19 @@ import { QidaoChannel } from './qidao-channel.js';
6
6
  import { registerAuthCommand } from './auth-cli.js';
7
7
 
8
8
  let connection = null;
9
+ let pluginApi = null;
10
+ let qidaoRuntime = null;
11
+
12
+ function setQidaoRuntime(r) {
13
+ qidaoRuntime = r;
14
+ }
15
+
16
+ function getQidaoRuntime() {
17
+ if (!qidaoRuntime) {
18
+ throw new Error('Qidao runtime not initialized - plugin not registered');
19
+ }
20
+ return qidaoRuntime;
21
+ }
9
22
 
10
23
  const qidaoChannel = {
11
24
  id: 'qidao',
@@ -19,6 +32,7 @@ const qidaoChannel = {
19
32
 
20
33
  capabilities: {
21
34
  chatTypes: ['direct', 'group'],
35
+ hasGateway: true,
22
36
  },
23
37
 
24
38
  config: {
@@ -126,37 +140,25 @@ const qidaoChannel = {
126
140
  }
127
141
  },
128
142
  },
129
- };
130
-
131
- export default function register(api) {
132
- api.logger.info('栖岛聊天插件加载中...');
133
143
 
134
- api.registerChannel({ plugin: qidaoChannel });
135
-
136
- // 注册认证命令
137
- registerAuthCommand(api);
138
-
139
- // 延迟初始化,确保配置已加载
140
- setTimeout(async () => {
141
- try {
142
- const cfg = api.getGatewayConfig?.() || {};
143
-
144
- // 调试日志
145
- api.logger.info(`栖岛聊天配置: ${JSON.stringify(cfg.channels?.qidao || {})}`);
144
+ gateway: {
145
+ startAccount: async (ctx) => {
146
+ const { account, cfg, runtime, abortSignal } = ctx;
146
147
 
147
- const account = qidaoChannel.config.resolveAccount(cfg);
148
+ runtime.log?.('🚀 栖岛聊天 gateway.startAccount 被调用!');
149
+ runtime.log?.(`账户信息: ${JSON.stringify(account)}`);
148
150
 
149
151
  if (!account.enabled) {
150
- api.logger.info('栖岛聊天未启用');
152
+ runtime.log?.('栖岛聊天未启用');
151
153
  return;
152
154
  }
153
155
 
154
156
  if (!account.chatId) {
155
- api.logger.warn('栖岛聊天缺少chatId配置');
157
+ runtime.log?.('栖岛聊天缺少chatId配置');
156
158
  return;
157
159
  }
158
160
 
159
- api.logger.info(`连接栖岛聊天 (chatId: ${account.chatId})`);
161
+ runtime.log?.(`连接栖岛聊天 (chatId: ${account.chatId})`);
160
162
 
161
163
  connection = new QidaoChannel({
162
164
  serverUrl: account.serverUrl,
@@ -165,38 +167,127 @@ export default function register(api) {
165
167
  });
166
168
 
167
169
  connection.on('connect', () => {
168
- api.logger.info('栖岛聊天已连接');
170
+ runtime.log?.('栖岛聊天已连接');
169
171
  });
170
172
 
171
173
  connection.on('disconnect', () => {
172
- api.logger.warn('栖岛聊天已断开');
174
+ runtime.log?.('栖岛聊天已断开');
173
175
  });
174
176
 
175
177
  connection.on('error', (error) => {
176
- api.logger.error(`栖岛聊天错误: ${error.message}`);
178
+ runtime.error?.(`栖岛聊天错误: ${error.message}`);
177
179
  });
178
180
 
179
- connection.on('message', (message) => {
181
+ connection.on('message', async (message) => {
180
182
  if (message.type === 'new_message') {
181
- api.ingestMessage({
182
- channelId: 'qidao',
183
- accountId: 'default',
184
- senderId: message.senderId.toString(),
185
- senderName: message.senderName,
186
- text: message.messageText,
187
- timestamp: message.timestamp,
188
- chatType: message.chatType === 0 ? 'direct' : 'group',
189
- chatId: message.chatId.toString(),
190
- });
183
+ try {
184
+ // 过滤掉机器人自己发送的消息,避免循环
185
+ // 栖岛消息中,senderId=1 是畅小猪,otherUserId=175 是机器人
186
+ if (message.senderId === 175 || message.otherUserId === 1) {
187
+ runtime.log?.(`跳过机器人自己的消息`);
188
+ return;
189
+ }
190
+
191
+ runtime.log?.(`收到栖岛消息: ${message.messageText}`);
192
+
193
+ const core = getQidaoRuntime();
194
+
195
+ const chatId = message.chatId.toString();
196
+ const chatType = message.chatType === 0 ? 'direct' : 'group';
197
+
198
+ // 解析路由信息
199
+ const route = core.channel.routing.resolveAgentRoute({
200
+ cfg,
201
+ channel: 'qidao',
202
+ accountId: account.accountId,
203
+ peer: {
204
+ kind: chatType,
205
+ id: chatId,
206
+ },
207
+ });
208
+
209
+ // 构建标准消息上下文(参考企业微信插件)
210
+ const ctxPayload = core.channel.reply.finalizeInboundContext({
211
+ Body: message.messageText,
212
+ RawBody: message.messageText,
213
+ CommandBody: message.messageText,
214
+ MessageSid: message.messageId?.toString() || `${Date.now()}`,
215
+ From: chatType === 'group' ? `qidao:group:${chatId}` : `qidao:${message.senderId}`,
216
+ To: `qidao:${chatId}`,
217
+ SenderId: message.senderId.toString(),
218
+ SessionKey: route.sessionKey,
219
+ AccountId: account.accountId,
220
+ ChatType: chatType,
221
+ ConversationLabel: chatType === 'group' ? `group:${chatId}` : `user:${message.senderId}`,
222
+ Timestamp: message.timestamp || Date.now(),
223
+ Provider: 'qidao',
224
+ Surface: 'qidao',
225
+ OriginatingChannel: 'qidao',
226
+ OriginatingTo: `qidao:${chatId}`,
227
+ CommandAuthorized: true,
228
+ });
229
+
230
+ // 使用 core.channel.reply.dispatchReplyWithBufferedBlockDispatcher 处理消息
231
+ await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
232
+ ctx: ctxPayload,
233
+ cfg,
234
+ dispatcherOptions: {
235
+ deliver: async (payload, info) => {
236
+ runtime.log?.(`发送回复: ${payload.text.substring(0, 50)}...`);
237
+
238
+ // 通过 connection 发送回复
239
+ if (info.kind === 'final') {
240
+ await connection.sendMessage(message.chatId, payload.text);
241
+ }
242
+ },
243
+ onError: (err, info) => {
244
+ runtime.error?.(`回复失败 (${info.kind}): ${err.message}`);
245
+ },
246
+ },
247
+ });
248
+
249
+ runtime.log?.('✅ 消息处理完成');
250
+ } catch (error) {
251
+ runtime.error?.(`处理消息失败: ${error.message}`);
252
+ }
191
253
  }
192
254
  });
193
255
 
256
+ // 处理中止信号
257
+ if (abortSignal) {
258
+ abortSignal.addEventListener('abort', () => {
259
+ runtime.log?.('栖岛聊天连接被中止');
260
+ if (connection) {
261
+ connection.disconnect();
262
+ connection = null;
263
+ }
264
+ });
265
+ }
266
+
194
267
  await connection.connect();
195
268
 
196
- } catch (error) {
197
- api.logger.error(`栖岛聊天插件初始化失败: ${error.message}`);
198
- }
199
- }, 2000); // 延迟2秒,确保配置已加载
269
+ // 返回 Promise,保持连接直到被中止
270
+ return new Promise((resolve) => {
271
+ if (abortSignal) {
272
+ abortSignal.addEventListener('abort', resolve);
273
+ }
274
+ });
275
+ },
276
+ },
277
+ };
278
+
279
+ export default function register(api) {
280
+ pluginApi = api;
281
+
282
+ // 设置 runtime(参考企业微信插件)
283
+ setQidaoRuntime(api.runtime);
284
+
285
+ api.logger.info('栖岛聊天插件加载中...');
286
+
287
+ api.registerChannel({ plugin: qidaoChannel });
288
+
289
+ // 注册认证命令
290
+ registerAuthCommand(api);
200
291
 
201
292
  api.logger.info('栖岛聊天插件加载完成');
202
293
  }