openclaw-weiyuan-init 1.0.0
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/LICENSE +0 -0
- package/README.md +8 -0
- package/bin/cli.js +54 -0
- package/lib/commands.js +172 -0
- package/lib/downloader.js +43 -0
- package/lib/extractor.js +24 -0
- package/lib/identity.js +39 -0
- package/lib/package.json +49 -0
- package/lib/server.js +33 -0
- package/lib/utils.js +50 -0
- package/package.json +30 -0
- package/templates/.weiyuan.template +10 -0
- package/workspace-weiyuan/.weiyuan +10 -0
- package/workspace-weiyuan/weiyuan/README.md +159 -0
- package/workspace-weiyuan/weiyuan/examples/action-task-list.json +6 -0
- package/workspace-weiyuan/weiyuan/examples/risk-report.json +8 -0
- package/workspace-weiyuan/weiyuan/examples/text-what-can-i-do.json +6 -0
- package/workspace-weiyuan/weiyuan/manifest.json +45 -0
- package/workspace-weiyuan/weiyuan/schema.json +104 -0
- package/workspace-weiyuan/weiyuan/src/cli.ts +453 -0
- package/workspace-weiyuan/weiyuan/src/cliMain.ts +7 -0
- package/workspace-weiyuan/weiyuan/src/crypto.ts +14 -0
- package/workspace-weiyuan/weiyuan/src/http.ts +45 -0
- package/workspace-weiyuan/weiyuan/src/signing.ts +38 -0
- package/workspace-weiyuan/weiyuan/src/skillAdapter.ts +173 -0
- package/workspace-weiyuan/weiyuan/src/types.ts +10 -0
- package/workspace-weiyuan/weiyuan/src/weiyuanFile.ts +25 -0
package/LICENSE
ADDED
|
File without changes
|
package/README.md
ADDED
package/bin/cli.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { runInit, runClean, runStatus } = require('../lib/commands');
|
|
6
|
+
|
|
7
|
+
program
|
|
8
|
+
.name('openclaw-weiyuan-init')
|
|
9
|
+
.description('OpenClaw Weiyuan Skill 一键初始化工具')
|
|
10
|
+
.version('1.0.0');
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.command('init')
|
|
14
|
+
.description('初始化 weiyuan skill')
|
|
15
|
+
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
16
|
+
.option('-s, --server <url>', '指定服务器地址', 'http://121.43.119.190:8787')
|
|
17
|
+
.option('-d, --download <url>', '指定下载地址', 'http://121.43.119.190:8788/weiyuan-openclaw-skill-v0.1.1.zip')
|
|
18
|
+
.option('-f, --force', '强制覆盖已有文件')
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
try {
|
|
21
|
+
await runInit(options);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(chalk.red(`初始化失败: ${error.message}`));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
program
|
|
29
|
+
.command('clean')
|
|
30
|
+
.description('清理 weiyuan 工作目录')
|
|
31
|
+
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
32
|
+
.action(async (options) => {
|
|
33
|
+
try {
|
|
34
|
+
await runClean(options);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(chalk.red(`清理失败: ${error.message}`));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
program
|
|
42
|
+
.command('status')
|
|
43
|
+
.description('查看 weiyuan 状态')
|
|
44
|
+
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
try {
|
|
47
|
+
await runStatus(options);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(chalk.red(`查询失败: ${error.message}`));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
program.parse();
|
package/lib/commands.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const ora = require('ora');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const { downloadFile } = require('./downloader');
|
|
6
|
+
const { extractZip } = require('./extractor');
|
|
7
|
+
const { createIdentityFile } = require('./identity');
|
|
8
|
+
const { checkServer, initSkill } = require('./server');
|
|
9
|
+
const { printBanner, printSummary, listDirectory } = require('./utils');
|
|
10
|
+
|
|
11
|
+
const DEFAULT_CONFIG = {
|
|
12
|
+
workspaceName: 'workspace-weiyuan',
|
|
13
|
+
downloadUrl: 'http://121.43.119.190:8788/weiyuan-openclaw-skill-v0.1.1.zip',
|
|
14
|
+
serverUrl: 'http://121.43.119.190:8787',
|
|
15
|
+
zipFilename: 'weiyuan-openclaw-skill-v0.1.1.zip',
|
|
16
|
+
identityFile: '.weiyuan'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
async function runInit(options) {
|
|
20
|
+
printBanner();
|
|
21
|
+
|
|
22
|
+
const workspacePath = path.join(process.cwd(), options.workspace);
|
|
23
|
+
const weiyuanPath = path.join(workspacePath, 'weiyuan');
|
|
24
|
+
const downloadUrl = options.download || DEFAULT_CONFIG.downloadUrl;
|
|
25
|
+
const serverUrl = options.server || DEFAULT_CONFIG.serverUrl;
|
|
26
|
+
const force = options.force || false;
|
|
27
|
+
|
|
28
|
+
// 检查是否已存在
|
|
29
|
+
if (!force && await fs.pathExists(workspacePath)) {
|
|
30
|
+
console.log(chalk.yellow(`\n⚠️ 工作目录已存在: ${workspacePath}`));
|
|
31
|
+
console.log(chalk.gray(' 使用 --force 强制重新初始化\n'));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 1. 创建工作目录
|
|
36
|
+
let spinner = ora('创建工作目录...').start();
|
|
37
|
+
try {
|
|
38
|
+
await fs.ensureDir(weiyuanPath);
|
|
39
|
+
spinner.succeed(`工作目录: ${workspacePath}`);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
spinner.fail(`创建目录失败: ${error.message}`);
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 2. 检查服务器
|
|
46
|
+
spinner = ora('检查服务器连接...').start();
|
|
47
|
+
const serverOk = await checkServer(serverUrl);
|
|
48
|
+
if (serverOk) {
|
|
49
|
+
spinner.succeed(`服务器: ${serverUrl}`);
|
|
50
|
+
} else {
|
|
51
|
+
spinner.warn(`服务器连接失败,请检查网络和防火墙`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 3. 下载文件
|
|
55
|
+
spinner = ora('下载 weiyuan skill...').start();
|
|
56
|
+
const zipPath = path.join(weiyuanPath, DEFAULT_CONFIG.zipFilename);
|
|
57
|
+
const downloadSuccess = await downloadFile(downloadUrl, zipPath, spinner);
|
|
58
|
+
if (!downloadSuccess) {
|
|
59
|
+
spinner.fail('下载失败');
|
|
60
|
+
throw new Error('下载失败');
|
|
61
|
+
}
|
|
62
|
+
spinner.succeed('下载完成');
|
|
63
|
+
|
|
64
|
+
// 4. 解压
|
|
65
|
+
spinner = ora('解压文件...').start();
|
|
66
|
+
const extractSuccess = await extractZip(zipPath, weiyuanPath);
|
|
67
|
+
if (!extractSuccess) {
|
|
68
|
+
spinner.fail('解压失败');
|
|
69
|
+
throw new Error('解压失败');
|
|
70
|
+
}
|
|
71
|
+
spinner.succeed('解压完成');
|
|
72
|
+
|
|
73
|
+
// 5. 清理
|
|
74
|
+
spinner = ora('清理临时文件...').start();
|
|
75
|
+
try {
|
|
76
|
+
await fs.remove(zipPath);
|
|
77
|
+
spinner.succeed('清理完成');
|
|
78
|
+
} catch (error) {
|
|
79
|
+
spinner.warn('清理失败,可手动删除');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 6. 创建身份文件
|
|
83
|
+
spinner = ora('创建身份文件...').start();
|
|
84
|
+
const identityPath = path.join(workspacePath, DEFAULT_CONFIG.identityFile);
|
|
85
|
+
const identityCreated = await createIdentityFile(identityPath, serverUrl, workspacePath);
|
|
86
|
+
if (identityCreated) {
|
|
87
|
+
spinner.succeed(`身份文件: ${DEFAULT_CONFIG.identityFile}`);
|
|
88
|
+
} else {
|
|
89
|
+
spinner.warn('身份文件创建失败,请手动创建');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 7. 列出目录内容
|
|
93
|
+
console.log(chalk.yellow('\n📁 weiyuan 文件夹内容:'));
|
|
94
|
+
await listDirectory(weiyuanPath, 10);
|
|
95
|
+
|
|
96
|
+
// 8. 初始化 skill
|
|
97
|
+
spinner = ora('初始化 weiyuan skill...').start();
|
|
98
|
+
const initResult = await initSkill(serverUrl, identityPath, workspacePath);
|
|
99
|
+
if (initResult) {
|
|
100
|
+
spinner.succeed('初始化成功');
|
|
101
|
+
} else {
|
|
102
|
+
spinner.warn('初始化端点不存在,请手动调用');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 打印总结
|
|
106
|
+
printSummary(workspacePath, serverUrl, downloadUrl);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function runClean(options) {
|
|
110
|
+
const workspacePath = path.join(process.cwd(), options.workspace);
|
|
111
|
+
|
|
112
|
+
if (!await fs.pathExists(workspacePath)) {
|
|
113
|
+
console.log(chalk.yellow(`工作目录不存在: ${workspacePath}`));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const spinner = ora(`清理工作目录: ${workspacePath}`).start();
|
|
118
|
+
try {
|
|
119
|
+
await fs.remove(workspacePath);
|
|
120
|
+
spinner.succeed(`清理完成`);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
spinner.fail(`清理失败: ${error.message}`);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function runStatus(options) {
|
|
128
|
+
const workspacePath = path.join(process.cwd(), options.workspace);
|
|
129
|
+
const weiyuanPath = path.join(workspacePath, 'weiyuan');
|
|
130
|
+
const identityPath = path.join(workspacePath, DEFAULT_CONFIG.identityFile);
|
|
131
|
+
|
|
132
|
+
console.log(chalk.cyan('\n' + '='.repeat(60)));
|
|
133
|
+
console.log(chalk.cyan.bold(' Weiyuan Skill 状态'));
|
|
134
|
+
console.log(chalk.cyan('='.repeat(60) + '\n'));
|
|
135
|
+
|
|
136
|
+
// 检查工作目录
|
|
137
|
+
if (await fs.pathExists(workspacePath)) {
|
|
138
|
+
console.log(chalk.green(`✅ 工作目录: ${workspacePath}`));
|
|
139
|
+
} else {
|
|
140
|
+
console.log(chalk.red(`❌ 工作目录不存在: ${workspacePath}`));
|
|
141
|
+
console.log(chalk.gray(' 运行 "openclaw-weiyuan-init init" 创建'));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 检查 weiyuan 文件夹
|
|
146
|
+
if (await fs.pathExists(weiyuanPath)) {
|
|
147
|
+
const files = await fs.readdir(weiyuanPath);
|
|
148
|
+
console.log(chalk.green(`✅ weiyuan 文件夹: ${files.length} 项`));
|
|
149
|
+
} else {
|
|
150
|
+
console.log(chalk.red(`❌ weiyuan 文件夹不存在`));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 检查身份文件
|
|
154
|
+
if (await fs.pathExists(identityPath)) {
|
|
155
|
+
const identity = await fs.readJson(identityPath);
|
|
156
|
+
console.log(chalk.green(`✅ 身份文件: ${identity.device_id || '已配置'}`));
|
|
157
|
+
} else {
|
|
158
|
+
console.log(chalk.red(`❌ 身份文件不存在`));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 检查服务器
|
|
162
|
+
const serverOk = await checkServer(DEFAULT_CONFIG.serverUrl);
|
|
163
|
+
if (serverOk) {
|
|
164
|
+
console.log(chalk.green(`✅ 服务器: ${DEFAULT_CONFIG.serverUrl}`));
|
|
165
|
+
} else {
|
|
166
|
+
console.log(chalk.red(`❌ 服务器不可达: ${DEFAULT_CONFIG.serverUrl}`));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log('');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = { runInit, runClean, runStatus, DEFAULT_CONFIG };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
|
|
4
|
+
async function downloadFile(url, outputPath, spinner = null) {
|
|
5
|
+
try {
|
|
6
|
+
const response = await axios({
|
|
7
|
+
method: 'GET',
|
|
8
|
+
url: url,
|
|
9
|
+
responseType: 'stream',
|
|
10
|
+
timeout: 60000,
|
|
11
|
+
maxContentLength: Infinity,
|
|
12
|
+
maxBodyLength: Infinity
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const totalLength = parseInt(response.headers['content-length'], 10);
|
|
16
|
+
let downloadedLength = 0;
|
|
17
|
+
|
|
18
|
+
const writer = fs.createWriteStream(outputPath);
|
|
19
|
+
|
|
20
|
+
response.data.on('data', (chunk) => {
|
|
21
|
+
downloadedLength += chunk.length;
|
|
22
|
+
if (spinner && totalLength) {
|
|
23
|
+
const percent = (downloadedLength / totalLength * 100).toFixed(1);
|
|
24
|
+
spinner.text = `下载中... ${percent}% (${(downloadedLength / 1024 / 1024).toFixed(1)}MB / ${(totalLength / 1024 / 1024).toFixed(1)}MB)`;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
response.data.pipe(writer);
|
|
29
|
+
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
writer.on('finish', () => resolve(true));
|
|
32
|
+
writer.on('error', reject);
|
|
33
|
+
response.data.on('error', reject);
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (spinner) {
|
|
37
|
+
spinner.text = `下载失败: ${error.message}`;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { downloadFile };
|
package/lib/extractor.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const AdmZip = require('adm-zip');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
|
|
4
|
+
async function extractZip(zipPath, outputPath) {
|
|
5
|
+
try {
|
|
6
|
+
const zip = new AdmZip(zipPath);
|
|
7
|
+
zip.extractAllTo(outputPath, true);
|
|
8
|
+
return true;
|
|
9
|
+
} catch (error) {
|
|
10
|
+
// 尝试使用系统 unzip 命令作为备选
|
|
11
|
+
const { exec } = require('child_process');
|
|
12
|
+
const util = require('util');
|
|
13
|
+
const execPromise = util.promisify(exec);
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
await execPromise(`unzip -o "${zipPath}" -d "${outputPath}"`);
|
|
17
|
+
return true;
|
|
18
|
+
} catch (unzipError) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = { extractZip };
|
package/lib/identity.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
|
|
4
|
+
async function createIdentityFile(identityPath, serverUrl, workspacePath) {
|
|
5
|
+
try {
|
|
6
|
+
if (await fs.pathExists(identityPath)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const identity = {
|
|
11
|
+
version: "1.0",
|
|
12
|
+
device_id: os.hostname(),
|
|
13
|
+
device_name: os.hostname(),
|
|
14
|
+
created_at: new Date().toISOString(),
|
|
15
|
+
server_url: serverUrl,
|
|
16
|
+
workspace: workspacePath,
|
|
17
|
+
skill_path: `${workspacePath}/weiyuan`,
|
|
18
|
+
note: "请根据实际情况修改此文件"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
await fs.writeJson(identityPath, identity, { spaces: 2 });
|
|
22
|
+
return true;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function readIdentityFile(identityPath) {
|
|
29
|
+
try {
|
|
30
|
+
if (await fs.pathExists(identityPath)) {
|
|
31
|
+
return await fs.readJson(identityPath);
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = { createIdentityFile, readIdentityFile };
|
package/lib/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weiyuan/openclaw-weiyuan-init",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenClaw Weiyuan Skill 一键初始化工具 - 自动下载、解压、配置身份文件",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"openclaw-weiyuan-init": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/cli.js init",
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"openclaw",
|
|
15
|
+
"weiyuan",
|
|
16
|
+
"skill",
|
|
17
|
+
"init",
|
|
18
|
+
"cli",
|
|
19
|
+
"one-click",
|
|
20
|
+
"deploy"
|
|
21
|
+
],
|
|
22
|
+
"author": "Weiyuan",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/weiyuan/openclaw-weiyuan-init.git"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=14.0.0"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"axios": "^1.6.0",
|
|
33
|
+
"adm-zip": "^0.5.10",
|
|
34
|
+
"chalk": "^4.1.2",
|
|
35
|
+
"commander": "^11.1.0",
|
|
36
|
+
"fs-extra": "^11.1.1",
|
|
37
|
+
"ora": "^5.4.1"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"bin/",
|
|
44
|
+
"lib/",
|
|
45
|
+
"templates/",
|
|
46
|
+
"index.js",
|
|
47
|
+
"README.md"
|
|
48
|
+
]
|
|
49
|
+
}
|
package/lib/server.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
async function checkServer(serverUrl) {
|
|
4
|
+
try {
|
|
5
|
+
await axios.get(serverUrl, { timeout: 5000 });
|
|
6
|
+
return true;
|
|
7
|
+
} catch (error) {
|
|
8
|
+
if (error.response && error.response.status === 404) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function initSkill(serverUrl, identityPath, workspacePath) {
|
|
16
|
+
try {
|
|
17
|
+
const response = await axios.post(`${serverUrl}/skill/init`, {
|
|
18
|
+
action: "init",
|
|
19
|
+
server: serverUrl,
|
|
20
|
+
identity_path: identityPath,
|
|
21
|
+
workspace: workspacePath
|
|
22
|
+
}, {
|
|
23
|
+
timeout: 10000,
|
|
24
|
+
validateStatus: (status) => status < 500
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return response.status === 200;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = { checkServer, initSkill };
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
function printBanner() {
|
|
6
|
+
console.log(chalk.cyan('\n' + '='.repeat(60)));
|
|
7
|
+
console.log(chalk.cyan.bold(' OpenClaw Weiyuan Skill 一键初始化'));
|
|
8
|
+
console.log(chalk.cyan('='.repeat(60) + '\n'));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function printSummary(workspacePath, serverUrl, downloadUrl) {
|
|
12
|
+
console.log(chalk.green('\n' + '='.repeat(60)));
|
|
13
|
+
console.log(chalk.green.bold('✅ 初始化完成!'));
|
|
14
|
+
console.log(chalk.white(`\n📁 工作目录: ${workspacePath}`));
|
|
15
|
+
console.log(chalk.white(` ├── weiyuan/ (解压后的文件)`));
|
|
16
|
+
console.log(chalk.white(` └── .weiyuan (身份配置文件)`));
|
|
17
|
+
console.log(chalk.white(`\n🌐 服务器地址: ${serverUrl}`));
|
|
18
|
+
console.log(chalk.white(`📥 下载源: ${downloadUrl}`));
|
|
19
|
+
console.log(chalk.cyan('\n使用说明:'));
|
|
20
|
+
console.log(chalk.gray(' 1. 如需修改身份配置,请编辑 .weiyuan 文件'));
|
|
21
|
+
console.log(chalk.gray(' 2. weiyuan skill 文件位于 weiyuan/ 目录下'));
|
|
22
|
+
console.log(chalk.gray(' 3. 可运行 weiyuan/ 中的启动脚本'));
|
|
23
|
+
console.log(chalk.green('='.repeat(60) + '\n'));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function listDirectory(dirPath, maxItems = 20) {
|
|
27
|
+
try {
|
|
28
|
+
const items = await fs.readdir(dirPath);
|
|
29
|
+
const displayItems = items.slice(0, maxItems);
|
|
30
|
+
|
|
31
|
+
for (const item of displayItems) {
|
|
32
|
+
const itemPath = path.join(dirPath, item);
|
|
33
|
+
const stat = await fs.stat(itemPath);
|
|
34
|
+
if (stat.isDirectory()) {
|
|
35
|
+
console.log(chalk.gray(` 📁 ${item}/`));
|
|
36
|
+
} else {
|
|
37
|
+
const size = (stat.size / 1024).toFixed(1);
|
|
38
|
+
console.log(chalk.gray(` 📄 ${item} (${size} KB)`));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (items.length > maxItems) {
|
|
43
|
+
console.log(chalk.gray(` ... 共 ${items.length} 项`));
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.log(chalk.gray(` (无法列出目录内容)`));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = { printBanner, printSummary, listDirectory };
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-weiyuan-init",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenClaw Weiyuan Skill 一键初始化工具",
|
|
5
|
+
"main": "bin/cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"openclaw-weiyuan-init": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/cli.js init",
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": ["openclaw", "weiyuan", "skill", "init", "cli"],
|
|
14
|
+
"author": "weiyuan",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"axios": "^1.6.0",
|
|
18
|
+
"adm-zip": "^0.5.10",
|
|
19
|
+
"chalk": "^4.1.2",
|
|
20
|
+
"commander": "^11.1.0",
|
|
21
|
+
"fs-extra": "^11.1.1",
|
|
22
|
+
"ora": "^5.4.1"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=14.0.0"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"device_id": "ZHAOTY",
|
|
4
|
+
"device_name": "ZHAOTY",
|
|
5
|
+
"created_at": "2026-03-28T14:27:13.667Z",
|
|
6
|
+
"server_url": "http://121.43.119.190:8787",
|
|
7
|
+
"workspace": "C:\\pythonProject1\\openclaw-weiyuan-init\\workspace-weiyuan",
|
|
8
|
+
"skill_path": "C:\\pythonProject1\\openclaw-weiyuan-init\\workspace-weiyuan/weiyuan",
|
|
9
|
+
"note": "请根据实际情况修改此文件"
|
|
10
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# 龙虾端 weiyuan CLI(MVP)
|
|
2
|
+
|
|
3
|
+
本目录提供一个最小可用的龙虾端 CLI,用于与微元云服务进行签名通信(Ed25519)。
|
|
4
|
+
|
|
5
|
+
## 快速开始
|
|
6
|
+
|
|
7
|
+
前置:微元云服务已启动(默认 `http://127.0.0.1:8787`)。
|
|
8
|
+
|
|
9
|
+
初始化身份(生成本地 `.weiyuan`):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm run weiyuan -- init --server http://127.0.0.1:8787 --out .weiyuan
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
创建项目(DNA 原文在本地输入,云端只存 dnaHash):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run weiyuan -- create --name "Demo" --goal "MVP" --dna "稳当第一"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
生成邀请口令(发起人执行):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run weiyuan -- invite --project <projectId> --role member
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
加入项目(成员执行):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run weiyuan -- join --project <projectId> --code <inviteCode>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
成员列表:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm run weiyuan -- member list --project <projectId>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
任务流转:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run weiyuan -- task create --project <projectId> --title "工具清点" --desc "检查工具"
|
|
43
|
+
npm run weiyuan -- task list --project <projectId>
|
|
44
|
+
npm run weiyuan -- task take --project <projectId> --task <taskId>
|
|
45
|
+
npm run weiyuan -- task submit --project <projectId> --task <taskId> --hash <contentHash> --type text/markdown
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
状态体检与事件同步:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm run weiyuan -- status --project <projectId>
|
|
52
|
+
npm run weiyuan -- sync --project <projectId>
|
|
53
|
+
npm run weiyuan -- sync --project <projectId> --follow --interval 2000
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
风险上报与查询:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm run weiyuan -- risk report --project <projectId> --severity warn --summary "3号库信号不稳"
|
|
60
|
+
npm run weiyuan -- risk list --project <projectId>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
进化胶囊:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run weiyuan -- capsule publish --name "Skill_Pump_Repair_V1" --kind industry --file ./capsule.bin --version v1 --dnaTags 维修,稳当第一
|
|
67
|
+
npm run weiyuan -- capsule search --query 维修
|
|
68
|
+
npm run weiyuan -- capsule pull --id <capsuleId> --out ./downloaded-capsule.bin
|
|
69
|
+
npm run weiyuan -- capsule report --id <capsuleId> --success true
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 身份文件
|
|
73
|
+
|
|
74
|
+
默认身份文件:当前目录的 `.weiyuan`(JSON)。
|
|
75
|
+
|
|
76
|
+
## 说明
|
|
77
|
+
|
|
78
|
+
- 这是 MVP 级 CLI:聚焦可跑通闭环与协议对齐;后续可升级为 OpenClaw skill 形态。
|
|
79
|
+
- 协议与鉴权细则见:[server/PROTOCOL.md](file:///c:/Users/10123/Documents/trae_projects/sky/server/PROTOCOL.md)
|
|
80
|
+
|
|
81
|
+
## OpenClaw Skill 适配入口(MVP)
|
|
82
|
+
|
|
83
|
+
适配器命令:`npm run weiyuan:skill`
|
|
84
|
+
|
|
85
|
+
输入为 JSON(stdin),支持两种模式:
|
|
86
|
+
|
|
87
|
+
1) `action` 模式(结构化)
|
|
88
|
+
2) `text` 模式(口语意图映射)
|
|
89
|
+
|
|
90
|
+
输入/输出 schema 见:`client/skill/schema.json`
|
|
91
|
+
|
|
92
|
+
示例(action):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
'{"action":"task.list","identity":".weiyuan.dev2","projectId":"prj_xxx"}' | npm run weiyuan:skill
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
示例(text):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
'{"text":"我能做什么","identity":".weiyuan.dev2","projectId":"prj_xxx"}' | npm run weiyuan:skill
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
输出格式:
|
|
105
|
+
|
|
106
|
+
- 成功:`{"ok": true, "data": ...}`
|
|
107
|
+
- 失败:`{"ok": false, "errorCode": "...", "message": "...", "rawError": "..."}`
|
|
108
|
+
|
|
109
|
+
## 生成 Skill 包
|
|
110
|
+
|
|
111
|
+
构建命令:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm run weiyuan:skill:build
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
输出目录:`dist/skill-package`
|
|
118
|
+
|
|
119
|
+
该目录包含:
|
|
120
|
+
|
|
121
|
+
- `manifest.json`
|
|
122
|
+
- `schema.json`
|
|
123
|
+
- `examples/*.json`
|
|
124
|
+
- 适配器与 CLI 源码(用于 OpenClaw 侧加载或二次封装)
|
|
125
|
+
|
|
126
|
+
## 版本与发布
|
|
127
|
+
|
|
128
|
+
版本递增(patch/minor/major):
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run weiyuan:skill:version -- patch
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
发布前校验门(manifest/schema/examples/adapter 契约):
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npm run weiyuan:skill:validate
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
一键发布(构建 + zip + 发布说明):
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm run weiyuan:skill:release
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
说明:`weiyuan:skill:release` 会先执行校验门,未通过则阻断发布。
|
|
147
|
+
|
|
148
|
+
发布产物:
|
|
149
|
+
|
|
150
|
+
- `dist/releases/weiyuan-openclaw-skill-v<version>.zip`
|
|
151
|
+
- `dist/releases/RELEASE_NOTES_<version>.md`
|
|
152
|
+
|
|
153
|
+
## CI 工作流
|
|
154
|
+
|
|
155
|
+
- `skill-ci`:push/PR 自动执行 `weiyuan:skill:validate` 与 `weiyuan:skill:build`
|
|
156
|
+
- `skill-release`:手动触发,支持 patch/minor/major 递增后自动执行:
|
|
157
|
+
- 版本递增并提交 `manifest.json`
|
|
158
|
+
- 创建并推送 git tag(`v<version>`)
|
|
159
|
+
- 生成 GitHub Release 并上传 zip/release notes
|