qidao-openclaw-plugin 2.0.0-beta.1 → 2.0.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.
package/src/auth-cli.js DELETED
@@ -1,187 +0,0 @@
1
- /**
2
- * 栖岛聊天认证 CLI 命令
3
- */
4
-
5
- import ws from 'ws';
6
- import { spawn } from 'child_process';
7
- import { DeviceFingerprint } from './device-fingerprint.js';
8
-
9
- export function registerAuthCommand(api) {
10
- api.registerCli(
11
- ({ program }) => {
12
- program
13
- .command('qidao-auth')
14
- .description('栖岛聊天认证')
15
- .action(async () => {
16
-
17
- try {
18
- // 创建临时连接到 Server 进行认证
19
- const tempWs = new ws('wss://oc.qidao.chat/ws');
20
-
21
- const chatId = await new Promise((resolve, reject) => {
22
- const timeout = setTimeout(() => {
23
- tempWs.close();
24
- reject(new Error('连接超时'));
25
- }, 10000);
26
-
27
- // 初始化设备指纹
28
- const deviceFP = new DeviceFingerprint();
29
- // console.log('🔍 设备信息:', deviceFP.getDeviceInfo());
30
-
31
- tempWs.on('open', () => {
32
- clearTimeout(timeout);
33
- runtime.log?.('已连接到栖岛认证服务器');
34
-
35
- // 请求生成二维码
36
- tempWs.send(JSON.stringify({ action: 'startAuth' }));
37
- });
38
-
39
- tempWs.on('message', async (data) => {
40
- try {
41
- const message = JSON.parse(data.toString());
42
-
43
- // 兼容Server的响应格式
44
- // 格式1: { id, code: 1, msg, data: { code, qrUrl } }
45
- // 格式2: { action: 'authStarted', code, qrUrl }
46
- if ((message.code === 1 && message.data && message.data.qrUrl) ||
47
- (message.action === 'authStarted')) {
48
- const code = message.data?.code || message.code;
49
- const qrUrl = message.data?.qrUrl || message.qrUrl;
50
-
51
- // 启动本地HTTP服务显示二维码
52
- try {
53
- const { createQRServer } = await import('./qr-server.js');
54
- const qrServerUrl = await createQRServer(qrUrl);
55
-
56
- runtime.log?.(`栖岛认证页面: ${qrServerUrl}`);
57
-
58
- // 打开浏览器显示二维码页面
59
- const openCommand = process.platform === 'win32' ? 'start' :
60
- process.platform === 'darwin' ? 'open' : 'xdg-open';
61
- spawn(openCommand, [qrServerUrl], { shell: true, detached: true });
62
-
63
- } catch (error) {
64
- runtime.error?.(`启动认证服务失败: ${error.message}`);
65
- }
66
-
67
- runtime.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
- // runtime.log?.('扫码成功!');
86
-
87
- // 🔐 生成设备指纹并发送完成认证请求
88
- const deviceFingerprint = deviceFP.generate();
89
-
90
- // 请求完成认证获取 chatId(包含设备指纹)
91
- tempWs.send(JSON.stringify({
92
- action: 'completeAuth',
93
- uid,
94
- code: tempWs._code,
95
- deviceFingerprint: deviceFingerprint // 发送设备指纹
96
- }));
97
-
98
- } else if (status === 'waiting') {
99
- // 继续等待
100
- }
101
-
102
- } else if ((message.code === 1 && message.data && message.data.chatId) ||
103
- (message.action === 'authCompleted')) {
104
- // 清理轮询定时器
105
- if (tempWs._pollInterval) {
106
- clearInterval(tempWs._pollInterval);
107
- }
108
-
109
- const receivedChatId = message.data?.chatId || message.chatId;
110
- const receivedBindingToken = message.data?.bindingToken || message.bindingToken;
111
- const receivedUid = message.data?.uid || message.uid;
112
-
113
- runtime.log?.(`认证完成!`);
114
-
115
- tempWs.close();
116
-
117
- // 关闭二维码服务器
118
- try {
119
- const { closeQRServer } = await import('./qr-server.js');
120
- closeQRServer();
121
- } catch (error) {
122
- // 忽略关闭服务器的错误
123
- }
124
-
125
- resolve({
126
- chatId: receivedChatId,
127
- bindingToken: receivedBindingToken,
128
- uid: receivedUid
129
- });
130
-
131
- } else if (message.code === 0 || message.action === 'error') {
132
- if (tempWs._pollInterval) {
133
- clearInterval(tempWs._pollInterval);
134
- }
135
- tempWs.close();
136
- const errorMsg = message.msg || message.message || '认证失败';
137
- reject(new Error(errorMsg));
138
- }
139
- } catch (err) {
140
- console.error('处理消息失败:', err);
141
- reject(err);
142
- }
143
- });
144
-
145
- tempWs.on('error', (error) => {
146
- clearTimeout(timeout);
147
- if (tempWs._pollInterval) {
148
- clearInterval(tempWs._pollInterval);
149
- }
150
- reject(error);
151
- });
152
- });
153
-
154
- // 保存配置
155
- const { execSync } = await import('child_process');
156
- runtime.log?.('正在保存配置...');
157
-
158
- // 🔐 保存设备绑定配置
159
- let configCmd;
160
- if (chatId.bindingToken) {
161
- configCmd = `openclaw config set channels.qidao.chatId ${chatId.chatId} && openclaw config set channels.qidao.bindingToken "${chatId.bindingToken}" && openclaw config set channels.qidao.enabled true`;
162
- } else {
163
- throw new Error('认证失败:未获取到设备Token');
164
- }
165
-
166
- execSync(configCmd, { stdio: 'inherit' });
167
- runtime.log?.('配置保存成功!');
168
-
169
- // 执行重启命令后直接退出
170
- try {
171
- execSync('openclaw gateway restart');
172
- } catch (error) {
173
- // 忽略重启错误,配置已经保存成功
174
- }
175
-
176
- // 直接退出,不再继续
177
- process.exit(0);
178
-
179
- } catch (error) {
180
- console.error(`认证失败: ${error.message}`);
181
- process.exit(1);
182
- }
183
- });
184
- },
185
- { commands: ['qidao-auth'] }
186
- );
187
- }
package/src/config.js DELETED
@@ -1,116 +0,0 @@
1
- /**
2
- * 栖岛插件配置文件
3
- * 统一管理所有API地址和配置项
4
- */
5
-
6
- export const QIDAO_CONFIG = {
7
- // 服务器地址配置
8
- SERVER: {
9
- // 生产环境
10
- PRODUCTION: {
11
- WS_URL: 'wss://oc.qidao.chat/ws',
12
- HTTP_URL: 'https://oc.qidao.chat',
13
- HEALTH_CHECK: 'https://oc.qidao.chat/health'
14
- },
15
-
16
- // 开发环境
17
- DEVELOPMENT: {
18
- WS_URL: 'wss://oc.qidao.chat/ws',
19
- HTTP_URL: 'https://oc.qidao.chat',
20
- HEALTH_CHECK: 'https://oc.qidao.chat/health'
21
- }
22
- },
23
-
24
- // 栖岛官方API
25
- QIDAO_API: {
26
- BASE_URL: 'https://api.qidao.tvcloud.top',
27
- WS_CONNECT: 'wss://api.qidao.tvcloud.top/ws/connect',
28
- ENDPOINTS: {
29
- SEND_MESSAGE: '/websocket/im/sendMessage',
30
- ONLINE_USERS: '/websocket/im/chatRoomOnlineUsers',
31
- USER_STATUS: '/websocket/im/userOnlineStatus',
32
- CREATE_CHAT: '/websocket/im/createChat',
33
- IM_STATS: '/websocket/im/stats'
34
- }
35
- },
36
-
37
- // 默认配置
38
- DEFAULTS: {
39
- RECONNECT_INTERVAL: 5000,
40
- REQUEST_TIMEOUT: 30000,
41
- MAX_RECONNECT_ATTEMPTS: 10,
42
- DEBUG: false,
43
- AUTO_CONNECT: true
44
- },
45
-
46
- // 消息类型
47
- MESSAGE_TYPES: {
48
- TEXT: 0,
49
- IMAGE: 1,
50
- FILE: 2,
51
- SYSTEM: 99
52
- },
53
-
54
- // 聊天类型
55
- CHAT_TYPES: {
56
- PRIVATE: 0,
57
- GROUP: 1
58
- },
59
-
60
- // 事件类型
61
- EVENTS: {
62
- CONNECTED: 'connected',
63
- DISCONNECTED: 'disconnected',
64
- MESSAGE: 'message',
65
- MESSAGE_SENT: 'messageSent',
66
- MESSAGE_FAILED: 'messageFailed',
67
- CHAT_CREATED: 'chatCreated',
68
- ERROR: 'error',
69
- RECONNECTING: 'reconnecting',
70
- RECONNECTED: 'reconnected'
71
- }
72
- };
73
-
74
- /**
75
- * 获取当前环境配置
76
- */
77
- export function getCurrentConfig(env = 'production') {
78
- const environment = env.toLowerCase();
79
-
80
- if (environment === 'development' || environment === 'dev') {
81
- return QIDAO_CONFIG.SERVER.DEVELOPMENT;
82
- }
83
-
84
- return QIDAO_CONFIG.SERVER.PRODUCTION;
85
- }
86
-
87
- /**
88
- * 获取完整的WebSocket URL
89
- */
90
- export function getWebSocketUrl(env = 'production') {
91
- return getCurrentConfig(env).WS_URL;
92
- }
93
-
94
- /**
95
- * 获取HTTP API基础URL
96
- */
97
- export function getHttpUrl(env = 'production') {
98
- return getCurrentConfig(env).HTTP_URL;
99
- }
100
-
101
- /**
102
- * 获取健康检查URL
103
- */
104
- export function getHealthCheckUrl(env = 'production') {
105
- return getCurrentConfig(env).HEALTH_CHECK;
106
- }
107
-
108
- /**
109
- * 构建API端点URL
110
- */
111
- export function buildApiUrl(endpoint, env = 'production') {
112
- const baseUrl = getHttpUrl(env);
113
- return `${baseUrl}/api${endpoint}`;
114
- }
115
-
116
- export default QIDAO_CONFIG;