@workclaw/cli 1.0.322 → 1.0.323
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/dist/{index-ZySzMX4-.js → index-xy26TrIZ.js} +195 -113
- package/dist/index.js +1 -1
- package/dist/local/index.d.ts.map +1 -1
- package/dist/local/installer/installer.d.ts +5 -0
- package/dist/local/installer/installer.d.ts.map +1 -1
- package/dist/local/src/local.d.ts.map +1 -1
- package/dist/local/types/index.d.ts +1 -0
- package/dist/local/types/index.d.ts.map +1 -1
- package/dist/shared/utils/debug.d.ts +3 -4
- package/dist/shared/utils/debug.d.ts.map +1 -1
- package/dist/shared/utils/index.d.ts +1 -1
- package/dist/shared/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -24,8 +24,6 @@ function setDebug(enabled) {
|
|
|
24
24
|
debug.disable();
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
function debugLog(...args) {
|
|
28
|
-
}
|
|
29
27
|
const ERROR_CODES$1 = {
|
|
30
28
|
PHONE_REQUIRED: "PHONE_REQUIRED",
|
|
31
29
|
USER_PASS_REQUIRED: "USER_PASS_REQUIRED",
|
|
@@ -49,14 +47,18 @@ let AppError$1 = class AppError extends Error {
|
|
|
49
47
|
}
|
|
50
48
|
};
|
|
51
49
|
function checkEnv() {
|
|
50
|
+
debug.log("[环境检查] 检测 Node.js 版本...");
|
|
52
51
|
const nodeVersion = execSync("node --version", { stdio: "pipe" }).toString().trim();
|
|
52
|
+
debug.log(`[环境检查] Node.js 版本: ${nodeVersion}`);
|
|
53
53
|
if (!semver.gte(nodeVersion, "18.0.0")) {
|
|
54
54
|
throw new AppError$1(ERROR_CODES$1.NODE_VERSION_LOW, `Node.js 版本需要 >= 18.0.0,当前版本: ${nodeVersion}`);
|
|
55
55
|
}
|
|
56
|
+
debug.log("[环境检查] Node.js 版本检查通过");
|
|
57
|
+
debug.log("[环境检查] 检测 npm...");
|
|
56
58
|
try {
|
|
57
59
|
const npmVersion = execSync("npm --version", { stdio: "pipe" }).toString().trim();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
debug.log(`[环境检查] npm 版本: ${npmVersion}`);
|
|
61
|
+
debug.log("[环境检查] npm 检测通过");
|
|
60
62
|
} catch {
|
|
61
63
|
throw new AppError$1(ERROR_CODES$1.NPM_NOT_FOUND, "未检测到 npm,请先安装 Node.js 和 npm");
|
|
62
64
|
}
|
|
@@ -100,11 +102,13 @@ const wsUrlSchema = z$1.string().url({
|
|
|
100
102
|
}).optional();
|
|
101
103
|
z$1.boolean();
|
|
102
104
|
function validateOpenclawPath(openclawPath) {
|
|
105
|
+
debug.log(`[路径验证] 开始验证路径: ${openclawPath}`);
|
|
103
106
|
const result = openclawPathSchema.safeParse(openclawPath);
|
|
104
107
|
if (!result.success) {
|
|
105
|
-
|
|
108
|
+
debug.log(`[路径验证] 失败: ${result.error.issues[0].message}`);
|
|
106
109
|
throw new Error(result.error.issues[0].message);
|
|
107
110
|
}
|
|
111
|
+
debug.log(`[路径验证] 通过: ${openclawPath}`);
|
|
108
112
|
}
|
|
109
113
|
const CONFIG = {
|
|
110
114
|
PLUGIN_NAME: "openclaw-workclaw",
|
|
@@ -226,6 +230,7 @@ class BoxInstaller {
|
|
|
226
230
|
spinner;
|
|
227
231
|
prefixText = "";
|
|
228
232
|
validateConfig() {
|
|
233
|
+
debug.log("[验证配置] 检查 appKey 和 appSecret...");
|
|
229
234
|
if (!this.config.appKey) {
|
|
230
235
|
throw new AppError2(ERROR_CODES.APP_KEY_REQUIRED, "AppKey 不能为空,请使用 --app-key 参数");
|
|
231
236
|
}
|
|
@@ -233,6 +238,7 @@ class BoxInstaller {
|
|
|
233
238
|
throw new AppError2(ERROR_CODES.APP_SECRET_REQUIRED, "AppSecret 不能为空,请使用 --app-secret 参数");
|
|
234
239
|
}
|
|
235
240
|
if (this.config.env === "custom") {
|
|
241
|
+
debug.log("[验证配置] 检查自定义环境 IP...");
|
|
236
242
|
if (!this.config.customIp) {
|
|
237
243
|
throw new AppError2(ERROR_CODES.INVALID_ARGUMENT, "自定义环境必须提供 --customIp 参数");
|
|
238
244
|
}
|
|
@@ -240,18 +246,20 @@ class BoxInstaller {
|
|
|
240
246
|
if (!result.success) {
|
|
241
247
|
throw new AppError2(ERROR_CODES.INVALID_ARGUMENT, result.error.issues[0].message);
|
|
242
248
|
}
|
|
249
|
+
debug.log("[验证配置] 自定义环境 IP 验证通过");
|
|
243
250
|
}
|
|
251
|
+
debug.log("[验证配置] 配置检查通过");
|
|
244
252
|
}
|
|
245
253
|
getPaths() {
|
|
246
254
|
const env = this.config.env || "test";
|
|
247
|
-
|
|
255
|
+
debug.log(`[getConfig] env=${env}, customIp=${this.config.customIp}`);
|
|
248
256
|
const config = getConfig(env, this.config.customIp);
|
|
249
257
|
let baseDir;
|
|
250
258
|
if (this.config.openclawPath) {
|
|
251
|
-
|
|
259
|
+
debug.log(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
|
|
252
260
|
try {
|
|
253
261
|
validateOpenclawPath(this.config.openclawPath);
|
|
254
|
-
|
|
262
|
+
debug.log("[路径验证] 通过");
|
|
255
263
|
} catch (error) {
|
|
256
264
|
throw new AppError2(ERROR_CODES.INVALID_OPENCLAW_PATH, error.message);
|
|
257
265
|
}
|
|
@@ -277,6 +285,7 @@ class BoxInstaller {
|
|
|
277
285
|
updateSpinner(text) {
|
|
278
286
|
this.spinner.prefixText = this.prefixText;
|
|
279
287
|
this.spinner.text = chalk.cyan(text);
|
|
288
|
+
debug.log(`[Spinner] ${text}`);
|
|
280
289
|
}
|
|
281
290
|
getPrefixText() {
|
|
282
291
|
return this.prefixText;
|
|
@@ -289,7 +298,7 @@ class BoxInstaller {
|
|
|
289
298
|
}
|
|
290
299
|
async install() {
|
|
291
300
|
try {
|
|
292
|
-
|
|
301
|
+
debug.log("[盒子安装] 开始安装...");
|
|
293
302
|
this.validateConfig();
|
|
294
303
|
this.prefixText += chalk.green(` ✓ 配置验证完成
|
|
295
304
|
`);
|
|
@@ -299,25 +308,27 @@ class BoxInstaller {
|
|
|
299
308
|
await this.doDownloadFromNpm();
|
|
300
309
|
await this.doUpdateConfig(paths);
|
|
301
310
|
this.spinner.stop();
|
|
302
|
-
|
|
311
|
+
debug.log("[盒子安装] 安装完成");
|
|
303
312
|
} catch (error) {
|
|
304
313
|
this.spinner.stop();
|
|
305
|
-
|
|
314
|
+
debug.log(`[盒子安装] 安装失败: ${error.message}`);
|
|
306
315
|
throw error;
|
|
307
316
|
}
|
|
308
317
|
}
|
|
309
318
|
async doCleanOldFiles(paths) {
|
|
319
|
+
debug.log("[清理旧版本] 开始清理旧版本...");
|
|
310
320
|
this.prefixText += chalk.green(` ✓ 开始清理旧版本
|
|
311
321
|
`);
|
|
312
322
|
this.updateSpinner("正在清理旧版本...");
|
|
313
323
|
try {
|
|
314
324
|
await fs.access(paths.target);
|
|
315
|
-
|
|
325
|
+
debug.log("[清理旧版本] 删除旧版本目录...");
|
|
316
326
|
await fs.rm(paths.target, { recursive: true, force: true });
|
|
317
327
|
this.prefixText += chalk.green(` ✓ 旧版本清理成功
|
|
318
328
|
`);
|
|
319
|
-
|
|
329
|
+
debug.log("[清理旧版本] 旧版本清理成功");
|
|
320
330
|
} catch {
|
|
331
|
+
debug.log("[清理旧版本] 无旧版本需要清理");
|
|
321
332
|
this.prefixText += chalk.green(` ✓ 无旧版本需要清理
|
|
322
333
|
`);
|
|
323
334
|
}
|
|
@@ -325,27 +336,33 @@ class BoxInstaller {
|
|
|
325
336
|
await fs.access(paths.temp);
|
|
326
337
|
await fs.rm(paths.temp, { recursive: true, force: true });
|
|
327
338
|
} catch {
|
|
339
|
+
debug.log("[清理旧版本] 无临时目录需要清理");
|
|
328
340
|
}
|
|
329
341
|
}
|
|
330
342
|
async doDownloadFromNpm() {
|
|
331
343
|
const paths = this.getPaths();
|
|
332
344
|
this.spinner.prefixText = this.prefixText;
|
|
333
345
|
this.spinner.text = chalk.cyan("正在准备安装目录...");
|
|
346
|
+
debug.log("[下载插件] 创建扩展目录...");
|
|
334
347
|
await fs.mkdir(paths.extensions, { recursive: true });
|
|
335
|
-
|
|
348
|
+
debug.log(`[下载插件] 扩展目录: ${paths.extensions}`);
|
|
336
349
|
const tempDir = path.join(paths.temp, `install-${Date.now()}`);
|
|
350
|
+
debug.log(`[下载插件] 创建临时目录: ${tempDir}`);
|
|
337
351
|
await fs.mkdir(tempDir, { recursive: true });
|
|
338
352
|
this.spinner.prefixText = this.prefixText;
|
|
339
353
|
this.spinner.text = chalk.cyan("正在下载插件...");
|
|
354
|
+
debug.log("[下载插件] 执行 npm pack 下载源码包");
|
|
355
|
+
debug.log(`[下载插件] 工作目录: ${tempDir}`);
|
|
340
356
|
const maxRetries = 3;
|
|
341
357
|
let lastError = "";
|
|
342
358
|
let tarballPath = "";
|
|
343
359
|
for (let i = 1; i <= maxRetries; i++) {
|
|
344
360
|
this.spinner.prefixText = this.prefixText;
|
|
345
361
|
this.spinner.text = chalk.cyan(`正在下载 (${i}/${maxRetries})...`);
|
|
362
|
+
debug.log(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
|
|
346
363
|
try {
|
|
347
364
|
const packageName = this.getPackageName();
|
|
348
|
-
|
|
365
|
+
debug.log(`[下载插件] 下载包名: ${packageName}`);
|
|
349
366
|
this.spinner.text = chalk.cyan("正在从 npm 获取插件...");
|
|
350
367
|
const output = await execAsync$1(
|
|
351
368
|
`npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts --quiet`,
|
|
@@ -354,12 +371,14 @@ class BoxInstaller {
|
|
|
354
371
|
const lines = output.trim().split("\n").filter((line) => line.trim());
|
|
355
372
|
const filename = lines[lines.length - 1] || "";
|
|
356
373
|
tarballPath = path.join(tempDir, filename);
|
|
357
|
-
|
|
374
|
+
debug.log(`[下载插件] tarball 下载成功: ${tarballPath}`);
|
|
358
375
|
break;
|
|
359
376
|
} catch (error) {
|
|
360
377
|
lastError = error.message || "未知错误";
|
|
378
|
+
debug.log(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
|
|
361
379
|
if (i < maxRetries) {
|
|
362
380
|
this.spinner.text = chalk.cyan(`下载失败,3秒后重试...`);
|
|
381
|
+
debug.log("[下载插件] 等待 3 秒后重试...");
|
|
363
382
|
await new Promise((resolve2) => setTimeout(resolve2, 3e3));
|
|
364
383
|
}
|
|
365
384
|
}
|
|
@@ -369,16 +388,16 @@ class BoxInstaller {
|
|
|
369
388
|
}
|
|
370
389
|
this.spinner.prefixText = this.prefixText;
|
|
371
390
|
this.spinner.text = chalk.cyan("正在解压插件...");
|
|
372
|
-
|
|
391
|
+
debug.log(`[下载插件] 创建插件目录: ${paths.target}`);
|
|
373
392
|
await fs.mkdir(paths.target, { recursive: true });
|
|
374
|
-
|
|
393
|
+
debug.log(`[下载插件] 解压 tarball 到: ${paths.target}`);
|
|
375
394
|
try {
|
|
376
395
|
await tar.extract({
|
|
377
396
|
file: tarballPath,
|
|
378
397
|
cwd: paths.target,
|
|
379
398
|
strip: 1
|
|
380
399
|
});
|
|
381
|
-
|
|
400
|
+
debug.log("[下载插件] tarball 解压成功");
|
|
382
401
|
} catch (error) {
|
|
383
402
|
throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
|
|
384
403
|
}
|
|
@@ -387,27 +406,35 @@ class BoxInstaller {
|
|
|
387
406
|
if (!pluginExists) {
|
|
388
407
|
throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
|
|
389
408
|
}
|
|
409
|
+
debug.log("[下载插件] 插件解压成功");
|
|
390
410
|
this.spinner.prefixText = this.prefixText;
|
|
391
411
|
this.spinner.text = chalk.cyan("正在安装依赖...");
|
|
412
|
+
debug.log("[下载插件] 执行 npm install 安装生产环境依赖");
|
|
392
413
|
try {
|
|
393
414
|
await execAsync$1("npm install --omit=dev --ignore-scripts --quiet", {
|
|
394
415
|
cwd: paths.target,
|
|
395
416
|
timeout: 12e4
|
|
396
417
|
});
|
|
397
|
-
|
|
418
|
+
debug.log("[下载插件] npm install 执行成功");
|
|
398
419
|
} catch (error) {
|
|
399
420
|
const errorMsg = error.message || "";
|
|
400
|
-
if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated"))
|
|
421
|
+
if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) {
|
|
422
|
+
debug.log("[下载插件] npm install 有警告但可能成功,继续流程");
|
|
423
|
+
} else {
|
|
424
|
+
debug.log(`[下载插件] npm install 失败: ${errorMsg}`);
|
|
425
|
+
}
|
|
401
426
|
}
|
|
402
427
|
this.prefixText += chalk.green(` ✓ 插件安装完成
|
|
403
428
|
`);
|
|
404
429
|
try {
|
|
405
430
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
406
|
-
|
|
431
|
+
debug.log("[下载插件] 清理临时目录完成");
|
|
407
432
|
} catch {
|
|
433
|
+
debug.log("[下载插件] 清理临时目录失败(忽略)");
|
|
408
434
|
}
|
|
409
435
|
}
|
|
410
436
|
async doUpdateConfig(paths) {
|
|
437
|
+
debug.log("[更新配置] 开始更新配置...");
|
|
411
438
|
this.prefixText += chalk.green(` ✓ 开始更新配置
|
|
412
439
|
`);
|
|
413
440
|
this.updateSpinner("正在生成配置...");
|
|
@@ -415,8 +442,9 @@ class BoxInstaller {
|
|
|
415
442
|
try {
|
|
416
443
|
const content = await fs.readFile(paths.config, "utf-8");
|
|
417
444
|
originalConfig = JSON.parse(content);
|
|
418
|
-
|
|
445
|
+
debug.log("[更新配置] 读取原有配置成功");
|
|
419
446
|
} catch {
|
|
447
|
+
debug.log("[更新配置] 无原有配置");
|
|
420
448
|
}
|
|
421
449
|
const config = getConfig(this.config.env || "test", this.config.customIp);
|
|
422
450
|
const newConfig = {
|
|
@@ -655,16 +683,19 @@ class BoxInstaller {
|
|
|
655
683
|
};
|
|
656
684
|
const finalConfig = deepMerge$1(originalConfig, newConfig);
|
|
657
685
|
this.updateSpinner("正在写入配置...");
|
|
686
|
+
debug.log("[更新配置] 写入配置文件...");
|
|
658
687
|
await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
|
|
659
688
|
this.prefixText += chalk.green(` ✓ 配置文件更新成功
|
|
660
689
|
`);
|
|
661
|
-
|
|
690
|
+
debug.log(`[更新配置] 配置文件写入成功: ${paths.config}`);
|
|
662
691
|
}
|
|
663
692
|
}
|
|
664
693
|
async function createBoxCommand(options) {
|
|
665
694
|
setDebug(!!options.debug);
|
|
666
|
-
|
|
695
|
+
debug.log("[盒子安装] 开始处理...");
|
|
696
|
+
debug.log(`[盒子安装] 参数: env=${options.env}, appKey=${options.appKey ? "***" : "未提供"}, customIp=${options.customIp}, debug=${options.debug}`);
|
|
667
697
|
checkEnv();
|
|
698
|
+
debug.log("[盒子安装] 环境检查通过");
|
|
668
699
|
try {
|
|
669
700
|
let env = options.env;
|
|
670
701
|
let appKey = options.appKey;
|
|
@@ -672,7 +703,7 @@ async function createBoxCommand(options) {
|
|
|
672
703
|
let customIp = options.customIp;
|
|
673
704
|
const questions = [];
|
|
674
705
|
if (!env) {
|
|
675
|
-
|
|
706
|
+
debug.log("[盒子安装] 需要选择环境");
|
|
676
707
|
questions.push({
|
|
677
708
|
type: "list",
|
|
678
709
|
name: "env",
|
|
@@ -685,10 +716,10 @@ async function createBoxCommand(options) {
|
|
|
685
716
|
]
|
|
686
717
|
});
|
|
687
718
|
} else {
|
|
688
|
-
|
|
719
|
+
debug.log(`[盒子安装] 使用命令行参数: env=${env}`);
|
|
689
720
|
}
|
|
690
721
|
if (!appKey) {
|
|
691
|
-
|
|
722
|
+
debug.log("[盒子安装] 需要输入 AppKey");
|
|
692
723
|
questions.push({
|
|
693
724
|
type: "input",
|
|
694
725
|
name: "appKey",
|
|
@@ -702,10 +733,10 @@ async function createBoxCommand(options) {
|
|
|
702
733
|
}
|
|
703
734
|
});
|
|
704
735
|
} else {
|
|
705
|
-
|
|
736
|
+
debug.log("[盒子安装] 使用命令行参数: appKey");
|
|
706
737
|
}
|
|
707
738
|
if (!appSecret) {
|
|
708
|
-
|
|
739
|
+
debug.log("[盒子安装] 需要输入 AppSecret");
|
|
709
740
|
questions.push({
|
|
710
741
|
type: "input",
|
|
711
742
|
name: "appSecret",
|
|
@@ -719,18 +750,18 @@ async function createBoxCommand(options) {
|
|
|
719
750
|
}
|
|
720
751
|
});
|
|
721
752
|
} else {
|
|
722
|
-
|
|
753
|
+
debug.log("[盒子安装] 使用命令行参数: appSecret");
|
|
723
754
|
}
|
|
724
755
|
if (questions.length > 0) {
|
|
725
|
-
|
|
756
|
+
debug.log(`[盒子安装] 开始交互式问答,共 ${questions.length} 个问题`);
|
|
726
757
|
const answers = await inquirer.prompt(questions);
|
|
727
|
-
|
|
758
|
+
debug.log("[盒子安装] 交互式问答完成");
|
|
728
759
|
env = env || answers.env || "test";
|
|
729
760
|
appKey = appKey || answers.appKey;
|
|
730
761
|
appSecret = appSecret || answers.appSecret;
|
|
731
762
|
}
|
|
732
763
|
if (env === "custom" && !customIp) {
|
|
733
|
-
|
|
764
|
+
debug.log("[盒子安装] 自定义环境需要输入后端 IP");
|
|
734
765
|
const answer = await inquirer.prompt([{
|
|
735
766
|
type: "input",
|
|
736
767
|
name: "customIp",
|
|
@@ -748,12 +779,12 @@ async function createBoxCommand(options) {
|
|
|
748
779
|
}
|
|
749
780
|
}]);
|
|
750
781
|
customIp = answer.customIp;
|
|
751
|
-
|
|
782
|
+
debug.log("[盒子安装] 获取自定义 customIp");
|
|
752
783
|
} else if (env === "custom" && customIp) {
|
|
753
|
-
|
|
784
|
+
debug.log(`[盒子安装] 使用命令行参数: customIp=${customIp}`);
|
|
754
785
|
}
|
|
755
|
-
|
|
756
|
-
|
|
786
|
+
debug.log(`[盒子安装] 最终参数: env=${env}, customIp=${customIp}, openclawPath=${options.openclawPath}`);
|
|
787
|
+
debug.log("[盒子安装] 创建 BoxInstaller 实例...");
|
|
757
788
|
const installer = new BoxInstaller({
|
|
758
789
|
appKey,
|
|
759
790
|
appSecret,
|
|
@@ -763,9 +794,9 @@ async function createBoxCommand(options) {
|
|
|
763
794
|
pluginVersion: options.pluginVersion,
|
|
764
795
|
openclawPath: options.openclawPath
|
|
765
796
|
});
|
|
766
|
-
|
|
797
|
+
debug.log("[盒子安装] 开始安装...");
|
|
767
798
|
await installer.install();
|
|
768
|
-
|
|
799
|
+
debug.log("[盒子安装] 安装完成");
|
|
769
800
|
console.log(installer.getPrefixText() + boxen(
|
|
770
801
|
`${chalk.green("✦")} 插件初始化成功!`,
|
|
771
802
|
{
|
|
@@ -779,7 +810,7 @@ async function createBoxCommand(options) {
|
|
|
779
810
|
}
|
|
780
811
|
));
|
|
781
812
|
} catch (error) {
|
|
782
|
-
|
|
813
|
+
debug.log(`[盒子安装] 发生错误: ${error.message}`);
|
|
783
814
|
console.error(boxen(
|
|
784
815
|
`${chalk.yellow(error.message)}`,
|
|
785
816
|
{
|
|
@@ -809,12 +840,13 @@ function createHttpClient(baseURL) {
|
|
|
809
840
|
}
|
|
810
841
|
async function httpPost(url, data, config) {
|
|
811
842
|
const client = createHttpClient();
|
|
812
|
-
|
|
813
|
-
|
|
843
|
+
debug.log(`[HTTP POST] 请求地址: ${url}`);
|
|
844
|
+
debug.log(`[HTTP POST] 请求参数: ${JSON.stringify(data)}`);
|
|
845
|
+
debug.log(`[HTTP POST] 请求头: ${JSON.stringify(config?.headers || {})}`);
|
|
814
846
|
try {
|
|
815
847
|
const response = await client.post(url, data, config);
|
|
816
|
-
|
|
817
|
-
|
|
848
|
+
debug.log(`[HTTP POST] 响应状态: ${response.status}`);
|
|
849
|
+
debug.log(`[HTTP POST] 响应内容: ${JSON.stringify(response.data)}`);
|
|
818
850
|
return {
|
|
819
851
|
status: response.status,
|
|
820
852
|
data: response.data
|
|
@@ -823,9 +855,9 @@ async function httpPost(url, data, config) {
|
|
|
823
855
|
const axiosError = error;
|
|
824
856
|
if (axiosError.response) {
|
|
825
857
|
const responseData = axiosError.response.data;
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
858
|
+
debug.log(`[HTTP POST] 响应状态: ${axiosError.response.status}`);
|
|
859
|
+
debug.log(`[HTTP POST] 响应状态文本: ${axiosError.response.statusText}`);
|
|
860
|
+
debug.log(`[HTTP POST] 响应数据: ${JSON.stringify(responseData)}`);
|
|
829
861
|
if (typeof responseData === "string") {
|
|
830
862
|
throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${responseData}`);
|
|
831
863
|
} else if (responseData && typeof responseData === "object" && "message" in responseData) {
|
|
@@ -834,40 +866,48 @@ async function httpPost(url, data, config) {
|
|
|
834
866
|
throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${axiosError.response.statusText}`);
|
|
835
867
|
}
|
|
836
868
|
} else if (axiosError.request) {
|
|
837
|
-
|
|
869
|
+
debug.log(`[HTTP POST] 未收到响应`);
|
|
870
|
+
debug.log(`[HTTP POST] 错误信息: ${axiosError.message}`);
|
|
838
871
|
throw new AppError$1(ERROR_CODES$1.NETWORK_ERROR, `网络错误: ${axiosError.message}`);
|
|
839
872
|
} else {
|
|
840
|
-
|
|
873
|
+
debug.log(`[HTTP POST] 请求配置错误`);
|
|
874
|
+
debug.log(`[HTTP POST] 错误信息: ${axiosError.message}`);
|
|
841
875
|
throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求配置错误: ${axiosError.message}`);
|
|
842
876
|
}
|
|
843
877
|
}
|
|
844
878
|
}
|
|
845
879
|
async function login(phone, password, config) {
|
|
846
880
|
const url = `${config.API.TUZAI_BASE_URL}/user/login/pass`;
|
|
881
|
+
debug.log("[登录] 开始登录...");
|
|
882
|
+
debug.log(`[登录] 请求地址: ${url}`);
|
|
883
|
+
debug.log(`[登录] 请求参数: phone=${phone}, password=***`);
|
|
847
884
|
try {
|
|
848
885
|
const response = await httpPost(url, {
|
|
849
886
|
phone,
|
|
850
887
|
userPass: password
|
|
851
888
|
});
|
|
852
889
|
const data = response.data;
|
|
853
|
-
|
|
890
|
+
debug.log(`[登录] 响应数据: ${JSON.stringify(data)}`);
|
|
854
891
|
if (data.code === 200 && data.data?.token) {
|
|
855
|
-
|
|
892
|
+
debug.log("[登录] 登录成功,获取到 token");
|
|
856
893
|
return data.data.token;
|
|
857
894
|
}
|
|
858
|
-
|
|
895
|
+
debug.log("[登录] 登录失败");
|
|
859
896
|
throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, data.message || "登录失败");
|
|
860
897
|
} catch (error) {
|
|
861
898
|
if (error instanceof AppError$1) {
|
|
862
899
|
throw error;
|
|
863
900
|
}
|
|
864
|
-
|
|
901
|
+
debug.log(`[登录] 发生错误: ${error.message}`);
|
|
865
902
|
throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, error.message);
|
|
866
903
|
}
|
|
867
904
|
}
|
|
868
905
|
async function fetchBoundConfig(token, phone, localCode, config) {
|
|
869
906
|
const url = `${config.API.TUZAI_BASE_URL}/work-bot/local/bound/init`;
|
|
870
|
-
|
|
907
|
+
debug.log("[获取绑定配置] 开始获取绑定配置...");
|
|
908
|
+
debug.log(`[获取绑定配置] 请求地址: ${url}`);
|
|
909
|
+
debug.log(`[获取绑定配置] 请求参数: phone=${phone}, localCode=${localCode}`);
|
|
910
|
+
debug.log(`[获取绑定配置] 请求头: Authorization=${token.substring(0, 20)}...`);
|
|
871
911
|
try {
|
|
872
912
|
const response = await httpPost(url, {
|
|
873
913
|
phone,
|
|
@@ -878,7 +918,7 @@ async function fetchBoundConfig(token, phone, localCode, config) {
|
|
|
878
918
|
}
|
|
879
919
|
});
|
|
880
920
|
const data = response.data;
|
|
881
|
-
|
|
921
|
+
debug.log(`[获取绑定配置] 响应数据: ${JSON.stringify(data)}`);
|
|
882
922
|
if (data.code === 200 && data.data) {
|
|
883
923
|
const boundConfig = {
|
|
884
924
|
appKey: data.data.app_key,
|
|
@@ -888,26 +928,26 @@ async function fetchBoundConfig(token, phone, localCode, config) {
|
|
|
888
928
|
modelApiKey: data.data.model_api_key,
|
|
889
929
|
modelApiBaseUrl: data.data.model_api_base_url
|
|
890
930
|
};
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
931
|
+
debug.log("[获取绑定配置] 获取绑定配置成功");
|
|
932
|
+
debug.log(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
|
|
933
|
+
debug.log(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
|
|
934
|
+
debug.log(`[获取绑定配置] userId: ${boundConfig.userId}`);
|
|
935
|
+
debug.log(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
|
|
936
|
+
debug.log(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
|
|
937
|
+
debug.log(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
|
|
898
938
|
if (!boundConfig.appKey || !boundConfig.appSecret || !boundConfig.agentId) {
|
|
899
|
-
|
|
939
|
+
debug.log("[获取绑定配置] 缺少必要字段");
|
|
900
940
|
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, "获取绑定配置失败:缺少必要字段");
|
|
901
941
|
}
|
|
902
942
|
return boundConfig;
|
|
903
943
|
}
|
|
904
|
-
|
|
944
|
+
debug.log("[获取绑定配置] 获取绑定配置失败");
|
|
905
945
|
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, data.message || data.msg || "获取绑定配置失败");
|
|
906
946
|
} catch (error) {
|
|
907
947
|
if (error instanceof AppError$1) {
|
|
908
948
|
throw error;
|
|
909
949
|
}
|
|
910
|
-
|
|
950
|
+
debug.log(`[获取绑定配置] 发生错误: ${error.message}`);
|
|
911
951
|
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, error.message);
|
|
912
952
|
}
|
|
913
953
|
}
|
|
@@ -4893,6 +4933,7 @@ class LocalInstaller {
|
|
|
4893
4933
|
prefixText = "";
|
|
4894
4934
|
config;
|
|
4895
4935
|
envConfig;
|
|
4936
|
+
token = "";
|
|
4896
4937
|
/**
|
|
4897
4938
|
* 构造函数
|
|
4898
4939
|
*/
|
|
@@ -4906,25 +4947,27 @@ class LocalInstaller {
|
|
|
4906
4947
|
* 验证安装配置
|
|
4907
4948
|
*/
|
|
4908
4949
|
validateConfig() {
|
|
4950
|
+
debug.log("[验证配置] 检查配置...");
|
|
4909
4951
|
const result = LocalInstallerConfigSchema.safeParse(this.config);
|
|
4910
4952
|
if (!result.success) {
|
|
4911
|
-
|
|
4953
|
+
debug.log(`[验证配置] 验证失败: ${result.error.issues[0].message}`);
|
|
4912
4954
|
throw new AppError$1(ERROR_CODES$1.INVALID_ARGUMENT, result.error.issues[0].message);
|
|
4913
4955
|
}
|
|
4956
|
+
debug.log("[验证配置] 配置验证通过");
|
|
4914
4957
|
}
|
|
4915
4958
|
/**
|
|
4916
4959
|
* 执行安装流程
|
|
4917
4960
|
*/
|
|
4918
4961
|
async install() {
|
|
4919
4962
|
try {
|
|
4920
|
-
|
|
4963
|
+
debug.log("[安装开始]");
|
|
4921
4964
|
this.validateConfig();
|
|
4922
4965
|
let baseDir;
|
|
4923
4966
|
if (this.config.openclawPath) {
|
|
4924
|
-
|
|
4967
|
+
debug.log(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
|
|
4925
4968
|
try {
|
|
4926
4969
|
validateOpenclawPath(this.config.openclawPath);
|
|
4927
|
-
|
|
4970
|
+
debug.log("[路径验证] 通过");
|
|
4928
4971
|
} catch (error) {
|
|
4929
4972
|
throw new AppError$1(ERROR_CODES$1.INVALID_OPENCLAW_PATH, error.message);
|
|
4930
4973
|
}
|
|
@@ -4941,25 +4984,26 @@ class LocalInstaller {
|
|
|
4941
4984
|
workspace: path.join(baseDir, this.envConfig.DIRS.WORKSPACE),
|
|
4942
4985
|
temp: path.join(baseDir, this.envConfig.DIRS.TEMP)
|
|
4943
4986
|
};
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4987
|
+
debug.log(`[路径配置] home=${paths.home}`);
|
|
4988
|
+
debug.log(`[路径配置] extensions=${paths.extensions}`);
|
|
4989
|
+
debug.log(`[路径配置] target=${paths.target}`);
|
|
4990
|
+
debug.log(`[路径配置] config=${paths.config}`);
|
|
4991
|
+
debug.log(`[路径配置] workspace=${paths.workspace}`);
|
|
4949
4992
|
const machineId = generateMachineId();
|
|
4950
4993
|
const localCode = buildLocalCode(this.config.phone, machineId);
|
|
4951
|
-
|
|
4952
|
-
|
|
4994
|
+
debug.log(`[机器码] machineId=${machineId}`);
|
|
4995
|
+
debug.log(`[机器码] localCode=${localCode}`);
|
|
4953
4996
|
const token = await this.doLogin();
|
|
4997
|
+
this.token = token;
|
|
4954
4998
|
const boundConfig = await this.doFetchBoundConfig(token, localCode);
|
|
4955
4999
|
await this.doCleanOldFiles(paths.target);
|
|
4956
5000
|
await this.doDownloadFromNpm(paths);
|
|
4957
5001
|
await this.doUpdateConfig(paths, boundConfig);
|
|
4958
5002
|
try {
|
|
4959
5003
|
await fs.rm(paths.temp, { recursive: true, force: true });
|
|
4960
|
-
|
|
5004
|
+
debug.log("[安装完成] 清理根临时目录完成");
|
|
4961
5005
|
} catch {
|
|
4962
|
-
|
|
5006
|
+
debug.log("[安装完成] 清理根临时目录失败(忽略)");
|
|
4963
5007
|
}
|
|
4964
5008
|
this.spinner.stop();
|
|
4965
5009
|
} catch (error) {
|
|
@@ -4973,6 +5017,12 @@ class LocalInstaller {
|
|
|
4973
5017
|
getPrefixText() {
|
|
4974
5018
|
return this.prefixText;
|
|
4975
5019
|
}
|
|
5020
|
+
/**
|
|
5021
|
+
* 获取登录 token
|
|
5022
|
+
*/
|
|
5023
|
+
getToken() {
|
|
5024
|
+
return this.token;
|
|
5025
|
+
}
|
|
4976
5026
|
/**
|
|
4977
5027
|
* 获取完整的 npm 包名(包含版本号)
|
|
4978
5028
|
*/
|
|
@@ -4988,14 +5038,18 @@ class LocalInstaller {
|
|
|
4988
5038
|
async doLogin() {
|
|
4989
5039
|
this.spinner.prefixText = this.prefixText;
|
|
4990
5040
|
this.spinner.text = chalk.cyan("正在验证账号...");
|
|
4991
|
-
|
|
5041
|
+
debug.log(`[用户登录] 手机号: ${this.config.phone}`);
|
|
5042
|
+
debug.log("[用户登录] RSA 加密密码...");
|
|
4992
5043
|
const encryptedPassword = rsaEncrypt(this.config.userPass);
|
|
4993
5044
|
if (!encryptedPassword) {
|
|
4994
5045
|
throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, "密码加密失败");
|
|
4995
5046
|
}
|
|
5047
|
+
debug.log("[用户登录] 密码加密成功");
|
|
5048
|
+
debug.log("[用户登录] 调用登录接口...");
|
|
4996
5049
|
const token = await login(this.config.phone, encryptedPassword, this.envConfig);
|
|
4997
5050
|
this.prefixText += chalk.green(` ✓ 账号验证成功
|
|
4998
5051
|
`);
|
|
5052
|
+
debug.log("[用户登录] 登录成功");
|
|
4999
5053
|
return token;
|
|
5000
5054
|
}
|
|
5001
5055
|
/**
|
|
@@ -5004,10 +5058,13 @@ class LocalInstaller {
|
|
|
5004
5058
|
async doFetchBoundConfig(token, localCode) {
|
|
5005
5059
|
this.spinner.prefixText = this.prefixText;
|
|
5006
5060
|
this.spinner.text = chalk.cyan("正在获取绑定信息...");
|
|
5061
|
+
debug.log("[获取配置] 调用绑定配置接口...");
|
|
5062
|
+
debug.log(`[获取配置] localCode=${localCode}`);
|
|
5007
5063
|
const boundConfig = await fetchBoundConfig(token, this.config.phone, localCode, this.envConfig);
|
|
5008
|
-
|
|
5064
|
+
debug.log(`[获取配置] agentId=${boundConfig.agentId}, appKey=${boundConfig.appKey?.slice(0, 8)}...`);
|
|
5009
5065
|
this.prefixText += chalk.green(` ✓ 绑定信息获取成功
|
|
5010
5066
|
`);
|
|
5067
|
+
debug.log("[获取配置] 获取成功");
|
|
5011
5068
|
return boundConfig;
|
|
5012
5069
|
}
|
|
5013
5070
|
/**
|
|
@@ -5016,17 +5073,19 @@ class LocalInstaller {
|
|
|
5016
5073
|
async doCleanOldFiles(targetPath) {
|
|
5017
5074
|
this.spinner.prefixText = this.prefixText;
|
|
5018
5075
|
this.spinner.text = chalk.cyan("正在检查已安装版本...");
|
|
5076
|
+
debug.log(`[清理旧版本] 检查目录: ${targetPath}`);
|
|
5019
5077
|
try {
|
|
5020
5078
|
await fs.access(targetPath);
|
|
5021
5079
|
this.spinner.text = chalk.cyan("正在清理旧文件...");
|
|
5022
|
-
|
|
5080
|
+
debug.log("[清理旧版本] 发现旧版本,开始清理...");
|
|
5023
5081
|
await fs.rm(targetPath, { recursive: true, force: true });
|
|
5024
5082
|
this.prefixText += chalk.green(` ✓ 旧版本清理完成
|
|
5025
5083
|
`);
|
|
5026
|
-
|
|
5084
|
+
debug.log("[清理旧版本] 清理完成");
|
|
5027
5085
|
} catch {
|
|
5028
5086
|
this.prefixText += chalk.green(` ✓ 无旧版本需要清理
|
|
5029
5087
|
`);
|
|
5088
|
+
debug.log("[清理旧版本] 未发现旧版本");
|
|
5030
5089
|
}
|
|
5031
5090
|
}
|
|
5032
5091
|
/**
|
|
@@ -5035,21 +5094,26 @@ class LocalInstaller {
|
|
|
5035
5094
|
async doDownloadFromNpm(paths) {
|
|
5036
5095
|
this.spinner.prefixText = this.prefixText;
|
|
5037
5096
|
this.spinner.text = chalk.cyan("正在准备安装目录...");
|
|
5097
|
+
debug.log("[下载插件] 创建扩展目录...");
|
|
5038
5098
|
await fs.mkdir(paths.extensions, { recursive: true });
|
|
5039
|
-
|
|
5099
|
+
debug.log(`[下载插件] 扩展目录: ${paths.extensions}`);
|
|
5040
5100
|
const tempDir = path.join(paths.temp, `install-${Date.now()}`);
|
|
5101
|
+
debug.log(`[下载插件] 创建临时目录: ${tempDir}`);
|
|
5041
5102
|
await fs.mkdir(tempDir, { recursive: true });
|
|
5042
5103
|
this.spinner.prefixText = this.prefixText;
|
|
5043
5104
|
this.spinner.text = chalk.cyan("正在下载插件...");
|
|
5105
|
+
debug.log("[下载插件] 执行 npm pack 下载源码包");
|
|
5106
|
+
debug.log(`[下载插件] 工作目录: ${tempDir}`);
|
|
5044
5107
|
const maxRetries = 3;
|
|
5045
5108
|
let lastError = "";
|
|
5046
5109
|
let tarballPath = "";
|
|
5047
5110
|
for (let i = 1; i <= maxRetries; i++) {
|
|
5048
5111
|
this.spinner.prefixText = this.prefixText;
|
|
5049
5112
|
this.spinner.text = chalk.cyan(`正在下载 (${i}/${maxRetries})...`);
|
|
5113
|
+
debug.log(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
|
|
5050
5114
|
try {
|
|
5051
5115
|
const packageName = this.getPackageName();
|
|
5052
|
-
|
|
5116
|
+
debug.log(`[下载插件] 下载包名: ${packageName}`);
|
|
5053
5117
|
this.spinner.text = chalk.cyan("正在从 npm 获取插件...");
|
|
5054
5118
|
const output = await execAsync(
|
|
5055
5119
|
`npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts --quiet`,
|
|
@@ -5058,12 +5122,14 @@ class LocalInstaller {
|
|
|
5058
5122
|
const lines = output.trim().split("\n").filter((line) => line.trim());
|
|
5059
5123
|
const filename = lines[lines.length - 1] || "";
|
|
5060
5124
|
tarballPath = path.join(tempDir, filename);
|
|
5061
|
-
|
|
5125
|
+
debug.log(`[下载插件] tarball 下载成功: ${tarballPath}`);
|
|
5062
5126
|
break;
|
|
5063
5127
|
} catch (error) {
|
|
5064
5128
|
lastError = error.message || "未知错误";
|
|
5129
|
+
debug.log(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
|
|
5065
5130
|
if (i < maxRetries) {
|
|
5066
5131
|
this.spinner.text = chalk.cyan(`下载失败,3秒后重试...`);
|
|
5132
|
+
debug.log("[下载插件] 等待 3 秒后重试...");
|
|
5067
5133
|
await new Promise((resolve2) => setTimeout(resolve2, 3e3));
|
|
5068
5134
|
}
|
|
5069
5135
|
}
|
|
@@ -5073,16 +5139,16 @@ class LocalInstaller {
|
|
|
5073
5139
|
}
|
|
5074
5140
|
this.spinner.prefixText = this.prefixText;
|
|
5075
5141
|
this.spinner.text = chalk.cyan("正在解压插件...");
|
|
5076
|
-
|
|
5142
|
+
debug.log(`[下载插件] 创建插件目录: ${paths.target}`);
|
|
5077
5143
|
await fs.mkdir(paths.target, { recursive: true });
|
|
5078
|
-
|
|
5144
|
+
debug.log(`[下载插件] 解压 tarball 到: ${paths.target}`);
|
|
5079
5145
|
try {
|
|
5080
5146
|
await tar.extract({
|
|
5081
5147
|
file: tarballPath,
|
|
5082
5148
|
cwd: paths.target,
|
|
5083
5149
|
strip: 1
|
|
5084
5150
|
});
|
|
5085
|
-
|
|
5151
|
+
debug.log("[下载插件] tarball 解压成功");
|
|
5086
5152
|
} catch (error) {
|
|
5087
5153
|
throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
|
|
5088
5154
|
}
|
|
@@ -5091,18 +5157,22 @@ class LocalInstaller {
|
|
|
5091
5157
|
if (!pluginExists) {
|
|
5092
5158
|
throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
|
|
5093
5159
|
}
|
|
5160
|
+
debug.log("[下载插件] 插件解压成功");
|
|
5094
5161
|
this.spinner.prefixText = this.prefixText;
|
|
5095
5162
|
this.spinner.text = chalk.cyan("正在安装依赖...");
|
|
5163
|
+
debug.log("[下载插件] 执行 npm install 安装生产环境依赖");
|
|
5096
5164
|
try {
|
|
5097
5165
|
await execAsync("npm install --omit=dev --ignore-scripts --quiet", {
|
|
5098
5166
|
cwd: paths.target,
|
|
5099
5167
|
timeout: 12e4
|
|
5100
5168
|
});
|
|
5101
|
-
|
|
5169
|
+
debug.log("[下载插件] npm install 执行成功");
|
|
5102
5170
|
} catch (error) {
|
|
5103
5171
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
5104
|
-
if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated"))
|
|
5105
|
-
|
|
5172
|
+
if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) {
|
|
5173
|
+
debug.log("[下载插件] npm install 有警告但可能成功,继续流程");
|
|
5174
|
+
} else {
|
|
5175
|
+
debug.log(`[下载插件] npm install 失败: ${errorMsg}`);
|
|
5106
5176
|
throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `依赖安装失败: ${errorMsg}`);
|
|
5107
5177
|
}
|
|
5108
5178
|
}
|
|
@@ -5110,8 +5180,9 @@ class LocalInstaller {
|
|
|
5110
5180
|
`);
|
|
5111
5181
|
try {
|
|
5112
5182
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
5113
|
-
|
|
5183
|
+
debug.log("[下载插件] 清理临时下载目录完成");
|
|
5114
5184
|
} catch {
|
|
5185
|
+
debug.log("[下载插件] 清理临时下载目录失败(忽略)");
|
|
5115
5186
|
}
|
|
5116
5187
|
}
|
|
5117
5188
|
/**
|
|
@@ -5120,14 +5191,18 @@ class LocalInstaller {
|
|
|
5120
5191
|
async doUpdateConfig(paths, boundConfig) {
|
|
5121
5192
|
this.spinner.prefixText = this.prefixText;
|
|
5122
5193
|
this.spinner.text = chalk.cyan("正在生成配置...");
|
|
5194
|
+
debug.log("[更新配置] 创建目录...");
|
|
5123
5195
|
await fs.mkdir(paths.home, { recursive: true });
|
|
5124
5196
|
await fs.mkdir(paths.workspace, { recursive: true });
|
|
5197
|
+
debug.log("[更新配置] 目录创建完成");
|
|
5198
|
+
debug.log("[更新配置] 读取原有配置...");
|
|
5125
5199
|
let originalConfig = {};
|
|
5126
5200
|
try {
|
|
5127
5201
|
const content = await fs.readFile(paths.config, "utf-8");
|
|
5128
5202
|
originalConfig = JSON.parse(content);
|
|
5129
|
-
|
|
5203
|
+
debug.log("[更新配置] 读取原有配置成功");
|
|
5130
5204
|
} catch {
|
|
5205
|
+
debug.log("[更新配置] 无原有配置");
|
|
5131
5206
|
}
|
|
5132
5207
|
const config = this.envConfig;
|
|
5133
5208
|
const newConfig = {
|
|
@@ -5296,16 +5371,19 @@ class LocalInstaller {
|
|
|
5296
5371
|
const finalConfig = deepMerge(originalConfig, newConfig);
|
|
5297
5372
|
this.spinner.prefixText = this.prefixText;
|
|
5298
5373
|
this.spinner.text = chalk.cyan("正在写入配置...");
|
|
5374
|
+
debug.log("[更新配置] 写入配置文件...");
|
|
5299
5375
|
await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
|
|
5300
5376
|
this.prefixText += chalk.green(` ✓ 配置更新完成
|
|
5301
5377
|
`);
|
|
5302
|
-
|
|
5378
|
+
debug.log(`[更新配置] 配置文件写入成功: ${paths.config}`);
|
|
5303
5379
|
}
|
|
5304
5380
|
}
|
|
5305
5381
|
async function createLocalCommand(options) {
|
|
5306
5382
|
setDebug(!!options.debug);
|
|
5307
|
-
|
|
5383
|
+
debug.log("[初始化] 开始处理...");
|
|
5384
|
+
debug.log(`[初始化] 参数: env=${options.env}, phone=${options.phone}, customIp=${options.customIp}, debug=${options.debug}`);
|
|
5308
5385
|
checkEnv();
|
|
5386
|
+
debug.log("[初始化] 环境检查通过");
|
|
5309
5387
|
try {
|
|
5310
5388
|
let env = options.env;
|
|
5311
5389
|
let phone = options.phone;
|
|
@@ -5313,7 +5391,7 @@ async function createLocalCommand(options) {
|
|
|
5313
5391
|
let customIp = options.customIp;
|
|
5314
5392
|
const questions = [];
|
|
5315
5393
|
if (!env) {
|
|
5316
|
-
|
|
5394
|
+
debug.log("[初始化] 需要选择环境");
|
|
5317
5395
|
questions.push({
|
|
5318
5396
|
type: "list",
|
|
5319
5397
|
name: "env",
|
|
@@ -5326,10 +5404,10 @@ async function createLocalCommand(options) {
|
|
|
5326
5404
|
]
|
|
5327
5405
|
});
|
|
5328
5406
|
} else {
|
|
5329
|
-
|
|
5407
|
+
debug.log(`[初始化] 使用命令行参数: env=${env}`);
|
|
5330
5408
|
}
|
|
5331
5409
|
if (!phone) {
|
|
5332
|
-
|
|
5410
|
+
debug.log("[初始化] 需要输入手机号码");
|
|
5333
5411
|
questions.push({
|
|
5334
5412
|
type: "input",
|
|
5335
5413
|
name: "phone",
|
|
@@ -5346,10 +5424,10 @@ async function createLocalCommand(options) {
|
|
|
5346
5424
|
}
|
|
5347
5425
|
});
|
|
5348
5426
|
} else {
|
|
5349
|
-
|
|
5427
|
+
debug.log("[初始化] 使用命令行参数: phone");
|
|
5350
5428
|
}
|
|
5351
5429
|
if (!userPass) {
|
|
5352
|
-
|
|
5430
|
+
debug.log("[初始化] 需要输入用户密码");
|
|
5353
5431
|
questions.push({
|
|
5354
5432
|
type: "input",
|
|
5355
5433
|
name: "userPass",
|
|
@@ -5363,18 +5441,18 @@ async function createLocalCommand(options) {
|
|
|
5363
5441
|
}
|
|
5364
5442
|
});
|
|
5365
5443
|
} else {
|
|
5366
|
-
|
|
5444
|
+
debug.log("[初始化] 使用命令行参数: userPass");
|
|
5367
5445
|
}
|
|
5368
5446
|
if (questions.length > 0) {
|
|
5369
|
-
|
|
5447
|
+
debug.log(`[初始化] 开始交互式问答,共 ${questions.length} 个问题`);
|
|
5370
5448
|
const answers = await inquirer.prompt(questions);
|
|
5371
|
-
|
|
5449
|
+
debug.log("[初始化] 交互式问答完成");
|
|
5372
5450
|
env = env || answers.env || "test";
|
|
5373
5451
|
phone = phone || answers.phone;
|
|
5374
5452
|
userPass = userPass || answers.userPass;
|
|
5375
5453
|
}
|
|
5376
5454
|
if (env === "custom" && !customIp) {
|
|
5377
|
-
|
|
5455
|
+
debug.log("[初始化] 自定义环境需要输入后端 IP");
|
|
5378
5456
|
const answer = await inquirer.prompt([{
|
|
5379
5457
|
type: "input",
|
|
5380
5458
|
name: "customIp",
|
|
@@ -5392,12 +5470,12 @@ async function createLocalCommand(options) {
|
|
|
5392
5470
|
}
|
|
5393
5471
|
}]);
|
|
5394
5472
|
customIp = answer.customIp;
|
|
5395
|
-
|
|
5473
|
+
debug.log("[初始化] 获取自定义 customIp");
|
|
5396
5474
|
} else if (env === "custom" && customIp) {
|
|
5397
|
-
|
|
5475
|
+
debug.log(`[初始化] 使用命令行参数: customIp=${customIp}`);
|
|
5398
5476
|
}
|
|
5399
|
-
|
|
5400
|
-
|
|
5477
|
+
debug.log(`[初始化] 最终参数: env=${env}, phone=${phone}, customIp=${customIp}, pluginVersion=${options.pluginVersion}, openclawPath=${options.openclawPath}`);
|
|
5478
|
+
debug.log("[初始化] 创建 LocalInstaller 实例...");
|
|
5401
5479
|
const installer = new LocalInstaller({
|
|
5402
5480
|
phone,
|
|
5403
5481
|
userPass,
|
|
@@ -5407,9 +5485,9 @@ async function createLocalCommand(options) {
|
|
|
5407
5485
|
pluginVersion: options.pluginVersion,
|
|
5408
5486
|
openclawPath: options.openclawPath
|
|
5409
5487
|
});
|
|
5410
|
-
|
|
5488
|
+
debug.log("[初始化] 开始安装...");
|
|
5411
5489
|
await installer.install();
|
|
5412
|
-
|
|
5490
|
+
debug.log("[初始化] 安装完成");
|
|
5413
5491
|
console.log(installer.getPrefixText() + boxen(
|
|
5414
5492
|
`${chalk.green("✦")} 插件初始化成功!`,
|
|
5415
5493
|
{
|
|
@@ -5422,8 +5500,12 @@ async function createLocalCommand(options) {
|
|
|
5422
5500
|
textAlignment: "center"
|
|
5423
5501
|
}
|
|
5424
5502
|
));
|
|
5503
|
+
if (options.printToken) {
|
|
5504
|
+
const token = installer.getToken();
|
|
5505
|
+
console.log("\n" + chalk.cyan("Token: ") + token);
|
|
5506
|
+
}
|
|
5425
5507
|
} catch (error) {
|
|
5426
|
-
|
|
5508
|
+
debug.log(`[初始化] 发生错误: ${error.message}`);
|
|
5427
5509
|
console.error(boxen(
|
|
5428
5510
|
`${chalk.yellow(error.message)}`,
|
|
5429
5511
|
{
|
|
@@ -5440,7 +5522,7 @@ async function createLocalCommand(options) {
|
|
|
5440
5522
|
}
|
|
5441
5523
|
}
|
|
5442
5524
|
function registerCommands(program2) {
|
|
5443
|
-
program2.command("local").description("本地账户安装(需要登录)").option("-e, --env <env>", "环境 (test/prod/custom)").option("--phone <phone>", "手机号码").option("--user-pass <userPass>", "用户密码").option("--custom-ip <ip>", "自定义后端 IP(仅 custom 环境生效)").option("--ws-url <url>", "自定义 WebSocket URL(仅 custom 环境生效,默认自动生成)").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--openclaw-path <path>", "OpenClaw 安装目录路径(默认 ~/.openclaw)").option("--debug", "开启调试日志").action(createLocalCommand);
|
|
5525
|
+
program2.command("local").description("本地账户安装(需要登录)").option("-e, --env <env>", "环境 (test/prod/custom)").option("--phone <phone>", "手机号码").option("--user-pass <userPass>", "用户密码").option("--custom-ip <ip>", "自定义后端 IP(仅 custom 环境生效)").option("--ws-url <url>", "自定义 WebSocket URL(仅 custom 环境生效,默认自动生成)").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--openclaw-path <path>", "OpenClaw 安装目录路径(默认 ~/.openclaw)").option("--debug", "开启调试日志").option("--print-token", "执行完成后输出 token").action(createLocalCommand);
|
|
5444
5526
|
}
|
|
5445
5527
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
5446
5528
|
const __dirname$1 = dirname(__filename$1);
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAavD"}
|
|
@@ -8,6 +8,7 @@ export declare class LocalInstaller {
|
|
|
8
8
|
private prefixText;
|
|
9
9
|
private readonly config;
|
|
10
10
|
private readonly envConfig;
|
|
11
|
+
private token;
|
|
11
12
|
/**
|
|
12
13
|
* 构造函数
|
|
13
14
|
*/
|
|
@@ -24,6 +25,10 @@ export declare class LocalInstaller {
|
|
|
24
25
|
* 获取前缀文本(用于显示安装进度)
|
|
25
26
|
*/
|
|
26
27
|
getPrefixText(): string;
|
|
28
|
+
/**
|
|
29
|
+
* 获取登录 token
|
|
30
|
+
*/
|
|
31
|
+
getToken(): string;
|
|
27
32
|
/**
|
|
28
33
|
* 获取完整的 npm 包名(包含版本号)
|
|
29
34
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/local/installer/installer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA6B,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAgF/E;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/local/installer/installer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA6B,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAgF/E;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,KAAK,CAAa;IAE1B;;OAEG;gBACS,MAAM,EAAE,oBAAoB;IAOxC;;OAEG;IACH,cAAc,IAAI,IAAI;IAUtB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgE9B;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIlB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;YACW,OAAO;IAoBrB;;OAEG;YACW,kBAAkB;IAchC;;OAEG;YACW,eAAe;IAmB7B;;OAEG;YACW,iBAAiB;IAoH/B;;OAEG;YACW,cAAc;CAmN7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/local/src/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAQ5C;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/local/src/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAQ5C;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+J7E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAWvB,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAWvB,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;iBAmBtC,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAA;AAE7E;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;iBAO5B,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE3D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Debug } from '@mingto/debug';
|
|
2
|
+
declare const debug: Debug;
|
|
1
3
|
/**
|
|
2
4
|
* 设置调试模式
|
|
3
5
|
*/
|
|
@@ -6,8 +8,5 @@ export declare function setDebug(enabled: boolean): void;
|
|
|
6
8
|
* 检查是否为调试模式
|
|
7
9
|
*/
|
|
8
10
|
export declare function isDebugMode(): boolean;
|
|
9
|
-
|
|
10
|
-
* 输出调试日志
|
|
11
|
-
*/
|
|
12
|
-
export declare function debugLog(...args: unknown[]): void;
|
|
11
|
+
export { debug };
|
|
13
12
|
//# sourceMappingURL=debug.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/debug.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/debug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAErC,QAAA,MAAM,KAAK,OAAc,CAAA;AAEzB;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO/C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAC/C,YAAY,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,QAAQ,EACR,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA"}
|