@workclaw/cli 1.0.311 → 1.0.313

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.
@@ -10,6 +10,7 @@ export declare const ERROR_CODES: {
10
10
  readonly NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED";
11
11
  readonly CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED";
12
12
  readonly PLUGIN_EXTRACT_FAILED: "PLUGIN_EXTRACT_FAILED";
13
+ readonly INVALID_OPENCLAW_PATH: "INVALID_OPENCLAW_PATH";
13
14
  };
14
15
  export type ErrorCode = keyof typeof ERROR_CODES;
15
16
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/box/error/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;CASd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAA;AAEhD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CASpD,CAAA;AAED;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAExB,IAAI,EAAE,SAAS;gBAAf,IAAI,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM;CAKlB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/box/error/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;CAUd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAA;AAEhD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAUpD,CAAA;AAED;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAExB,IAAI,EAAE,SAAS;gBAAf,IAAI,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM;CAKlB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/box/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CASvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/box/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAUvD"}
@@ -5,9 +5,11 @@ export declare class BoxInstaller {
5
5
  private prefixText;
6
6
  constructor(config: BoxInstallerConfig);
7
7
  validateConfig(): void;
8
+ private validateOpenclawPath;
8
9
  private getPaths;
9
10
  private updateSpinner;
10
11
  getPrefixText(): string;
12
+ private getPackageName;
11
13
  install(): Promise<void>;
12
14
  private doCleanOldFiles;
13
15
  private doDownloadFromNpm;
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/box/installer/installer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,UAAU,CAAA;AAoDhE,qBAAa,YAAY;IAIX,OAAO,CAAC,MAAM;IAH1B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAa;gBAEX,MAAM,EAAE,kBAAkB;IAI9C,cAAc,IAAI,IAAI;IAatB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,aAAa;IAMrB,aAAa,IAAI,MAAM;IAIjB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YA0BhB,eAAe;YA0Bf,iBAAiB;YAuBjB,cAAc;CAqQ7B"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/box/installer/installer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,UAAU,CAAA;AAqDhE,qBAAa,YAAY;IAIX,OAAO,CAAC,MAAM;IAH1B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAa;gBAEX,MAAM,EAAE,kBAAkB;IAI9C,cAAc,IAAI,IAAI;IAatB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,QAAQ;IA2BhB,OAAO,CAAC,aAAa;IAMrB,aAAa,IAAI,MAAM;IAIvB,OAAO,CAAC,cAAc;IAOhB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YA0BhB,eAAe;YA0Bf,iBAAiB;YAoHjB,cAAc;CAiR7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"box.d.ts","sourceRoot":"","sources":["../../../src/box/src/box.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAgC1C,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAqHzE"}
1
+ {"version":3,"file":"box.d.ts","sourceRoot":"","sources":["../../../src/box/src/box.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAgC1C,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuHzE"}
@@ -4,6 +4,7 @@ export interface BoxOptions {
4
4
  appKey?: string;
5
5
  appSecret?: string;
6
6
  pluginVersion?: string;
7
+ openclawPath?: string;
7
8
  debug?: boolean;
8
9
  }
9
10
  export interface BoxInstallerConfig {
@@ -13,6 +14,7 @@ export interface BoxInstallerConfig {
13
14
  appKey: string;
14
15
  appSecret: string;
15
16
  pluginVersion?: string;
17
+ openclawPath?: string;
16
18
  }
17
19
  export interface InstallResult {
18
20
  success: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/box/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,WAAW,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,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/box/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,WAAW,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,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"}
@@ -9,9 +9,9 @@ import chalk from "chalk";
9
9
  import inquirer from "inquirer";
10
10
  import semver from "semver";
11
11
  import fs from "node:fs/promises";
12
+ import tar from "tar";
12
13
  import ora from "ora";
13
14
  import axios from "axios";
14
- import "node:os";
15
15
  let isDebug = false;
16
16
  function setDebug(debug) {
17
17
  isDebug = debug;
@@ -26,7 +26,8 @@ const ERROR_CODES$1 = {
26
26
  APP_SECRET_REQUIRED: "APP_SECRET_REQUIRED",
27
27
  NODE_VERSION_LOW: "NODE_VERSION_LOW",
28
28
  NPM_NOT_FOUND: "NPM_NOT_FOUND",
29
- NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED"
29
+ NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED",
30
+ INVALID_OPENCLAW_PATH: "INVALID_OPENCLAW_PATH"
30
31
  };
31
32
  let AppError$1 = class AppError extends Error {
32
33
  constructor(code, message) {
@@ -43,6 +44,7 @@ const CONFIG = {
43
44
  DIRS: {
44
45
  OPENCLAW: ".openclaw",
45
46
  EXTENSIONS: "extensions",
47
+ PLUGINS: "plugins",
46
48
  CONFIG_FILE: "openclaw.json",
47
49
  WORKSPACE: "workspace",
48
50
  TEMP: ".temp"
@@ -62,6 +64,7 @@ const TEST_CONFIG = {
62
64
  DIRS: {
63
65
  OPENCLAW: ".openclaw",
64
66
  EXTENSIONS: "extensions",
67
+ PLUGINS: "plugins",
65
68
  CONFIG_FILE: "openclaw.json",
66
69
  WORKSPACE: "workspace",
67
70
  TEMP: ".temp"
@@ -121,16 +124,43 @@ class BoxInstaller {
121
124
  }
122
125
  debugLog("[验证配置] 配置检查通过");
123
126
  }
127
+ validateOpenclawPath(openclawPath) {
128
+ debugLog(`[路径验证] 开始验证路径: ${openclawPath}`);
129
+ if (!path.isAbsolute(openclawPath)) {
130
+ debugLog("[路径验证] 失败: 不是绝对路径");
131
+ throw new AppError$1(
132
+ ERROR_CODES$1.INVALID_OPENCLAW_PATH,
133
+ `路径必须是绝对路径,当前输入: ${openclawPath}`
134
+ );
135
+ }
136
+ const invalidChars = /[<>:"|?*]/.test(openclawPath);
137
+ if (invalidChars) {
138
+ debugLog("[路径验证] 失败: 包含非法字符");
139
+ throw new AppError$1(
140
+ ERROR_CODES$1.INVALID_OPENCLAW_PATH,
141
+ '路径不能包含特殊字符: < > : " | ? *'
142
+ );
143
+ }
144
+ debugLog("[路径验证] 通过");
145
+ }
124
146
  getPaths() {
125
- const home = getHomeDir$1();
126
- const openclawDir = path.join(home, ".openclaw");
127
- const extensionsDir = path.join(openclawDir, "extensions");
128
- const targetDir = path.join(extensionsDir, "openclaw-workclaw");
129
- const configFile = path.join(openclawDir, "openclaw.json");
130
- const workspaceDir = path.join(openclawDir, "workspace");
131
- const tempDir = path.join(openclawDir, ".temp");
147
+ const config = getConfig(this.config.env);
148
+ let baseDir;
149
+ if (this.config.openclawPath) {
150
+ debugLog(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
151
+ this.validateOpenclawPath(this.config.openclawPath);
152
+ baseDir = this.config.openclawPath;
153
+ } else {
154
+ const home = getHomeDir$1();
155
+ baseDir = path.join(home, config.DIRS.OPENCLAW);
156
+ }
157
+ const extensionsDir = path.join(baseDir, config.DIRS.EXTENSIONS);
158
+ const targetDir = path.join(extensionsDir, config.PLUGIN_NAME);
159
+ const configFile = path.join(baseDir, config.DIRS.CONFIG_FILE);
160
+ const workspaceDir = path.join(baseDir, config.DIRS.WORKSPACE);
161
+ const tempDir = path.join(baseDir, config.DIRS.TEMP);
132
162
  return {
133
- home,
163
+ home: baseDir,
134
164
  extensions: extensionsDir,
135
165
  target: targetDir,
136
166
  config: configFile,
@@ -146,6 +176,12 @@ class BoxInstaller {
146
176
  getPrefixText() {
147
177
  return this.prefixText;
148
178
  }
179
+ getPackageName() {
180
+ if (this.config.pluginVersion) {
181
+ return `${PLUGIN_PACKAGE_NAME$1}@${this.config.pluginVersion}`;
182
+ }
183
+ return PLUGIN_PACKAGE_NAME$1;
184
+ }
149
185
  async install() {
150
186
  try {
151
187
  debugLog("[盒子安装] 开始安装...");
@@ -190,25 +226,97 @@ class BoxInstaller {
190
226
  }
191
227
  }
192
228
  async doDownloadFromNpm() {
193
- debugLog("[安装插件] 开始安装插件...");
194
- this.prefixText += chalk.green(` ✓ 开始安装插件
195
- `);
229
+ const paths = this.getPaths();
230
+ this.spinner.prefixText = this.prefixText;
231
+ this.spinner.text = chalk.cyan("正在准备安装目录...");
232
+ debugLog("[下载插件] 创建扩展目录...");
233
+ await fs.mkdir(paths.extensions, { recursive: true });
234
+ debugLog(`[下载插件] 扩展目录: ${paths.extensions}`);
235
+ const tempDir = path.join(paths.temp, `install-${Date.now()}`);
236
+ debugLog(`[下载插件] 创建临时目录: ${tempDir}`);
237
+ await fs.mkdir(tempDir, { recursive: true });
196
238
  this.spinner.prefixText = this.prefixText;
197
- this.spinner.text = chalk.cyan("正在安装插件...");
239
+ this.spinner.text = chalk.cyan("正在下载插件...");
240
+ debugLog("[下载插件] 执行 npm pack 下载源码包");
241
+ debugLog(`[下载插件] 工作目录: ${tempDir}`);
242
+ const maxRetries = 3;
243
+ let lastError = "";
244
+ let tarballPath = "";
245
+ for (let i = 1; i <= maxRetries; i++) {
246
+ this.spinner.prefixText = this.prefixText;
247
+ this.spinner.text = chalk.cyan(`正在下载 (${i}/${maxRetries})...`);
248
+ debugLog(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
249
+ try {
250
+ const packageName = this.getPackageName();
251
+ debugLog(`[下载插件] 下载包名: ${packageName}`);
252
+ this.spinner.text = chalk.cyan("正在从 npm 获取插件...");
253
+ const output = await execAsync$1(
254
+ `npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts --quiet`,
255
+ { cwd: tempDir, timeout: 12e4 }
256
+ );
257
+ const lines = output.trim().split("\n").filter((line) => line.trim());
258
+ const filename = lines[lines.length - 1] || "";
259
+ tarballPath = path.join(tempDir, filename);
260
+ debugLog(`[下载插件] tarball 下载成功: ${tarballPath}`);
261
+ break;
262
+ } catch (error) {
263
+ lastError = error.message || "未知错误";
264
+ debugLog(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
265
+ if (i < maxRetries) {
266
+ this.spinner.text = chalk.cyan(`下载失败,3秒后重试...`);
267
+ debugLog("[下载插件] 等待 3 秒后重试...");
268
+ await new Promise((resolve2) => setTimeout(resolve2, 3e3));
269
+ }
270
+ }
271
+ }
272
+ if (!tarballPath || !await fs.access(tarballPath).then(() => true).catch(() => false)) {
273
+ throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `tarball 下载失败: ${lastError}`);
274
+ }
275
+ this.spinner.prefixText = this.prefixText;
276
+ this.spinner.text = chalk.cyan("正在解压插件...");
277
+ debugLog(`[下载插件] 创建插件目录: ${paths.target}`);
278
+ await fs.mkdir(paths.target, { recursive: true });
279
+ debugLog(`[下载插件] 解压 tarball 到: ${paths.target}`);
198
280
  try {
199
- await execAsync$1(
200
- `openclaw plugins install ${PLUGIN_PACKAGE_NAME$1} --dangerously-force-unsafe-install`,
201
- { timeout: 12e4 }
202
- );
203
- debugLog("[安装插件] openclaw plugins install 执行成功");
204
- this.prefixText += chalk.green(` ✓ 插件安装完成
205
- `);
281
+ await tar.extract({
282
+ file: tarballPath,
283
+ cwd: paths.target,
284
+ strip: 1
285
+ });
286
+ debugLog("[下载插件] tarball 解压成功");
206
287
  } catch (error) {
207
- const errorMsg = error.message || "未知错误";
208
- debugLog(`[安装插件] 安装失败: ${errorMsg}`);
209
- this.prefixText += chalk.red(`✗ 安装失败
288
+ throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
289
+ }
290
+ const pluginPath = path.join(paths.target, "package.json");
291
+ const pluginExists = await fs.access(pluginPath).then(() => true).catch(() => false);
292
+ if (!pluginExists) {
293
+ throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
294
+ }
295
+ debugLog("[下载插件] 插件解压成功");
296
+ this.spinner.prefixText = this.prefixText;
297
+ this.spinner.text = chalk.cyan("正在安装依赖...");
298
+ debugLog("[下载插件] 执行 npm install 安装生产环境依赖");
299
+ try {
300
+ await execAsync$1("npm install --omit=dev --ignore-scripts --quiet", {
301
+ cwd: paths.target,
302
+ timeout: 12e4
303
+ });
304
+ debugLog("[下载插件] npm install 执行成功");
305
+ } catch (error) {
306
+ const errorMsg = error.message || "";
307
+ if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) {
308
+ debugLog("[下载插件] npm install 有警告但可能成功,继续流程");
309
+ } else {
310
+ debugLog(`[下载插件] npm install 失败: ${errorMsg}`);
311
+ }
312
+ }
313
+ this.prefixText += chalk.green(` ✓ 插件安装完成
210
314
  `);
211
- throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `插件安装失败: ${errorMsg}`);
315
+ try {
316
+ await fs.rm(tempDir, { recursive: true, force: true });
317
+ debugLog("[下载插件] 清理临时目录完成");
318
+ } catch {
319
+ debugLog("[下载插件] 清理临时目录失败(忽略)");
212
320
  }
213
321
  }
214
322
  async doUpdateConfig(paths) {
@@ -444,7 +552,19 @@ class BoxInstaller {
444
552
  redactPatterns: ["sk-.*"]
445
553
  },
446
554
  // plugins: 插件配置
447
- plugins: {}
555
+ plugins: {
556
+ allow: [config.PLUGIN_NAME],
557
+ installs: {
558
+ [config.PLUGIN_NAME]: {
559
+ source: "npm",
560
+ spec: PLUGIN_PACKAGE_NAME$1,
561
+ installPath: paths.target
562
+ }
563
+ },
564
+ entries: {
565
+ [config.PLUGIN_NAME]: { enabled: true }
566
+ }
567
+ }
448
568
  };
449
569
  const finalConfig = deepMerge$1(originalConfig, newConfig);
450
570
  this.updateSpinner("正在写入配置...");
@@ -538,12 +658,14 @@ async function createBoxCommand(options) {
538
658
  appKey = appKey || answers.appKey;
539
659
  appSecret = appSecret || answers.appSecret;
540
660
  }
541
- debugLog(`[盒子安装] 最终参数: env=${env}`);
661
+ debugLog(`[盒子安装] 最终参数: env=${env}, openclawPath=${options.openclawPath}`);
542
662
  debugLog("[盒子安装] 创建 BoxInstaller 实例...");
543
663
  const installer = new BoxInstaller({
544
664
  appKey,
545
665
  appSecret,
546
- env
666
+ env,
667
+ pluginVersion: options.pluginVersion,
668
+ openclawPath: options.openclawPath
547
669
  });
548
670
  debugLog("[盒子安装] 开始安装...");
549
671
  await installer.install();
@@ -578,7 +700,7 @@ async function createBoxCommand(options) {
578
700
  }
579
701
  }
580
702
  function registerCommands$1(program2) {
581
- program2.command("box").description("盒子设备安装(无需登录)").option("-e, --env <env>", "环境 (test/prod)").option("--app-key <appKey>", "App Key").option("--app-secret <appSecret>", "App Secret").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--debug", "开启调试日志").action(createBoxCommand);
703
+ program2.command("box").description("盒子设备安装(无需登录)").option("-e, --env <env>", "环境 (test/prod)").option("--app-key <appKey>", "App Key").option("--app-secret <appSecret>", "App Secret").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--openclaw-path <path>", "OpenClaw 安装目录路径(默认 ~/.openclaw)").option("--debug", "开启调试日志").action(createBoxCommand);
582
704
  }
583
705
  const ERROR_CODES = {
584
706
  PHONE_REQUIRED: "PHONE_REQUIRED",
@@ -591,7 +713,8 @@ const ERROR_CODES = {
591
713
  NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED",
592
714
  CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED",
593
715
  HTTP_ERROR: "HTTP_ERROR",
594
- NETWORK_ERROR: "NETWORK_ERROR"
716
+ NETWORK_ERROR: "NETWORK_ERROR",
717
+ INVALID_OPENCLAW_PATH: "INVALID_OPENCLAW_PATH"
595
718
  };
596
719
  class AppError2 extends Error {
597
720
  constructor(code, message) {
@@ -4658,20 +4781,47 @@ class LocalInstaller {
4658
4781
  }
4659
4782
  debugLog("[验证配置] 配置验证通过");
4660
4783
  }
4784
+ validateOpenclawPath(openclawPath) {
4785
+ debugLog(`[路径验证] 开始验证路径: ${openclawPath}`);
4786
+ if (!path.isAbsolute(openclawPath)) {
4787
+ debugLog("[路径验证] 失败: 不是绝对路径");
4788
+ throw new AppError2(
4789
+ ERROR_CODES.INVALID_OPENCLAW_PATH,
4790
+ `路径必须是绝对路径,当前输入: ${openclawPath}`
4791
+ );
4792
+ }
4793
+ const invalidChars = /[<>:"|?*]/.test(openclawPath);
4794
+ if (invalidChars) {
4795
+ debugLog("[路径验证] 失败: 包含非法字符");
4796
+ throw new AppError2(
4797
+ ERROR_CODES.INVALID_OPENCLAW_PATH,
4798
+ '路径不能包含特殊字符: < > : " | ? *'
4799
+ );
4800
+ }
4801
+ debugLog("[路径验证] 通过");
4802
+ }
4661
4803
  async install() {
4662
4804
  try {
4663
4805
  debugLog("[安装开始]");
4664
4806
  this.validateConfig();
4665
4807
  const env = this.config.env || "test";
4666
4808
  const config = getConfig(env);
4667
- const homeDir = getHomeDir();
4809
+ let baseDir;
4810
+ if (this.config.openclawPath) {
4811
+ debugLog(`[路径验证] 验证自定义路径: ${this.config.openclawPath}`);
4812
+ this.validateOpenclawPath(this.config.openclawPath);
4813
+ baseDir = this.config.openclawPath;
4814
+ } else {
4815
+ const homeDir = getHomeDir();
4816
+ baseDir = path.join(homeDir, config.DIRS.OPENCLAW);
4817
+ }
4668
4818
  const paths = {
4669
- home: path.join(homeDir, config.DIRS.OPENCLAW),
4670
- extensions: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.EXTENSIONS),
4671
- target: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.EXTENSIONS, config.PLUGIN_NAME),
4672
- config: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.CONFIG_FILE),
4673
- workspace: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.WORKSPACE),
4674
- temp: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.TEMP)
4819
+ home: baseDir,
4820
+ extensions: path.join(baseDir, config.DIRS.EXTENSIONS),
4821
+ target: path.join(baseDir, config.DIRS.EXTENSIONS, config.PLUGIN_NAME),
4822
+ config: path.join(baseDir, config.DIRS.CONFIG_FILE),
4823
+ workspace: path.join(baseDir, config.DIRS.WORKSPACE),
4824
+ temp: path.join(baseDir, config.DIRS.TEMP)
4675
4825
  };
4676
4826
  debugLog(`[路径配置] home=${paths.home}`);
4677
4827
  debugLog(`[路径配置] extensions=${paths.extensions}`);
@@ -4692,6 +4842,12 @@ class LocalInstaller {
4692
4842
  getPrefixText() {
4693
4843
  return this.prefixText;
4694
4844
  }
4845
+ getPackageName() {
4846
+ if (this.config.pluginVersion) {
4847
+ return `${PLUGIN_PACKAGE_NAME}@${this.config.pluginVersion}`;
4848
+ }
4849
+ return PLUGIN_PACKAGE_NAME;
4850
+ }
4695
4851
  async doLogin(env) {
4696
4852
  this.spinner.prefixText = this.prefixText;
4697
4853
  this.spinner.text = chalk.cyan("正在验证账号...");
@@ -4740,23 +4896,95 @@ class LocalInstaller {
4740
4896
  }
4741
4897
  async doDownloadFromNpm(paths) {
4742
4898
  this.spinner.prefixText = this.prefixText;
4743
- this.spinner.text = chalk.cyan("正在安装插件...");
4744
- debugLog("[安装插件] 创建扩展目录...");
4899
+ this.spinner.text = chalk.cyan("正在准备安装目录...");
4900
+ debugLog("[下载插件] 创建扩展目录...");
4745
4901
  await fs.mkdir(paths.extensions, { recursive: true });
4746
- debugLog(`[安装插件] 扩展目录: ${paths.extensions}`);
4747
- debugLog("[安装插件] 执行 openclaw plugins install 命令");
4902
+ debugLog(`[下载插件] 扩展目录: ${paths.extensions}`);
4903
+ const tempDir = path.join(paths.temp, `install-${Date.now()}`);
4904
+ debugLog(`[下载插件] 创建临时目录: ${tempDir}`);
4905
+ await fs.mkdir(tempDir, { recursive: true });
4906
+ this.spinner.prefixText = this.prefixText;
4907
+ this.spinner.text = chalk.cyan("正在下载插件...");
4908
+ debugLog("[下载插件] 执行 npm pack 下载源码包");
4909
+ debugLog(`[下载插件] 工作目录: ${tempDir}`);
4910
+ const maxRetries = 3;
4911
+ let lastError = "";
4912
+ let tarballPath = "";
4913
+ for (let i = 1; i <= maxRetries; i++) {
4914
+ this.spinner.prefixText = this.prefixText;
4915
+ this.spinner.text = chalk.cyan(`正在下载 (${i}/${maxRetries})...`);
4916
+ debugLog(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
4917
+ try {
4918
+ const packageName = this.getPackageName();
4919
+ debugLog(`[下载插件] 下载包名: ${packageName}`);
4920
+ this.spinner.text = chalk.cyan("正在从 npm 获取插件...");
4921
+ const output = await execAsync(
4922
+ `npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts --quiet`,
4923
+ { cwd: tempDir, timeout: 12e4 }
4924
+ );
4925
+ const lines = output.trim().split("\n").filter((line) => line.trim());
4926
+ const filename = lines[lines.length - 1] || "";
4927
+ tarballPath = path.join(tempDir, filename);
4928
+ debugLog(`[下载插件] tarball 下载成功: ${tarballPath}`);
4929
+ break;
4930
+ } catch (error) {
4931
+ lastError = error.message || "未知错误";
4932
+ debugLog(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
4933
+ if (i < maxRetries) {
4934
+ this.spinner.text = chalk.cyan(`下载失败,3秒后重试...`);
4935
+ debugLog("[下载插件] 等待 3 秒后重试...");
4936
+ await new Promise((resolve2) => setTimeout(resolve2, 3e3));
4937
+ }
4938
+ }
4939
+ }
4940
+ if (!tarballPath || !await fs.access(tarballPath).then(() => true).catch(() => false)) {
4941
+ throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `tarball 下载失败: ${lastError}`);
4942
+ }
4943
+ this.spinner.prefixText = this.prefixText;
4944
+ this.spinner.text = chalk.cyan("正在解压插件...");
4945
+ debugLog(`[下载插件] 创建插件目录: ${paths.target}`);
4946
+ await fs.mkdir(paths.target, { recursive: true });
4947
+ debugLog(`[下载插件] 解压 tarball 到: ${paths.target}`);
4748
4948
  try {
4749
- await execAsync(
4750
- `openclaw plugins install ${PLUGIN_PACKAGE_NAME} --dangerously-force-unsafe-install --pin`,
4751
- { timeout: 12e4 }
4752
- );
4753
- debugLog("[安装插件] openclaw plugins install 执行成功");
4754
- this.prefixText += chalk.green(` ✓ 插件安装完成
4755
- `);
4949
+ await tar.extract({
4950
+ file: tarballPath,
4951
+ cwd: paths.target,
4952
+ strip: 1
4953
+ });
4954
+ debugLog("[下载插件] tarball 解压成功");
4756
4955
  } catch (error) {
4757
- const errorMsg = error.message || "未知错误";
4758
- debugLog(`[安装插件] 安装失败: ${errorMsg}`);
4759
- throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `插件安装失败: ${errorMsg}`);
4956
+ throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
4957
+ }
4958
+ const pluginPath = path.join(paths.target, "package.json");
4959
+ const pluginExists = await fs.access(pluginPath).then(() => true).catch(() => false);
4960
+ if (!pluginExists) {
4961
+ throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
4962
+ }
4963
+ debugLog("[下载插件] 插件解压成功");
4964
+ this.spinner.prefixText = this.prefixText;
4965
+ this.spinner.text = chalk.cyan("正在安装依赖...");
4966
+ debugLog("[下载插件] 执行 npm install 安装生产环境依赖");
4967
+ try {
4968
+ await execAsync("npm install --omit=dev --ignore-scripts --quiet", {
4969
+ cwd: paths.target,
4970
+ timeout: 12e4
4971
+ });
4972
+ debugLog("[下载插件] npm install 执行成功");
4973
+ } catch (error) {
4974
+ const errorMsg = error.message || "";
4975
+ if (errorMsg.includes("npm warn") || errorMsg.includes("deprecated")) {
4976
+ debugLog("[下载插件] npm install 有警告但可能成功,继续流程");
4977
+ } else {
4978
+ debugLog(`[下载插件] npm install 失败: ${errorMsg}`);
4979
+ }
4980
+ }
4981
+ this.prefixText += chalk.green(` ✓ 插件安装完成
4982
+ `);
4983
+ try {
4984
+ await fs.rm(tempDir, { recursive: true, force: true });
4985
+ debugLog("[下载插件] 清理临时目录完成");
4986
+ } catch {
4987
+ debugLog("[下载插件] 清理临时目录失败(忽略)");
4760
4988
  }
4761
4989
  }
4762
4990
  async doUpdateConfig(paths, boundConfig, env) {
@@ -4967,31 +5195,14 @@ function checkEnv() {
4967
5195
  async function createLocalCommand(options) {
4968
5196
  setDebug(!!options.debug);
4969
5197
  debugLog("[初始化] 开始处理...");
4970
- debugLog(`[初始化] 参数: scenario=${options.scenario}, env=${options.env}, phone=${options.phone}, debug=${options.debug}`);
5198
+ debugLog(`[初始化] 参数: env=${options.env}, phone=${options.phone}, debug=${options.debug}`);
4971
5199
  checkEnv();
4972
5200
  debugLog("[初始化] 环境检查通过");
4973
5201
  try {
4974
- let scenario = options.scenario;
4975
5202
  let env = options.env;
4976
5203
  let phone = options.phone;
4977
5204
  let userPass = options.userPass;
4978
5205
  const questions = [];
4979
- if (!scenario) {
4980
- debugLog("[初始化] 需要选择安装场景");
4981
- questions.push({
4982
- type: "list",
4983
- name: "scenario",
4984
- message: chalk.cyan("请选择安装场景:"),
4985
- default: "windows-local",
4986
- choices: [
4987
- { name: `${chalk.green("Windows")} ${chalk.dim("本地安装")}`, value: "windows-local" },
4988
- { name: `${chalk.green("macOS")} ${chalk.dim("本地安装")}`, value: "mac-local" },
4989
- { name: `${chalk.green("Linux")} ${chalk.dim("本地安装")}`, value: "linux-local" }
4990
- ]
4991
- });
4992
- } else {
4993
- debugLog(`[初始化] 使用命令行参数: scenario=${scenario}`);
4994
- }
4995
5206
  if (!env) {
4996
5207
  debugLog("[初始化] 需要选择环境");
4997
5208
  questions.push({
@@ -5046,19 +5257,18 @@ async function createLocalCommand(options) {
5046
5257
  debugLog(`[初始化] 开始交互式问答,共 ${questions.length} 个问题`);
5047
5258
  const answers = await inquirer.prompt(questions);
5048
5259
  debugLog("[初始化] 交互式问答完成");
5049
- scenario = scenario || answers.scenario;
5050
5260
  env = env || answers.env || "test";
5051
5261
  phone = phone || answers.phone;
5052
5262
  userPass = userPass || answers.userPass;
5053
5263
  }
5054
- debugLog(`[初始化] 最终参数: scenario=${scenario}, env=${env}, phone=${phone}, pluginVersion=${options.pluginVersion}`);
5264
+ debugLog(`[初始化] 最终参数: env=${env}, phone=${phone}, pluginVersion=${options.pluginVersion}, openclawPath=${options.openclawPath}`);
5055
5265
  debugLog("[初始化] 创建 LocalInstaller 实例...");
5056
5266
  const installer = new LocalInstaller({
5057
5267
  phone,
5058
5268
  userPass,
5059
- scenario,
5060
5269
  env,
5061
- pluginVersion: options.pluginVersion
5270
+ pluginVersion: options.pluginVersion,
5271
+ openclawPath: options.openclawPath
5062
5272
  });
5063
5273
  debugLog("[初始化] 开始安装...");
5064
5274
  await installer.install();
@@ -5093,7 +5303,7 @@ async function createLocalCommand(options) {
5093
5303
  }
5094
5304
  }
5095
5305
  function registerCommands(program2) {
5096
- program2.command("local").description("本地账户安装(需要登录)").option("-s, --scenario <scenario>", "安装场景").option("-e, --env <env>", "环境 (test/prod)").option("--phone <phone>", "手机号码").option("--user-pass <userPass>", "用户密码").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--debug", "开启调试日志").action(createLocalCommand);
5306
+ program2.command("local").description("本地账户安装(需要登录)").option("-e, --env <env>", "环境 (test/prod)").option("--phone <phone>", "手机号码").option("--user-pass <userPass>", "用户密码").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--openclaw-path <path>", "OpenClaw 安装目录路径(默认 ~/.openclaw)").option("--debug", "开启调试日志").action(createLocalCommand);
5097
5307
  }
5098
5308
  const __filename$1 = fileURLToPath(import.meta.url);
5099
5309
  const __dirname$1 = dirname(__filename$1);
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import("./index-CEtTvwO1.js").then((cli) => {
2
+ import("./index-BZh3SXHn.js").then((cli) => {
3
3
  cli.default();
4
4
  });
@@ -13,6 +13,7 @@ export declare const ERROR_CODES: {
13
13
  readonly CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED";
14
14
  readonly HTTP_ERROR: "HTTP_ERROR";
15
15
  readonly NETWORK_ERROR: "NETWORK_ERROR";
16
+ readonly INVALID_OPENCLAW_PATH: "INVALID_OPENCLAW_PATH";
16
17
  };
17
18
  export type ErrorCode = keyof typeof ERROR_CODES;
18
19
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/error/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;CAYd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAA;AAEhD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAYpD,CAAA;AAED;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAExB,IAAI,EAAE,SAAS;gBAAf,IAAI,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM;CAKlB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/error/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAad,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAA;AAEhD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAapD,CAAA;AAED;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAExB,IAAI,EAAE,SAAS;gBAAf,IAAI,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM;CAKlB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD"}
@@ -5,8 +5,10 @@ export declare class LocalInstaller {
5
5
  private prefixText;
6
6
  constructor(config: LocalInstallerConfig);
7
7
  validateConfig(): void;
8
+ private validateOpenclawPath;
8
9
  install(): Promise<void>;
9
10
  getPrefixText(): string;
11
+ private getPackageName;
10
12
  private doLogin;
11
13
  private doFetchBoundConfig;
12
14
  private doCleanOldFiles;
@@ -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;AAsD/E,qBAAa,cAAc;IAIb,OAAO,CAAC,MAAM;IAH1B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAa;gBAEX,MAAM,EAAE,oBAAoB;IAIhD,cAAc,IAAI,IAAI;IAYhB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC9B,aAAa,IAAI,MAAM;YAIT,OAAO;YAoBP,kBAAkB;YAalB,eAAe;YAmBf,iBAAiB;YAyBjB,cAAc;CA+M7B"}
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;AAuD/E,qBAAa,cAAc;IAIb,OAAO,CAAC,MAAM;IAH1B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAa;gBAEX,MAAM,EAAE,oBAAoB;IAIhD,cAAc,IAAI,IAAI;IAYtB,OAAO,CAAC,oBAAoB;IAyBtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4C9B,aAAa,IAAI,MAAM;IAIvB,OAAO,CAAC,cAAc;YAOR,OAAO;YAoBP,kBAAkB;YAalB,eAAe;YAmBf,iBAAiB;YAmHjB,cAAc;CA+M7B"}
@@ -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;AAgC5C,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8I7E"}
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;AAgC5C,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuH7E"}
@@ -1,21 +1,20 @@
1
- import { Scenario } from '../utils';
2
1
  import { Environment } from '../../shared/config';
3
2
  export interface LocalOptions {
4
- scenario?: string;
5
3
  env?: string;
6
4
  phone?: string;
7
5
  userPass?: string;
8
6
  pluginVersion?: string;
7
+ openclawPath?: string;
9
8
  debug?: boolean;
10
9
  }
11
10
  export interface LocalInstallerConfig {
12
- scenario?: Scenario;
13
11
  env?: Environment;
14
12
  baseUrl?: string;
15
13
  wsUrl?: string;
16
14
  phone: string;
17
15
  userPass: string;
18
16
  pluginVersion?: string;
17
+ openclawPath?: string;
19
18
  }
20
19
  export interface BoundConfig {
21
20
  appKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,GAAG,CAAC,EAAE,WAAW,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,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,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,WAAW,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,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,4 +1,3 @@
1
1
  export { rsaEncrypt } from './crypto';
2
- export { detectOS, getHomeDir, getPathByScenario } from './path';
3
- export type { Scenario } from './path';
2
+ export { getHomeDir, getPathByScenario } from './path';
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAChE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/local/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA"}
@@ -1,7 +1,6 @@
1
- export type Scenario = 'windows-local' | 'mac-local' | 'linux-local';
1
+ import { Environment } from '../../shared/config';
2
2
  export declare function getHomeDir(): string;
3
- export declare function detectOS(): Scenario;
4
- export declare function getPathByScenario(): {
3
+ export declare function getPathByScenario(env: Environment, openclawPath?: string): {
5
4
  configDir: string;
6
5
  configFile: string;
7
6
  pluginDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/local/utils/path.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,eAAe,GAAG,WAAW,GAAG,aAAa,CAAA;AAEpE,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,QAAQ,IAAI,QAAQ,CAanC;AAED,wBAAgB,iBAAiB,IAAI;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAShG"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/local/utils/path.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAevI"}
@@ -18,6 +18,7 @@ export interface ConfigInterface {
18
18
  DIRS: {
19
19
  OPENCLAW: string;
20
20
  EXTENSIONS: string;
21
+ PLUGINS: string;
21
22
  CONFIG_FILE: string;
22
23
  WORKSPACE: string;
23
24
  TEMP: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/config/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAA;AAEzC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,oBAAoB;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe;IACf,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW;IACX,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,EAAE,MAAM,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,WAAW;IACX,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,aAAa;IACb,GAAG,EAAE;QACH,cAAc,EAAE,MAAM,CAAA;QACtB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF;AAED;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,eAkBpB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,eAkBzB,CAAA;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,eAAe,CAE3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/config/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAA;AAEzC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,oBAAoB;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe;IACf,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW;IACX,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;QAClB,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,WAAW;IACX,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,aAAa;IACb,GAAG,EAAE;QACH,cAAc,EAAE,MAAM,CAAA;QACtB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF;AAED;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,eAmBpB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,eAmBzB,CAAA;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,eAAe,CAE3D"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@workclaw/cli",
3
3
  "type": "module",
4
- "version": "1.0.311",
4
+ "version": "1.0.313",
5
5
  "description": "WorkClaw CLI 工具 - 用于初始化和配置 WorkClaw 插件",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@types/semver": "^7.7.0",
30
+ "@types/tar": "^6.1.13",
30
31
  "axios": "^1.7.9",
31
32
  "boxen": "^8.0.1",
32
33
  "chalk": "^5.6.2",
@@ -34,6 +35,7 @@
34
35
  "inquirer": "^12.7.0",
35
36
  "jsencrypt": "^3.5.4",
36
37
  "ora": "^8.2.0",
37
- "semver": "^7.7.1"
38
+ "semver": "^7.7.1",
39
+ "tar": "^6.2.1"
38
40
  }
39
41
  }