@workclaw/cli 1.0.322 → 1.0.326

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.
@@ -14,17 +14,11 @@ import fs from "node:fs/promises";
14
14
  import ora from "ora";
15
15
  import tar from "tar";
16
16
  import axios from "axios";
17
- import os from "node:os";
18
17
  import crypto from "node:crypto";
18
+ import os from "node:os";
19
19
  const debug = new Debug();
20
20
  function setDebug(enabled) {
21
- if (enabled) {
22
- debug.enable();
23
- } else {
24
- debug.disable();
25
- }
26
- }
27
- function debugLog(...args) {
21
+ debug.enable(enabled);
28
22
  }
29
23
  const ERROR_CODES$1 = {
30
24
  PHONE_REQUIRED: "PHONE_REQUIRED",
@@ -49,14 +43,18 @@ let AppError$1 = class AppError extends Error {
49
43
  }
50
44
  };
51
45
  function checkEnv() {
46
+ debug.log("[环境检查] 检测 Node.js 版本...");
52
47
  const nodeVersion = execSync("node --version", { stdio: "pipe" }).toString().trim();
48
+ debug.log(`[环境检查] Node.js 版本: ${nodeVersion}`);
53
49
  if (!semver.gte(nodeVersion, "18.0.0")) {
54
50
  throw new AppError$1(ERROR_CODES$1.NODE_VERSION_LOW, `Node.js 版本需要 >= 18.0.0,当前版本: ${nodeVersion}`);
55
51
  }
52
+ debug.log("[环境检查] Node.js 版本检查通过");
53
+ debug.log("[环境检查] 检测 npm...");
56
54
  try {
57
55
  const npmVersion = execSync("npm --version", { stdio: "pipe" }).toString().trim();
58
- debugLog(`[环境检查] npm 版本: ${npmVersion}`);
59
- debugLog("[环境检查] npm 检测通过");
56
+ debug.log(`[环境检查] npm 版本: ${npmVersion}`);
57
+ debug.log("[环境检查] npm 检测通过");
60
58
  } catch {
61
59
  throw new AppError$1(ERROR_CODES$1.NPM_NOT_FOUND, "未检测到 npm,请先安装 Node.js 和 npm");
62
60
  }
@@ -99,12 +97,22 @@ const wsUrlSchema = z$1.string().url({
99
97
  message: "请输入有效的 WebSocket URL"
100
98
  }).optional();
101
99
  z$1.boolean();
100
+ function cleanWindowsLongPath(inputPath) {
101
+ return inputPath.replace(/^[\\?]+/, "");
102
+ }
103
+ function normalizePath(inputPath) {
104
+ const cleaned = cleanWindowsLongPath(inputPath);
105
+ const normalized = path.normalize(cleaned);
106
+ return path.resolve(normalized);
107
+ }
102
108
  function validateOpenclawPath(openclawPath) {
109
+ debug.log(`[路径验证] 开始验证路径: ${openclawPath}`);
103
110
  const result = openclawPathSchema.safeParse(openclawPath);
104
111
  if (!result.success) {
105
- debugLog(`[路径验证] 失败: ${result.error.issues[0].message}`);
112
+ debug.log(`[路径验证] 失败: ${result.error.issues[0].message}`);
106
113
  throw new Error(result.error.issues[0].message);
107
114
  }
115
+ debug.log(`[路径验证] 通过: ${openclawPath}`);
108
116
  }
109
117
  const CONFIG = {
110
118
  PLUGIN_NAME: "openclaw-workclaw",
@@ -226,6 +234,7 @@ class BoxInstaller {
226
234
  spinner;
227
235
  prefixText = "";
228
236
  validateConfig() {
237
+ debug.log("[验证配置] 检查 appKey 和 appSecret...");
229
238
  if (!this.config.appKey) {
230
239
  throw new AppError2(ERROR_CODES.APP_KEY_REQUIRED, "AppKey 不能为空,请使用 --app-key 参数");
231
240
  }
@@ -233,6 +242,7 @@ class BoxInstaller {
233
242
  throw new AppError2(ERROR_CODES.APP_SECRET_REQUIRED, "AppSecret 不能为空,请使用 --app-secret 参数");
234
243
  }
235
244
  if (this.config.env === "custom") {
245
+ debug.log("[验证配置] 检查自定义环境 IP...");
236
246
  if (!this.config.customIp) {
237
247
  throw new AppError2(ERROR_CODES.INVALID_ARGUMENT, "自定义环境必须提供 --customIp 参数");
238
248
  }
@@ -240,22 +250,24 @@ class BoxInstaller {
240
250
  if (!result.success) {
241
251
  throw new AppError2(ERROR_CODES.INVALID_ARGUMENT, result.error.issues[0].message);
242
252
  }
253
+ debug.log("[验证配置] 自定义环境 IP 验证通过");
243
254
  }
255
+ debug.log("[验证配置] 配置检查通过");
244
256
  }
245
257
  getPaths() {
246
258
  const env = this.config.env || "test";
247
- debugLog(`[getConfig] env=${env}, customIp=${this.config.customIp}`);
259
+ debug.log(`[getConfig] env=${env}, customIp=${this.config.customIp}`);
248
260
  const config = getConfig(env, this.config.customIp);
249
261
  let baseDir;
250
262
  if (this.config.openclawPath) {
251
- debugLog(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
263
+ debug.log(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
252
264
  try {
253
265
  validateOpenclawPath(this.config.openclawPath);
254
- debugLog("[路径验证] 通过");
266
+ debug.log("[路径验证] 通过");
255
267
  } catch (error) {
256
268
  throw new AppError2(ERROR_CODES.INVALID_OPENCLAW_PATH, error.message);
257
269
  }
258
- baseDir = this.config.openclawPath;
270
+ baseDir = normalizePath(this.config.openclawPath);
259
271
  } else {
260
272
  const home = getHomeDir$1();
261
273
  baseDir = path.join(home, config.DIRS.OPENCLAW);
@@ -277,6 +289,7 @@ class BoxInstaller {
277
289
  updateSpinner(text) {
278
290
  this.spinner.prefixText = this.prefixText;
279
291
  this.spinner.text = chalk.cyan(text);
292
+ debug.log(`[Spinner] ${text}`);
280
293
  }
281
294
  getPrefixText() {
282
295
  return this.prefixText;
@@ -289,7 +302,7 @@ class BoxInstaller {
289
302
  }
290
303
  async install() {
291
304
  try {
292
- debugLog("[盒子安装] 开始安装...");
305
+ debug.log("[盒子安装] 开始安装...");
293
306
  this.validateConfig();
294
307
  this.prefixText += chalk.green(` ✓ 配置验证完成
295
308
  `);
@@ -299,25 +312,27 @@ class BoxInstaller {
299
312
  await this.doDownloadFromNpm();
300
313
  await this.doUpdateConfig(paths);
301
314
  this.spinner.stop();
302
- debugLog("[盒子安装] 安装完成");
315
+ debug.log("[盒子安装] 安装完成");
303
316
  } catch (error) {
304
317
  this.spinner.stop();
305
- debugLog(`[盒子安装] 安装失败: ${error.message}`);
318
+ debug.log(`[盒子安装] 安装失败: ${error.message}`);
306
319
  throw error;
307
320
  }
308
321
  }
309
322
  async doCleanOldFiles(paths) {
323
+ debug.log("[清理旧版本] 开始清理旧版本...");
310
324
  this.prefixText += chalk.green(` ✓ 开始清理旧版本
311
325
  `);
312
326
  this.updateSpinner("正在清理旧版本...");
313
327
  try {
314
328
  await fs.access(paths.target);
315
- debugLog("[清理旧版本] 删除旧版本目录...");
329
+ debug.log("[清理旧版本] 删除旧版本目录...");
316
330
  await fs.rm(paths.target, { recursive: true, force: true });
317
331
  this.prefixText += chalk.green(` ✓ 旧版本清理成功
318
332
  `);
319
- debugLog("[清理旧版本] 旧版本清理成功");
333
+ debug.log("[清理旧版本] 旧版本清理成功");
320
334
  } catch {
335
+ debug.log("[清理旧版本] 无旧版本需要清理");
321
336
  this.prefixText += chalk.green(` ✓ 无旧版本需要清理
322
337
  `);
323
338
  }
@@ -325,27 +340,33 @@ class BoxInstaller {
325
340
  await fs.access(paths.temp);
326
341
  await fs.rm(paths.temp, { recursive: true, force: true });
327
342
  } catch {
343
+ debug.log("[清理旧版本] 无临时目录需要清理");
328
344
  }
329
345
  }
330
346
  async doDownloadFromNpm() {
331
347
  const paths = this.getPaths();
332
348
  this.spinner.prefixText = this.prefixText;
333
349
  this.spinner.text = chalk.cyan("正在准备安装目录...");
350
+ debug.log("[下载插件] 创建扩展目录...");
334
351
  await fs.mkdir(paths.extensions, { recursive: true });
335
- debugLog(`[下载插件] 扩展目录: ${paths.extensions}`);
352
+ debug.log(`[下载插件] 扩展目录: ${paths.extensions}`);
336
353
  const tempDir = path.join(paths.temp, `install-${Date.now()}`);
354
+ debug.log(`[下载插件] 创建临时目录: ${tempDir}`);
337
355
  await fs.mkdir(tempDir, { recursive: true });
338
356
  this.spinner.prefixText = this.prefixText;
339
357
  this.spinner.text = chalk.cyan("正在下载插件...");
358
+ debug.log("[下载插件] 执行 npm pack 下载源码包");
359
+ debug.log(`[下载插件] 工作目录: ${tempDir}`);
340
360
  const maxRetries = 3;
341
361
  let lastError = "";
342
362
  let tarballPath = "";
343
363
  for (let i = 1; i <= maxRetries; i++) {
344
364
  this.spinner.prefixText = this.prefixText;
345
365
  this.spinner.text = chalk.cyan(`正在下载 (${i}/${maxRetries})...`);
366
+ debug.log(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
346
367
  try {
347
368
  const packageName = this.getPackageName();
348
- debugLog(`[下载插件] 下载包名: ${packageName}`);
369
+ debug.log(`[下载插件] 下载包名: ${packageName}`);
349
370
  this.spinner.text = chalk.cyan("正在从 npm 获取插件...");
350
371
  const output = await execAsync$1(
351
372
  `npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts --quiet`,
@@ -354,12 +375,14 @@ class BoxInstaller {
354
375
  const lines = output.trim().split("\n").filter((line) => line.trim());
355
376
  const filename = lines[lines.length - 1] || "";
356
377
  tarballPath = path.join(tempDir, filename);
357
- debugLog(`[下载插件] tarball 下载成功: ${tarballPath}`);
378
+ debug.log(`[下载插件] tarball 下载成功: ${tarballPath}`);
358
379
  break;
359
380
  } catch (error) {
360
381
  lastError = error.message || "未知错误";
382
+ debug.log(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
361
383
  if (i < maxRetries) {
362
384
  this.spinner.text = chalk.cyan(`下载失败,3秒后重试...`);
385
+ debug.log("[下载插件] 等待 3 秒后重试...");
363
386
  await new Promise((resolve2) => setTimeout(resolve2, 3e3));
364
387
  }
365
388
  }
@@ -369,16 +392,16 @@ class BoxInstaller {
369
392
  }
370
393
  this.spinner.prefixText = this.prefixText;
371
394
  this.spinner.text = chalk.cyan("正在解压插件...");
372
- debugLog(`[下载插件] 创建插件目录: ${paths.target}`);
395
+ debug.log(`[下载插件] 创建插件目录: ${paths.target}`);
373
396
  await fs.mkdir(paths.target, { recursive: true });
374
- debugLog(`[下载插件] 解压 tarball 到: ${paths.target}`);
397
+ debug.log(`[下载插件] 解压 tarball 到: ${paths.target}`);
375
398
  try {
376
399
  await tar.extract({
377
400
  file: tarballPath,
378
401
  cwd: paths.target,
379
402
  strip: 1
380
403
  });
381
- debugLog("[下载插件] tarball 解压成功");
404
+ debug.log("[下载插件] tarball 解压成功");
382
405
  } catch (error) {
383
406
  throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
384
407
  }
@@ -387,27 +410,35 @@ class BoxInstaller {
387
410
  if (!pluginExists) {
388
411
  throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
389
412
  }
413
+ debug.log("[下载插件] 插件解压成功");
390
414
  this.spinner.prefixText = this.prefixText;
391
415
  this.spinner.text = chalk.cyan("正在安装依赖...");
416
+ debug.log("[下载插件] 执行 npm install 安装生产环境依赖");
392
417
  try {
393
418
  await execAsync$1("npm install --omit=dev --ignore-scripts --quiet", {
394
419
  cwd: paths.target,
395
420
  timeout: 12e4
396
421
  });
397
- debugLog("[下载插件] npm install 执行成功");
422
+ debug.log("[下载插件] npm install 执行成功");
398
423
  } catch (error) {
399
424
  const errorMsg = error.message || "";
400
- if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) ;
425
+ if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) {
426
+ debug.log("[下载插件] npm install 有警告但可能成功,继续流程");
427
+ } else {
428
+ debug.log(`[下载插件] npm install 失败: ${errorMsg}`);
429
+ }
401
430
  }
402
431
  this.prefixText += chalk.green(` ✓ 插件安装完成
403
432
  `);
404
433
  try {
405
434
  await fs.rm(tempDir, { recursive: true, force: true });
406
- debugLog("[下载插件] 清理临时目录完成");
435
+ debug.log("[下载插件] 清理临时目录完成");
407
436
  } catch {
437
+ debug.log("[下载插件] 清理临时目录失败(忽略)");
408
438
  }
409
439
  }
410
440
  async doUpdateConfig(paths) {
441
+ debug.log("[更新配置] 开始更新配置...");
411
442
  this.prefixText += chalk.green(` ✓ 开始更新配置
412
443
  `);
413
444
  this.updateSpinner("正在生成配置...");
@@ -415,8 +446,9 @@ class BoxInstaller {
415
446
  try {
416
447
  const content = await fs.readFile(paths.config, "utf-8");
417
448
  originalConfig = JSON.parse(content);
418
- debugLog("[更新配置] 读取原有配置成功");
449
+ debug.log("[更新配置] 读取原有配置成功");
419
450
  } catch {
451
+ debug.log("[更新配置] 无原有配置");
420
452
  }
421
453
  const config = getConfig(this.config.env || "test", this.config.customIp);
422
454
  const newConfig = {
@@ -655,16 +687,19 @@ class BoxInstaller {
655
687
  };
656
688
  const finalConfig = deepMerge$1(originalConfig, newConfig);
657
689
  this.updateSpinner("正在写入配置...");
690
+ debug.log("[更新配置] 写入配置文件...");
658
691
  await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
659
692
  this.prefixText += chalk.green(` ✓ 配置文件更新成功
660
693
  `);
661
- debugLog(`[更新配置] 配置文件写入成功: ${paths.config}`);
694
+ debug.log(`[更新配置] 配置文件写入成功: ${paths.config}`);
662
695
  }
663
696
  }
664
697
  async function createBoxCommand(options) {
665
698
  setDebug(!!options.debug);
666
- debugLog(`[盒子安装] 参数: env=${options.env}, appKey=${options.appKey ? "***" : "未提供"}, customIp=${options.customIp}, debug=${options.debug}`);
699
+ debug.log("[盒子安装] 开始处理...");
700
+ debug.log(`[盒子安装] 参数: env=${options.env}, appKey=${options.appKey ? "***" : "未提供"}, customIp=${options.customIp}, debug=${options.debug}`);
667
701
  checkEnv();
702
+ debug.log("[盒子安装] 环境检查通过");
668
703
  try {
669
704
  let env = options.env;
670
705
  let appKey = options.appKey;
@@ -672,7 +707,7 @@ async function createBoxCommand(options) {
672
707
  let customIp = options.customIp;
673
708
  const questions = [];
674
709
  if (!env) {
675
- debugLog("[盒子安装] 需要选择环境");
710
+ debug.log("[盒子安装] 需要选择环境");
676
711
  questions.push({
677
712
  type: "list",
678
713
  name: "env",
@@ -685,10 +720,10 @@ async function createBoxCommand(options) {
685
720
  ]
686
721
  });
687
722
  } else {
688
- debugLog(`[盒子安装] 使用命令行参数: env=${env}`);
723
+ debug.log(`[盒子安装] 使用命令行参数: env=${env}`);
689
724
  }
690
725
  if (!appKey) {
691
- debugLog("[盒子安装] 需要输入 AppKey");
726
+ debug.log("[盒子安装] 需要输入 AppKey");
692
727
  questions.push({
693
728
  type: "input",
694
729
  name: "appKey",
@@ -702,10 +737,10 @@ async function createBoxCommand(options) {
702
737
  }
703
738
  });
704
739
  } else {
705
- debugLog("[盒子安装] 使用命令行参数: appKey");
740
+ debug.log("[盒子安装] 使用命令行参数: appKey");
706
741
  }
707
742
  if (!appSecret) {
708
- debugLog("[盒子安装] 需要输入 AppSecret");
743
+ debug.log("[盒子安装] 需要输入 AppSecret");
709
744
  questions.push({
710
745
  type: "input",
711
746
  name: "appSecret",
@@ -719,18 +754,18 @@ async function createBoxCommand(options) {
719
754
  }
720
755
  });
721
756
  } else {
722
- debugLog("[盒子安装] 使用命令行参数: appSecret");
757
+ debug.log("[盒子安装] 使用命令行参数: appSecret");
723
758
  }
724
759
  if (questions.length > 0) {
725
- debugLog(`[盒子安装] 开始交互式问答,共 ${questions.length} 个问题`);
760
+ debug.log(`[盒子安装] 开始交互式问答,共 ${questions.length} 个问题`);
726
761
  const answers = await inquirer.prompt(questions);
727
- debugLog("[盒子安装] 交互式问答完成");
762
+ debug.log("[盒子安装] 交互式问答完成");
728
763
  env = env || answers.env || "test";
729
764
  appKey = appKey || answers.appKey;
730
765
  appSecret = appSecret || answers.appSecret;
731
766
  }
732
767
  if (env === "custom" && !customIp) {
733
- debugLog("[盒子安装] 自定义环境需要输入后端 IP");
768
+ debug.log("[盒子安装] 自定义环境需要输入后端 IP");
734
769
  const answer = await inquirer.prompt([{
735
770
  type: "input",
736
771
  name: "customIp",
@@ -748,12 +783,12 @@ async function createBoxCommand(options) {
748
783
  }
749
784
  }]);
750
785
  customIp = answer.customIp;
751
- debugLog("[盒子安装] 获取自定义 customIp");
786
+ debug.log("[盒子安装] 获取自定义 customIp");
752
787
  } else if (env === "custom" && customIp) {
753
- debugLog(`[盒子安装] 使用命令行参数: customIp=${customIp}`);
788
+ debug.log(`[盒子安装] 使用命令行参数: customIp=${customIp}`);
754
789
  }
755
- debugLog(`[盒子安装] 最终参数: env=${env}, customIp=${customIp}, openclawPath=${options.openclawPath}`);
756
- debugLog("[盒子安装] 创建 BoxInstaller 实例...");
790
+ debug.log(`[盒子安装] 最终参数: env=${env}, customIp=${customIp}, openclawPath=${options.openclawPath}`);
791
+ debug.log("[盒子安装] 创建 BoxInstaller 实例...");
757
792
  const installer = new BoxInstaller({
758
793
  appKey,
759
794
  appSecret,
@@ -763,9 +798,9 @@ async function createBoxCommand(options) {
763
798
  pluginVersion: options.pluginVersion,
764
799
  openclawPath: options.openclawPath
765
800
  });
766
- debugLog("[盒子安装] 开始安装...");
801
+ debug.log("[盒子安装] 开始安装...");
767
802
  await installer.install();
768
- debugLog("[盒子安装] 安装完成");
803
+ debug.log("[盒子安装] 安装完成");
769
804
  console.log(installer.getPrefixText() + boxen(
770
805
  `${chalk.green("✦")} 插件初始化成功!`,
771
806
  {
@@ -779,7 +814,7 @@ async function createBoxCommand(options) {
779
814
  }
780
815
  ));
781
816
  } catch (error) {
782
- debugLog(`[盒子安装] 发生错误: ${error.message}`);
817
+ debug.log(`[盒子安装] 发生错误: ${error.message}`);
783
818
  console.error(boxen(
784
819
  `${chalk.yellow(error.message)}`,
785
820
  {
@@ -809,12 +844,13 @@ function createHttpClient(baseURL) {
809
844
  }
810
845
  async function httpPost(url, data, config) {
811
846
  const client = createHttpClient();
812
- debugLog(`[HTTP POST] 请求参数: ${JSON.stringify(data)}`);
813
- debugLog(`[HTTP POST] 请求头: ${JSON.stringify(config?.headers || {})}`);
847
+ debug.log(`[HTTP POST] 请求地址: ${url}`);
848
+ debug.log(`[HTTP POST] 请求参数: ${JSON.stringify(data)}`);
849
+ debug.log(`[HTTP POST] 请求头: ${JSON.stringify(config?.headers || {})}`);
814
850
  try {
815
851
  const response = await client.post(url, data, config);
816
- debugLog(`[HTTP POST] 响应状态: ${response.status}`);
817
- debugLog(`[HTTP POST] 响应内容: ${JSON.stringify(response.data)}`);
852
+ debug.log(`[HTTP POST] 响应状态: ${response.status}`);
853
+ debug.log(`[HTTP POST] 响应内容: ${JSON.stringify(response.data)}`);
818
854
  return {
819
855
  status: response.status,
820
856
  data: response.data
@@ -823,9 +859,9 @@ async function httpPost(url, data, config) {
823
859
  const axiosError = error;
824
860
  if (axiosError.response) {
825
861
  const responseData = axiosError.response.data;
826
- debugLog(`[HTTP POST] 响应状态: ${axiosError.response.status}`);
827
- debugLog(`[HTTP POST] 响应状态文本: ${axiosError.response.statusText}`);
828
- debugLog(`[HTTP POST] 响应数据: ${JSON.stringify(responseData)}`);
862
+ debug.log(`[HTTP POST] 响应状态: ${axiosError.response.status}`);
863
+ debug.log(`[HTTP POST] 响应状态文本: ${axiosError.response.statusText}`);
864
+ debug.log(`[HTTP POST] 响应数据: ${JSON.stringify(responseData)}`);
829
865
  if (typeof responseData === "string") {
830
866
  throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${responseData}`);
831
867
  } else if (responseData && typeof responseData === "object" && "message" in responseData) {
@@ -834,40 +870,48 @@ async function httpPost(url, data, config) {
834
870
  throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${axiosError.response.statusText}`);
835
871
  }
836
872
  } else if (axiosError.request) {
837
- debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
873
+ debug.log(`[HTTP POST] 未收到响应`);
874
+ debug.log(`[HTTP POST] 错误信息: ${axiosError.message}`);
838
875
  throw new AppError$1(ERROR_CODES$1.NETWORK_ERROR, `网络错误: ${axiosError.message}`);
839
876
  } else {
840
- debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
877
+ debug.log(`[HTTP POST] 请求配置错误`);
878
+ debug.log(`[HTTP POST] 错误信息: ${axiosError.message}`);
841
879
  throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求配置错误: ${axiosError.message}`);
842
880
  }
843
881
  }
844
882
  }
845
883
  async function login(phone, password, config) {
846
884
  const url = `${config.API.TUZAI_BASE_URL}/user/login/pass`;
885
+ debug.log("[登录] 开始登录...");
886
+ debug.log(`[登录] 请求地址: ${url}`);
887
+ debug.log(`[登录] 请求参数: phone=${phone}, password=***`);
847
888
  try {
848
889
  const response = await httpPost(url, {
849
890
  phone,
850
891
  userPass: password
851
892
  });
852
893
  const data = response.data;
853
- debugLog(`[登录] 响应数据: ${JSON.stringify(data)}`);
894
+ debug.log(`[登录] 响应数据: ${JSON.stringify(data)}`);
854
895
  if (data.code === 200 && data.data?.token) {
855
- debugLog("[登录] 登录成功,获取到 token");
896
+ debug.log("[登录] 登录成功,获取到 token");
856
897
  return data.data.token;
857
898
  }
858
- debugLog("[登录] 登录失败");
899
+ debug.log("[登录] 登录失败");
859
900
  throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, data.message || "登录失败");
860
901
  } catch (error) {
861
902
  if (error instanceof AppError$1) {
862
903
  throw error;
863
904
  }
864
- debugLog(`[登录] 发生错误: ${error.message}`);
905
+ debug.log(`[登录] 发生错误: ${error.message}`);
865
906
  throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, error.message);
866
907
  }
867
908
  }
868
909
  async function fetchBoundConfig(token, phone, localCode, config) {
869
910
  const url = `${config.API.TUZAI_BASE_URL}/work-bot/local/bound/init`;
870
- debugLog(`[获取绑定配置] 请求头: Authorization=${token.substring(0, 20)}...`);
911
+ debug.log("[获取绑定配置] 开始获取绑定配置...");
912
+ debug.log(`[获取绑定配置] 请求地址: ${url}`);
913
+ debug.log(`[获取绑定配置] 请求参数: phone=${phone}, localCode=${localCode}`);
914
+ debug.log(`[获取绑定配置] 请求头: Authorization=${token.substring(0, 20)}...`);
871
915
  try {
872
916
  const response = await httpPost(url, {
873
917
  phone,
@@ -878,7 +922,7 @@ async function fetchBoundConfig(token, phone, localCode, config) {
878
922
  }
879
923
  });
880
924
  const data = response.data;
881
- debugLog(`[获取绑定配置] 响应数据: ${JSON.stringify(data)}`);
925
+ debug.log(`[获取绑定配置] 响应数据: ${JSON.stringify(data)}`);
882
926
  if (data.code === 200 && data.data) {
883
927
  const boundConfig = {
884
928
  appKey: data.data.app_key,
@@ -888,26 +932,26 @@ async function fetchBoundConfig(token, phone, localCode, config) {
888
932
  modelApiKey: data.data.model_api_key,
889
933
  modelApiBaseUrl: data.data.model_api_base_url
890
934
  };
891
- debugLog("[获取绑定配置] 获取绑定配置成功");
892
- debugLog(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
893
- debugLog(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
894
- debugLog(`[获取绑定配置] userId: ${boundConfig.userId}`);
895
- debugLog(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
896
- debugLog(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
897
- debugLog(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
935
+ debug.log("[获取绑定配置] 获取绑定配置成功");
936
+ debug.log(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
937
+ debug.log(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
938
+ debug.log(`[获取绑定配置] userId: ${boundConfig.userId}`);
939
+ debug.log(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
940
+ debug.log(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
941
+ debug.log(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
898
942
  if (!boundConfig.appKey || !boundConfig.appSecret || !boundConfig.agentId) {
899
- debugLog("[获取绑定配置] 缺少必要字段");
943
+ debug.log("[获取绑定配置] 缺少必要字段");
900
944
  throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, "获取绑定配置失败:缺少必要字段");
901
945
  }
902
946
  return boundConfig;
903
947
  }
904
- debugLog("[获取绑定配置] 获取绑定配置失败");
948
+ debug.log("[获取绑定配置] 获取绑定配置失败");
905
949
  throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, data.message || data.msg || "获取绑定配置失败");
906
950
  } catch (error) {
907
951
  if (error instanceof AppError$1) {
908
952
  throw error;
909
953
  }
910
- debugLog(`[获取绑定配置] 发生错误: ${error.message}`);
954
+ debug.log(`[获取绑定配置] 发生错误: ${error.message}`);
911
955
  throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, error.message);
912
956
  }
913
957
  }
@@ -4893,6 +4937,7 @@ class LocalInstaller {
4893
4937
  prefixText = "";
4894
4938
  config;
4895
4939
  envConfig;
4940
+ token = "";
4896
4941
  /**
4897
4942
  * 构造函数
4898
4943
  */
@@ -4906,29 +4951,31 @@ class LocalInstaller {
4906
4951
  * 验证安装配置
4907
4952
  */
4908
4953
  validateConfig() {
4954
+ debug.log("[验证配置] 检查配置...");
4909
4955
  const result = LocalInstallerConfigSchema.safeParse(this.config);
4910
4956
  if (!result.success) {
4911
- debugLog(`[验证配置] 验证失败: ${result.error.issues[0].message}`);
4957
+ debug.log(`[验证配置] 验证失败: ${result.error.issues[0].message}`);
4912
4958
  throw new AppError$1(ERROR_CODES$1.INVALID_ARGUMENT, result.error.issues[0].message);
4913
4959
  }
4960
+ debug.log("[验证配置] 配置验证通过");
4914
4961
  }
4915
4962
  /**
4916
4963
  * 执行安装流程
4917
4964
  */
4918
4965
  async install() {
4919
4966
  try {
4920
- debugLog("[安装开始]");
4967
+ debug.log("[安装开始]");
4921
4968
  this.validateConfig();
4922
4969
  let baseDir;
4923
4970
  if (this.config.openclawPath) {
4924
- debugLog(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
4971
+ debug.log(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
4925
4972
  try {
4926
4973
  validateOpenclawPath(this.config.openclawPath);
4927
- debugLog("[路径验证] 通过");
4974
+ debug.log("[路径验证] 通过");
4928
4975
  } catch (error) {
4929
4976
  throw new AppError$1(ERROR_CODES$1.INVALID_OPENCLAW_PATH, error.message);
4930
4977
  }
4931
- baseDir = this.config.openclawPath;
4978
+ baseDir = normalizePath(this.config.openclawPath);
4932
4979
  } else {
4933
4980
  const homeDir = getHomeDir();
4934
4981
  baseDir = path.join(homeDir, this.envConfig.DIRS.OPENCLAW);
@@ -4941,25 +4988,26 @@ class LocalInstaller {
4941
4988
  workspace: path.join(baseDir, this.envConfig.DIRS.WORKSPACE),
4942
4989
  temp: path.join(baseDir, this.envConfig.DIRS.TEMP)
4943
4990
  };
4944
- debugLog(`[路径配置] home=${paths.home}`);
4945
- debugLog(`[路径配置] extensions=${paths.extensions}`);
4946
- debugLog(`[路径配置] target=${paths.target}`);
4947
- debugLog(`[路径配置] config=${paths.config}`);
4948
- debugLog(`[路径配置] workspace=${paths.workspace}`);
4991
+ debug.log(`[路径配置] home=${paths.home}`);
4992
+ debug.log(`[路径配置] extensions=${paths.extensions}`);
4993
+ debug.log(`[路径配置] target=${paths.target}`);
4994
+ debug.log(`[路径配置] config=${paths.config}`);
4995
+ debug.log(`[路径配置] workspace=${paths.workspace}`);
4949
4996
  const machineId = generateMachineId();
4950
4997
  const localCode = buildLocalCode(this.config.phone, machineId);
4951
- debugLog(`[机器码] machineId=${machineId}`);
4952
- debugLog(`[机器码] localCode=${localCode}`);
4998
+ debug.log(`[机器码] machineId=${machineId}`);
4999
+ debug.log(`[机器码] localCode=${localCode}`);
4953
5000
  const token = await this.doLogin();
5001
+ this.token = token;
4954
5002
  const boundConfig = await this.doFetchBoundConfig(token, localCode);
4955
5003
  await this.doCleanOldFiles(paths.target);
4956
5004
  await this.doDownloadFromNpm(paths);
4957
5005
  await this.doUpdateConfig(paths, boundConfig);
4958
5006
  try {
4959
5007
  await fs.rm(paths.temp, { recursive: true, force: true });
4960
- debugLog("[安装完成] 清理根临时目录完成");
5008
+ debug.log("[安装完成] 清理根临时目录完成");
4961
5009
  } catch {
4962
- debugLog("[安装完成] 清理根临时目录失败(忽略)");
5010
+ debug.log("[安装完成] 清理根临时目录失败(忽略)");
4963
5011
  }
4964
5012
  this.spinner.stop();
4965
5013
  } catch (error) {
@@ -4973,6 +5021,12 @@ class LocalInstaller {
4973
5021
  getPrefixText() {
4974
5022
  return this.prefixText;
4975
5023
  }
5024
+ /**
5025
+ * 获取登录 token
5026
+ */
5027
+ getToken() {
5028
+ return this.token;
5029
+ }
4976
5030
  /**
4977
5031
  * 获取完整的 npm 包名(包含版本号)
4978
5032
  */
@@ -4988,14 +5042,18 @@ class LocalInstaller {
4988
5042
  async doLogin() {
4989
5043
  this.spinner.prefixText = this.prefixText;
4990
5044
  this.spinner.text = chalk.cyan("正在验证账号...");
4991
- debugLog(`[用户登录] 手机号: ${this.config.phone}`);
5045
+ debug.log(`[用户登录] 手机号: ${this.config.phone}`);
5046
+ debug.log("[用户登录] RSA 加密密码...");
4992
5047
  const encryptedPassword = rsaEncrypt(this.config.userPass);
4993
5048
  if (!encryptedPassword) {
4994
5049
  throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, "密码加密失败");
4995
5050
  }
5051
+ debug.log("[用户登录] 密码加密成功");
5052
+ debug.log("[用户登录] 调用登录接口...");
4996
5053
  const token = await login(this.config.phone, encryptedPassword, this.envConfig);
4997
5054
  this.prefixText += chalk.green(` ✓ 账号验证成功
4998
5055
  `);
5056
+ debug.log("[用户登录] 登录成功");
4999
5057
  return token;
5000
5058
  }
5001
5059
  /**
@@ -5004,10 +5062,13 @@ class LocalInstaller {
5004
5062
  async doFetchBoundConfig(token, localCode) {
5005
5063
  this.spinner.prefixText = this.prefixText;
5006
5064
  this.spinner.text = chalk.cyan("正在获取绑定信息...");
5065
+ debug.log("[获取配置] 调用绑定配置接口...");
5066
+ debug.log(`[获取配置] localCode=${localCode}`);
5007
5067
  const boundConfig = await fetchBoundConfig(token, this.config.phone, localCode, this.envConfig);
5008
- debugLog(`[获取配置] agentId=${boundConfig.agentId}, appKey=${boundConfig.appKey?.slice(0, 8)}...`);
5068
+ debug.log(`[获取配置] agentId=${boundConfig.agentId}, appKey=${boundConfig.appKey?.slice(0, 8)}...`);
5009
5069
  this.prefixText += chalk.green(` ✓ 绑定信息获取成功
5010
5070
  `);
5071
+ debug.log("[获取配置] 获取成功");
5011
5072
  return boundConfig;
5012
5073
  }
5013
5074
  /**
@@ -5016,17 +5077,19 @@ class LocalInstaller {
5016
5077
  async doCleanOldFiles(targetPath) {
5017
5078
  this.spinner.prefixText = this.prefixText;
5018
5079
  this.spinner.text = chalk.cyan("正在检查已安装版本...");
5080
+ debug.log(`[清理旧版本] 检查目录: ${targetPath}`);
5019
5081
  try {
5020
5082
  await fs.access(targetPath);
5021
5083
  this.spinner.text = chalk.cyan("正在清理旧文件...");
5022
- debugLog("[清理旧版本] 发现旧版本,开始清理...");
5084
+ debug.log("[清理旧版本] 发现旧版本,开始清理...");
5023
5085
  await fs.rm(targetPath, { recursive: true, force: true });
5024
5086
  this.prefixText += chalk.green(` ✓ 旧版本清理完成
5025
5087
  `);
5026
- debugLog("[清理旧版本] 清理完成");
5088
+ debug.log("[清理旧版本] 清理完成");
5027
5089
  } catch {
5028
5090
  this.prefixText += chalk.green(` ✓ 无旧版本需要清理
5029
5091
  `);
5092
+ debug.log("[清理旧版本] 未发现旧版本");
5030
5093
  }
5031
5094
  }
5032
5095
  /**
@@ -5035,21 +5098,26 @@ class LocalInstaller {
5035
5098
  async doDownloadFromNpm(paths) {
5036
5099
  this.spinner.prefixText = this.prefixText;
5037
5100
  this.spinner.text = chalk.cyan("正在准备安装目录...");
5101
+ debug.log("[下载插件] 创建扩展目录...");
5038
5102
  await fs.mkdir(paths.extensions, { recursive: true });
5039
- debugLog(`[下载插件] 扩展目录: ${paths.extensions}`);
5103
+ debug.log(`[下载插件] 扩展目录: ${paths.extensions}`);
5040
5104
  const tempDir = path.join(paths.temp, `install-${Date.now()}`);
5105
+ debug.log(`[下载插件] 创建临时目录: ${tempDir}`);
5041
5106
  await fs.mkdir(tempDir, { recursive: true });
5042
5107
  this.spinner.prefixText = this.prefixText;
5043
5108
  this.spinner.text = chalk.cyan("正在下载插件...");
5109
+ debug.log("[下载插件] 执行 npm pack 下载源码包");
5110
+ debug.log(`[下载插件] 工作目录: ${tempDir}`);
5044
5111
  const maxRetries = 3;
5045
5112
  let lastError = "";
5046
5113
  let tarballPath = "";
5047
5114
  for (let i = 1; i <= maxRetries; i++) {
5048
5115
  this.spinner.prefixText = this.prefixText;
5049
5116
  this.spinner.text = chalk.cyan(`正在下载 (${i}/${maxRetries})...`);
5117
+ debug.log(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
5050
5118
  try {
5051
5119
  const packageName = this.getPackageName();
5052
- debugLog(`[下载插件] 下载包名: ${packageName}`);
5120
+ debug.log(`[下载插件] 下载包名: ${packageName}`);
5053
5121
  this.spinner.text = chalk.cyan("正在从 npm 获取插件...");
5054
5122
  const output = await execAsync(
5055
5123
  `npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts --quiet`,
@@ -5058,12 +5126,14 @@ class LocalInstaller {
5058
5126
  const lines = output.trim().split("\n").filter((line) => line.trim());
5059
5127
  const filename = lines[lines.length - 1] || "";
5060
5128
  tarballPath = path.join(tempDir, filename);
5061
- debugLog(`[下载插件] tarball 下载成功: ${tarballPath}`);
5129
+ debug.log(`[下载插件] tarball 下载成功: ${tarballPath}`);
5062
5130
  break;
5063
5131
  } catch (error) {
5064
5132
  lastError = error.message || "未知错误";
5133
+ debug.log(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
5065
5134
  if (i < maxRetries) {
5066
5135
  this.spinner.text = chalk.cyan(`下载失败,3秒后重试...`);
5136
+ debug.log("[下载插件] 等待 3 秒后重试...");
5067
5137
  await new Promise((resolve2) => setTimeout(resolve2, 3e3));
5068
5138
  }
5069
5139
  }
@@ -5073,16 +5143,16 @@ class LocalInstaller {
5073
5143
  }
5074
5144
  this.spinner.prefixText = this.prefixText;
5075
5145
  this.spinner.text = chalk.cyan("正在解压插件...");
5076
- debugLog(`[下载插件] 创建插件目录: ${paths.target}`);
5146
+ debug.log(`[下载插件] 创建插件目录: ${paths.target}`);
5077
5147
  await fs.mkdir(paths.target, { recursive: true });
5078
- debugLog(`[下载插件] 解压 tarball 到: ${paths.target}`);
5148
+ debug.log(`[下载插件] 解压 tarball 到: ${paths.target}`);
5079
5149
  try {
5080
5150
  await tar.extract({
5081
5151
  file: tarballPath,
5082
5152
  cwd: paths.target,
5083
5153
  strip: 1
5084
5154
  });
5085
- debugLog("[下载插件] tarball 解压成功");
5155
+ debug.log("[下载插件] tarball 解压成功");
5086
5156
  } catch (error) {
5087
5157
  throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
5088
5158
  }
@@ -5091,18 +5161,22 @@ class LocalInstaller {
5091
5161
  if (!pluginExists) {
5092
5162
  throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
5093
5163
  }
5164
+ debug.log("[下载插件] 插件解压成功");
5094
5165
  this.spinner.prefixText = this.prefixText;
5095
5166
  this.spinner.text = chalk.cyan("正在安装依赖...");
5167
+ debug.log("[下载插件] 执行 npm install 安装生产环境依赖");
5096
5168
  try {
5097
5169
  await execAsync("npm install --omit=dev --ignore-scripts --quiet", {
5098
5170
  cwd: paths.target,
5099
5171
  timeout: 12e4
5100
5172
  });
5101
- debugLog("[下载插件] npm install 执行成功");
5173
+ debug.log("[下载插件] npm install 执行成功");
5102
5174
  } catch (error) {
5103
5175
  const errorMsg = error instanceof Error ? error.message : String(error);
5104
- if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) ;
5105
- else {
5176
+ if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) {
5177
+ debug.log("[下载插件] npm install 有警告但可能成功,继续流程");
5178
+ } else {
5179
+ debug.log(`[下载插件] npm install 失败: ${errorMsg}`);
5106
5180
  throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `依赖安装失败: ${errorMsg}`);
5107
5181
  }
5108
5182
  }
@@ -5110,8 +5184,9 @@ class LocalInstaller {
5110
5184
  `);
5111
5185
  try {
5112
5186
  await fs.rm(tempDir, { recursive: true, force: true });
5113
- debugLog("[下载插件] 清理临时下载目录完成");
5187
+ debug.log("[下载插件] 清理临时下载目录完成");
5114
5188
  } catch {
5189
+ debug.log("[下载插件] 清理临时下载目录失败(忽略)");
5115
5190
  }
5116
5191
  }
5117
5192
  /**
@@ -5120,14 +5195,18 @@ class LocalInstaller {
5120
5195
  async doUpdateConfig(paths, boundConfig) {
5121
5196
  this.spinner.prefixText = this.prefixText;
5122
5197
  this.spinner.text = chalk.cyan("正在生成配置...");
5198
+ debug.log("[更新配置] 创建目录...");
5123
5199
  await fs.mkdir(paths.home, { recursive: true });
5124
5200
  await fs.mkdir(paths.workspace, { recursive: true });
5201
+ debug.log("[更新配置] 目录创建完成");
5202
+ debug.log("[更新配置] 读取原有配置...");
5125
5203
  let originalConfig = {};
5126
5204
  try {
5127
5205
  const content = await fs.readFile(paths.config, "utf-8");
5128
5206
  originalConfig = JSON.parse(content);
5129
- debugLog("[更新配置] 读取原有配置成功");
5207
+ debug.log("[更新配置] 读取原有配置成功");
5130
5208
  } catch {
5209
+ debug.log("[更新配置] 无原有配置");
5131
5210
  }
5132
5211
  const config = this.envConfig;
5133
5212
  const newConfig = {
@@ -5296,16 +5375,19 @@ class LocalInstaller {
5296
5375
  const finalConfig = deepMerge(originalConfig, newConfig);
5297
5376
  this.spinner.prefixText = this.prefixText;
5298
5377
  this.spinner.text = chalk.cyan("正在写入配置...");
5378
+ debug.log("[更新配置] 写入配置文件...");
5299
5379
  await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
5300
5380
  this.prefixText += chalk.green(` ✓ 配置更新完成
5301
5381
  `);
5302
- debugLog(`[更新配置] 配置文件写入成功: ${paths.config}`);
5382
+ debug.log(`[更新配置] 配置文件写入成功: ${paths.config}`);
5303
5383
  }
5304
5384
  }
5305
5385
  async function createLocalCommand(options) {
5306
5386
  setDebug(!!options.debug);
5307
- debugLog(`[初始化] 参数: env=${options.env}, phone=${options.phone}, customIp=${options.customIp}, debug=${options.debug}`);
5387
+ debug.log("[初始化] 开始处理...");
5388
+ debug.log(`[初始化] 参数: env=${options.env}, phone=${options.phone}, customIp=${options.customIp}, debug=${options.debug}`);
5308
5389
  checkEnv();
5390
+ debug.log("[初始化] 环境检查通过");
5309
5391
  try {
5310
5392
  let env = options.env;
5311
5393
  let phone = options.phone;
@@ -5313,7 +5395,7 @@ async function createLocalCommand(options) {
5313
5395
  let customIp = options.customIp;
5314
5396
  const questions = [];
5315
5397
  if (!env) {
5316
- debugLog("[初始化] 需要选择环境");
5398
+ debug.log("[初始化] 需要选择环境");
5317
5399
  questions.push({
5318
5400
  type: "list",
5319
5401
  name: "env",
@@ -5326,10 +5408,10 @@ async function createLocalCommand(options) {
5326
5408
  ]
5327
5409
  });
5328
5410
  } else {
5329
- debugLog(`[初始化] 使用命令行参数: env=${env}`);
5411
+ debug.log(`[初始化] 使用命令行参数: env=${env}`);
5330
5412
  }
5331
5413
  if (!phone) {
5332
- debugLog("[初始化] 需要输入手机号码");
5414
+ debug.log("[初始化] 需要输入手机号码");
5333
5415
  questions.push({
5334
5416
  type: "input",
5335
5417
  name: "phone",
@@ -5346,10 +5428,10 @@ async function createLocalCommand(options) {
5346
5428
  }
5347
5429
  });
5348
5430
  } else {
5349
- debugLog("[初始化] 使用命令行参数: phone");
5431
+ debug.log("[初始化] 使用命令行参数: phone");
5350
5432
  }
5351
5433
  if (!userPass) {
5352
- debugLog("[初始化] 需要输入用户密码");
5434
+ debug.log("[初始化] 需要输入用户密码");
5353
5435
  questions.push({
5354
5436
  type: "input",
5355
5437
  name: "userPass",
@@ -5363,18 +5445,18 @@ async function createLocalCommand(options) {
5363
5445
  }
5364
5446
  });
5365
5447
  } else {
5366
- debugLog("[初始化] 使用命令行参数: userPass");
5448
+ debug.log("[初始化] 使用命令行参数: userPass");
5367
5449
  }
5368
5450
  if (questions.length > 0) {
5369
- debugLog(`[初始化] 开始交互式问答,共 ${questions.length} 个问题`);
5451
+ debug.log(`[初始化] 开始交互式问答,共 ${questions.length} 个问题`);
5370
5452
  const answers = await inquirer.prompt(questions);
5371
- debugLog("[初始化] 交互式问答完成");
5453
+ debug.log("[初始化] 交互式问答完成");
5372
5454
  env = env || answers.env || "test";
5373
5455
  phone = phone || answers.phone;
5374
5456
  userPass = userPass || answers.userPass;
5375
5457
  }
5376
5458
  if (env === "custom" && !customIp) {
5377
- debugLog("[初始化] 自定义环境需要输入后端 IP");
5459
+ debug.log("[初始化] 自定义环境需要输入后端 IP");
5378
5460
  const answer = await inquirer.prompt([{
5379
5461
  type: "input",
5380
5462
  name: "customIp",
@@ -5392,12 +5474,12 @@ async function createLocalCommand(options) {
5392
5474
  }
5393
5475
  }]);
5394
5476
  customIp = answer.customIp;
5395
- debugLog("[初始化] 获取自定义 customIp");
5477
+ debug.log("[初始化] 获取自定义 customIp");
5396
5478
  } else if (env === "custom" && customIp) {
5397
- debugLog(`[初始化] 使用命令行参数: customIp=${customIp}`);
5479
+ debug.log(`[初始化] 使用命令行参数: customIp=${customIp}`);
5398
5480
  }
5399
- debugLog(`[初始化] 最终参数: env=${env}, phone=${phone}, customIp=${customIp}, pluginVersion=${options.pluginVersion}, openclawPath=${options.openclawPath}`);
5400
- debugLog("[初始化] 创建 LocalInstaller 实例...");
5481
+ debug.log(`[初始化] 最终参数: env=${env}, phone=${phone}, customIp=${customIp}, pluginVersion=${options.pluginVersion}, openclawPath=${options.openclawPath}`);
5482
+ debug.log("[初始化] 创建 LocalInstaller 实例...");
5401
5483
  const installer = new LocalInstaller({
5402
5484
  phone,
5403
5485
  userPass,
@@ -5407,9 +5489,9 @@ async function createLocalCommand(options) {
5407
5489
  pluginVersion: options.pluginVersion,
5408
5490
  openclawPath: options.openclawPath
5409
5491
  });
5410
- debugLog("[初始化] 开始安装...");
5492
+ debug.log("[初始化] 开始安装...");
5411
5493
  await installer.install();
5412
- debugLog("[初始化] 安装完成");
5494
+ debug.log("[初始化] 安装完成");
5413
5495
  console.log(installer.getPrefixText() + boxen(
5414
5496
  `${chalk.green("✦")} 插件初始化成功!`,
5415
5497
  {
@@ -5422,8 +5504,13 @@ async function createLocalCommand(options) {
5422
5504
  textAlignment: "center"
5423
5505
  }
5424
5506
  ));
5507
+ if (options.printToken) {
5508
+ const token = installer.getToken();
5509
+ console.log(`
5510
+ ${chalk.cyan("Token: ")}${token}`);
5511
+ }
5425
5512
  } catch (error) {
5426
- debugLog(`[初始化] 发生错误: ${error.message}`);
5513
+ debug.log(`[初始化] 发生错误: ${error.message}`);
5427
5514
  console.error(boxen(
5428
5515
  `${chalk.yellow(error.message)}`,
5429
5516
  {
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import("./index-ZySzMX4-.js").then((cli) => {
2
+ import("./index-CtwdWK1B.js").then((cli) => {
3
3
  cli.default();
4
4
  });
@@ -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;IAE3C;;OAEG;gBACS,MAAM,EAAE,oBAAoB;IAOxC;;OAEG;IACH,cAAc,IAAI,IAAI;IAUtB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+D9B;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;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
+ {"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,CA0J7E"}
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"}
@@ -8,6 +8,7 @@ export interface LocalOptions {
8
8
  pluginVersion?: string;
9
9
  openclawPath?: string;
10
10
  debug?: boolean;
11
+ printToken?: boolean;
11
12
  }
12
13
  /**
13
14
  * LocalInstaller 配置验证 schema
@@ -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;CAChB;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
+ {"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":"AAKA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQ/C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CACjD"}
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,CAE/C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -1,7 +1,7 @@
1
- export { debugLog, isDebugMode, setDebug } from './debug';
1
+ export { debug, isDebugMode, setDebug } from './debug';
2
2
  export { checkEnv } from './env';
3
3
  export { createLogger, logger } from './logger';
4
4
  export type { Logger } from './logger';
5
- export { validateOpenclawPath } from './path';
5
+ export { normalizePath, validateOpenclawPath } from './path';
6
6
  export { absolutePathSchema, appKeySchema, appSecretSchema, booleanSchema, EnvironmentSchema, ipv4Schema, isValid, openclawPathSchema, phoneSchema, pluginVersionSchema, userPassSchema, validate, validateWithMessage, windowsPathSchema, withMessage, wsUrlSchema, } from './validate';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzD,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"}
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,aAAa,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAA;AAC5D,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"}
@@ -1,3 +1,9 @@
1
+ /**
2
+ * 规范化路径格式
3
+ * @param inputPath - 原始路径
4
+ * @returns 规范化后的绝对路径
5
+ */
6
+ export declare function normalizePath(inputPath: string): string;
1
7
  /**
2
8
  * 验证 OpenClaw 安装路径
3
9
  * @param openclawPath - 待验证的路径
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/path.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAU/D"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/path.ts"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAU/D"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@workclaw/cli",
3
3
  "type": "module",
4
- "version": "1.0.322",
4
+ "version": "1.0.326",
5
5
  "description": "WorkClaw CLI 工具 - 用于初始化和配置 WorkClaw 插件",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -26,7 +26,7 @@
26
26
  "build": "vite build"
27
27
  },
28
28
  "dependencies": {
29
- "@mingto/debug": "^1.0.25",
29
+ "@mingto/debug": "^1.0.27",
30
30
  "@types/semver": "^7.7.0",
31
31
  "@types/tar": "^6.1.13",
32
32
  "axios": "^1.7.9",
@@ -40,4 +40,4 @@
40
40
  "tar": "^6.2.1",
41
41
  "zod": "^4.3.6"
42
42
  }
43
- }
43
+ }