soulhubcli 1.0.15 → 1.0.17
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 +31 -22
- package/dist/index.cjs +117 -113
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SoulHub CLI
|
|
2
2
|
|
|
3
|
-
SoulHub CLI —
|
|
3
|
+
SoulHub CLI — 用于发现、安装和管理 AI Agent 灵魂(Soul)的命令行工具。支持从 SoulHub Registry 或本地目录安装单 Agent 和多 Agent 团队,兼容 OpenClaw 和 LightClaw。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -34,14 +34,14 @@ npx soulhubcli <command>
|
|
|
34
34
|
|
|
35
35
|
| 命令 | 说明 |
|
|
36
36
|
|------|------|
|
|
37
|
-
| `soulhub search <keyword>` |
|
|
38
|
-
| `soulhub info <name>` | 查看 Agent
|
|
39
|
-
| `soulhub install <name>` | 从 Registry 安装 Agent
|
|
37
|
+
| `soulhub search <keyword>` | 搜索 Agent |
|
|
38
|
+
| `soulhub info <name>` | 查看 Agent 详细信息(identity、soul、skills 等) |
|
|
39
|
+
| `soulhub install <name>` | 从 Registry 安装 Agent 或团队(默认为 worker,安装到所有检测到的 claw) |
|
|
40
|
+
| `soulhub install <name> --main` | 安装为主 Agent |
|
|
40
41
|
| `soulhub install --from <source>` | 从本地目录、ZIP 文件或 URL 安装 |
|
|
41
42
|
| `soulhub list` | 列出已安装的 Agent |
|
|
42
43
|
| `soulhub update [name]` | 更新已安装的 Agent |
|
|
43
|
-
| `soulhub
|
|
44
|
-
| `soulhub publish` | 验证并发布你的 Agent |
|
|
44
|
+
| `soulhub rollback` | 回滚到上一次安装状态 |
|
|
45
45
|
|
|
46
46
|
## 使用方法
|
|
47
47
|
|
|
@@ -56,11 +56,16 @@ soulhub search "content writing"
|
|
|
56
56
|
|
|
57
57
|
CLI 会自动识别目标是单 Agent 还是多 Agent 团队,无需手动区分。
|
|
58
58
|
|
|
59
|
+
**默认行为:安装为 Worker Agent,自动安装到所有检测到的 claw 目录。**
|
|
60
|
+
|
|
59
61
|
**从 Registry 安装:**
|
|
60
62
|
|
|
61
63
|
```bash
|
|
62
|
-
# 安装单 Agent
|
|
63
|
-
soulhub install
|
|
64
|
+
# 安装单 Agent(默认为 worker,安装到所有检测到的 claw)
|
|
65
|
+
soulhub install writer-wechat
|
|
66
|
+
|
|
67
|
+
# 安装为主 Agent
|
|
68
|
+
soulhub install writer-wechat --main
|
|
64
69
|
|
|
65
70
|
# 安装多 Agent 团队(调度 Agent + 工作 Agent)
|
|
66
71
|
soulhub install dev-squad
|
|
@@ -82,11 +87,11 @@ soulhub install --from https://example.com/agent-team.zip
|
|
|
82
87
|
**指定目标目录:**
|
|
83
88
|
|
|
84
89
|
```bash
|
|
85
|
-
# 安装到自定义目录(不依赖 OpenClaw 环境)
|
|
86
|
-
soulhub install
|
|
90
|
+
# 安装到自定义目录(不依赖 OpenClaw/LightClaw 环境)
|
|
91
|
+
soulhub install writer-wechat --dir ./my-agents
|
|
87
92
|
|
|
88
|
-
# 指定
|
|
89
|
-
soulhub install
|
|
93
|
+
# 指定 claw 安装目录(只安装到该 claw)
|
|
94
|
+
soulhub install writer-wechat --claw-dir ~/.lightclaw
|
|
90
95
|
```
|
|
91
96
|
|
|
92
97
|
### 列出已安装的 Agent
|
|
@@ -112,9 +117,11 @@ soulhub uninstall ops-assistant
|
|
|
112
117
|
|
|
113
118
|
### 单 Agent 安装
|
|
114
119
|
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
120
|
+
- **默认安装为 Worker Agent**(子 agent),部署到 `workspace-<agentId>/` 目录
|
|
121
|
+
- 使用 `--main` 参数可安装为主 Agent,部署到 `workspace/` 目录
|
|
122
|
+
- **自动安装到所有检测到的 claw 目录**(OpenClaw / LightClaw),使用 `--claw-dir` 可指定单个 claw
|
|
123
|
+
- 如果目标目录已存在,CLI 会**自动备份**(复制到 `agentbackup/`)
|
|
124
|
+
- 仅覆盖 `IDENTITY.md`、`SOUL.md` 等灵魂文件,不影响 workspace 中的其他运行时文件
|
|
118
125
|
- 安装完成后自动重启 OpenClaw Gateway;若重启失败会提示手动重启
|
|
119
126
|
|
|
120
127
|
### 多 Agent 团队安装
|
|
@@ -122,7 +129,7 @@ soulhub uninstall ops-assistant
|
|
|
122
129
|
- **调度 Agent(Dispatcher)** 作为主 Agent 安装到 `workspace/` 目录
|
|
123
130
|
- **工作 Agent(Worker)** 安装到各自的 `workspace-<agentId>/` 目录
|
|
124
131
|
- 自动配置多 Agent 之间的通信
|
|
125
|
-
- Worker Agent
|
|
132
|
+
- Worker Agent 自动注册到 claw 配置中
|
|
126
133
|
- 安装完成后自动重启 OpenClaw Gateway
|
|
127
134
|
|
|
128
135
|
## 配置
|
|
@@ -137,18 +144,20 @@ CLI 将配置存储在 `~/.soulhub/config.json`。
|
|
|
137
144
|
export SOULHUB_REGISTRY_URL=https://your-registry.example.com
|
|
138
145
|
```
|
|
139
146
|
|
|
140
|
-
### OpenClaw 目录
|
|
147
|
+
### OpenClaw / LightClaw 目录
|
|
148
|
+
|
|
149
|
+
CLI 按以下优先级查找 claw 安装目录:
|
|
141
150
|
|
|
142
|
-
|
|
151
|
+
1. `--claw-dir` 命令行参数(指定时只安装到该 claw)
|
|
152
|
+
2. `OPENCLAW_HOME` / `LIGHTCLAW_HOME` 环境变量
|
|
153
|
+
3. 默认路径 `~/.openclaw`、`~/.lightclaw`
|
|
143
154
|
|
|
144
|
-
|
|
145
|
-
2. `OPENCLAW_HOME` 环境变量
|
|
146
|
-
3. 默认路径 `~/.openclaw`
|
|
155
|
+
未指定 `--claw-dir` 时,CLI 会检测所有可用的 claw 目录并全部安装。
|
|
147
156
|
|
|
148
157
|
## 环境要求
|
|
149
158
|
|
|
150
159
|
- Node.js >= 18.0.0
|
|
151
|
-
- OpenClaw(可选,使用 `--dir` 参数时不需要)
|
|
160
|
+
- OpenClaw 或 LightClaw(可选,使用 `--dir` 参数时不需要)
|
|
152
161
|
|
|
153
162
|
## License
|
|
154
163
|
|
package/dist/index.cjs
CHANGED
|
@@ -19246,6 +19246,10 @@ function addAgentToOpenClawConfig(clawDir, agentId, agentName, isMain) {
|
|
|
19246
19246
|
const existing = config.agents.list.find((a) => a.id === agentId);
|
|
19247
19247
|
if (existing) {
|
|
19248
19248
|
existing.name = agentName;
|
|
19249
|
+
if (!isMain) {
|
|
19250
|
+
existing.workspace = import_node_path11.default.join(clawDir, `workspace-${agentId}`);
|
|
19251
|
+
existing.agentDir = import_node_path11.default.join(clawDir, `agents/${agentId}/agent`);
|
|
19252
|
+
}
|
|
19249
19253
|
return config;
|
|
19250
19254
|
}
|
|
19251
19255
|
if (isMain) {
|
|
@@ -19440,25 +19444,44 @@ function registerAgentToOpenClaw(agentName, workspaceDir, _clawDir) {
|
|
|
19440
19444
|
} catch (cliError) {
|
|
19441
19445
|
const stderr = cliError && typeof cliError === "object" && "stderr" in cliError ? String(cliError.stderr) : "";
|
|
19442
19446
|
if (stderr.includes("already exists")) {
|
|
19447
|
+
logger.info(`Agent "${agentId}" already exists in CLI, updating config...`);
|
|
19448
|
+
try {
|
|
19449
|
+
const clawDir = _clawDir || import_node_path11.default.dirname(workspaceDir);
|
|
19450
|
+
addAgentToOpenClawConfig(clawDir, agentId, agentName, false);
|
|
19451
|
+
} catch {
|
|
19452
|
+
logger.warn(`Failed to update config for existing agent "${agentId}", skipping.`);
|
|
19453
|
+
}
|
|
19443
19454
|
return {
|
|
19444
19455
|
success: true,
|
|
19445
|
-
message: `Agent "${agentId}" already registered.`
|
|
19456
|
+
message: `Agent "${agentId}" already registered, config updated.`
|
|
19446
19457
|
};
|
|
19447
19458
|
}
|
|
19448
|
-
const
|
|
19449
|
-
|
|
19450
|
-
|
|
19459
|
+
const errMsg = cliError instanceof Error ? cliError.message : String(cliError);
|
|
19460
|
+
logger.warn(`CLI agents add failed, falling back to config file modification`, { agentId, stderr, error: errMsg });
|
|
19461
|
+
try {
|
|
19462
|
+
const clawDir = _clawDir || import_node_path11.default.dirname(workspaceDir);
|
|
19463
|
+
const configUpdated = addAgentToOpenClawConfig(clawDir, agentId, agentName, false);
|
|
19464
|
+
if (configUpdated) {
|
|
19465
|
+
logger.info(`Agent "${agentId}" registered via config file fallback.`);
|
|
19466
|
+
return {
|
|
19467
|
+
success: true,
|
|
19468
|
+
message: `Agent "${agentId}" registered via config file (CLI fallback).`
|
|
19469
|
+
};
|
|
19470
|
+
} else {
|
|
19471
|
+
logger.error(`Failed to update config file for agent "${agentId}"`);
|
|
19472
|
+
return {
|
|
19473
|
+
success: false,
|
|
19474
|
+
message: `Failed to register "${agentId}": CLI command failed and config file update also failed.`
|
|
19475
|
+
};
|
|
19476
|
+
}
|
|
19477
|
+
} catch (configError) {
|
|
19478
|
+
const configErrMsg = configError instanceof Error ? configError.message : String(configError);
|
|
19479
|
+
logger.error(`Config file fallback also failed`, { agentId, error: configErrMsg });
|
|
19451
19480
|
return {
|
|
19452
19481
|
success: false,
|
|
19453
|
-
message: "
|
|
19482
|
+
message: `Failed to register "${agentId}": CLI failed (${stderr || errMsg}), config fallback also failed (${configErrMsg}).`
|
|
19454
19483
|
};
|
|
19455
19484
|
}
|
|
19456
|
-
const errMsg = cliError instanceof Error ? cliError.message : String(cliError);
|
|
19457
|
-
logger.error(`openclaw agents add failed`, { agentId, stderr, error: errMsg });
|
|
19458
|
-
return {
|
|
19459
|
-
success: false,
|
|
19460
|
-
message: `openclaw agents add failed: ${stderr || errMsg}`
|
|
19461
|
-
};
|
|
19462
19485
|
}
|
|
19463
19486
|
}
|
|
19464
19487
|
function detectClawCommand() {
|
|
@@ -19725,40 +19748,20 @@ function createSpinner(initialText = "") {
|
|
|
19725
19748
|
// src/commands/install.ts
|
|
19726
19749
|
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
19727
19750
|
var import_node_path12 = __toESM(require("path"), 1);
|
|
19728
|
-
var import_node_readline2 = __toESM(require("readline"), 1);
|
|
19729
19751
|
async function resolveClawDir(clawDir) {
|
|
19730
19752
|
if (clawDir) {
|
|
19731
19753
|
return findOpenClawDir(clawDir);
|
|
19732
19754
|
}
|
|
19733
19755
|
return promptSelectClawDir();
|
|
19734
19756
|
}
|
|
19735
|
-
|
|
19736
|
-
|
|
19737
|
-
|
|
19738
|
-
|
|
19739
|
-
|
|
19740
|
-
|
|
19741
|
-
console.log();
|
|
19742
|
-
const rl = import_node_readline2.default.createInterface({
|
|
19743
|
-
input: process.stdin,
|
|
19744
|
-
output: process.stdout
|
|
19745
|
-
});
|
|
19746
|
-
return new Promise((resolve) => {
|
|
19747
|
-
rl.question(" Please select (1-2, default: 2): ", (answer) => {
|
|
19748
|
-
rl.close();
|
|
19749
|
-
const trimmed = answer.trim();
|
|
19750
|
-
if (trimmed === "" || trimmed === "2") {
|
|
19751
|
-
resolve(false);
|
|
19752
|
-
} else if (trimmed === "1") {
|
|
19753
|
-
resolve(true);
|
|
19754
|
-
} else {
|
|
19755
|
-
console.log(" Invalid selection, operation cancelled.");
|
|
19756
|
-
resolve(null);
|
|
19757
|
-
}
|
|
19758
|
-
});
|
|
19759
|
-
});
|
|
19757
|
+
function resolveAllClawDirs(clawDir) {
|
|
19758
|
+
if (clawDir) {
|
|
19759
|
+
const resolved = findOpenClawDir(clawDir);
|
|
19760
|
+
return resolved ? [resolved] : [];
|
|
19761
|
+
}
|
|
19762
|
+
return findAllClawDirs();
|
|
19760
19763
|
}
|
|
19761
|
-
var installCommand = new Command("install").description("Install an agent or team from the SoulHub registry (default: as worker)").argument("[name]", "Agent or team name to install").option("--from <source>", "Install from a local directory, ZIP file, or URL").option("--main", "Install as main agent
|
|
19764
|
+
var installCommand = new Command("install").description("Install an agent or team from the SoulHub registry (default: as worker, installs to all detected claws)").argument("[name]", "Agent or team name to install").option("--from <source>", "Install from a local directory, ZIP file, or URL").option("--main", "Install as main agent").option(
|
|
19762
19765
|
"--dir <path>",
|
|
19763
19766
|
"Target directory (defaults to OpenClaw/LightClaw workspace)"
|
|
19764
19767
|
).option(
|
|
@@ -19766,13 +19769,7 @@ var installCommand = new Command("install").description("Install an agent or tea
|
|
|
19766
19769
|
"OpenClaw/LightClaw installation directory (overrides OPENCLAW_HOME/LIGHTCLAW_HOME env var, defaults to ~/.openclaw or ~/.lightclaw)"
|
|
19767
19770
|
).action(async (name, options) => {
|
|
19768
19771
|
try {
|
|
19769
|
-
|
|
19770
|
-
if (options.main && options.worker) {
|
|
19771
|
-
console.error(source_default.red("Error: --main and --worker cannot be used together."));
|
|
19772
|
-
process.exit(1);
|
|
19773
|
-
}
|
|
19774
|
-
if (options.main) asMain = true;
|
|
19775
|
-
if (options.worker) asMain = false;
|
|
19772
|
+
const asMain = !!options.main;
|
|
19776
19773
|
if (options.from) {
|
|
19777
19774
|
await installFromSource(options.from, options.dir, options.clawDir, asMain);
|
|
19778
19775
|
} else if (name) {
|
|
@@ -19780,12 +19777,11 @@ var installCommand = new Command("install").description("Install an agent or tea
|
|
|
19780
19777
|
} else {
|
|
19781
19778
|
console.error(source_default.red("Please specify an agent or team name, or use --from to install from a local source."));
|
|
19782
19779
|
console.log(source_default.dim(" Examples:"));
|
|
19783
|
-
console.log(source_default.dim(" soulhub install writer-wechat #
|
|
19784
|
-
console.log(source_default.dim(" soulhub install writer-wechat --main #
|
|
19785
|
-
console.log(source_default.dim(" soulhub install
|
|
19786
|
-
console.log(source_default.dim(" soulhub install
|
|
19787
|
-
console.log(source_default.dim(" soulhub install --
|
|
19788
|
-
console.log(source_default.dim(" soulhub install writer-wechat --claw-dir ~/.lightclaw # \u975E\u4EA4\u4E92\u5F0F\u6307\u5B9A claw \u76EE\u5F55"));
|
|
19780
|
+
console.log(source_default.dim(" soulhub install writer-wechat # Install as worker to all detected claws"));
|
|
19781
|
+
console.log(source_default.dim(" soulhub install writer-wechat --main # Install as main agent"));
|
|
19782
|
+
console.log(source_default.dim(" soulhub install dev-squad # Install a team from registry"));
|
|
19783
|
+
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"));
|
|
19789
19785
|
process.exit(1);
|
|
19790
19786
|
}
|
|
19791
19787
|
} catch (error) {
|
|
@@ -19804,7 +19800,7 @@ async function installFromRegistry(name, targetDir, clawDir, asMain) {
|
|
|
19804
19800
|
const recipe = index.recipes.find((r) => r.name === name);
|
|
19805
19801
|
if (agent && !recipe) {
|
|
19806
19802
|
spinner.stop();
|
|
19807
|
-
logger.info(`Installing single agent from registry: ${name}, asMain=${asMain
|
|
19803
|
+
logger.info(`Installing single agent from registry: ${name}, asMain=${asMain}`);
|
|
19808
19804
|
await installSingleAgent(name, targetDir, clawDir, asMain);
|
|
19809
19805
|
} else if (recipe) {
|
|
19810
19806
|
spinner.stop();
|
|
@@ -19816,31 +19812,18 @@ async function installFromRegistry(name, targetDir, clawDir, asMain) {
|
|
|
19816
19812
|
console.log(source_default.dim(" Use 'soulhub search' to find available agents and teams."));
|
|
19817
19813
|
}
|
|
19818
19814
|
}
|
|
19819
|
-
async function installSingleAgent(name, targetDir, clawDir, asMain) {
|
|
19820
|
-
|
|
19821
|
-
|
|
19822
|
-
|
|
19823
|
-
spinner.stop();
|
|
19824
|
-
selectedClawDir = await resolveClawDir(clawDir);
|
|
19825
|
-
if (!selectedClawDir) {
|
|
19826
|
-
console.log(source_default.red("OpenClaw/LightClaw workspace directory not found."));
|
|
19827
|
-
printOpenClawInstallHelp();
|
|
19828
|
-
return;
|
|
19829
|
-
}
|
|
19830
|
-
const brand = detectClawBrand(selectedClawDir);
|
|
19831
|
-
console.log(source_default.dim(` ${brand} detected: ${selectedClawDir}`));
|
|
19832
|
-
}
|
|
19833
|
-
const agentId = name.toLowerCase().replace(/[\s_]+/g, "-");
|
|
19834
|
-
if (asMain === void 0) {
|
|
19835
|
-
const choice = await promptInstallRole(agentId);
|
|
19836
|
-
if (choice === null) return;
|
|
19837
|
-
asMain = choice;
|
|
19815
|
+
async function installSingleAgent(name, targetDir, clawDir, asMain = false) {
|
|
19816
|
+
if (targetDir) {
|
|
19817
|
+
await installSingleAgentToClaw(name, null, targetDir, asMain);
|
|
19818
|
+
return;
|
|
19838
19819
|
}
|
|
19839
|
-
|
|
19840
|
-
if (
|
|
19841
|
-
|
|
19820
|
+
const allClawDirs = resolveAllClawDirs(clawDir);
|
|
19821
|
+
if (allClawDirs.length === 0) {
|
|
19822
|
+
console.log(source_default.red("OpenClaw/LightClaw workspace directory not found."));
|
|
19823
|
+
printOpenClawInstallHelp();
|
|
19824
|
+
return;
|
|
19842
19825
|
}
|
|
19843
|
-
spinner
|
|
19826
|
+
const spinner = createSpinner(`Fetching agent ${source_default.cyan(name)}...`).start();
|
|
19844
19827
|
const index = await fetchIndex();
|
|
19845
19828
|
const agent = index.agents.find((a) => a.name === name);
|
|
19846
19829
|
if (!agent) {
|
|
@@ -19848,6 +19831,32 @@ async function installSingleAgent(name, targetDir, clawDir, asMain) {
|
|
|
19848
19831
|
console.log(source_default.dim(" Use 'soulhub search' to find available agents."));
|
|
19849
19832
|
return;
|
|
19850
19833
|
}
|
|
19834
|
+
spinner.text = `Downloading ${source_default.cyan(agent.displayName)} package...`;
|
|
19835
|
+
const pkgDir = await downloadAgentPackage(name, agent.version);
|
|
19836
|
+
spinner.succeed(`Package ${source_default.cyan(agent.displayName)} downloaded.`);
|
|
19837
|
+
for (const selectedClawDir of allClawDirs) {
|
|
19838
|
+
await installSingleAgentToClaw(name, selectedClawDir, void 0, asMain, pkgDir, agent);
|
|
19839
|
+
}
|
|
19840
|
+
import_node_fs9.default.rmSync(pkgDir, { recursive: true, force: true });
|
|
19841
|
+
}
|
|
19842
|
+
async function installSingleAgentToClaw(name, selectedClawDir, targetDir, asMain = false, preDownloadedPkgDir, preLoadedAgent) {
|
|
19843
|
+
const brand = selectedClawDir ? detectClawBrand(selectedClawDir) : null;
|
|
19844
|
+
const clawLabel = brand ? `${brand} (${selectedClawDir})` : targetDir;
|
|
19845
|
+
const spinner = createSpinner(`Installing to ${source_default.dim(clawLabel)}...`).start();
|
|
19846
|
+
const agentId = name.toLowerCase().replace(/[\s_]+/g, "-");
|
|
19847
|
+
logger.info(`Install role resolved: asMain=${asMain}, claw=${selectedClawDir || targetDir}`);
|
|
19848
|
+
let agent = preLoadedAgent;
|
|
19849
|
+
if (!agent) {
|
|
19850
|
+
spinner.text = `Fetching agent ${source_default.cyan(name)}...`;
|
|
19851
|
+
const index = await fetchIndex();
|
|
19852
|
+
const found = index.agents.find((a) => a.name === name);
|
|
19853
|
+
if (!found) {
|
|
19854
|
+
spinner.fail(`Agent "${name}" not found in registry.`);
|
|
19855
|
+
console.log(source_default.dim(" Use 'soulhub search' to find available agents."));
|
|
19856
|
+
return;
|
|
19857
|
+
}
|
|
19858
|
+
agent = found;
|
|
19859
|
+
}
|
|
19851
19860
|
let workspaceDir;
|
|
19852
19861
|
if (targetDir) {
|
|
19853
19862
|
workspaceDir = import_node_path12.default.resolve(targetDir);
|
|
@@ -19860,9 +19869,7 @@ async function installSingleAgent(name, targetDir, clawDir, asMain) {
|
|
|
19860
19869
|
if (!targetDir && asMain) {
|
|
19861
19870
|
const mainCheck = checkMainAgentExists(selectedClawDir);
|
|
19862
19871
|
if (mainCheck.hasContent) {
|
|
19863
|
-
spinner.warn(
|
|
19864
|
-
`Existing main agent detected. Backing up workspace...`
|
|
19865
|
-
);
|
|
19872
|
+
spinner.warn(`Existing main agent detected. Backing up workspace...`);
|
|
19866
19873
|
const backupDir = backupAgentWorkspace(workspaceDir);
|
|
19867
19874
|
if (backupDir) {
|
|
19868
19875
|
console.log(source_default.yellow(` \u26A0 Existing main agent backed up to: ${backupDir}`));
|
|
@@ -19902,21 +19909,23 @@ async function installSingleAgent(name, targetDir, clawDir, asMain) {
|
|
|
19902
19909
|
if (asMain) {
|
|
19903
19910
|
spinner.text = `Registering ${source_default.cyan(agent.displayName)} as main agent...`;
|
|
19904
19911
|
addAgentToOpenClawConfig(selectedClawDir, "main", name, true);
|
|
19905
|
-
spinner.text = source_default.dim(`Main agent registered in config`);
|
|
19906
19912
|
} else {
|
|
19907
19913
|
spinner.text = `Registering ${source_default.cyan(agent.displayName)} as worker agent...`;
|
|
19908
|
-
const regResult = registerAgentToOpenClaw(agentId, workspaceDir
|
|
19914
|
+
const regResult = registerAgentToOpenClaw(agentId, workspaceDir);
|
|
19909
19915
|
if (!regResult.success) {
|
|
19910
19916
|
spinner.fail(`Failed to register ${agentId}: ${regResult.message}`);
|
|
19911
19917
|
return;
|
|
19912
19918
|
}
|
|
19913
|
-
spinner.text = source_default.dim(`Worker agent ${agentId} registered in config`);
|
|
19914
19919
|
}
|
|
19915
19920
|
}
|
|
19916
|
-
|
|
19917
|
-
|
|
19918
|
-
|
|
19919
|
-
|
|
19921
|
+
if (preDownloadedPkgDir) {
|
|
19922
|
+
copyAgentFilesFromPackage(preDownloadedPkgDir, workspaceDir);
|
|
19923
|
+
} else {
|
|
19924
|
+
spinner.text = `Downloading ${source_default.cyan(agent.displayName)} package...`;
|
|
19925
|
+
const pkgDir = await downloadAgentPackage(name, agent.version);
|
|
19926
|
+
copyAgentFilesFromPackage(pkgDir, workspaceDir);
|
|
19927
|
+
import_node_fs9.default.rmSync(pkgDir, { recursive: true, force: true });
|
|
19928
|
+
}
|
|
19920
19929
|
recordInstall(name, agent.version, workspaceDir);
|
|
19921
19930
|
if (backupRecord) {
|
|
19922
19931
|
if (asMain) {
|
|
@@ -19930,9 +19939,8 @@ async function installSingleAgent(name, targetDir, clawDir, asMain) {
|
|
|
19930
19939
|
const typeLabel = asMain ? source_default.blue("Single Agent (Main)") : source_default.green("Single Agent (Worker)");
|
|
19931
19940
|
logger.info(`Single agent installed as ${roleLabel}: ${name}`, { version: agent.version, workspace: workspaceDir });
|
|
19932
19941
|
spinner.succeed(
|
|
19933
|
-
`${source_default.cyan.bold(agent.displayName)} installed as ${roleLabel}
|
|
19942
|
+
`${source_default.cyan.bold(agent.displayName)} installed as ${roleLabel} \u2192 ${source_default.dim(clawLabel)}`
|
|
19934
19943
|
);
|
|
19935
|
-
console.log();
|
|
19936
19944
|
console.log(` ${source_default.dim("Location:")} ${workspaceDir}`);
|
|
19937
19945
|
console.log(` ${source_default.dim("Version:")} ${agent.version}`);
|
|
19938
19946
|
console.log(` ${source_default.dim("Type:")} ${typeLabel}`);
|
|
@@ -20099,32 +20107,29 @@ async function installFromSource(source, targetDir, clawDir, asMain) {
|
|
|
20099
20107
|
import_node_fs9.default.rmSync(tempDir, { recursive: true, force: true });
|
|
20100
20108
|
}
|
|
20101
20109
|
}
|
|
20102
|
-
async function installSingleAgentFromDir(packageDir, targetDir, clawDir, asMain) {
|
|
20103
|
-
const spinner = createSpinner("Installing single agent...").start();
|
|
20110
|
+
async function installSingleAgentFromDir(packageDir, targetDir, clawDir, asMain = false) {
|
|
20104
20111
|
const pkg = readSoulHubPackage(packageDir);
|
|
20105
20112
|
const agentName = pkg?.name || import_node_path12.default.basename(packageDir);
|
|
20106
|
-
|
|
20107
|
-
|
|
20108
|
-
|
|
20109
|
-
selectedClawDir = await resolveClawDir(clawDir);
|
|
20110
|
-
if (!selectedClawDir) {
|
|
20111
|
-
console.log(source_default.red("OpenClaw/LightClaw workspace directory not found."));
|
|
20112
|
-
printOpenClawInstallHelp();
|
|
20113
|
-
return;
|
|
20114
|
-
}
|
|
20115
|
-
const brand = detectClawBrand(selectedClawDir);
|
|
20116
|
-
console.log(source_default.dim(` ${brand} detected: ${selectedClawDir}`));
|
|
20113
|
+
if (targetDir) {
|
|
20114
|
+
await installSingleAgentFromDirToClaw(packageDir, agentName, pkg, null, targetDir, asMain);
|
|
20115
|
+
return;
|
|
20117
20116
|
}
|
|
20118
|
-
const
|
|
20119
|
-
if (
|
|
20120
|
-
|
|
20121
|
-
|
|
20122
|
-
|
|
20117
|
+
const allClawDirs = resolveAllClawDirs(clawDir);
|
|
20118
|
+
if (allClawDirs.length === 0) {
|
|
20119
|
+
console.log(source_default.red("OpenClaw/LightClaw workspace directory not found."));
|
|
20120
|
+
printOpenClawInstallHelp();
|
|
20121
|
+
return;
|
|
20123
20122
|
}
|
|
20124
|
-
|
|
20125
|
-
|
|
20126
|
-
spinner.start();
|
|
20123
|
+
for (const selectedClawDir of allClawDirs) {
|
|
20124
|
+
await installSingleAgentFromDirToClaw(packageDir, agentName, pkg, selectedClawDir, void 0, asMain);
|
|
20127
20125
|
}
|
|
20126
|
+
}
|
|
20127
|
+
async function installSingleAgentFromDirToClaw(packageDir, agentName, pkg, selectedClawDir, targetDir, asMain = false) {
|
|
20128
|
+
const brand = selectedClawDir ? detectClawBrand(selectedClawDir) : null;
|
|
20129
|
+
const clawLabel = brand ? `${brand} (${selectedClawDir})` : targetDir;
|
|
20130
|
+
const spinner = createSpinner(`Installing to ${source_default.dim(clawLabel)}...`).start();
|
|
20131
|
+
const agentId = agentName.toLowerCase().replace(/[\s_]+/g, "-");
|
|
20132
|
+
logger.info(`Install role resolved: asMain=${asMain}, claw=${selectedClawDir || targetDir}`);
|
|
20128
20133
|
let workspaceDir;
|
|
20129
20134
|
if (targetDir) {
|
|
20130
20135
|
workspaceDir = import_node_path12.default.resolve(targetDir);
|
|
@@ -20174,7 +20179,7 @@ async function installSingleAgentFromDir(packageDir, targetDir, clawDir, asMain)
|
|
|
20174
20179
|
addAgentToOpenClawConfig(selectedClawDir, "main", agentName, true);
|
|
20175
20180
|
} else {
|
|
20176
20181
|
spinner.text = `Registering ${source_default.cyan(agentName)} as worker agent...`;
|
|
20177
|
-
const regResult = registerAgentToOpenClaw(agentId, workspaceDir
|
|
20182
|
+
const regResult = registerAgentToOpenClaw(agentId, workspaceDir);
|
|
20178
20183
|
if (!regResult.success) {
|
|
20179
20184
|
spinner.fail(`Failed to register ${agentId}: ${regResult.message}`);
|
|
20180
20185
|
return;
|
|
@@ -20195,8 +20200,7 @@ async function installSingleAgentFromDir(packageDir, targetDir, clawDir, asMain)
|
|
|
20195
20200
|
const roleLabel = asMain ? "main agent" : "worker agent";
|
|
20196
20201
|
const typeLabel = asMain ? source_default.blue("Single Agent (Main)") : source_default.green("Single Agent (Worker)");
|
|
20197
20202
|
logger.info(`Single agent installed from dir as ${roleLabel}: ${agentName}`, { source: packageDir, workspace: workspaceDir });
|
|
20198
|
-
spinner.succeed(`${source_default.cyan.bold(agentName)} installed as ${roleLabel}
|
|
20199
|
-
console.log();
|
|
20203
|
+
spinner.succeed(`${source_default.cyan.bold(agentName)} installed as ${roleLabel} \u2192 ${source_default.dim(clawLabel)}`);
|
|
20200
20204
|
console.log(` ${source_default.dim("Location:")} ${workspaceDir}`);
|
|
20201
20205
|
console.log(` ${source_default.dim("Source:")} ${packageDir}`);
|
|
20202
20206
|
console.log(` ${source_default.dim("Type:")} ${typeLabel}`);
|
|
@@ -20702,13 +20706,13 @@ function formatInstallType(type2) {
|
|
|
20702
20706
|
|
|
20703
20707
|
// src/index.ts
|
|
20704
20708
|
var program2 = new Command();
|
|
20705
|
-
program2.name("soulhub").description("SoulHub CLI - Discover, install and manage AI agent souls").version("1.0.
|
|
20709
|
+
program2.name("soulhub").description("SoulHub CLI - Discover, install and manage AI agent souls").version("1.0.17").option("--verbose", "Enable verbose debug logging").hook("preAction", () => {
|
|
20706
20710
|
const opts = program2.opts();
|
|
20707
20711
|
const verbose = opts.verbose || process.env.SOULHUB_DEBUG === "1";
|
|
20708
20712
|
logger.init(verbose);
|
|
20709
20713
|
logger.info("CLI started", {
|
|
20710
20714
|
args: process.argv.slice(2),
|
|
20711
|
-
version: "1.0.
|
|
20715
|
+
version: "1.0.17",
|
|
20712
20716
|
node: process.version
|
|
20713
20717
|
});
|
|
20714
20718
|
});
|