@lingyao037/openclaw-lingyao-cli 0.3.1 → 0.3.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/cli.mjs +96 -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 = false) {
|
|
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,21 @@ class LingyaoInstaller {
|
|
|
242
226
|
}
|
|
243
227
|
}
|
|
244
228
|
|
|
229
|
+
// 从 npx/npm 临时目录一起复制运行时依赖,避免目标 Gateway 再执行一次安装。
|
|
230
|
+
const runtimeModulesPath = join(__dirname, 'node_modules');
|
|
231
|
+
if (existsSync(runtimeModulesPath) && statSync(runtimeModulesPath).isDirectory()) {
|
|
232
|
+
if (!this.skipDeps) {
|
|
233
|
+
this.log('复制运行时依赖...');
|
|
234
|
+
this.copyDirectory(runtimeModulesPath, join(targetDir, 'node_modules'));
|
|
235
|
+
} else {
|
|
236
|
+
this.info('跳过复制运行时依赖 (--no-deps)');
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
if (!this.skipDeps) {
|
|
240
|
+
this.warn('未找到本地 node_modules,目标 OpenClaw 可能仍需自行安装依赖');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
245
244
|
this.success('插件文件复制成功');
|
|
246
245
|
} catch (error) {
|
|
247
246
|
this.error(`复制失败: ${error.message}`);
|
|
@@ -346,7 +345,9 @@ class LingyaoInstaller {
|
|
|
346
345
|
return true;
|
|
347
346
|
}
|
|
348
347
|
|
|
349
|
-
this.
|
|
348
|
+
this.warn('Gateway 自动重启失败,插件文件和配置已经写入');
|
|
349
|
+
this.log('可能是当前 OpenClaw CLI 自身依赖不完整,而不是灵尧插件缺少依赖。');
|
|
350
|
+
this.log('请在修复 OpenClaw CLI 后手动重启:');
|
|
350
351
|
this.log(' openclaw gateway restart');
|
|
351
352
|
return false;
|
|
352
353
|
}
|
|
@@ -357,14 +358,14 @@ class LingyaoInstaller {
|
|
|
357
358
|
this.log(' 安装完成!', CYAN);
|
|
358
359
|
this.log('═══════════════════════════════════════════════════\n', CYAN);
|
|
359
360
|
|
|
360
|
-
this.success('
|
|
361
|
+
this.success('灵爻 Plugin 已成功安装到 OpenClaw!\n');
|
|
361
362
|
|
|
362
363
|
this.info('快速开始:');
|
|
363
364
|
this.log('');
|
|
364
365
|
this.log(' # 查看插件状态');
|
|
365
366
|
this.log(' openclaw plugins list');
|
|
366
367
|
this.log('');
|
|
367
|
-
this.log(' #
|
|
368
|
+
this.log(' # 查看灵爻通道状态');
|
|
368
369
|
this.log(' openclaw channels status --channel lingyao');
|
|
369
370
|
this.log('');
|
|
370
371
|
this.log(' # 查看收到的消息');
|
|
@@ -383,12 +384,12 @@ class LingyaoInstaller {
|
|
|
383
384
|
this.log('');
|
|
384
385
|
|
|
385
386
|
this.info('架构说明:');
|
|
386
|
-
this.log('
|
|
387
|
-
this.log(' Agent → OpenClaw Gateway → lingyao.live →
|
|
387
|
+
this.log(' 灵爻 App → lingyao.live → OpenClaw Gateway');
|
|
388
|
+
this.log(' Agent → OpenClaw Gateway → lingyao.live → 灵爻 App');
|
|
388
389
|
this.log('');
|
|
389
390
|
|
|
390
391
|
this.info('文档:');
|
|
391
|
-
this.log(' •
|
|
392
|
+
this.log(' • 安装说明: INSTALL.md');
|
|
392
393
|
this.log(' • API 文档: README.md');
|
|
393
394
|
this.log('');
|
|
394
395
|
}
|
|
@@ -412,13 +413,15 @@ class LingyaoInstaller {
|
|
|
412
413
|
}
|
|
413
414
|
|
|
414
415
|
// 步骤 4: 重启网关
|
|
415
|
-
|
|
416
|
-
return false;
|
|
417
|
-
}
|
|
416
|
+
const restarted = this.restartGateway();
|
|
418
417
|
|
|
419
418
|
// 步骤 5: 显示说明
|
|
420
419
|
this.showInstructions();
|
|
421
420
|
|
|
421
|
+
if (!restarted) {
|
|
422
|
+
this.warn('安装已完成,但需要你在 OpenClaw CLI 可用后手动重启 Gateway。');
|
|
423
|
+
}
|
|
424
|
+
|
|
422
425
|
return true;
|
|
423
426
|
|
|
424
427
|
} catch (error) {
|
|
@@ -430,7 +433,7 @@ class LingyaoInstaller {
|
|
|
430
433
|
// 卸载插件
|
|
431
434
|
async uninstall() {
|
|
432
435
|
try {
|
|
433
|
-
this.log('\n
|
|
436
|
+
this.log('\n正在卸载灵爻插件...\n');
|
|
434
437
|
|
|
435
438
|
const openclawPath = this.findOpenClawPath();
|
|
436
439
|
if (!openclawPath) {
|
|
@@ -520,7 +523,7 @@ class LingyaoInstaller {
|
|
|
520
523
|
return false;
|
|
521
524
|
}
|
|
522
525
|
|
|
523
|
-
this.success('\n
|
|
526
|
+
this.success('\n插件已安装,请在 OpenClaw CLI 可用后手动重启 Gateway:');
|
|
524
527
|
this.log(' openclaw gateway restart\n');
|
|
525
528
|
return true;
|
|
526
529
|
|
|
@@ -537,17 +540,20 @@ async function main() {
|
|
|
537
540
|
const args = process.argv.slice(2);
|
|
538
541
|
let command = 'install';
|
|
539
542
|
let customPath = null;
|
|
543
|
+
let skipDeps = false;
|
|
540
544
|
|
|
541
545
|
for (let i = 0; i < args.length; i++) {
|
|
542
546
|
if (args[i] === '--path' && i + 1 < args.length) {
|
|
543
547
|
customPath = args[i + 1];
|
|
544
548
|
i++; // 跳过路径参数
|
|
549
|
+
} else if (args[i] === '--no-deps') {
|
|
550
|
+
skipDeps = true;
|
|
545
551
|
} else if (!args[i].startsWith('--')) {
|
|
546
552
|
command = args[i];
|
|
547
553
|
}
|
|
548
554
|
}
|
|
549
555
|
|
|
550
|
-
const installer = new LingyaoInstaller(customPath);
|
|
556
|
+
const installer = new LingyaoInstaller(customPath, skipDeps);
|
|
551
557
|
|
|
552
558
|
if (command === 'install') {
|
|
553
559
|
const success = await installer.install();
|
|
@@ -563,7 +569,7 @@ async function main() {
|
|
|
563
569
|
|
|
564
570
|
} else if (command === 'help') {
|
|
565
571
|
console.log(`
|
|
566
|
-
|
|
572
|
+
灵爻 Plugin 一键安装器
|
|
567
573
|
|
|
568
574
|
使用方法:
|
|
569
575
|
node cli.mjs install # 完整安装(包含配对和重启)
|
|
@@ -573,6 +579,7 @@ async function main() {
|
|
|
573
579
|
|
|
574
580
|
参数:
|
|
575
581
|
--path <目录> # 指定 OpenClaw 安装目录
|
|
582
|
+
--no-deps # 跳过复制 node_modules (解决依赖冲突)
|
|
576
583
|
|
|
577
584
|
环境要求:
|
|
578
585
|
• Node.js >= 22
|
|
@@ -582,6 +589,9 @@ async function main() {
|
|
|
582
589
|
# 从 npm 安装(推荐)
|
|
583
590
|
npx -y @lingyao/openclaw-lingyao-cli install
|
|
584
591
|
|
|
592
|
+
# 跳过复制 node_modules (如遇到 @anthropic-ai/vertex-sdk 缺失等报错)
|
|
593
|
+
npx -y @lingyao/openclaw-lingyao-cli install --no-deps
|
|
594
|
+
|
|
585
595
|
# 从 npm 卸载
|
|
586
596
|
npx -y @lingyao/openclaw-lingyao-cli uninstall
|
|
587
597
|
|
package/package.json
CHANGED