@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.
- package/cli.mjs +98 -86
- 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
|
-
*
|
|
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('
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
'
|
|
210
|
+
'dist',
|
|
226
211
|
'openclaw.plugin.json',
|
|
227
212
|
'package.json',
|
|
228
|
-
'
|
|
229
|
-
'
|
|
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.
|
|
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('
|
|
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('
|
|
387
|
-
this.log(' Agent → OpenClaw Gateway → lingyao.live →
|
|
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(' •
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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