qidao-openclaw-plugin 1.2.8 → 1.3.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/auth-cli.js +157 -9
- package/src/index.js +157 -50
package/package.json
CHANGED
package/src/auth-cli.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* 栖岛聊天认证 CLI 命令
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import ws from 'ws';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
|
|
5
8
|
export function registerAuthCommand(api) {
|
|
6
9
|
api.registerCli(
|
|
7
10
|
({ program }) => {
|
|
@@ -9,17 +12,162 @@ export function registerAuthCommand(api) {
|
|
|
9
12
|
.command('qidao-auth')
|
|
10
13
|
.description('栖岛聊天二维码认证')
|
|
11
14
|
.action(async () => {
|
|
12
|
-
console.log('🔐 开始栖岛聊天认证流程...');
|
|
13
15
|
console.log('');
|
|
14
|
-
console.log('
|
|
15
|
-
console.log('
|
|
16
|
-
console.log('
|
|
17
|
-
console.log('
|
|
16
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
17
|
+
console.log('');
|
|
18
|
+
console.log(' 🔐 栖岛聊天二维码认证');
|
|
19
|
+
console.log('');
|
|
20
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
18
21
|
console.log('');
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// 创建临时连接到 Server 进行认证
|
|
25
|
+
const tempWs = new ws('wss://oc.qidao.chat/ws');
|
|
26
|
+
|
|
27
|
+
const chatId = await new Promise((resolve, reject) => {
|
|
28
|
+
const timeout = setTimeout(() => {
|
|
29
|
+
tempWs.close();
|
|
30
|
+
reject(new Error('连接超时'));
|
|
31
|
+
}, 10000);
|
|
32
|
+
|
|
33
|
+
tempWs.on('open', () => {
|
|
34
|
+
clearTimeout(timeout);
|
|
35
|
+
console.log('✅ 已连接到认证服务器');
|
|
36
|
+
console.log('');
|
|
37
|
+
|
|
38
|
+
// 请求生成二维码
|
|
39
|
+
tempWs.send(JSON.stringify({ action: 'startAuth' }));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
tempWs.on('message', async (data) => {
|
|
43
|
+
try {
|
|
44
|
+
const message = JSON.parse(data.toString());
|
|
45
|
+
|
|
46
|
+
// 兼容Server的响应格式
|
|
47
|
+
// 格式1: { id, code: 1, msg, data: { code, qrUrl } }
|
|
48
|
+
// 格式2: { action: 'authStarted', code, qrUrl }
|
|
49
|
+
if ((message.code === 1 && message.data && message.data.qrUrl) ||
|
|
50
|
+
(message.action === 'authStarted')) {
|
|
51
|
+
const code = message.data?.code || message.code;
|
|
52
|
+
const qrUrl = message.data?.qrUrl || message.qrUrl;
|
|
53
|
+
|
|
54
|
+
console.log('📱 请使用栖岛 APP 扫描二维码:');
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log(` ${qrUrl}`);
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log('正在打开浏览器...');
|
|
59
|
+
console.log('');
|
|
60
|
+
|
|
61
|
+
// 打开浏览器显示二维码
|
|
62
|
+
const openCommand = process.platform === 'win32' ? 'start' :
|
|
63
|
+
process.platform === 'darwin' ? 'open' : 'xdg-open';
|
|
64
|
+
spawn(openCommand, [qrUrl], { shell: true, detached: true });
|
|
65
|
+
|
|
66
|
+
console.log('⏳ 等待扫码...');
|
|
67
|
+
console.log('');
|
|
68
|
+
|
|
69
|
+
// 开始轮询扫码状态
|
|
70
|
+
const pollInterval = setInterval(() => {
|
|
71
|
+
tempWs.send(JSON.stringify({ action: 'checkAuthStatus', code }));
|
|
72
|
+
}, 2000);
|
|
73
|
+
|
|
74
|
+
// 保存轮询定时器以便后续清理
|
|
75
|
+
tempWs._pollInterval = pollInterval;
|
|
76
|
+
tempWs._code = code;
|
|
77
|
+
|
|
78
|
+
} else if ((message.code === 1 && message.data && message.data.status) ||
|
|
79
|
+
(message.action === 'authStatus')) {
|
|
80
|
+
// 兼容两种格式的扫码状态响应
|
|
81
|
+
const status = message.data?.status || message.status;
|
|
82
|
+
const uid = message.data?.uid || message.uid;
|
|
83
|
+
|
|
84
|
+
if (status === 'success') {
|
|
85
|
+
console.log('✅ 扫码成功!');
|
|
86
|
+
console.log('');
|
|
87
|
+
|
|
88
|
+
// 请求完成认证获取 chatId
|
|
89
|
+
tempWs.send(JSON.stringify({
|
|
90
|
+
action: 'completeAuth',
|
|
91
|
+
uid,
|
|
92
|
+
code: tempWs._code
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
} else if (status === 'waiting') {
|
|
96
|
+
// 继续等待
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
} else if ((message.code === 1 && message.data && message.data.chatId) ||
|
|
100
|
+
(message.action === 'authCompleted')) {
|
|
101
|
+
// 清理轮询定时器
|
|
102
|
+
if (tempWs._pollInterval) {
|
|
103
|
+
clearInterval(tempWs._pollInterval);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const receivedChatId = message.data?.chatId || message.chatId;
|
|
107
|
+
console.log(`🎉 认证完成!您的 chatId: ${receivedChatId}`);
|
|
108
|
+
console.log('');
|
|
109
|
+
|
|
110
|
+
tempWs.close();
|
|
111
|
+
resolve(receivedChatId);
|
|
112
|
+
|
|
113
|
+
} else if (message.code === 0 || message.action === 'error') {
|
|
114
|
+
if (tempWs._pollInterval) {
|
|
115
|
+
clearInterval(tempWs._pollInterval);
|
|
116
|
+
}
|
|
117
|
+
tempWs.close();
|
|
118
|
+
const errorMsg = message.msg || message.message || '认证失败';
|
|
119
|
+
reject(new Error(errorMsg));
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error('处理消息失败:', err);
|
|
123
|
+
reject(err);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
tempWs.on('error', (error) => {
|
|
128
|
+
clearTimeout(timeout);
|
|
129
|
+
if (tempWs._pollInterval) {
|
|
130
|
+
clearInterval(tempWs._pollInterval);
|
|
131
|
+
}
|
|
132
|
+
reject(error);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 自动保存配置
|
|
137
|
+
console.log('正在保存配置...');
|
|
138
|
+
console.log('');
|
|
139
|
+
|
|
140
|
+
const { execSync } = await import('child_process');
|
|
141
|
+
execSync(`openclaw config set channels.qidao.chatId ${chatId}`, { stdio: 'inherit' });
|
|
142
|
+
execSync(`openclaw config set channels.qidao.enabled true`, { stdio: 'inherit' });
|
|
143
|
+
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log(' ✅ 配置完成!');
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(' 请重启 Gateway 以应用配置:');
|
|
150
|
+
console.log('');
|
|
151
|
+
console.log(' openclaw gateway restart');
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
154
|
+
console.log('');
|
|
155
|
+
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error('');
|
|
158
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
159
|
+
console.error('');
|
|
160
|
+
console.error(' ❌ 认证失败:', error.message);
|
|
161
|
+
console.error('');
|
|
162
|
+
console.error(' 请重试或手动配置:');
|
|
163
|
+
console.error('');
|
|
164
|
+
console.error(' openclaw config set channels.qidao.chatId <您的chatId>');
|
|
165
|
+
console.error(' openclaw config set channels.qidao.enabled true');
|
|
166
|
+
console.error('');
|
|
167
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
168
|
+
console.error('');
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
23
171
|
});
|
|
24
172
|
},
|
|
25
173
|
{ commands: ['qidao-auth'] }
|
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: {
|
|
@@ -32,7 +46,7 @@ const qidaoChannel = {
|
|
|
32
46
|
enabled: qidaoConfig.enabled !== false,
|
|
33
47
|
chatId: qidaoConfig.chatId,
|
|
34
48
|
userId: qidaoConfig.userId,
|
|
35
|
-
serverUrl:
|
|
49
|
+
serverUrl: 'wss://oc.qidao.chat/ws', // 固定的服务器地址
|
|
36
50
|
};
|
|
37
51
|
},
|
|
38
52
|
},
|
|
@@ -67,40 +81,56 @@ const qidaoChannel = {
|
|
|
67
81
|
|
|
68
82
|
// 提示用户
|
|
69
83
|
console.log('');
|
|
70
|
-
console.log('
|
|
71
|
-
console.log('
|
|
84
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
85
|
+
console.log('');
|
|
86
|
+
console.log(' 📱 栖岛聊天配置');
|
|
87
|
+
console.log('');
|
|
88
|
+
console.log(' 推荐使用二维码认证(自动获取 chatId):');
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(' 请退出此向导(按 Ctrl+C),然后运行:');
|
|
91
|
+
console.log('');
|
|
92
|
+
console.log(' openclaw qidao-auth');
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(' 或者继续手动输入 chatId');
|
|
95
|
+
console.log('');
|
|
96
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
72
97
|
console.log('');
|
|
73
98
|
|
|
74
99
|
const chatIdInput = await prompter.text({
|
|
75
|
-
message: '请输入栖岛 Chat ID:',
|
|
100
|
+
message: '请输入栖岛 Chat ID (或按 Ctrl+C 退出后使用 openclaw qidao-auth):',
|
|
76
101
|
default: qidaoConfig.chatId?.toString() || '',
|
|
77
102
|
});
|
|
78
103
|
|
|
79
104
|
// 检查输入是否为空或只有空格
|
|
80
105
|
if (!chatIdInput || chatIdInput.trim() === '') {
|
|
106
|
+
console.log('');
|
|
81
107
|
console.log('未输入 chatId,取消配置');
|
|
108
|
+
console.log('');
|
|
109
|
+
console.log('提示:运行 openclaw qidao-auth 使用二维码认证');
|
|
110
|
+
console.log('');
|
|
82
111
|
return { cfg };
|
|
83
112
|
}
|
|
84
113
|
|
|
85
|
-
const
|
|
86
|
-
message: '请输入服务器地址:',
|
|
87
|
-
default: qidaoConfig.serverUrl || 'wss://oc.qidao.chat/ws',
|
|
88
|
-
});
|
|
114
|
+
const chatId = parseInt(chatIdInput.trim());
|
|
89
115
|
|
|
90
|
-
// 构建新配置
|
|
116
|
+
// 构建新配置
|
|
91
117
|
const newCfg = {
|
|
92
118
|
...cfg,
|
|
93
119
|
channels: {
|
|
94
120
|
...cfg.channels,
|
|
95
121
|
qidao: {
|
|
96
122
|
enabled: true,
|
|
97
|
-
chatId
|
|
98
|
-
serverUrl: (serverUrl && serverUrl.trim()) || 'wss://oc.qidao.chat/ws',
|
|
123
|
+
chatId,
|
|
99
124
|
},
|
|
100
125
|
},
|
|
101
126
|
};
|
|
102
127
|
|
|
103
|
-
console.log('
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log('✅ 配置已保存:', newCfg.channels.qidao);
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log('请重启 Gateway 以应用配置:');
|
|
132
|
+
console.log(' openclaw gateway restart');
|
|
133
|
+
console.log('');
|
|
104
134
|
|
|
105
135
|
return { cfg: newCfg, accountId: 'default' };
|
|
106
136
|
},
|
|
@@ -126,37 +156,25 @@ const qidaoChannel = {
|
|
|
126
156
|
}
|
|
127
157
|
},
|
|
128
158
|
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
export default function register(api) {
|
|
132
|
-
api.logger.info('栖岛聊天插件加载中...');
|
|
133
|
-
|
|
134
|
-
api.registerChannel({ plugin: qidaoChannel });
|
|
135
|
-
|
|
136
|
-
// 注册认证命令
|
|
137
|
-
registerAuthCommand(api);
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const cfg = api.getGatewayConfig?.() || {};
|
|
143
|
-
|
|
144
|
-
// 调试日志
|
|
145
|
-
api.logger.info(`栖岛聊天配置: ${JSON.stringify(cfg.channels?.qidao || {})}`);
|
|
160
|
+
gateway: {
|
|
161
|
+
startAccount: async (ctx) => {
|
|
162
|
+
const { account, cfg, runtime, abortSignal } = ctx;
|
|
146
163
|
|
|
147
|
-
|
|
164
|
+
runtime.log?.('🚀 栖岛聊天 gateway.startAccount 被调用!');
|
|
165
|
+
runtime.log?.(`账户信息: ${JSON.stringify(account)}`);
|
|
148
166
|
|
|
149
167
|
if (!account.enabled) {
|
|
150
|
-
|
|
168
|
+
runtime.log?.('栖岛聊天未启用');
|
|
151
169
|
return;
|
|
152
170
|
}
|
|
153
171
|
|
|
154
172
|
if (!account.chatId) {
|
|
155
|
-
|
|
173
|
+
runtime.log?.('栖岛聊天缺少chatId配置');
|
|
156
174
|
return;
|
|
157
175
|
}
|
|
158
176
|
|
|
159
|
-
|
|
177
|
+
runtime.log?.(`连接栖岛聊天 (chatId: ${account.chatId})`);
|
|
160
178
|
|
|
161
179
|
connection = new QidaoChannel({
|
|
162
180
|
serverUrl: account.serverUrl,
|
|
@@ -165,38 +183,127 @@ export default function register(api) {
|
|
|
165
183
|
});
|
|
166
184
|
|
|
167
185
|
connection.on('connect', () => {
|
|
168
|
-
|
|
186
|
+
runtime.log?.('栖岛聊天已连接');
|
|
169
187
|
});
|
|
170
188
|
|
|
171
189
|
connection.on('disconnect', () => {
|
|
172
|
-
|
|
190
|
+
runtime.log?.('栖岛聊天已断开');
|
|
173
191
|
});
|
|
174
192
|
|
|
175
193
|
connection.on('error', (error) => {
|
|
176
|
-
|
|
194
|
+
runtime.error?.(`栖岛聊天错误: ${error.message}`);
|
|
177
195
|
});
|
|
178
196
|
|
|
179
|
-
connection.on('message', (message) => {
|
|
197
|
+
connection.on('message', async (message) => {
|
|
180
198
|
if (message.type === 'new_message') {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
try {
|
|
200
|
+
// 过滤掉机器人自己发送的消息,避免循环
|
|
201
|
+
// 栖岛消息中,senderId=1 是畅小猪,otherUserId=175 是机器人
|
|
202
|
+
if (message.senderId === 175 || message.otherUserId === 1) {
|
|
203
|
+
runtime.log?.(`跳过机器人自己的消息`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
runtime.log?.(`收到栖岛消息: ${message.messageText}`);
|
|
208
|
+
|
|
209
|
+
const core = getQidaoRuntime();
|
|
210
|
+
|
|
211
|
+
const chatId = message.chatId.toString();
|
|
212
|
+
const chatType = message.chatType === 0 ? 'direct' : 'group';
|
|
213
|
+
|
|
214
|
+
// 解析路由信息
|
|
215
|
+
const route = core.channel.routing.resolveAgentRoute({
|
|
216
|
+
cfg,
|
|
217
|
+
channel: 'qidao',
|
|
218
|
+
accountId: account.accountId,
|
|
219
|
+
peer: {
|
|
220
|
+
kind: chatType,
|
|
221
|
+
id: chatId,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// 构建标准消息上下文(参考企业微信插件)
|
|
226
|
+
const ctxPayload = core.channel.reply.finalizeInboundContext({
|
|
227
|
+
Body: message.messageText,
|
|
228
|
+
RawBody: message.messageText,
|
|
229
|
+
CommandBody: message.messageText,
|
|
230
|
+
MessageSid: message.messageId?.toString() || `${Date.now()}`,
|
|
231
|
+
From: chatType === 'group' ? `qidao:group:${chatId}` : `qidao:${message.senderId}`,
|
|
232
|
+
To: `qidao:${chatId}`,
|
|
233
|
+
SenderId: message.senderId.toString(),
|
|
234
|
+
SessionKey: route.sessionKey,
|
|
235
|
+
AccountId: account.accountId,
|
|
236
|
+
ChatType: chatType,
|
|
237
|
+
ConversationLabel: chatType === 'group' ? `group:${chatId}` : `user:${message.senderId}`,
|
|
238
|
+
Timestamp: message.timestamp || Date.now(),
|
|
239
|
+
Provider: 'qidao',
|
|
240
|
+
Surface: 'qidao',
|
|
241
|
+
OriginatingChannel: 'qidao',
|
|
242
|
+
OriginatingTo: `qidao:${chatId}`,
|
|
243
|
+
CommandAuthorized: true,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// 使用 core.channel.reply.dispatchReplyWithBufferedBlockDispatcher 处理消息
|
|
247
|
+
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
248
|
+
ctx: ctxPayload,
|
|
249
|
+
cfg,
|
|
250
|
+
dispatcherOptions: {
|
|
251
|
+
deliver: async (payload, info) => {
|
|
252
|
+
runtime.log?.(`发送回复: ${payload.text.substring(0, 50)}...`);
|
|
253
|
+
|
|
254
|
+
// 通过 connection 发送回复
|
|
255
|
+
if (info.kind === 'final') {
|
|
256
|
+
await connection.sendMessage(message.chatId, payload.text);
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
onError: (err, info) => {
|
|
260
|
+
runtime.error?.(`回复失败 (${info.kind}): ${err.message}`);
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
runtime.log?.('✅ 消息处理完成');
|
|
266
|
+
} catch (error) {
|
|
267
|
+
runtime.error?.(`处理消息失败: ${error.message}`);
|
|
268
|
+
}
|
|
191
269
|
}
|
|
192
270
|
});
|
|
193
271
|
|
|
272
|
+
// 处理中止信号
|
|
273
|
+
if (abortSignal) {
|
|
274
|
+
abortSignal.addEventListener('abort', () => {
|
|
275
|
+
runtime.log?.('栖岛聊天连接被中止');
|
|
276
|
+
if (connection) {
|
|
277
|
+
connection.disconnect();
|
|
278
|
+
connection = null;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
194
283
|
await connection.connect();
|
|
195
284
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
285
|
+
// 返回 Promise,保持连接直到被中止
|
|
286
|
+
return new Promise((resolve) => {
|
|
287
|
+
if (abortSignal) {
|
|
288
|
+
abortSignal.addEventListener('abort', resolve);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export default function register(api) {
|
|
296
|
+
pluginApi = api;
|
|
297
|
+
|
|
298
|
+
// 设置 runtime(参考企业微信插件)
|
|
299
|
+
setQidaoRuntime(api.runtime);
|
|
300
|
+
|
|
301
|
+
api.logger.info('栖岛聊天插件加载中...');
|
|
302
|
+
|
|
303
|
+
api.registerChannel({ plugin: qidaoChannel });
|
|
304
|
+
|
|
305
|
+
// 注册认证命令
|
|
306
|
+
registerAuthCommand(api);
|
|
200
307
|
|
|
201
308
|
api.logger.info('栖岛聊天插件加载完成');
|
|
202
309
|
}
|