@lingyao037/openclaw-lingyao-cli 0.3.1 → 0.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.
Files changed (2) hide show
  1. package/cli.mjs +98 -86
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * Lingyao Plugin One-Line Installer
4
4
  *
5
- * 一行命令安装灵尧 Channel Plugin 到 OpenClaw
5
+ * 一行命令安装灵爻 Channel Plugin 到 OpenClaw
6
6
  *
7
7
  * 使用方法:
8
8
  * npx -y @lingyao/openclaw-lingyao-cli install
@@ -27,9 +27,10 @@ const CYAN = '\x1b[36m';
27
27
  const NC = '\x1b[0m';
28
28
 
29
29
  class LingyaoInstaller {
30
- constructor(customPath = null) {
30
+ constructor(customPath = null, skipDeps = true) {
31
31
  this.openclawPath = null;
32
32
  this.customPath = customPath;
33
+ this.skipDeps = skipDeps;
33
34
  this.pluginName = '@lingyao/openclaw-lingyao-cli';
34
35
  this.channelId = 'lingyao';
35
36
  }
@@ -79,10 +80,54 @@ class LingyaoInstaller {
79
80
  }
80
81
  }
81
82
 
83
+ getHomeCandidates() {
84
+ const values = [
85
+ process.env.HOME,
86
+ process.env.USERPROFILE,
87
+ process.env.LOCALAPPDATA,
88
+ process.env.APPDATA
89
+ ].filter((value, index, array) => typeof value === 'string' && value.length > 0 && array.indexOf(value) === index);
90
+
91
+ return values;
92
+ }
93
+
94
+ getOpenClawSearchPaths() {
95
+ const candidates = [];
96
+ for (const home of this.getHomeCandidates()) {
97
+ candidates.push(join(home, '.openclaw'));
98
+ candidates.push(join(home, 'openclaw'));
99
+ candidates.push(join(home, 'Dev', 'openclaw'));
100
+ }
101
+
102
+ candidates.push('/usr/local/lib/openclaw');
103
+ candidates.push('./openclaw');
104
+
105
+ return candidates.filter((value, index, array) => array.indexOf(value) === index);
106
+ }
107
+
108
+ getCommandPathCandidates() {
109
+ const commands = process.platform === 'win32'
110
+ ? ['where openclaw']
111
+ : ['command -v openclaw', 'which openclaw'];
112
+
113
+ for (const command of commands) {
114
+ try {
115
+ const output = execSync(command, { encoding: 'utf-8' }).trim();
116
+ if (output) {
117
+ return output.split(/\r?\n/).filter(Boolean);
118
+ }
119
+ } catch {
120
+ // Ignore and try next resolver.
121
+ }
122
+ }
123
+
124
+ return [];
125
+ }
126
+
82
127
  // 检查 OpenClaw 是否安装
83
128
  checkOpenClaw() {
84
129
  this.log('\n═══════════════════════════════════════════════════', CYAN);
85
- this.log(' 灵尧 (Lingyao) Plugin 安装器', CYAN);
130
+ this.log(' 灵爻 (Lingyao) Plugin 安装器', CYAN);
86
131
  this.log('═══════════════════════════════════════════════════\n', CYAN);
87
132
 
88
133
  // 检查 OpenClaw 命令
@@ -114,60 +159,12 @@ class LingyaoInstaller {
114
159
  }
115
160
  }
116
161
 
117
- // 使用 which/command -v 查找 OpenClaw 命令
118
- try {
119
- let openclawPath = null;
120
-
121
- // 尝试 command -v (POSIX 标准)
122
- try {
123
- openclawPath = execSync('command -v openclaw', { encoding: 'utf-8' }).trim();
124
- } catch {
125
- // 降级到 which
126
- try {
127
- openclawPath = execSync('which openclaw', { encoding: 'utf-8' }).trim();
128
- } catch {
129
- // 命令不存在,继续手动搜索
130
- }
131
- }
132
-
133
- if (openclawPath) {
134
- this.info(`找到 openclaw 命令: ${openclawPath}`);
135
-
136
- // 尝试从命令路径推导项目目录
137
- // npm 全局安装: ~/.nvm/versions/node/vX.X.X/bin/openclaw
138
- // 项目目录通常在: ~/.openclaw 或 ~/openclaw
139
- const searchPaths = [
140
- process.env.HOME ? `${process.env.HOME}/.openclaw` : null,
141
- process.env.HOME ? `${process.env.HOME}/openclaw` : null,
142
- process.env.HOME ? `${process.env.HOME}/Dev/openclaw` : null,
143
- '/usr/local/lib/openclaw',
144
- './openclaw'
145
- ].filter(p => p !== null);
146
-
147
- for (const path of searchPaths) {
148
- if (existsSync(path)) {
149
- if (existsSync(join(path, 'openclaw.json')) ||
150
- existsSync(join(path, 'config.json'))) {
151
- this.openclawPath = path;
152
- this.success(`找到 OpenClaw: ${path}`);
153
- return path;
154
- }
155
- }
156
- }
157
- }
158
- } catch (error) {
159
- // 出错时继续手动搜索
162
+ const commandPaths = this.getCommandPathCandidates();
163
+ if (commandPaths.length > 0) {
164
+ this.info(`找到 openclaw 命令: ${commandPaths[0]}`);
160
165
  }
161
166
 
162
- // 手动搜索(降级方案)
163
- const fallbackPaths = [
164
- process.env.HOME ? `${process.env.HOME}/openclaw` : null,
165
- process.env.HOME ? `${process.env.HOME}/Dev/openclaw` : null,
166
- '/usr/local/lib/openclaw',
167
- './openclaw'
168
- ].filter(p => p !== null);
169
-
170
- for (const path of fallbackPaths) {
167
+ for (const path of this.getOpenClawSearchPaths()) {
171
168
  if (existsSync(path)) {
172
169
  if (existsSync(join(path, 'openclaw.json')) ||
173
170
  existsSync(join(path, 'config.json'))) {
@@ -183,20 +180,8 @@ class LingyaoInstaller {
183
180
 
184
181
  // 安装插件
185
182
  installPlugin() {
186
- this.log('\n正在安装灵尧插件...');
187
-
188
- // 使用 OpenClaw CLI 安装插件
189
- const result = this.exec('openclaw', ['plugins', 'install', '.'], {
190
- cwd: __dirname
191
- });
192
-
193
- if (result.success) {
194
- this.success('插件安装成功');
195
- return true;
196
- }
197
-
198
- // 如果 CLI 安装失败,尝试手动复制到本地 OpenClaw
199
- this.warn('CLI 安装失败,尝试手动安装...');
183
+ this.log('\n正在安装灵爻插件...');
184
+ this.info('使用兼容安装模式,直接部署插件文件到 OpenClaw 目录');
200
185
  return this.manualInstall();
201
186
  }
202
187
 
@@ -222,12 +207,11 @@ class LingyaoInstaller {
222
207
 
223
208
  // 复制所有必要的文件
224
209
  const filesToCopy = [
225
- 'index.ts',
210
+ 'dist',
226
211
  'openclaw.plugin.json',
227
212
  'package.json',
228
- 'tsconfig.json',
229
- 'tsup.config.ts',
230
- 'src/'
213
+ 'package-lock.json',
214
+ 'README.md'
231
215
  ];
232
216
 
233
217
  for (const file of filesToCopy) {
@@ -242,6 +226,23 @@ class LingyaoInstaller {
242
226
  }
243
227
  }
244
228
 
229
+ // 从 npx/npm 临时目录一起复制运行时依赖,避免目标 Gateway 再执行一次安装。
230
+ // 注意:默认不复制 node_modules,因为插件依赖(axios/ws/zod)已在目标 OpenClaw 环境中可用。
231
+ // 如遇特殊情况需强制复制依赖,可传入 --with-deps 参数。
232
+ const runtimeModulesPath = join(__dirname, 'node_modules');
233
+ if (existsSync(runtimeModulesPath) && statSync(runtimeModulesPath).isDirectory()) {
234
+ if (this.skipDeps) {
235
+ this.info('跳过复制 node_modules (默认行为,使用目标环境已有依赖)');
236
+ } else {
237
+ this.log('复制运行时依赖...');
238
+ this.copyDirectory(runtimeModulesPath, join(targetDir, 'node_modules'));
239
+ }
240
+ } else {
241
+ if (!this.skipDeps) {
242
+ this.warn('未找到本地 node_modules,目标 OpenClaw 可能仍需自行安装依赖');
243
+ }
244
+ }
245
+
245
246
  this.success('插件文件复制成功');
246
247
  } catch (error) {
247
248
  this.error(`复制失败: ${error.message}`);
@@ -346,7 +347,9 @@ class LingyaoInstaller {
346
347
  return true;
347
348
  }
348
349
 
349
- this.error('Gateway 重启失败,请手动重启:');
350
+ this.warn('Gateway 自动重启失败,插件文件和配置已经写入');
351
+ this.log('可能是当前 OpenClaw CLI 自身依赖不完整,而不是灵尧插件缺少依赖。');
352
+ this.log('请在修复 OpenClaw CLI 后手动重启:');
350
353
  this.log(' openclaw gateway restart');
351
354
  return false;
352
355
  }
@@ -357,14 +360,14 @@ class LingyaoInstaller {
357
360
  this.log(' 安装完成!', CYAN);
358
361
  this.log('═══════════════════════════════════════════════════\n', CYAN);
359
362
 
360
- this.success('灵尧 Plugin 已成功安装到 OpenClaw!\n');
363
+ this.success('灵爻 Plugin 已成功安装到 OpenClaw!\n');
361
364
 
362
365
  this.info('快速开始:');
363
366
  this.log('');
364
367
  this.log(' # 查看插件状态');
365
368
  this.log(' openclaw plugins list');
366
369
  this.log('');
367
- this.log(' # 查看灵尧通道状态');
370
+ this.log(' # 查看灵爻通道状态');
368
371
  this.log(' openclaw channels status --channel lingyao');
369
372
  this.log('');
370
373
  this.log(' # 查看收到的消息');
@@ -383,12 +386,12 @@ class LingyaoInstaller {
383
386
  this.log('');
384
387
 
385
388
  this.info('架构说明:');
386
- this.log(' 灵尧 App → lingyao.live → OpenClaw Gateway');
387
- this.log(' Agent → OpenClaw Gateway → lingyao.live → 灵尧 App');
389
+ this.log(' 灵爻 App → lingyao.live → OpenClaw Gateway');
390
+ this.log(' Agent → OpenClaw Gateway → lingyao.live → 灵爻 App');
388
391
  this.log('');
389
392
 
390
393
  this.info('文档:');
391
- this.log(' • 完整测试指南: TESTING.md');
394
+ this.log(' • 安装说明: INSTALL.md');
392
395
  this.log(' • API 文档: README.md');
393
396
  this.log('');
394
397
  }
@@ -412,13 +415,15 @@ class LingyaoInstaller {
412
415
  }
413
416
 
414
417
  // 步骤 4: 重启网关
415
- if (!this.restartGateway()) {
416
- return false;
417
- }
418
+ const restarted = this.restartGateway();
418
419
 
419
420
  // 步骤 5: 显示说明
420
421
  this.showInstructions();
421
422
 
423
+ if (!restarted) {
424
+ this.warn('安装已完成,但需要你在 OpenClaw CLI 可用后手动重启 Gateway。');
425
+ }
426
+
422
427
  return true;
423
428
 
424
429
  } catch (error) {
@@ -430,7 +435,7 @@ class LingyaoInstaller {
430
435
  // 卸载插件
431
436
  async uninstall() {
432
437
  try {
433
- this.log('\n正在卸载灵尧插件...\n');
438
+ this.log('\n正在卸载灵爻插件...\n');
434
439
 
435
440
  const openclawPath = this.findOpenClawPath();
436
441
  if (!openclawPath) {
@@ -520,7 +525,7 @@ class LingyaoInstaller {
520
525
  return false;
521
526
  }
522
527
 
523
- this.success('\n插件已安装,请手动重启 OpenClaw Gateway:');
528
+ this.success('\n插件已安装,请在 OpenClaw CLI 可用后手动重启 Gateway:');
524
529
  this.log(' openclaw gateway restart\n');
525
530
  return true;
526
531
 
@@ -537,17 +542,20 @@ async function main() {
537
542
  const args = process.argv.slice(2);
538
543
  let command = 'install';
539
544
  let customPath = null;
545
+ let skipDeps = true;
540
546
 
541
547
  for (let i = 0; i < args.length; i++) {
542
548
  if (args[i] === '--path' && i + 1 < args.length) {
543
549
  customPath = args[i + 1];
544
550
  i++; // 跳过路径参数
551
+ } else if (args[i] === '--with-deps') {
552
+ skipDeps = false;
545
553
  } else if (!args[i].startsWith('--')) {
546
554
  command = args[i];
547
555
  }
548
556
  }
549
557
 
550
- const installer = new LingyaoInstaller(customPath);
558
+ const installer = new LingyaoInstaller(customPath, skipDeps);
551
559
 
552
560
  if (command === 'install') {
553
561
  const success = await installer.install();
@@ -563,7 +571,7 @@ async function main() {
563
571
 
564
572
  } else if (command === 'help') {
565
573
  console.log(`
566
- 灵尧 Plugin 一键安装器
574
+ 灵爻 Plugin 一键安装器
567
575
 
568
576
  使用方法:
569
577
  node cli.mjs install # 完整安装(包含配对和重启)
@@ -573,6 +581,7 @@ async function main() {
573
581
 
574
582
  参数:
575
583
  --path <目录> # 指定 OpenClaw 安装目录
584
+ --with-deps # 复制 node_modules(默认不复制,避免依赖冲突)
576
585
 
577
586
  环境要求:
578
587
  • Node.js >= 22
@@ -582,6 +591,9 @@ async function main() {
582
591
  # 从 npm 安装(推荐)
583
592
  npx -y @lingyao/openclaw-lingyao-cli install
584
593
 
594
+ # 强制复制 node_modules(仅在明确需要时使用)
595
+ npx -y @lingyao/openclaw-lingyao-cli install --with-deps
596
+
585
597
  # 从 npm 卸载
586
598
  npx -y @lingyao/openclaw-lingyao-cli uninstall
587
599
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingyao037/openclaw-lingyao-cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Lingyao Channel Plugin for OpenClaw - bidirectional sync via lingyao.live server relay",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",