openclaw-weiyuan-init 1.0.5 → 1.0.9
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 +4 -4
- package/bin/cli.js +7 -7
- package/lib/commands.js +66 -66
- package/lib/downloader.js +31 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ OpenClaw Weiyuan Skill 一键初始化工具
|
|
|
5
5
|
## 一键部署
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx -y
|
|
8
|
+
npx -y openclaw-weiyuan-init@latest init
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## 版本化 zip 自动识别
|
|
@@ -17,13 +17,13 @@ npx -y @weiyuan/openclaw-weiyuan-init@latest init
|
|
|
17
17
|
## 常用参数
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npx -y
|
|
20
|
+
npx -y openclaw-weiyuan-init@latest init --upgrade <upgradeBaseUrl> --server <serverUrl>
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
邀请码一键入组(推荐):
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npx -y
|
|
26
|
+
npx -y openclaw-weiyuan-init@latest init --invite <inviteToken>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
`inviteToken` 包含 `server/upgrade/project/code`,会自动完成安装与入组。
|
|
@@ -31,5 +31,5 @@ npx -y @weiyuan/openclaw-weiyuan-init@latest init --invite <inviteToken>
|
|
|
31
31
|
如需指定固定 zip,可覆盖自动识别:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
npx -y
|
|
34
|
+
npx -y openclaw-weiyuan-init@latest init --download <zipUrl> --server <serverUrl>
|
|
35
35
|
```
|
package/bin/cli.js
CHANGED
|
@@ -14,11 +14,11 @@ program
|
|
|
14
14
|
.description('初始化 weiyuan skill')
|
|
15
15
|
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
16
16
|
.option('-s, --server <url>', '指定服务器地址', 'http://121.43.119.190:8787')
|
|
17
|
-
.option('-u, --upgrade <url>', '指定升级源地址(含 LATEST_SKILL_VERSION.txt)', 'http://121.43.119.190
|
|
18
|
-
.option('-d, --download <url>', '指定下载地址(可覆盖自动版本解析)')
|
|
19
|
-
.option('-i, --invite <token>', '邀请码令牌(包含 server/upgrade/project/code)')
|
|
20
|
-
.option('-p, --project <id>', '邀请加入的项目 ID')
|
|
21
|
-
.option('-c, --code <code>', '邀请口令')
|
|
17
|
+
.option('-u, --upgrade <url>', '指定升级源地址(含 LATEST_SKILL_VERSION.txt)', 'http://121.43.119.190/upgrade')
|
|
18
|
+
.option('-d, --download <url>', '指定下载地址(可覆盖自动版本解析)')
|
|
19
|
+
.option('-i, --invite <token>', '邀请码令牌(包含 server/upgrade/project/code)')
|
|
20
|
+
.option('-p, --project <id>', '邀请加入的项目 ID')
|
|
21
|
+
.option('-c, --code <code>', '邀请口令')
|
|
22
22
|
.option('-f, --force', '强制覆盖已有文件')
|
|
23
23
|
.action(async (options) => {
|
|
24
24
|
try {
|
|
@@ -46,7 +46,7 @@ program
|
|
|
46
46
|
.command('status')
|
|
47
47
|
.description('查看 weiyuan 状态')
|
|
48
48
|
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
49
|
-
.option('-s, --server <url>', '指定服务器地址', 'http://121.43.119.190:8787')
|
|
49
|
+
.option('-s, --server <url>', '指定服务器地址', 'http://121.43.119.190:8787')
|
|
50
50
|
.action(async (options) => {
|
|
51
51
|
try {
|
|
52
52
|
await runStatus(options);
|
|
@@ -56,4 +56,4 @@ program
|
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
program.parse();
|
|
59
|
+
program.parse();
|
package/lib/commands.js
CHANGED
|
@@ -2,59 +2,59 @@ const chalk = require('chalk');
|
|
|
2
2
|
const ora = require('ora');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs-extra');
|
|
5
|
-
const { execFile } = require('child_process');
|
|
6
|
-
const { promisify } = require('util');
|
|
7
|
-
const { downloadFile, resolvePackageSource } = require('./downloader');
|
|
5
|
+
const { execFile } = require('child_process');
|
|
6
|
+
const { promisify } = require('util');
|
|
7
|
+
const { downloadFile, resolvePackageSource } = require('./downloader');
|
|
8
8
|
const { extractZip } = require('./extractor');
|
|
9
9
|
const { createIdentityFile } = require('./identity');
|
|
10
10
|
const { checkServer, initSkill } = require('./server');
|
|
11
11
|
const { printBanner, printSummary, listDirectory } = require('./utils');
|
|
12
|
-
const execFileAsync = promisify(execFile);
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
13
|
|
|
14
14
|
const DEFAULT_CONFIG = {
|
|
15
15
|
workspaceName: 'workspace-weiyuan',
|
|
16
|
-
upgradeBaseUrl: 'http://121.43.119.190
|
|
17
|
-
downloadUrl: '',
|
|
16
|
+
upgradeBaseUrl: 'http://121.43.119.190/upgrade',
|
|
17
|
+
downloadUrl: '',
|
|
18
18
|
serverUrl: 'http://121.43.119.190:8787',
|
|
19
19
|
identityFile: '.weiyuan'
|
|
20
20
|
};
|
|
21
|
-
|
|
22
|
-
function decodeInviteToken(token) {
|
|
23
|
-
if (!token || typeof token !== 'string') return null;
|
|
24
|
-
try {
|
|
25
|
-
const normalized = token.replace(/-/g, '+').replace(/_/g, '/');
|
|
26
|
-
const pad = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));
|
|
27
|
-
const raw = Buffer.from(normalized + pad, 'base64').toString('utf8');
|
|
28
|
-
const parsed = JSON.parse(raw);
|
|
29
|
-
if (!parsed || parsed.v !== 1) return null;
|
|
30
|
-
if (!parsed.api || !parsed.upgrade || !parsed.projectId || !parsed.code) return null;
|
|
31
|
-
return parsed;
|
|
32
|
-
} catch (_) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function runJoin(weiyuanPath, identityPath, projectId, code) {
|
|
38
|
-
await execFileAsync('npm', ['--prefix', weiyuanPath, 'run', 'weiyuan', '--', 'join', '--identity', identityPath, '--project', projectId, '--code', code], {
|
|
39
|
-
cwd: weiyuanPath
|
|
40
|
-
});
|
|
41
|
-
}
|
|
21
|
+
|
|
22
|
+
function decodeInviteToken(token) {
|
|
23
|
+
if (!token || typeof token !== 'string') return null;
|
|
24
|
+
try {
|
|
25
|
+
const normalized = token.replace(/-/g, '+').replace(/_/g, '/');
|
|
26
|
+
const pad = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));
|
|
27
|
+
const raw = Buffer.from(normalized + pad, 'base64').toString('utf8');
|
|
28
|
+
const parsed = JSON.parse(raw);
|
|
29
|
+
if (!parsed || parsed.v !== 1) return null;
|
|
30
|
+
if (!parsed.api || !parsed.upgrade || !parsed.projectId || !parsed.code) return null;
|
|
31
|
+
return parsed;
|
|
32
|
+
} catch (_) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function runJoin(weiyuanPath, identityPath, projectId, code) {
|
|
38
|
+
await execFileAsync('npm', ['--prefix', weiyuanPath, 'run', 'weiyuan', '--', 'join', '--identity', identityPath, '--project', projectId, '--code', code], {
|
|
39
|
+
cwd: weiyuanPath
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
42
|
|
|
43
43
|
async function runInit(options) {
|
|
44
44
|
printBanner();
|
|
45
|
-
|
|
46
|
-
const invite = decodeInviteToken(options.invite);
|
|
47
|
-
if (invite) {
|
|
48
|
-
options.server = options.server || invite.api;
|
|
49
|
-
options.upgrade = options.upgrade || invite.upgrade;
|
|
50
|
-
options.project = options.project || invite.projectId;
|
|
51
|
-
options.code = options.code || invite.code;
|
|
52
|
-
}
|
|
45
|
+
|
|
46
|
+
const invite = decodeInviteToken(options.invite);
|
|
47
|
+
if (invite) {
|
|
48
|
+
options.server = options.server || invite.api;
|
|
49
|
+
options.upgrade = options.upgrade || invite.upgrade;
|
|
50
|
+
options.project = options.project || invite.projectId;
|
|
51
|
+
options.code = options.code || invite.code;
|
|
52
|
+
}
|
|
53
53
|
|
|
54
54
|
const workspacePath = path.join(process.cwd(), options.workspace);
|
|
55
55
|
const weiyuanPath = path.join(workspacePath, 'weiyuan');
|
|
56
|
-
const upgradeBaseUrl = options.upgrade || DEFAULT_CONFIG.upgradeBaseUrl;
|
|
57
|
-
const requestedDownloadUrl = options.download || DEFAULT_CONFIG.downloadUrl;
|
|
56
|
+
const upgradeBaseUrl = options.upgrade || DEFAULT_CONFIG.upgradeBaseUrl;
|
|
57
|
+
const requestedDownloadUrl = options.download || DEFAULT_CONFIG.downloadUrl;
|
|
58
58
|
const serverUrl = options.server || DEFAULT_CONFIG.serverUrl;
|
|
59
59
|
const force = options.force || false;
|
|
60
60
|
|
|
@@ -85,22 +85,22 @@ async function runInit(options) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// 3. 下载文件
|
|
88
|
-
spinner = ora('解析下载包...').start();
|
|
89
|
-
const source = await resolvePackageSource({
|
|
90
|
-
downloadUrl: requestedDownloadUrl,
|
|
91
|
-
upgradeBaseUrl,
|
|
92
|
-
spinner
|
|
93
|
-
});
|
|
94
|
-
spinner.succeed(`下载源: ${source.downloadUrl}`);
|
|
95
|
-
|
|
96
|
-
spinner = ora('下载 weiyuan skill...').start();
|
|
97
|
-
const zipPath = path.join(weiyuanPath, source.zipFilename);
|
|
98
|
-
const downloadSuccess = await downloadFile(source.downloadUrl, zipPath, spinner);
|
|
88
|
+
spinner = ora('解析下载包...').start();
|
|
89
|
+
const source = await resolvePackageSource({
|
|
90
|
+
downloadUrl: requestedDownloadUrl,
|
|
91
|
+
upgradeBaseUrl,
|
|
92
|
+
spinner
|
|
93
|
+
});
|
|
94
|
+
spinner.succeed(`下载源: ${source.downloadUrl}`);
|
|
95
|
+
|
|
96
|
+
spinner = ora('下载 weiyuan skill...').start();
|
|
97
|
+
const zipPath = path.join(weiyuanPath, source.zipFilename);
|
|
98
|
+
const downloadSuccess = await downloadFile(source.downloadUrl, zipPath, spinner);
|
|
99
99
|
if (!downloadSuccess) {
|
|
100
100
|
spinner.fail('下载失败');
|
|
101
101
|
throw new Error('下载失败');
|
|
102
102
|
}
|
|
103
|
-
spinner.succeed(`下载完成: ${source.zipFilename}`);
|
|
103
|
+
spinner.succeed(`下载完成: ${source.zipFilename}`);
|
|
104
104
|
|
|
105
105
|
// 4. 解压
|
|
106
106
|
spinner = ora('解压文件...').start();
|
|
@@ -142,20 +142,20 @@ async function runInit(options) {
|
|
|
142
142
|
} else {
|
|
143
143
|
spinner.warn('初始化端点不存在,请手动调用');
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
if (options.project && options.code) {
|
|
147
|
-
spinner = ora('自动加入微元项目...').start();
|
|
148
|
-
try {
|
|
149
|
-
await runJoin(weiyuanPath, identityPath, options.project, options.code);
|
|
150
|
-
spinner.succeed(`已加入项目: ${options.project}`);
|
|
151
|
-
} catch (error) {
|
|
152
|
-
spinner.fail(`自动入组失败: ${error.message}`);
|
|
153
|
-
throw error;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
145
|
+
|
|
146
|
+
if (options.project && options.code) {
|
|
147
|
+
spinner = ora('自动加入微元项目...').start();
|
|
148
|
+
try {
|
|
149
|
+
await runJoin(weiyuanPath, identityPath, options.project, options.code);
|
|
150
|
+
spinner.succeed(`已加入项目: ${options.project}`);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
spinner.fail(`自动入组失败: ${error.message}`);
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
156
|
|
|
157
157
|
// 打印总结
|
|
158
|
-
printSummary(workspacePath, serverUrl, source.downloadUrl);
|
|
158
|
+
printSummary(workspacePath, serverUrl, source.downloadUrl);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
async function runClean(options) {
|
|
@@ -211,15 +211,15 @@ async function runStatus(options) {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
// 检查服务器
|
|
214
|
-
const serverUrl = options.server || DEFAULT_CONFIG.serverUrl;
|
|
215
|
-
const serverOk = await checkServer(serverUrl);
|
|
214
|
+
const serverUrl = options.server || DEFAULT_CONFIG.serverUrl;
|
|
215
|
+
const serverOk = await checkServer(serverUrl);
|
|
216
216
|
if (serverOk) {
|
|
217
|
-
console.log(chalk.green(`✅ 服务器: ${serverUrl}`));
|
|
217
|
+
console.log(chalk.green(`✅ 服务器: ${serverUrl}`));
|
|
218
218
|
} else {
|
|
219
|
-
console.log(chalk.red(`❌ 服务器不可达: ${serverUrl}`));
|
|
219
|
+
console.log(chalk.red(`❌ 服务器不可达: ${serverUrl}`));
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
console.log('');
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
module.exports = { runInit, runClean, runStatus, DEFAULT_CONFIG };
|
|
225
|
+
module.exports = { runInit, runClean, runStatus, DEFAULT_CONFIG };
|
package/lib/downloader.js
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
const fs = require('fs-extra');
|
|
3
3
|
|
|
4
|
-
function trimSlash(url) {
|
|
5
|
-
return String(url || '').replace(/\/+$/, '');
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function toZipFilename(downloadUrl) {
|
|
9
|
-
const clean = String(downloadUrl || '').split('?')[0].split('#')[0];
|
|
10
|
-
const parts = clean.split('/');
|
|
11
|
-
return parts[parts.length - 1] || 'weiyuan-openclaw-skill.zip';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function resolvePackageSource({ downloadUrl, upgradeBaseUrl, spinner = null }) {
|
|
15
|
-
if (downloadUrl) {
|
|
16
|
-
return { downloadUrl, zipFilename: toZipFilename(downloadUrl), version: null, from: 'download_url' };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const base = trimSlash(upgradeBaseUrl);
|
|
20
|
-
const latestUrl = `${base}/LATEST_SKILL_VERSION.txt`;
|
|
21
|
-
const latestResp = await axios.get(latestUrl, { timeout: 10000 });
|
|
22
|
-
const version = String(latestResp.data || '').trim();
|
|
23
|
-
if (!version) {
|
|
24
|
-
throw new Error('empty_latest_version');
|
|
25
|
-
}
|
|
26
|
-
const zipFilename = `weiyuan-openclaw-skill-v${version}.zip`;
|
|
27
|
-
const resolvedDownloadUrl = `${base}/${zipFilename}`;
|
|
28
|
-
if (spinner) {
|
|
29
|
-
spinner.text = `已解析最新版本: v${version}`;
|
|
30
|
-
}
|
|
31
|
-
return { downloadUrl: resolvedDownloadUrl, zipFilename, version, from: 'latest_version' };
|
|
32
|
-
}
|
|
33
|
-
|
|
4
|
+
function trimSlash(url) {
|
|
5
|
+
return String(url || '').replace(/\/+$/, '');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function toZipFilename(downloadUrl) {
|
|
9
|
+
const clean = String(downloadUrl || '').split('?')[0].split('#')[0];
|
|
10
|
+
const parts = clean.split('/');
|
|
11
|
+
return parts[parts.length - 1] || 'weiyuan-openclaw-skill.zip';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function resolvePackageSource({ downloadUrl, upgradeBaseUrl, spinner = null }) {
|
|
15
|
+
if (downloadUrl) {
|
|
16
|
+
return { downloadUrl, zipFilename: toZipFilename(downloadUrl), version: null, from: 'download_url' };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const base = trimSlash(upgradeBaseUrl);
|
|
20
|
+
const latestUrl = `${base}/LATEST_SKILL_VERSION.txt`;
|
|
21
|
+
const latestResp = await axios.get(latestUrl, { timeout: 10000 });
|
|
22
|
+
const version = String(latestResp.data || '').trim();
|
|
23
|
+
if (!version) {
|
|
24
|
+
throw new Error('empty_latest_version');
|
|
25
|
+
}
|
|
26
|
+
const zipFilename = `weiyuan-openclaw-skill-v${version}.zip`;
|
|
27
|
+
const resolvedDownloadUrl = `${base}/${zipFilename}`;
|
|
28
|
+
if (spinner) {
|
|
29
|
+
spinner.text = `已解析最新版本: v${version}`;
|
|
30
|
+
}
|
|
31
|
+
return { downloadUrl: resolvedDownloadUrl, zipFilename, version, from: 'latest_version' };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
34
|
async function downloadFile(url, outputPath, spinner = null) {
|
|
35
35
|
try {
|
|
36
36
|
const response = await axios({
|
|
@@ -70,4 +70,4 @@ async function downloadFile(url, outputPath, spinner = null) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
module.exports = { downloadFile, resolvePackageSource };
|
|
73
|
+
module.exports = { downloadFile, resolvePackageSource };
|