aisoulhub 1.0.7 → 1.0.8
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 +53 -1
- package/package.json +2 -1
- package/src/commands/install.js +30 -18
- package/src/commands/update.js +29 -15
- package/src/index.js +4 -4
- package/src/utils/check.js +7 -7
- package/src/utils/download.js +8 -4
- package/src/utils/meta.js +10 -10
- package/src/utils/openclaw.js +19 -10
package/README.md
CHANGED
|
@@ -1,2 +1,54 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AISoulHub CLI
|
|
2
|
+
|
|
3
|
+
A powerful command-line interface tool to easily install, update, and manage AI Soul configurations and skills for OpenClaw agents. It seamlessly integrates with [AISoulHub](https://aisoulhub.com) to provide a streamlined experience.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before using this tool, ensure you have the following installed:
|
|
8
|
+
- [Node.js](https://nodejs.org/) (v16 or higher recommended)
|
|
9
|
+
- [OpenClaw](https://openclaw.ai/) CLI (`openclaw` command must be available in your PATH)
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
You can run `aisoulhub` directly via `npx` without needing to install it globally.
|
|
14
|
+
|
|
15
|
+
### 1. Install an AI Soul
|
|
16
|
+
|
|
17
|
+
Downloads and installs an AI Soul package into a new or existing OpenClaw Agent.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx aisoulhub install <ai_soul_id>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**What happens during install?**
|
|
24
|
+
- Checks for OpenClaw dependency.
|
|
25
|
+
- Prompts for your email (if not already logged in) and saves it to `~/.aisoulhub.json`.
|
|
26
|
+
- Asks you to select an existing Agent or create a new one.
|
|
27
|
+
- Downloads the corresponding zip package from AISoulHub.
|
|
28
|
+
- Extracts files (like `SOUL.md`, `AGENTS.md`, `IDENTITY.md`, `aisoul-meta.json`) into the Agent's workspace.
|
|
29
|
+
- Automatically reads `aisoul-meta.json` and installs all defined skills via OpenClaw.
|
|
30
|
+
|
|
31
|
+
### 2. Update an AI Soul
|
|
32
|
+
|
|
33
|
+
Updates an existing OpenClaw Agent with the latest AI Soul package configuration and skills.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx aisoulhub update
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**What happens during update?**
|
|
40
|
+
- Displays a list of your existing Agents for you to select.
|
|
41
|
+
- Attempts to read the `ai_soul_id` from the Agent's `aisoul-meta.json`. If missing, prompts you to input it.
|
|
42
|
+
- Downloads the latest zip package from AISoulHub.
|
|
43
|
+
- Extracts and overwrites the existing configuration files in the workspace.
|
|
44
|
+
- Updates/re-installs the skills defined in the new `aisoul-meta.json`.
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
The CLI saves a minimal configuration file at `~/.aisoulhub.json` which currently stores your login email to streamline subsequent command executions.
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
ISC
|
|
53
|
+
|
|
2
54
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aisoulhub",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"@inquirer/prompts": "^8.3.2",
|
|
26
26
|
"axios": "^1.13.6",
|
|
27
27
|
"chalk": "^5.6.2",
|
|
28
|
+
"clawhub": "^0.9.0",
|
|
28
29
|
"commander": "^14.0.3",
|
|
29
30
|
"ora": "^9.3.0",
|
|
30
31
|
"shelljs": "^0.10.0",
|
package/src/commands/install.js
CHANGED
|
@@ -2,14 +2,14 @@ import { checkOpenclaw, checkLogin } from '../utils/check.js';
|
|
|
2
2
|
import { getAgents, addAgent } from '../utils/openclaw.js';
|
|
3
3
|
import { downloadAndExtract } from '../utils/download.js';
|
|
4
4
|
import { processMetaJson } from '../utils/meta.js';
|
|
5
|
-
import { select, input } from '@inquirer/prompts';
|
|
5
|
+
import { select, input, confirm } from '@inquirer/prompts';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import os from 'os';
|
|
9
9
|
|
|
10
10
|
export async function installCommand(aiSoulId) {
|
|
11
11
|
if (!aiSoulId) {
|
|
12
|
-
console.error(chalk.red('❌
|
|
12
|
+
console.error(chalk.red('❌ Error: ai_soul_id is required, e.g.: aisoulhub install <ai_soul_id>'));
|
|
13
13
|
process.exit(1);
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -22,40 +22,52 @@ export async function installCommand(aiSoulId) {
|
|
|
22
22
|
try {
|
|
23
23
|
agents = getAgents();
|
|
24
24
|
} catch (err) {
|
|
25
|
-
console.error(chalk.yellow(`⚠️
|
|
25
|
+
console.error(chalk.yellow(`⚠️ Failed to get agents list: ${err.message}`));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// 3. 提示用户选择或创建 Agent
|
|
29
29
|
const choices = [
|
|
30
|
-
{ name: '✨
|
|
31
|
-
...agents.map(a => ({ name: `📁 ${a.name} (${a.path})`, value: a.path }))
|
|
30
|
+
{ name: '✨ Create new Agent', value: { name: 'create_new', path: null } },
|
|
31
|
+
...agents.map(a => ({ name: `📁 ${a.name} (${a.path})`, value: { name: a.name, path: a.path } }))
|
|
32
32
|
];
|
|
33
33
|
|
|
34
34
|
const agentChoice = await select({
|
|
35
|
-
message: '
|
|
35
|
+
message: 'Please select the Agent to install:',
|
|
36
36
|
choices
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
if (agentChoice.name === 'main') {
|
|
40
|
+
const isConfirmed = await confirm({
|
|
41
|
+
message: chalk.yellow('⚠️ Warning: Overwriting the "main" agent might cause unexpected issues. Are you sure you want to continue?'),
|
|
42
|
+
default: false
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!isConfirmed) {
|
|
46
|
+
console.log(chalk.blue('ℹ️ Operation cancelled by user.'));
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let targetPath = agentChoice.path;
|
|
40
52
|
|
|
41
|
-
if (agentChoice === 'create_new') {
|
|
53
|
+
if (agentChoice.name === 'create_new') {
|
|
42
54
|
const newAgentName = await input({
|
|
43
|
-
message: '
|
|
44
|
-
validate: (val) => val.trim().length > 0 ? true : 'Agent
|
|
55
|
+
message: 'Please enter the name of the new Agent:',
|
|
56
|
+
validate: (val) => val.trim().length > 0 ? true : 'Agent name cannot be empty'
|
|
45
57
|
});
|
|
46
58
|
|
|
47
59
|
const defaultWorkspace = path.join(os.homedir(), '.openclaw', `workspace-${newAgentName}`);
|
|
48
60
|
|
|
49
61
|
const newWorkspacePath = await input({
|
|
50
|
-
message: '
|
|
62
|
+
message: 'Please enter the workspace directory for the new Agent:',
|
|
51
63
|
default: defaultWorkspace,
|
|
52
|
-
validate: (val) => val.trim().length > 0 ? true : '
|
|
64
|
+
validate: (val) => val.trim().length > 0 ? true : 'Workspace directory cannot be empty'
|
|
53
65
|
});
|
|
54
66
|
|
|
55
|
-
console.log(chalk.cyan(`🔄
|
|
67
|
+
console.log(chalk.cyan(`🔄 Creating Agent [${newAgentName}]...`));
|
|
56
68
|
try {
|
|
57
69
|
addAgent(newAgentName, newWorkspacePath);
|
|
58
|
-
console.log(chalk.green(`✅ Agent [${newAgentName}]
|
|
70
|
+
console.log(chalk.green(`✅ Agent [${newAgentName}] created successfully.`));
|
|
59
71
|
|
|
60
72
|
// 重新获取列表以获取新 agent 的路径
|
|
61
73
|
const updatedAgents = getAgents();
|
|
@@ -72,11 +84,11 @@ export async function installCommand(aiSoulId) {
|
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
if (!targetPath) {
|
|
75
|
-
console.error(chalk.red('❌
|
|
87
|
+
console.error(chalk.red('❌ Error: Unable to determine the workspace directory path for the Agent.'));
|
|
76
88
|
process.exit(1);
|
|
77
89
|
}
|
|
78
90
|
|
|
79
|
-
console.log(chalk.blue(`ℹ️
|
|
91
|
+
console.log(chalk.blue(`ℹ️ Target workspace directory: ${targetPath}`));
|
|
80
92
|
|
|
81
93
|
// 4. 下载并解压 ZIP 文件
|
|
82
94
|
const downloadSuccess = await downloadAndExtract(aiSoulId, targetPath);
|
|
@@ -84,8 +96,8 @@ export async function installCommand(aiSoulId) {
|
|
|
84
96
|
process.exit(1);
|
|
85
97
|
}
|
|
86
98
|
|
|
87
|
-
// 5. 解析 meta.json 并安装技能
|
|
99
|
+
// 5. 解析 aisoul-meta.json 并安装技能
|
|
88
100
|
await processMetaJson(targetPath);
|
|
89
101
|
|
|
90
|
-
console.log(chalk.green(`🎉
|
|
102
|
+
console.log(chalk.green(`🎉 Successfully installed ${aiSoulId} to the Agent.`));
|
|
91
103
|
}
|
package/src/commands/update.js
CHANGED
|
@@ -2,7 +2,7 @@ import { checkOpenclaw, checkLogin } from '../utils/check.js';
|
|
|
2
2
|
import { getAgents } from '../utils/openclaw.js';
|
|
3
3
|
import { downloadAndExtract } from '../utils/download.js';
|
|
4
4
|
import { processMetaJson } from '../utils/meta.js';
|
|
5
|
-
import { select, input } from '@inquirer/prompts';
|
|
5
|
+
import { select, input, confirm } from '@inquirer/prompts';
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import chalk from 'chalk';
|
|
@@ -17,49 +17,63 @@ export async function updateCommand() {
|
|
|
17
17
|
try {
|
|
18
18
|
agents = getAgents();
|
|
19
19
|
} catch (err) {
|
|
20
|
-
console.error(chalk.red(`❌
|
|
20
|
+
console.error(chalk.red(`❌ Failed to get agents list: ${err.message}`));
|
|
21
21
|
process.exit(1);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if (agents.length === 0) {
|
|
25
|
-
console.error(chalk.yellow('⚠️
|
|
25
|
+
console.error(chalk.yellow('⚠️ No agents available to update. Please install one first using the install command.'));
|
|
26
26
|
process.exit(1);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// 3. 提示用户选择 Agent
|
|
30
|
-
const choices = agents.map(a => ({ name: `📁 ${a.name} (${a.path})`, value: a.path }));
|
|
30
|
+
const choices = agents.map(a => ({ name: `📁 ${a.name} (${a.path})`, value: { name: a.name, path: a.path } }));
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
message: '
|
|
32
|
+
const agentChoice = await select({
|
|
33
|
+
message: 'Please select the Agent to update:',
|
|
34
34
|
choices
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
+
if (agentChoice.name === 'main') {
|
|
38
|
+
const isConfirmed = await confirm({
|
|
39
|
+
message: chalk.yellow('⚠️ Warning: Overwriting the "main" agent might cause unexpected issues. Are you sure you want to continue?'),
|
|
40
|
+
default: false
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!isConfirmed) {
|
|
44
|
+
console.log(chalk.blue('ℹ️ Operation cancelled by user.'));
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const targetPath = agentChoice.path;
|
|
50
|
+
|
|
37
51
|
if (!targetPath || !fs.existsSync(targetPath)) {
|
|
38
|
-
console.error(chalk.red('❌
|
|
52
|
+
console.error(chalk.red('❌ Error: Invalid Agent workspace directory.'));
|
|
39
53
|
process.exit(1);
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
// 4. 确定 ai_soul_id
|
|
43
57
|
let aiSoulId = null;
|
|
44
|
-
const metaPath = path.join(targetPath, 'meta.json');
|
|
58
|
+
const metaPath = path.join(targetPath, 'aisoul-meta.json');
|
|
45
59
|
if (fs.existsSync(metaPath)) {
|
|
46
60
|
try {
|
|
47
61
|
const content = fs.readFileSync(metaPath, 'utf-8');
|
|
48
62
|
const meta = JSON.parse(content);
|
|
49
63
|
if (meta.ai_soul_id) {
|
|
50
64
|
aiSoulId = meta.ai_soul_id;
|
|
51
|
-
console.log(chalk.blue(`ℹ️
|
|
65
|
+
console.log(chalk.blue(`ℹ️ Detected ai_soul_id from aisoul-meta.json: ${aiSoulId}`));
|
|
52
66
|
}
|
|
53
67
|
} catch (e) {
|
|
54
|
-
console.warn(chalk.yellow('⚠️
|
|
68
|
+
console.warn(chalk.yellow('⚠️ Unable to parse aisoul-meta.json.'));
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
if (!aiSoulId) {
|
|
59
|
-
console.log(chalk.yellow('ℹ️
|
|
73
|
+
console.log(chalk.yellow('ℹ️ Unable to get ai_soul_id from the current Agent\'s aisoul-meta.json.'));
|
|
60
74
|
aiSoulId = await input({
|
|
61
|
-
message: '
|
|
62
|
-
validate: (val) => val.trim().length > 0 ? true : 'ai_soul_id
|
|
75
|
+
message: 'Please enter the ai_soul_id to update:',
|
|
76
|
+
validate: (val) => val.trim().length > 0 ? true : 'ai_soul_id cannot be empty'
|
|
63
77
|
});
|
|
64
78
|
}
|
|
65
79
|
|
|
@@ -69,8 +83,8 @@ export async function updateCommand() {
|
|
|
69
83
|
process.exit(1);
|
|
70
84
|
}
|
|
71
85
|
|
|
72
|
-
// 6. 解析 meta.json 并更新技能
|
|
86
|
+
// 6. 解析 aisoul-meta.json 并更新技能
|
|
73
87
|
await processMetaJson(targetPath);
|
|
74
88
|
|
|
75
|
-
console.log(chalk.green(`🎉
|
|
89
|
+
console.log(chalk.green(`🎉 Successfully updated Agent [${aiSoulId}].`));
|
|
76
90
|
}
|
package/src/index.js
CHANGED
|
@@ -16,20 +16,20 @@ export async function main() {
|
|
|
16
16
|
|
|
17
17
|
program
|
|
18
18
|
.name('aisoulhub')
|
|
19
|
-
.description('AISoulHub CLI
|
|
19
|
+
.description('AISoulHub CLI tool for installing and updating Agent skills and configurations')
|
|
20
20
|
.version(pkg.version);
|
|
21
21
|
|
|
22
22
|
program
|
|
23
23
|
.command('install')
|
|
24
|
-
.description('
|
|
25
|
-
.argument('<ai_soul_id>', '
|
|
24
|
+
.description('Install new Agent configuration and skills')
|
|
25
|
+
.argument('<ai_soul_id>', 'Specify the ai_soul_id to install (e.g.: 12345)')
|
|
26
26
|
.action(async (aiSoulId) => {
|
|
27
27
|
await installCommand(aiSoulId);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
program
|
|
31
31
|
.command('update')
|
|
32
|
-
.description('
|
|
32
|
+
.description('Update existing Agent configuration and skills')
|
|
33
33
|
.action(async () => {
|
|
34
34
|
await updateCommand();
|
|
35
35
|
});
|
package/src/utils/check.js
CHANGED
|
@@ -7,7 +7,7 @@ import { input } from '@inquirer/prompts';
|
|
|
7
7
|
|
|
8
8
|
export function checkOpenclaw() {
|
|
9
9
|
if (!shell.which('openclaw')) {
|
|
10
|
-
console.error(chalk.red('❌
|
|
10
|
+
console.error(chalk.red('❌ Error: openclaw command not found. Please follow the instructions at https://openclaw.ai to install openclaw, then try again.'));
|
|
11
11
|
process.exit(1);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -26,27 +26,27 @@ export async function checkLogin() {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (!config.email) {
|
|
29
|
-
console.log(chalk.yellow('ℹ️
|
|
29
|
+
console.log(chalk.yellow('ℹ️ No login information detected. Please enter your email to login:'));
|
|
30
30
|
const email = await input({
|
|
31
|
-
message: '
|
|
31
|
+
message: 'Please enter your email address:',
|
|
32
32
|
validate: (value) => {
|
|
33
33
|
const pass = value.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
|
|
34
34
|
if (pass) {
|
|
35
35
|
return true;
|
|
36
36
|
}
|
|
37
|
-
return '
|
|
37
|
+
return 'Please enter a valid email address';
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
config.email = email;
|
|
42
42
|
try {
|
|
43
43
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
|
|
44
|
-
console.log(chalk.green(`✅
|
|
44
|
+
console.log(chalk.green(`✅ Login successful! Email: ${email} saved.`));
|
|
45
45
|
} catch (e) {
|
|
46
|
-
console.log(chalk.yellow(`⚠️
|
|
46
|
+
console.log(chalk.yellow(`⚠️ Login successful, but unable to save to ${CONFIG_PATH}: ${e.message}`));
|
|
47
47
|
}
|
|
48
48
|
} else {
|
|
49
|
-
console.log(chalk.blue(`ℹ️
|
|
49
|
+
console.log(chalk.blue(`ℹ️ Currently logged in as: ${config.email}`));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
return config.email;
|
package/src/utils/download.js
CHANGED
|
@@ -11,7 +11,7 @@ export async function downloadAndExtract(aiSoulId, targetPath) {
|
|
|
11
11
|
const tempDir = os.tmpdir();
|
|
12
12
|
const zipPath = path.join(tempDir, `${aiSoulId}.zip`);
|
|
13
13
|
|
|
14
|
-
const spinner = ora(
|
|
14
|
+
const spinner = ora(`Downloading package ${aiSoulId}...`).start();
|
|
15
15
|
|
|
16
16
|
try {
|
|
17
17
|
const response = await axios({
|
|
@@ -30,7 +30,7 @@ export async function downloadAndExtract(aiSoulId, targetPath) {
|
|
|
30
30
|
writer.on('error', reject);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
spinner.text =
|
|
33
|
+
spinner.text = `Download complete, extracting...`;
|
|
34
34
|
|
|
35
35
|
// Ensure target path exists
|
|
36
36
|
if (!fs.existsSync(targetPath)) {
|
|
@@ -42,13 +42,17 @@ export async function downloadAndExtract(aiSoulId, targetPath) {
|
|
|
42
42
|
.pipe(unzipper.Extract({ path: targetPath }))
|
|
43
43
|
.promise();
|
|
44
44
|
|
|
45
|
-
spinner.succeed(chalk.green(
|
|
45
|
+
spinner.succeed(chalk.green(`Package ${aiSoulId} downloaded and extracted successfully.`));
|
|
46
46
|
|
|
47
47
|
// Cleanup temp zip
|
|
48
48
|
fs.unlinkSync(zipPath);
|
|
49
49
|
return true;
|
|
50
50
|
} catch (err) {
|
|
51
|
-
|
|
51
|
+
if (err.response && err.response.status === 404) {
|
|
52
|
+
spinner.fail(chalk.red(`Error: Package not found. Please check if the ai_soul_id [${aiSoulId}] is correct.`));
|
|
53
|
+
} else {
|
|
54
|
+
spinner.fail(chalk.red(`Error: Failed to download or extract the package: ${err.message}`));
|
|
55
|
+
}
|
|
52
56
|
if (fs.existsSync(zipPath)) {
|
|
53
57
|
fs.unlinkSync(zipPath);
|
|
54
58
|
}
|
package/src/utils/meta.js
CHANGED
|
@@ -4,9 +4,9 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { installSkill } from './openclaw.js';
|
|
5
5
|
|
|
6
6
|
export async function processMetaJson(workspacePath) {
|
|
7
|
-
const metaPath = path.join(workspacePath, 'meta.json');
|
|
7
|
+
const metaPath = path.join(workspacePath, 'aisoul-meta.json');
|
|
8
8
|
if (!fs.existsSync(metaPath)) {
|
|
9
|
-
console.log(chalk.yellow(`ℹ️
|
|
9
|
+
console.log(chalk.yellow(`ℹ️ aisoul-meta.json not found, skipping skill installation. (${metaPath})`));
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -16,22 +16,22 @@ export async function processMetaJson(workspacePath) {
|
|
|
16
16
|
const skills = meta.skills || [];
|
|
17
17
|
|
|
18
18
|
if (skills.length === 0) {
|
|
19
|
-
console.log(chalk.blue('ℹ️ meta.json
|
|
19
|
+
console.log(chalk.blue('ℹ️ No skills defined to install in aisoul-meta.json.'));
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
console.log(chalk.cyan(`🔄
|
|
23
|
+
console.log(chalk.cyan(`🔄 Starting installation of ${skills.length} skills...`));
|
|
24
24
|
for (const skill of skills) {
|
|
25
|
-
console.log(chalk.blue(`⏳
|
|
26
|
-
const success = installSkill(workspacePath, skill);
|
|
25
|
+
console.log(chalk.blue(`⏳ Installing skill: ${skill}...`));
|
|
26
|
+
const success = await installSkill(workspacePath, skill);
|
|
27
27
|
if (success) {
|
|
28
|
-
console.log(chalk.green(`✅
|
|
28
|
+
console.log(chalk.green(`✅ Skill ${skill} installed successfully.`));
|
|
29
29
|
} else {
|
|
30
|
-
console.log(chalk.red(`❌
|
|
30
|
+
console.log(chalk.red(`❌ Failed to install skill ${skill}.`));
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
console.log(chalk.green('🎉
|
|
33
|
+
console.log(chalk.green('🎉 All skills installation processes completed.'));
|
|
34
34
|
} catch (err) {
|
|
35
|
-
console.error(chalk.red(`❌
|
|
35
|
+
console.error(chalk.red(`❌ Failed to read or parse aisoul-meta.json: ${err.message}`));
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/utils/openclaw.js
CHANGED
|
@@ -3,7 +3,7 @@ import shell from 'shelljs';
|
|
|
3
3
|
export function getAgents() {
|
|
4
4
|
const result = shell.exec('openclaw agents list --json', { silent: true });
|
|
5
5
|
if (result.code !== 0) {
|
|
6
|
-
throw new Error('
|
|
6
|
+
throw new Error('Failed to get agents list: ' + result.stderr);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
// Try to parse JSON first
|
|
@@ -45,21 +45,30 @@ export function addAgent(name, workspacePath) {
|
|
|
45
45
|
}
|
|
46
46
|
const result = shell.exec(cmd, { silent: true });
|
|
47
47
|
if (result.code !== 0) {
|
|
48
|
-
throw new Error(
|
|
48
|
+
throw new Error(`Failed to create agent [${name}]: ` + result.stderr);
|
|
49
49
|
}
|
|
50
50
|
return result.stdout;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function installSkill(workspacePath, skillStr) {
|
|
54
|
-
|
|
55
|
-
const result = shell.exec(`
|
|
53
|
+
export async function installSkill(workspacePath, skillStr, retryCount = 0) {
|
|
54
|
+
const maxRetries = 3;
|
|
55
|
+
const result = shell.exec(`npx clawhub install ${skillStr} --workdir "${workspacePath}"`, { silent: true });
|
|
56
|
+
|
|
56
57
|
if (result.code !== 0) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
const errorOutput = result.stderr || result.stdout;
|
|
59
|
+
if (errorOutput.includes('Rate limit exceeded')) {
|
|
60
|
+
if (retryCount < maxRetries) {
|
|
61
|
+
console.log(`⚠️ Rate limit exceeded. Waiting 5 seconds before retrying (${retryCount + 1}/${maxRetries})...`);
|
|
62
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
63
|
+
return installSkill(workspacePath, skillStr, retryCount + 1);
|
|
64
|
+
} else {
|
|
65
|
+
console.error(`❌ Failed to install skill ${skillStr} after ${maxRetries} retries due to rate limit.`);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
62
68
|
}
|
|
69
|
+
|
|
70
|
+
console.error(`❌ Failed to install skill ${skillStr}: `, errorOutput);
|
|
71
|
+
return false;
|
|
63
72
|
}
|
|
64
73
|
return true;
|
|
65
74
|
}
|