claw_messenger 0.0.1
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/README.md +111 -0
- package/bin/auto-init.js +98 -0
- package/bin/dm-bridge.js +12 -0
- package/bin/install.js +217 -0
- package/bin/setup.js +160 -0
- package/bridge-runner.ts +324 -0
- package/dist/bridge-runner.d.ts +2 -0
- package/dist/bridge-runner.d.ts.map +1 -0
- package/dist/bridge-runner.js +268 -0
- package/dist/bridge-runner.js.map +1 -0
- package/dist/src/auto-register.d.ts +2 -0
- package/dist/src/auto-register.d.ts.map +1 -0
- package/dist/src/auto-register.js +82 -0
- package/dist/src/auto-register.js.map +1 -0
- package/dist/src/env-polyfill.d.ts +8 -0
- package/dist/src/env-polyfill.d.ts.map +1 -0
- package/dist/src/env-polyfill.js +101 -0
- package/dist/src/env-polyfill.js.map +1 -0
- package/dist/src/index.d.ts +36 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +75 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/plugin-entry.d.ts +9 -0
- package/dist/src/plugin-entry.d.ts.map +1 -0
- package/dist/src/plugin-entry.js +174 -0
- package/dist/src/plugin-entry.js.map +1 -0
- package/dist/src/rongcloud-client.d.ts +21 -0
- package/dist/src/rongcloud-client.d.ts.map +1 -0
- package/dist/src/rongcloud-client.js +87 -0
- package/dist/src/rongcloud-client.js.map +1 -0
- package/dist/test-bridge.js +81 -0
- package/dist/test-connection.js +65 -0
- package/dist/test-mock.js +72 -0
- package/openclaw.plugin.json +24 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# claw_messenger
|
|
2
|
+
|
|
3
|
+
OpenClaw 融云 IM 桥接插件,让 OpenClaw 直接连接融云收发消息。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
### 首次安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx claw_messenger@latest
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
安装过程:
|
|
14
|
+
1. 提示输入节点昵称
|
|
15
|
+
2. 自动复制插件文件
|
|
16
|
+
3. **使用淘宝镜像源安装依赖** (`https://registry.npmmirror.com`)
|
|
17
|
+
4. 自动启用插件
|
|
18
|
+
5. 自动注册节点
|
|
19
|
+
|
|
20
|
+
### 更新安装
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx claw_messenger@latest
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
如果已有配置,会显示:
|
|
27
|
+
```
|
|
28
|
+
✅ 检测到已有配置:
|
|
29
|
+
节点 ID: claw_xxx
|
|
30
|
+
昵称:xxx
|
|
31
|
+
|
|
32
|
+
是否重新注册新节点?(y/N):
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
直接按回车(默认 N)即可保留原有配置,无需重新输入昵称。
|
|
36
|
+
|
|
37
|
+
### 手动重新配置
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx claw-bridge-setup
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 使用
|
|
44
|
+
|
|
45
|
+
安装完成后,重启 OpenClaw 网关:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
openclaw gateway
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
插件会自动:
|
|
52
|
+
- ✅ 连接融云 IM
|
|
53
|
+
- ✅ 监听消息
|
|
54
|
+
- ✅ 调用 OpenClaw AI 处理
|
|
55
|
+
- ✅ 发送回复
|
|
56
|
+
|
|
57
|
+
### 在应用内聊天
|
|
58
|
+
|
|
59
|
+
直接在融云 App 中发送消息,插件会自动回复 AI 生成的内容。
|
|
60
|
+
|
|
61
|
+
## 配置项
|
|
62
|
+
|
|
63
|
+
| 配置项 | 说明 | 默认值 |
|
|
64
|
+
|--------|------|--------|
|
|
65
|
+
| `nodeName` | 节点昵称 | 安装时输入 |
|
|
66
|
+
|
|
67
|
+
## 故障排查
|
|
68
|
+
|
|
69
|
+
### 查看插件状态
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
openclaw plugins list
|
|
73
|
+
openclaw plugins inspect claw_messenger
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 查看日志
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
openclaw logs
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 依赖安装失败
|
|
83
|
+
|
|
84
|
+
如果淘宝镜像源不可用,可以手动安装:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cd ~/.openclaw/extensions/claw_messenger
|
|
88
|
+
npm install --legacy-peer-deps --registry=https://registry.npmmirror.com
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 重置节点
|
|
92
|
+
|
|
93
|
+
删除配置文件可重新注册节点:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Windows
|
|
97
|
+
del %USERPROFILE%\.claw-bridge\config.json
|
|
98
|
+
|
|
99
|
+
# macOS/Linux
|
|
100
|
+
rm ~/.claw-bridge/config.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
然后运行:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx claw-bridge-setup
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 许可证
|
|
110
|
+
|
|
111
|
+
MIT
|
package/bin/auto-init.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* claw_messenger - 自动初始化
|
|
5
|
+
* 无需用户交互,自动生成配置
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import * as crypto from 'crypto';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
import axios from 'axios';
|
|
13
|
+
|
|
14
|
+
const SERVER_URL = process.env.DM_SERVER_URL || 'https://newsradar.dreamdt.cn/im';
|
|
15
|
+
const CONFIG_DIR = path.join(os.homedir(), '.claw-bridge');
|
|
16
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
17
|
+
|
|
18
|
+
function generateNodeId() {
|
|
19
|
+
const random = crypto.randomBytes(3).toString('hex');
|
|
20
|
+
return `claw_${random}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function loadConfig() {
|
|
24
|
+
try {
|
|
25
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
26
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
27
|
+
return JSON.parse(content);
|
|
28
|
+
}
|
|
29
|
+
} catch {}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function saveConfig(config) {
|
|
34
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
35
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function registerNode(nodeName) {
|
|
41
|
+
const nodeId = generateNodeId();
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const resp = await axios.post(`${SERVER_URL}/api/claw/register`, {
|
|
45
|
+
node_id: nodeId,
|
|
46
|
+
name: nodeName,
|
|
47
|
+
}, { timeout: 10000 });
|
|
48
|
+
|
|
49
|
+
if (resp.data?.code === 200 || resp.data?.code === 409) {
|
|
50
|
+
const tokenResp = await axios.get(`${SERVER_URL}/api/claw/token/${nodeId}`, { timeout: 10000 });
|
|
51
|
+
|
|
52
|
+
if (tokenResp.data?.code === 200) {
|
|
53
|
+
return {
|
|
54
|
+
nodeId,
|
|
55
|
+
token: tokenResp.data.data.token,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return null;
|
|
61
|
+
} catch (err) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function main() {
|
|
67
|
+
// 检查已有配置
|
|
68
|
+
let config = loadConfig();
|
|
69
|
+
|
|
70
|
+
if (config) {
|
|
71
|
+
// 已有配置,跳过
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 自动生成节点名
|
|
76
|
+
const nodeName = `OpenClaw-${crypto.randomBytes(2).toString('hex')}`;
|
|
77
|
+
|
|
78
|
+
// 注册节点
|
|
79
|
+
const result = await registerNode(nodeName);
|
|
80
|
+
|
|
81
|
+
if (!result) {
|
|
82
|
+
throw new Error('自动注册失败');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
config = {
|
|
86
|
+
nodeId: result.nodeId,
|
|
87
|
+
nodeName: nodeName,
|
|
88
|
+
token: result.token,
|
|
89
|
+
createdAt: new Date().toISOString(),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
saveConfig(config);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
main().catch(err => {
|
|
96
|
+
// 静默失败,不影响安装
|
|
97
|
+
process.exit(0);
|
|
98
|
+
});
|
package/bin/dm-bridge.js
ADDED
package/bin/install.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* claw_messenger - OpenClaw 插件安装脚本
|
|
5
|
+
* 首次安装需输入昵称,更新时自动跳过
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { existsSync, mkdirSync, rmSync, cpSync, writeFileSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import * as readline from 'readline';
|
|
14
|
+
import * as crypto from 'crypto';
|
|
15
|
+
import axios from 'axios';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import * as os from 'os';
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const PACKAGE_ROOT = join(__dirname, '..');
|
|
21
|
+
|
|
22
|
+
const SERVER_URL = process.env.DM_SERVER_URL || 'https://newsradar.dreamdt.cn/im';
|
|
23
|
+
const CONFIG_DIR = path.join(os.homedir(), '.claw-bridge');
|
|
24
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
25
|
+
|
|
26
|
+
// 获取 OpenClaw extensions 目录
|
|
27
|
+
function getExtensionsDir() {
|
|
28
|
+
const profile = process.env.OPENCLAW_PROFILE || '';
|
|
29
|
+
const baseDir = profile
|
|
30
|
+
? join(homedir(), `.openclaw-${profile}`)
|
|
31
|
+
: join(homedir(), '.openclaw');
|
|
32
|
+
|
|
33
|
+
const extensionsDir = join(baseDir, 'extensions', 'claw_messenger');
|
|
34
|
+
|
|
35
|
+
if (existsSync(extensionsDir)) {
|
|
36
|
+
try {
|
|
37
|
+
rmSync(extensionsDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
38
|
+
} catch (e) {
|
|
39
|
+
// 忽略
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!existsSync(extensionsDir)) {
|
|
44
|
+
mkdirSync(extensionsDir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return extensionsDir;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function generateNodeId() {
|
|
51
|
+
const random = crypto.randomBytes(3).toString('hex');
|
|
52
|
+
return `claw_${random}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function loadConfig() {
|
|
56
|
+
try {
|
|
57
|
+
if (existsSync(CONFIG_FILE)) {
|
|
58
|
+
const content = readFileSync(CONFIG_FILE, 'utf-8');
|
|
59
|
+
return JSON.parse(content);
|
|
60
|
+
}
|
|
61
|
+
} catch {}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function registerNode(nodeName) {
|
|
66
|
+
const nodeId = generateNodeId();
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const resp = await axios.post(`${SERVER_URL}/api/claw/register`, {
|
|
70
|
+
node_id: nodeId,
|
|
71
|
+
name: nodeName,
|
|
72
|
+
}, { timeout: 10000 });
|
|
73
|
+
|
|
74
|
+
if (resp.data?.code === 200 || resp.data?.code === 409) {
|
|
75
|
+
const tokenResp = await axios.get(`${SERVER_URL}/api/claw/token/${nodeId}`, { timeout: 10000 });
|
|
76
|
+
|
|
77
|
+
if (tokenResp.data?.code === 200) {
|
|
78
|
+
return {
|
|
79
|
+
nodeId,
|
|
80
|
+
token: tokenResp.data.data.token,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function main() {
|
|
92
|
+
const rl = readline.createInterface({
|
|
93
|
+
input: process.stdin,
|
|
94
|
+
output: process.stdout
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const question = (prompt) => new Promise(resolve => rl.question(prompt, resolve));
|
|
98
|
+
|
|
99
|
+
console.log('🦞 claw_messenger - 安装\n');
|
|
100
|
+
|
|
101
|
+
// 检查已有配置
|
|
102
|
+
const existingConfig = loadConfig();
|
|
103
|
+
|
|
104
|
+
let nodeName = null;
|
|
105
|
+
let config = existingConfig;
|
|
106
|
+
|
|
107
|
+
if (existingConfig) {
|
|
108
|
+
console.log(`✅ 检测到已有配置:`);
|
|
109
|
+
console.log(` 节点 ID: ${existingConfig.nodeId}`);
|
|
110
|
+
console.log(` 昵称:${existingConfig.nodeName}`);
|
|
111
|
+
|
|
112
|
+
const update = await question('\n是否重新注册新节点?(y/N): ');
|
|
113
|
+
if (update.toLowerCase() === 'y') {
|
|
114
|
+
nodeName = await question('请输入新节点昵称 (如:小助手): ');
|
|
115
|
+
config = null;
|
|
116
|
+
} else {
|
|
117
|
+
console.log('\n使用已有配置');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!config) {
|
|
122
|
+
if (!nodeName) {
|
|
123
|
+
nodeName = await question('请输入节点昵称 (如:小助手): ');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!nodeName || !nodeName.trim()) {
|
|
127
|
+
rl.close();
|
|
128
|
+
console.error('❌ 昵称不能为空');
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
rl.close();
|
|
134
|
+
|
|
135
|
+
const extensionsDir = getExtensionsDir();
|
|
136
|
+
console.log(`\n📦 安装位置:${extensionsDir}`);
|
|
137
|
+
|
|
138
|
+
// 复制插件文件
|
|
139
|
+
console.log('📦 复制文件...');
|
|
140
|
+
const filesToCopy = ['dist', 'openclaw.plugin.json', 'package.json', 'README.md'];
|
|
141
|
+
|
|
142
|
+
for (const file of filesToCopy) {
|
|
143
|
+
const src = join(PACKAGE_ROOT, file);
|
|
144
|
+
const dest = join(extensionsDir, file);
|
|
145
|
+
if (existsSync(src)) {
|
|
146
|
+
cpSync(src, dest, { recursive: true, force: true });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
console.log(' ✅ 文件复制完成');
|
|
150
|
+
|
|
151
|
+
// 安装依赖(使用淘宝镜像,静默快速)
|
|
152
|
+
console.log('📦 安装依赖...');
|
|
153
|
+
try {
|
|
154
|
+
execSync('npm install --legacy-peer-deps --registry=https://registry.npmmirror.com --prefer-offline --no-audit --no-fund --silent', {
|
|
155
|
+
cwd: extensionsDir,
|
|
156
|
+
stdio: 'pipe',
|
|
157
|
+
});
|
|
158
|
+
console.log(' ✅ 依赖安装完成');
|
|
159
|
+
} catch (e) {
|
|
160
|
+
console.log(' ⚠️ 依赖将在后台安装');
|
|
161
|
+
execSync('start /b npm install --legacy-peer-deps --registry=https://registry.npmmirror.com --silent', {
|
|
162
|
+
cwd: extensionsDir,
|
|
163
|
+
stdio: 'ignore',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 启用插件
|
|
168
|
+
console.log('🔌 启用插件...');
|
|
169
|
+
try {
|
|
170
|
+
execSync('openclaw plugins enable claw_messenger', {
|
|
171
|
+
stdio: 'pipe',
|
|
172
|
+
});
|
|
173
|
+
console.log(' ✅ 插件已启用');
|
|
174
|
+
} catch (e) {
|
|
175
|
+
// 忽略
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 注册节点(仅首次或用户选择重新注册)
|
|
179
|
+
if (!existingConfig || !config) {
|
|
180
|
+
console.log('🚀 注册节点...');
|
|
181
|
+
const result = await registerNode(nodeName.trim());
|
|
182
|
+
|
|
183
|
+
if (!result) {
|
|
184
|
+
console.log(' ⚠️ 注册失败,稍后可手动运行:npx dm-bridge-setup');
|
|
185
|
+
} else {
|
|
186
|
+
// 保存配置
|
|
187
|
+
config = {
|
|
188
|
+
nodeId: result.nodeId,
|
|
189
|
+
nodeName: nodeName.trim(),
|
|
190
|
+
token: result.token,
|
|
191
|
+
createdAt: new Date().toISOString(),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
195
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
196
|
+
}
|
|
197
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
198
|
+
|
|
199
|
+
console.log(' ✅ 节点已注册');
|
|
200
|
+
console.log(` 节点 ID: ${result.nodeId}`);
|
|
201
|
+
console.log(` 昵称:${nodeName.trim()}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
console.log('\n✅ 安装完成!');
|
|
206
|
+
console.log('\n下一步:');
|
|
207
|
+
console.log(' 1. 重启 OpenClaw: openclaw gateway');
|
|
208
|
+
console.log(' 2. 在应用内发送消息测试');
|
|
209
|
+
console.log('\n配置:');
|
|
210
|
+
console.log(' 如需更改节点昵称:npx claw-bridge-setup');
|
|
211
|
+
console.log('\nGitHub: https://github.com/your-org/claw_messenger');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
main().catch(err => {
|
|
215
|
+
console.error('❌ 安装失败:', err.message);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
});
|
package/bin/setup.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* claw_messenger - 手动设置
|
|
5
|
+
* 用于重新配置节点昵称
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as readline from 'readline';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as crypto from 'crypto';
|
|
12
|
+
import * as os from 'os';
|
|
13
|
+
import axios from 'axios';
|
|
14
|
+
import qrcode from 'qrcode-terminal';
|
|
15
|
+
|
|
16
|
+
const SERVER_URL = process.env.DM_SERVER_URL || 'https://newsradar.dreamdt.cn/im';
|
|
17
|
+
const CONFIG_DIR = path.join(os.homedir(), '.claw-bridge');
|
|
18
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
19
|
+
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const question = (prompt) => new Promise(resolve => rl.question(prompt, resolve));
|
|
26
|
+
|
|
27
|
+
function generateNodeId() {
|
|
28
|
+
const random = crypto.randomBytes(3).toString('hex');
|
|
29
|
+
return `claw_${random}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function loadConfig() {
|
|
33
|
+
try {
|
|
34
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
35
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
36
|
+
return JSON.parse(content);
|
|
37
|
+
}
|
|
38
|
+
} catch {}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function saveConfig(config) {
|
|
43
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
44
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function registerNode(nodeName) {
|
|
50
|
+
const nodeId = generateNodeId();
|
|
51
|
+
console.log(`\n正在注册节点:${nodeId}...`);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const resp = await axios.post(`${SERVER_URL}/api/claw/register`, {
|
|
55
|
+
node_id: nodeId,
|
|
56
|
+
name: nodeName,
|
|
57
|
+
}, { timeout: 10000 });
|
|
58
|
+
|
|
59
|
+
if (resp.data?.code === 200 || resp.data?.code === 409) {
|
|
60
|
+
const tokenResp = await axios.get(`${SERVER_URL}/api/claw/token/${nodeId}`, { timeout: 10000 });
|
|
61
|
+
|
|
62
|
+
if (tokenResp.data?.code === 200) {
|
|
63
|
+
return {
|
|
64
|
+
nodeId,
|
|
65
|
+
token: tokenResp.data.data.token,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.error('注册失败:', resp.data?.message || '未知错误');
|
|
71
|
+
return null;
|
|
72
|
+
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error('注册异常:', err.message);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function showBindQRCode(nodeId, nodeName) {
|
|
80
|
+
console.log('\n========================================');
|
|
81
|
+
console.log(' 请使用 App 扫码绑定');
|
|
82
|
+
console.log('========================================\n');
|
|
83
|
+
|
|
84
|
+
const bindData = JSON.stringify({
|
|
85
|
+
type: 'bind_openclaw',
|
|
86
|
+
node_id: nodeId,
|
|
87
|
+
name: nodeName,
|
|
88
|
+
timestamp: Date.now(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log('绑定数据:', bindData);
|
|
92
|
+
console.log('\n');
|
|
93
|
+
|
|
94
|
+
qrcode.generate(bindData, { small: true });
|
|
95
|
+
|
|
96
|
+
console.log('\n');
|
|
97
|
+
console.log('节点 ID:', nodeId);
|
|
98
|
+
console.log('提示:打开 App -> AI 助手 -> 扫码添加');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function main() {
|
|
102
|
+
console.log('🦞 claw_messenger - 配置\n');
|
|
103
|
+
|
|
104
|
+
let config = loadConfig();
|
|
105
|
+
|
|
106
|
+
if (config) {
|
|
107
|
+
console.log('当前配置:');
|
|
108
|
+
console.log(` 节点 ID: ${config.nodeId}`);
|
|
109
|
+
console.log(` 节点名称:${config.nodeName}`);
|
|
110
|
+
|
|
111
|
+
const reset = await question('\n是否重新注册?(y/N): ');
|
|
112
|
+
if (reset.toLowerCase() !== 'y') {
|
|
113
|
+
rl.close();
|
|
114
|
+
console.log('\n✅ 配置未更改');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log('\n========================================');
|
|
120
|
+
console.log(' 节点注册');
|
|
121
|
+
console.log('========================================\n');
|
|
122
|
+
|
|
123
|
+
const nodeName = await question('请输入节点昵称 (如:我的龙虾): ');
|
|
124
|
+
|
|
125
|
+
if (!nodeName.trim()) {
|
|
126
|
+
console.error('昵称不能为空');
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const result = await registerNode(nodeName.trim());
|
|
131
|
+
|
|
132
|
+
if (!result) {
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
config = {
|
|
137
|
+
nodeId: result.nodeId,
|
|
138
|
+
nodeName: nodeName.trim(),
|
|
139
|
+
token: result.token,
|
|
140
|
+
createdAt: new Date().toISOString(),
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
saveConfig(config);
|
|
144
|
+
|
|
145
|
+
console.log('\n========================================');
|
|
146
|
+
console.log(' 注册成功!');
|
|
147
|
+
console.log(` 节点 ID: ${result.nodeId}`);
|
|
148
|
+
console.log(` 节点名称:${nodeName.trim()}`);
|
|
149
|
+
console.log('========================================\n');
|
|
150
|
+
|
|
151
|
+
await showBindQRCode(result.nodeId, nodeName.trim());
|
|
152
|
+
|
|
153
|
+
rl.close();
|
|
154
|
+
console.log('\n✅ 配置完成!重启 OpenClaw 后生效');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
main().catch(err => {
|
|
158
|
+
console.error('配置失败:', err);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
});
|