soulhubcli 1.0.19 → 1.0.21

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/README.md CHANGED
@@ -90,8 +90,8 @@ soulhub install --from https://example.com/agent-team.zip
90
90
  # 安装到自定义目录(不依赖 OpenClaw/LightClaw 环境)
91
91
  soulhub install writer-wechat --dir ./my-agents
92
92
 
93
- # 指定 claw 安装目录(只安装到该 claw)
94
- soulhub install writer-wechat --claw-dir ~/.lightclaw
93
+ # 指定 claw 类型(只安装到该 claw)
94
+ soulhub install writer-wechat --clawtype LightClaw
95
95
  ```
96
96
 
97
97
  ### 列出已安装的 Agent
@@ -119,7 +119,7 @@ soulhub uninstall ops-assistant
119
119
 
120
120
  - **默认安装为 Worker Agent**(子 agent),部署到 `workspace-<agentId>/` 目录
121
121
  - 使用 `--main` 参数可安装为主 Agent,部署到 `workspace/` 目录
122
- - **自动安装到所有检测到的 claw 目录**(OpenClaw / LightClaw),使用 `--claw-dir` 可指定单个 claw
122
+ - **自动安装到所有检测到的 claw 目录**(OpenClaw / LightClaw),使用 `--clawtype` 可指定单个 claw
123
123
  - 如果目标目录已存在,CLI 会**自动备份**(复制到 `agentbackup/`)
124
124
  - 仅覆盖 `IDENTITY.md`、`SOUL.md` 等灵魂文件,不影响 workspace 中的其他运行时文件
125
125
  - 安装完成后自动重启 OpenClaw Gateway;若重启失败会提示手动重启
@@ -148,11 +148,11 @@ export SOULHUB_REGISTRY_URL=https://your-registry.example.com
148
148
 
149
149
  CLI 按以下优先级查找 claw 安装目录:
150
150
 
151
- 1. `--claw-dir` 命令行参数(指定时只安装到该 claw)
151
+ 1. `--clawtype` 命令行参数(指定时只安装到该 claw)
152
152
  2. `OPENCLAW_HOME` / `LIGHTCLAW_HOME` 环境变量
153
153
  3. 默认路径 `~/.openclaw`、`~/.lightclaw`
154
154
 
155
- 未指定 `--claw-dir` 时,CLI 会检测所有可用的 claw 目录并全部安装。
155
+ 未指定 `--clawtype` 时,CLI 会检测所有可用的 claw 目录并全部安装。
156
156
 
157
157
  ## 环境要求
158
158
 
package/dist/index.cjs CHANGED
@@ -19033,11 +19033,15 @@ function copyAgentFilesFromPackage(packageDir, targetDir) {
19033
19033
  }
19034
19034
  function findOpenClawDir(customDir) {
19035
19035
  if (customDir) {
19036
- const resolved = import_node_path11.default.resolve(customDir);
19037
- if (import_node_fs8.default.existsSync(resolved)) {
19038
- return resolved;
19036
+ const home2 = import_node_os2.default.homedir();
19037
+ const lower = customDir.toLowerCase();
19038
+ if (lower === "openclaw") {
19039
+ return import_node_path11.default.join(home2, ".openclaw");
19039
19040
  }
19040
- return resolved;
19041
+ if (lower === "lightclaw") {
19042
+ return import_node_path11.default.join(home2, ".lightclaw");
19043
+ }
19044
+ throw new Error(`Unsupported claw type: "${customDir}". Only "OpenClaw" or "LightClaw" is supported (case-insensitive).`);
19041
19045
  }
19042
19046
  const envHome = process.env.OPENCLAW_HOME || process.env.LIGHTCLAW_HOME;
19043
19047
  if (envHome) {
@@ -19063,8 +19067,15 @@ function findOpenClawDir(customDir) {
19063
19067
  }
19064
19068
  function findAllClawDirs(customDir) {
19065
19069
  if (customDir) {
19066
- const resolved = import_node_path11.default.resolve(customDir);
19067
- return import_node_fs8.default.existsSync(resolved) ? [resolved] : [resolved];
19070
+ const home2 = import_node_os2.default.homedir();
19071
+ const lower = customDir.toLowerCase();
19072
+ if (lower === "openclaw") {
19073
+ return [import_node_path11.default.join(home2, ".openclaw")];
19074
+ }
19075
+ if (lower === "lightclaw") {
19076
+ return [import_node_path11.default.join(home2, ".lightclaw")];
19077
+ }
19078
+ throw new Error(`Unsupported claw type: "${customDir}". Only "OpenClaw" or "LightClaw" is supported (case-insensitive).`);
19068
19079
  }
19069
19080
  const envHome = process.env.OPENCLAW_HOME || process.env.LIGHTCLAW_HOME;
19070
19081
  if (envHome) {
@@ -19207,9 +19218,10 @@ function writeOpenClawConfig(clawDir, config) {
19207
19218
  import_node_fs8.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
19208
19219
  }
19209
19220
  function updateOpenClawConfig(clawDir, updater) {
19210
- const config = readOpenClawConfig(clawDir);
19221
+ let config = readOpenClawConfig(clawDir);
19211
19222
  if (!config) {
19212
- return false;
19223
+ logger.info(`Config file not found in ${clawDir}, creating default config.`);
19224
+ config = { agents: { list: [] } };
19213
19225
  }
19214
19226
  const updated = updater(config);
19215
19227
  writeOpenClawConfig(clawDir, updated);
@@ -19428,11 +19440,12 @@ var CATEGORY_LABELS = {
19428
19440
  education: "Education",
19429
19441
  dispatcher: "Dispatcher"
19430
19442
  };
19431
- function registerAgentToOpenClaw(agentName, workspaceDir, _clawDir) {
19443
+ function registerAgentToOpenClaw(agentName, workspaceDir, clawDir) {
19432
19444
  const agentId = agentName.toLowerCase().replace(/[\s_]+/g, "-");
19433
- logger.debug(`Registering agent to OpenClaw/LightClaw`, { agentId, workspaceDir });
19445
+ const brandName = clawDir ? detectClawBrand(clawDir) : "OpenClaw/LightClaw";
19446
+ logger.debug(`Registering agent to ${brandName}`, { agentId, workspaceDir });
19434
19447
  try {
19435
- const clawCmd = detectClawCommand();
19448
+ const clawCmd = detectClawCommand(clawDir);
19436
19449
  (0, import_node_child_process.execSync)(
19437
19450
  `${clawCmd} agents add "${agentId}" --workspace "${workspaceDir}" --non-interactive --json`,
19438
19451
  { stdio: "pipe", timeout: 15e3 }
@@ -19446,8 +19459,8 @@ function registerAgentToOpenClaw(agentName, workspaceDir, _clawDir) {
19446
19459
  if (stderr.includes("already exists")) {
19447
19460
  logger.info(`Agent "${agentId}" already exists in CLI, updating config...`);
19448
19461
  try {
19449
- const clawDir = _clawDir || import_node_path11.default.dirname(workspaceDir);
19450
- addAgentToOpenClawConfig(clawDir, agentId, agentName, false);
19462
+ const resolvedClawDir = clawDir || import_node_path11.default.dirname(workspaceDir);
19463
+ addAgentToOpenClawConfig(resolvedClawDir, agentId, agentName, false);
19451
19464
  } catch {
19452
19465
  logger.warn(`Failed to update config for existing agent "${agentId}", skipping.`);
19453
19466
  }
@@ -19459,8 +19472,8 @@ function registerAgentToOpenClaw(agentName, workspaceDir, _clawDir) {
19459
19472
  const errMsg = cliError instanceof Error ? cliError.message : String(cliError);
19460
19473
  logger.warn(`CLI agents add failed, falling back to config file modification`, { agentId, stderr, error: errMsg });
19461
19474
  try {
19462
- const clawDir = _clawDir || import_node_path11.default.dirname(workspaceDir);
19463
- const configUpdated = addAgentToOpenClawConfig(clawDir, agentId, agentName, false);
19475
+ const resolvedClawDir = clawDir || import_node_path11.default.dirname(workspaceDir);
19476
+ const configUpdated = addAgentToOpenClawConfig(resolvedClawDir, agentId, agentName, false);
19464
19477
  if (configUpdated) {
19465
19478
  logger.info(`Agent "${agentId}" registered via config file fallback.`);
19466
19479
  return {
@@ -19484,7 +19497,11 @@ function registerAgentToOpenClaw(agentName, workspaceDir, _clawDir) {
19484
19497
  }
19485
19498
  }
19486
19499
  }
19487
- function detectClawCommand() {
19500
+ function detectClawCommand(clawDir) {
19501
+ if (clawDir) {
19502
+ const brand = detectClawBrand(clawDir);
19503
+ return brand === "LightClaw" ? "lightclaw" : "openclaw";
19504
+ }
19488
19505
  try {
19489
19506
  (0, import_node_child_process.execSync)("which lightclaw 2>/dev/null || where lightclaw 2>nul", { stdio: "pipe" });
19490
19507
  return "lightclaw";
@@ -19497,8 +19514,8 @@ function detectClawCommand() {
19497
19514
  }
19498
19515
  return "openclaw";
19499
19516
  }
19500
- function restartOpenClawGateway() {
19501
- const clawCmd = detectClawCommand();
19517
+ function restartOpenClawGateway(clawDir) {
19518
+ const clawCmd = detectClawCommand(clawDir);
19502
19519
  logger.debug(`Restarting ${clawCmd} Gateway`);
19503
19520
  try {
19504
19521
  (0, import_node_child_process.execSync)(`${clawCmd} gateway restart`, {
@@ -19765,15 +19782,15 @@ var installCommand = new Command("install").description("Install an agent or tea
19765
19782
  "--dir <path>",
19766
19783
  "Target directory (defaults to OpenClaw/LightClaw workspace)"
19767
19784
  ).option(
19768
- "--claw-dir <path>",
19769
- "OpenClaw/LightClaw installation directory (overrides OPENCLAW_HOME/LIGHTCLAW_HOME env var, defaults to ~/.openclaw or ~/.lightclaw)"
19785
+ "--clawtype <type>",
19786
+ "Specify claw type: OpenClaw or LightClaw (case-insensitive)"
19770
19787
  ).action(async (name, options) => {
19771
19788
  try {
19772
19789
  const asMain = !!options.main;
19773
19790
  if (options.from) {
19774
- await installFromSource(options.from, options.dir, options.clawDir, asMain);
19791
+ await installFromSource(options.from, options.dir, options.clawtype, asMain);
19775
19792
  } else if (name) {
19776
- await installFromRegistry(name, options.dir, options.clawDir, asMain);
19793
+ await installFromRegistry(name, options.dir, options.clawtype, asMain);
19777
19794
  } else {
19778
19795
  console.error(source_default.red("Please specify an agent or team name, or use --from to install from a local source."));
19779
19796
  console.log(source_default.dim(" Examples:"));
@@ -19781,7 +19798,7 @@ var installCommand = new Command("install").description("Install an agent or tea
19781
19798
  console.log(source_default.dim(" soulhub install writer-wechat --main # Install as main agent"));
19782
19799
  console.log(source_default.dim(" soulhub install dev-squad # Install a team from registry"));
19783
19800
  console.log(source_default.dim(" soulhub install --from ./agent-team/ # Install from local directory"));
19784
- console.log(source_default.dim(" soulhub install writer-wechat --claw-dir ~/.lightclaw # Install to specific claw"));
19801
+ console.log(source_default.dim(" soulhub install writer-wechat --clawtype LightClaw # Install to specific claw"));
19785
19802
  process.exit(1);
19786
19803
  }
19787
19804
  } catch (error) {
@@ -19951,7 +19968,7 @@ async function installSingleAgentToClaw(name, selectedClawDir, targetDir, asMain
19951
19968
  console.log(` ${source_default.dim("Version:")} ${agent.version}`);
19952
19969
  console.log(` ${source_default.dim("Type:")} ${typeLabel}`);
19953
19970
  if (!targetDir) {
19954
- await tryRestartGateway();
19971
+ await tryRestartGateway(selectedClawDir || void 0);
19955
19972
  }
19956
19973
  console.log();
19957
19974
  }
@@ -20012,7 +20029,7 @@ async function installRecipeFromRegistry(name, recipe, targetDir, clawDir) {
20012
20029
  const agentId = worker.name;
20013
20030
  const workerDir = targetDir ? import_node_path12.default.join(resolvedClawDir, `workspace-${agentId}`) : getWorkspaceDir(resolvedClawDir, agentId);
20014
20031
  if (!targetDir) {
20015
- const regResult = registerAgentToOpenClaw(agentId, workerDir, clawDir);
20032
+ const regResult = registerAgentToOpenClaw(agentId, workerDir, resolvedClawDir);
20016
20033
  if (!regResult.success) {
20017
20034
  console.log(source_default.yellow(` \u26A0 Failed to register ${agentId}: ${regResult.message}`));
20018
20035
  continue;
@@ -20044,7 +20061,7 @@ async function installRecipeFromRegistry(name, recipe, targetDir, clawDir) {
20044
20061
  );
20045
20062
  printTeamSummary(pkg, workerIds);
20046
20063
  if (!targetDir) {
20047
- await tryRestartGateway();
20064
+ await tryRestartGateway(resolvedClawDir);
20048
20065
  }
20049
20066
  }
20050
20067
  async function installFromSource(source, targetDir, clawDir, asMain) {
@@ -20217,7 +20234,7 @@ async function installSingleAgentFromDirToClaw(packageDir, agentName, pkg, selec
20217
20234
  console.log(` ${source_default.dim("Source:")} ${packageDir}`);
20218
20235
  console.log(` ${source_default.dim("Type:")} ${typeLabel}`);
20219
20236
  if (!targetDir) {
20220
- await tryRestartGateway();
20237
+ await tryRestartGateway(selectedClawDir || void 0);
20221
20238
  }
20222
20239
  console.log();
20223
20240
  }
@@ -20303,7 +20320,7 @@ async function installTeamFromDir(packageDir, targetDir, clawDir) {
20303
20320
  spinner.text = `Installing worker ${source_default.cyan(agentId)}...`;
20304
20321
  const workerWorkspace = targetDir ? import_node_path12.default.join(resolvedClawDir, `workspace-${agentId}`) : getWorkspaceDir(resolvedClawDir, agentId);
20305
20322
  if (!targetDir) {
20306
- const regResult = registerAgentToOpenClaw(agentId, workerWorkspace, clawDir);
20323
+ const regResult = registerAgentToOpenClaw(agentId, workerWorkspace, resolvedClawDir);
20307
20324
  if (!regResult.success) {
20308
20325
  console.log(source_default.yellow(` \u26A0 Failed to register ${agentId}: ${regResult.message}`));
20309
20326
  continue;
@@ -20333,7 +20350,7 @@ async function installTeamFromDir(packageDir, targetDir, clawDir) {
20333
20350
  );
20334
20351
  printTeamSummary(pkg, workerIds);
20335
20352
  if (!targetDir) {
20336
- await tryRestartGateway();
20353
+ await tryRestartGateway(resolvedClawDir);
20337
20354
  }
20338
20355
  }
20339
20356
  function copyAgentFilesFromDir(sourceDir, targetDir) {
@@ -20401,7 +20418,7 @@ async function extractZipToDir(zip, targetDir) {
20401
20418
  }
20402
20419
  function printOpenClawInstallHelp() {
20403
20420
  console.log(source_default.dim(" Please install OpenClaw or LightClaw first, or use one of the following options:"));
20404
- console.log(source_default.dim(" --claw-dir <path> Specify OpenClaw/LightClaw installation directory"));
20421
+ console.log(source_default.dim(" --clawtype <type> Specify claw type: OpenClaw or LightClaw"));
20405
20422
  console.log(source_default.dim(" --dir <path> Specify agent target directory directly"));
20406
20423
  console.log(source_default.dim(" OPENCLAW_HOME=<path> Set environment variable (for OpenClaw)"));
20407
20424
  console.log(source_default.dim(" LIGHTCLAW_HOME=<path> Set environment variable (for LightClaw)"));
@@ -20421,11 +20438,11 @@ function printTeamSummary(pkg, workerIds) {
20421
20438
  }
20422
20439
  console.log();
20423
20440
  }
20424
- async function tryRestartGateway() {
20425
- const clawCmd = detectClawCommand();
20441
+ async function tryRestartGateway(clawDir) {
20442
+ const clawCmd = detectClawCommand(clawDir);
20426
20443
  const brandName = clawCmd === "lightclaw" ? "LightClaw" : "OpenClaw";
20427
20444
  const restartSpinner = createSpinner(`Restarting ${brandName} Gateway...`).start();
20428
- const result = restartOpenClawGateway();
20445
+ const result = restartOpenClawGateway(clawDir);
20429
20446
  if (result.success) {
20430
20447
  restartSpinner.succeed(`${brandName} Gateway restarted successfully.`);
20431
20448
  } else {
@@ -20534,16 +20551,16 @@ var updateCommand = new Command("update").description("Update installed agents t
20534
20551
  var import_node_fs11 = __toESM(require("fs"), 1);
20535
20552
  var import_node_path13 = __toESM(require("path"), 1);
20536
20553
  var rollbackCommand = new Command("rollback").description("Rollback to a previous agent installation state").option("--list", "List available rollback records").option("--id <id>", "Rollback to a specific backup record by ID").option(
20537
- "--claw-dir <path>",
20538
- "OpenClaw/LightClaw installation directory (overrides OPENCLAW_HOME/LIGHTCLAW_HOME env var)"
20554
+ "--clawtype <type>",
20555
+ "Specify claw type: OpenClaw or LightClaw (case-insensitive)"
20539
20556
  ).action(async (options) => {
20540
20557
  try {
20541
20558
  if (options.list) {
20542
20559
  listBackupRecords();
20543
20560
  } else if (options.id) {
20544
- await performRollback(options.id, options.clawDir);
20561
+ await performRollback(options.id, options.clawtype);
20545
20562
  } else {
20546
- await performRollback(void 0, options.clawDir);
20563
+ await performRollback(void 0, options.clawtype);
20547
20564
  }
20548
20565
  } catch (error) {
20549
20566
  logger.errorObj("Rollback command failed", error);
@@ -20684,10 +20701,10 @@ async function performRollback(recordId, clawDir) {
20684
20701
  spinner.succeed(
20685
20702
  `Rolled back ${source_default.cyan.bold(record.packageName)} successfully! (${restoredCount} item(s) restored)`
20686
20703
  );
20687
- const clawCmd = detectClawCommand();
20704
+ const clawCmd = detectClawCommand(resolvedClawDir);
20688
20705
  const brandName = clawCmd === "lightclaw" ? "LightClaw" : "OpenClaw";
20689
20706
  const restartSpinner = createSpinner(`Restarting ${brandName} Gateway...`).start();
20690
- const result = restartOpenClawGateway();
20707
+ const result = restartOpenClawGateway(resolvedClawDir);
20691
20708
  if (result.success) {
20692
20709
  restartSpinner.succeed(`${brandName} Gateway restarted successfully.`);
20693
20710
  } else {
@@ -20715,13 +20732,13 @@ function formatInstallType(type2) {
20715
20732
 
20716
20733
  // src/index.ts
20717
20734
  var program2 = new Command();
20718
- program2.name("soulhub").description("SoulHub CLI - Discover, install and manage AI agent souls").version("1.0.19").option("--verbose", "Enable verbose debug logging").hook("preAction", () => {
20735
+ program2.name("soulhub").description("SoulHub CLI - Discover, install and manage AI agent souls").version("1.0.21").option("--verbose", "Enable verbose debug logging").hook("preAction", () => {
20719
20736
  const opts = program2.opts();
20720
20737
  const verbose = opts.verbose || process.env.SOULHUB_DEBUG === "1";
20721
20738
  logger.init(verbose);
20722
20739
  logger.info("CLI started", {
20723
20740
  args: process.argv.slice(2),
20724
- version: "1.0.19",
20741
+ version: "1.0.21",
20725
20742
  node: process.version
20726
20743
  });
20727
20744
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soulhubcli",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "SoulHub CLI - Install and manage AI agent persona templates for OpenClaw",
5
5
  "type": "module",
6
6
  "bin": {