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 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
@@ -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
+ });
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * DM Bridge CLI 入口
5
+ */
6
+
7
+ const path = require('path');
8
+
9
+ // 使用编译后的 JS 文件
10
+ const runnerPath = path.resolve(__dirname, '../dist/bridge-runner.js');
11
+
12
+ require(runnerPath);
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
+ });