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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +93 -86
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qidao-openclaw-plugin",
3
- "version": "1.0.9",
3
+ "version": "1.1.3",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "description": "OpenClaw 栖岛聊天 Channel 插件 - 连接到栖岛聊天服务",
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
- outbound: {
54
- deliveryMode: 'direct',
55
-
56
- // 发送文本消息
57
- sendText: async ({ text, accountId, chatId }) => {
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
- if (!connection || !connection.isConnected()) {
61
- return {
62
- ok: false,
63
- error: '未连接到栖岛服务'
64
- };
65
- }
56
+ const chatId = await prompter.text({
57
+ message: '请输入栖岛 Chat ID:',
58
+ default: defaultAccount.chatId?.toString(),
59
+ });
66
60
 
67
- if (!chatId) {
68
- return {
69
- ok: false,
70
- error: '未指定chatId'
71
- };
72
- }
61
+ const userId = await prompter.text({
62
+ message: '请输入栖岛 User ID (可选):',
63
+ default: defaultAccount.userId?.toString() || '',
64
+ });
73
65
 
74
- try {
75
- await connection.sendMessage(parseInt(chatId), text);
76
- return { ok: true };
77
- } catch (error) {
78
- return {
79
- ok: false,
80
- error: error.message
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.sendImageMessage(parseInt(chatId), url);
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
- return;
141
+ continue;
133
142
  }
134
143
 
135
144
  if (!accountConfig.chatId) {
136
145
  api.logger.warn(`栖岛账户 ${accountId} 缺少chatId配置`);
137
- return;
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
- const connection = new QidaoChannel({
146
- serverUrl,
147
- chatId: accountConfig.chatId,
148
- userId: accountConfig.userId,
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
- // 将栖岛消息转换为OpenClaw消息格式
169
- if (message.type === 'new_message') {
170
- api.ingestMessage({
171
- channelId: 'qidao',
172
- accountId: accountId,
173
- senderId: message.senderId.toString(),
174
- senderName: message.senderName,
175
- text: message.messageText,
176
- timestamp: message.timestamp,
177
- chatType: message.chatType === 0 ? 'direct' : 'group',
178
- chatId: message.chatId.toString(),
179
- });
180
- }
181
- });
182
-
183
- // 连接到服务器
184
- connection.connect().catch((error) => {
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
  }