openclaw-weiyuan-init 1.0.41 → 1.0.54
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/bin/cli.js +59 -59
- package/lib/commands.js +317 -316
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
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>', '指定服务器地址', 'https://api.magon.com.cn/api')
|
|
17
|
-
.option('-u, --upgrade <url>', '指定升级源地址(含 LATEST_SKILL_VERSION.txt)', 'https://api.magon.com.cn/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
|
-
.option('-f, --force', '强制覆盖已有文件')
|
|
23
|
-
.action(async (options) => {
|
|
24
|
-
try {
|
|
25
|
-
await runInit(options);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error(chalk.red(`初始化失败: ${error.message}`));
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
program
|
|
33
|
-
.command('clean')
|
|
34
|
-
.description('清理 weiyuan 工作目录')
|
|
35
|
-
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
36
|
-
.action(async (options) => {
|
|
37
|
-
try {
|
|
38
|
-
await runClean(options);
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error(chalk.red(`清理失败: ${error.message}`));
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
program
|
|
46
|
-
.command('status')
|
|
47
|
-
.description('查看 weiyuan 状态')
|
|
48
|
-
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
49
|
-
.option('-s, --server <url>', '指定服务器地址', 'https://api.magon.com.cn/api')
|
|
50
|
-
.action(async (options) => {
|
|
51
|
-
try {
|
|
52
|
-
await runStatus(options);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error(chalk.red(`查询失败: ${error.message}`));
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
program.parse();
|
|
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>', '指定服务器地址', 'https://api.magon.com.cn/api')
|
|
17
|
+
.option('-u, --upgrade <url>', '指定升级源地址(含 LATEST_SKILL_VERSION.txt)', 'https://api.magon.com.cn/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
|
+
.option('-f, --force', '强制覆盖已有文件')
|
|
23
|
+
.action(async (options) => {
|
|
24
|
+
try {
|
|
25
|
+
await runInit(options);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(chalk.red(`初始化失败: ${error.message}`));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command('clean')
|
|
34
|
+
.description('清理 weiyuan 工作目录')
|
|
35
|
+
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
36
|
+
.action(async (options) => {
|
|
37
|
+
try {
|
|
38
|
+
await runClean(options);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(chalk.red(`清理失败: ${error.message}`));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.command('status')
|
|
47
|
+
.description('查看 weiyuan 状态')
|
|
48
|
+
.option('-w, --workspace <path>', '指定工作目录', 'workspace-weiyuan')
|
|
49
|
+
.option('-s, --server <url>', '指定服务器地址', 'https://api.magon.com.cn/api')
|
|
50
|
+
.action(async (options) => {
|
|
51
|
+
try {
|
|
52
|
+
await runStatus(options);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error(chalk.red(`查询失败: ${error.message}`));
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
program.parse();
|
package/lib/commands.js
CHANGED
|
@@ -1,316 +1,317 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const ora = require('ora');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs-extra');
|
|
5
|
-
const { execFile } = require('child_process');
|
|
6
|
-
const { promisify } = require('util');
|
|
7
|
-
const { downloadFile, resolvePackageSource } = require('./downloader');
|
|
8
|
-
const { extractZip } = require('./extractor');
|
|
9
|
-
const { createIdentityFile } = require('./identity');
|
|
10
|
-
const { checkServer, initSkill } = require('./server');
|
|
11
|
-
const { printBanner, printSummary, listDirectory } = require('./utils');
|
|
12
|
-
const execFileAsync = promisify(execFile);
|
|
13
|
-
|
|
14
|
-
const DEFAULT_CONFIG = {
|
|
15
|
-
workspaceName: 'workspace-weiyuan',
|
|
16
|
-
upgradeBaseUrl: 'https://api.magon.com.cn/upgrade',
|
|
17
|
-
downloadUrl: '',
|
|
18
|
-
serverUrl: 'https://api.magon.com.cn/api',
|
|
19
|
-
identityFile: '.weiyuan'
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const DEFAULT_SKILL_PACKAGE_JSON = {
|
|
23
|
-
name: 'weiyuan-skill-runtime',
|
|
24
|
-
private: true,
|
|
25
|
-
version: '0.0.0',
|
|
26
|
-
type: 'module',
|
|
27
|
-
scripts: {
|
|
28
|
-
weiyuan: 'tsx src/cliMain.ts',
|
|
29
|
-
'weiyuan:skill': 'tsx src/skillAdapter.ts'
|
|
30
|
-
},
|
|
31
|
-
dependencies: {
|
|
32
|
-
tweetnacl: '^1.0.3'
|
|
33
|
-
},
|
|
34
|
-
devDependencies: {
|
|
35
|
-
tsx: '^4.20.6',
|
|
36
|
-
typescript: '^5.9.3',
|
|
37
|
-
'@types/node': '^24.12.0'
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const DEFAULT_SKILL_TSCONFIG = {
|
|
42
|
-
compilerOptions: {
|
|
43
|
-
target: 'ES2022',
|
|
44
|
-
module: 'NodeNext',
|
|
45
|
-
moduleResolution: 'NodeNext',
|
|
46
|
-
strict: true,
|
|
47
|
-
esModuleInterop: true,
|
|
48
|
-
resolveJsonModule: true,
|
|
49
|
-
skipLibCheck: true
|
|
50
|
-
},
|
|
51
|
-
include: ['src']
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
function resolveWorkspacePath(workspaceOption) {
|
|
55
|
-
const raw = (workspaceOption || DEFAULT_CONFIG.workspaceName).trim();
|
|
56
|
-
const target = path.isAbsolute(raw) ? raw : path.join(process.cwd(), raw);
|
|
57
|
-
if (path.basename(target).toLowerCase() === DEFAULT_CONFIG.workspaceName.toLowerCase()) {
|
|
58
|
-
return target;
|
|
59
|
-
}
|
|
60
|
-
return path.join(target, DEFAULT_CONFIG.workspaceName);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function decodeInviteToken(token) {
|
|
64
|
-
if (!token || typeof token !== 'string') return null;
|
|
65
|
-
try {
|
|
66
|
-
const normalized = token.replace(/-/g, '+').replace(/_/g, '/');
|
|
67
|
-
const pad = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));
|
|
68
|
-
const raw = Buffer.from(normalized + pad, 'base64').toString('utf8');
|
|
69
|
-
const parsed = JSON.parse(raw);
|
|
70
|
-
if (!parsed || parsed.v !== 1) return null;
|
|
71
|
-
if (!parsed.api || !parsed.upgrade || !parsed.projectId || !parsed.code) return null;
|
|
72
|
-
return parsed;
|
|
73
|
-
} catch (_) {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function runJoin(weiyuanPath, identityPath, projectId, code) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
options.
|
|
124
|
-
options.
|
|
125
|
-
options.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
console.log(chalk.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
console.log(chalk.cyan
|
|
276
|
-
console.log(chalk.cyan('
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
console.log(chalk.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const ora = require('ora');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const { execFile } = require('child_process');
|
|
6
|
+
const { promisify } = require('util');
|
|
7
|
+
const { downloadFile, resolvePackageSource } = require('./downloader');
|
|
8
|
+
const { extractZip } = require('./extractor');
|
|
9
|
+
const { createIdentityFile } = require('./identity');
|
|
10
|
+
const { checkServer, initSkill } = require('./server');
|
|
11
|
+
const { printBanner, printSummary, listDirectory } = require('./utils');
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
|
|
14
|
+
const DEFAULT_CONFIG = {
|
|
15
|
+
workspaceName: 'workspace-weiyuan',
|
|
16
|
+
upgradeBaseUrl: 'https://api.magon.com.cn/upgrade',
|
|
17
|
+
downloadUrl: '',
|
|
18
|
+
serverUrl: 'https://api.magon.com.cn/api',
|
|
19
|
+
identityFile: '.weiyuan'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const DEFAULT_SKILL_PACKAGE_JSON = {
|
|
23
|
+
name: 'weiyuan-skill-runtime',
|
|
24
|
+
private: true,
|
|
25
|
+
version: '0.0.0',
|
|
26
|
+
type: 'module',
|
|
27
|
+
scripts: {
|
|
28
|
+
weiyuan: 'tsx src/cliMain.ts',
|
|
29
|
+
'weiyuan:skill': 'tsx src/skillAdapter.ts'
|
|
30
|
+
},
|
|
31
|
+
dependencies: {
|
|
32
|
+
tweetnacl: '^1.0.3'
|
|
33
|
+
},
|
|
34
|
+
devDependencies: {
|
|
35
|
+
tsx: '^4.20.6',
|
|
36
|
+
typescript: '^5.9.3',
|
|
37
|
+
'@types/node': '^24.12.0'
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const DEFAULT_SKILL_TSCONFIG = {
|
|
42
|
+
compilerOptions: {
|
|
43
|
+
target: 'ES2022',
|
|
44
|
+
module: 'NodeNext',
|
|
45
|
+
moduleResolution: 'NodeNext',
|
|
46
|
+
strict: true,
|
|
47
|
+
esModuleInterop: true,
|
|
48
|
+
resolveJsonModule: true,
|
|
49
|
+
skipLibCheck: true
|
|
50
|
+
},
|
|
51
|
+
include: ['src']
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function resolveWorkspacePath(workspaceOption) {
|
|
55
|
+
const raw = (workspaceOption || DEFAULT_CONFIG.workspaceName).trim();
|
|
56
|
+
const target = path.isAbsolute(raw) ? raw : path.join(process.cwd(), raw);
|
|
57
|
+
if (path.basename(target).toLowerCase() === DEFAULT_CONFIG.workspaceName.toLowerCase()) {
|
|
58
|
+
return target;
|
|
59
|
+
}
|
|
60
|
+
return path.join(target, DEFAULT_CONFIG.workspaceName);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function decodeInviteToken(token) {
|
|
64
|
+
if (!token || typeof token !== 'string') return null;
|
|
65
|
+
try {
|
|
66
|
+
const normalized = token.replace(/-/g, '+').replace(/_/g, '/');
|
|
67
|
+
const pad = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));
|
|
68
|
+
const raw = Buffer.from(normalized + pad, 'base64').toString('utf8');
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
if (!parsed || parsed.v !== 1) return null;
|
|
71
|
+
if (!parsed.api || !parsed.upgrade || !parsed.projectId || !parsed.code) return null;
|
|
72
|
+
return parsed;
|
|
73
|
+
} catch (_) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function runJoin(weiyuanPath, identityPath, projectId, code, fromInit = false) {
|
|
79
|
+
const extra = fromInit ? ['--fromInit'] : [];
|
|
80
|
+
try {
|
|
81
|
+
await execFileAsync('npm', ['--prefix', weiyuanPath, 'run', 'weiyuan', '--', 'join', '--identity', identityPath, '--project', projectId, '--code', code, ...extra], {
|
|
82
|
+
cwd: weiyuanPath
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
} catch (_) {
|
|
86
|
+
}
|
|
87
|
+
await execFileAsync('npx', ['-y', '-p', 'tsx', '-p', 'tweetnacl', 'tsx', path.join(weiyuanPath, 'src', 'cliMain.ts'), 'join', '--identity', identityPath, '--project', projectId, '--code', code, ...extra], {
|
|
88
|
+
cwd: weiyuanPath
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function ensureSkillRuntime(weiyuanPath) {
|
|
93
|
+
const pkgPath = path.join(weiyuanPath, 'package.json');
|
|
94
|
+
const tsconfigPath = path.join(weiyuanPath, 'tsconfig.json');
|
|
95
|
+
if (!await fs.pathExists(pkgPath)) {
|
|
96
|
+
await fs.writeJson(pkgPath, DEFAULT_SKILL_PACKAGE_JSON, { spaces: 2 });
|
|
97
|
+
}
|
|
98
|
+
if (!await fs.pathExists(tsconfigPath)) {
|
|
99
|
+
await fs.writeJson(tsconfigPath, DEFAULT_SKILL_TSCONFIG, { spaces: 2 });
|
|
100
|
+
}
|
|
101
|
+
await execFileAsync('npm', ['--prefix', weiyuanPath, 'install'], { cwd: weiyuanPath });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function runCliInit(weiyuanPath, identityPath, serverUrl) {
|
|
105
|
+
try {
|
|
106
|
+
await execFileAsync('npm', ['--prefix', weiyuanPath, 'run', 'weiyuan', '--', 'init', '--server', serverUrl, '--out', identityPath], {
|
|
107
|
+
cwd: weiyuanPath
|
|
108
|
+
});
|
|
109
|
+
return true;
|
|
110
|
+
} catch (_) {
|
|
111
|
+
}
|
|
112
|
+
await execFileAsync('npx', ['-y', '-p', 'tsx', '-p', 'tweetnacl', 'tsx', path.join(weiyuanPath, 'src', 'cliMain.ts'), 'init', '--server', serverUrl, '--out', identityPath], {
|
|
113
|
+
cwd: weiyuanPath
|
|
114
|
+
});
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function runInit(options) {
|
|
119
|
+
printBanner();
|
|
120
|
+
|
|
121
|
+
const invite = decodeInviteToken(options.invite);
|
|
122
|
+
if (invite) {
|
|
123
|
+
options.server = options.server || invite.api;
|
|
124
|
+
options.upgrade = options.upgrade || invite.upgrade;
|
|
125
|
+
options.project = options.project || invite.projectId;
|
|
126
|
+
options.code = options.code || invite.code;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const workspacePath = resolveWorkspacePath(options.workspace);
|
|
130
|
+
const weiyuanPath = path.join(workspacePath, 'weiyuan');
|
|
131
|
+
const upgradeBaseUrl = options.upgrade || DEFAULT_CONFIG.upgradeBaseUrl;
|
|
132
|
+
const requestedDownloadUrl = options.download || DEFAULT_CONFIG.downloadUrl;
|
|
133
|
+
const serverUrl = options.server || DEFAULT_CONFIG.serverUrl;
|
|
134
|
+
const force = options.force || false;
|
|
135
|
+
|
|
136
|
+
// 检查是否已存在
|
|
137
|
+
if (!force && await fs.pathExists(workspacePath)) {
|
|
138
|
+
console.log(chalk.yellow(`\n⚠️ 工作目录已存在: ${workspacePath}`));
|
|
139
|
+
console.log(chalk.gray(' 使用 --force 强制重新初始化\n'));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 1. 创建工作目录
|
|
144
|
+
let spinner = ora('创建工作目录...').start();
|
|
145
|
+
try {
|
|
146
|
+
await fs.ensureDir(weiyuanPath);
|
|
147
|
+
spinner.succeed(`工作目录: ${workspacePath}`);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
spinner.fail(`创建目录失败: ${error.message}`);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 2. 检查服务器
|
|
154
|
+
spinner = ora('检查服务器连接...').start();
|
|
155
|
+
const serverOk = await checkServer(serverUrl);
|
|
156
|
+
if (serverOk) {
|
|
157
|
+
spinner.succeed(`服务器: ${serverUrl}`);
|
|
158
|
+
} else {
|
|
159
|
+
spinner.warn(`服务器连接失败,请检查网络和防火墙`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 3. 下载文件
|
|
163
|
+
spinner = ora('解析下载包...').start();
|
|
164
|
+
const source = await resolvePackageSource({
|
|
165
|
+
downloadUrl: requestedDownloadUrl,
|
|
166
|
+
upgradeBaseUrl,
|
|
167
|
+
spinner
|
|
168
|
+
});
|
|
169
|
+
spinner.succeed(`下载源: ${source.downloadUrl}`);
|
|
170
|
+
|
|
171
|
+
spinner = ora('下载 weiyuan skill...').start();
|
|
172
|
+
const zipPath = path.join(weiyuanPath, source.zipFilename);
|
|
173
|
+
const downloadSuccess = await downloadFile(source.downloadUrl, zipPath, spinner);
|
|
174
|
+
if (!downloadSuccess) {
|
|
175
|
+
spinner.fail('下载失败');
|
|
176
|
+
throw new Error('下载失败');
|
|
177
|
+
}
|
|
178
|
+
spinner.succeed(`下载完成: ${source.zipFilename}`);
|
|
179
|
+
|
|
180
|
+
// 4. 解压
|
|
181
|
+
spinner = ora('解压文件...').start();
|
|
182
|
+
const extractSuccess = await extractZip(zipPath, weiyuanPath);
|
|
183
|
+
if (!extractSuccess) {
|
|
184
|
+
spinner.fail('解压失败');
|
|
185
|
+
throw new Error('解压失败');
|
|
186
|
+
}
|
|
187
|
+
spinner.succeed('解压完成');
|
|
188
|
+
|
|
189
|
+
// 5. 清理
|
|
190
|
+
spinner = ora('清理临时文件...').start();
|
|
191
|
+
try {
|
|
192
|
+
await fs.remove(zipPath);
|
|
193
|
+
spinner.succeed('清理完成');
|
|
194
|
+
} catch (error) {
|
|
195
|
+
spinner.warn('清理失败,可手动删除');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 6. 准备 CLI 运行时
|
|
199
|
+
spinner = ora('准备 CLI 运行时...').start();
|
|
200
|
+
try {
|
|
201
|
+
await ensureSkillRuntime(weiyuanPath);
|
|
202
|
+
spinner.succeed('CLI 运行时就绪');
|
|
203
|
+
} catch (error) {
|
|
204
|
+
spinner.fail(`CLI 运行时准备失败: ${error.message}`);
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 7. 创建身份文件
|
|
209
|
+
spinner = ora('创建身份文件...').start();
|
|
210
|
+
const identityPath = path.join(workspacePath, DEFAULT_CONFIG.identityFile);
|
|
211
|
+
let identityCreated = false;
|
|
212
|
+
try {
|
|
213
|
+
identityCreated = await runCliInit(weiyuanPath, identityPath, serverUrl);
|
|
214
|
+
} catch (_) {
|
|
215
|
+
identityCreated = await createIdentityFile(identityPath, serverUrl, workspacePath);
|
|
216
|
+
}
|
|
217
|
+
if (identityCreated) {
|
|
218
|
+
spinner.succeed(`身份文件: ${DEFAULT_CONFIG.identityFile}`);
|
|
219
|
+
} else {
|
|
220
|
+
spinner.fail('身份文件创建失败,请检查 /v1/init 可用性');
|
|
221
|
+
throw new Error('identity_create_failed');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 8. 列出目录内容
|
|
225
|
+
console.log(chalk.yellow('\n📁 weiyuan 文件夹内容:'));
|
|
226
|
+
await listDirectory(weiyuanPath, 10);
|
|
227
|
+
|
|
228
|
+
// 9. 初始化 skill
|
|
229
|
+
spinner = ora('初始化 weiyuan skill...').start();
|
|
230
|
+
const initResult = await initSkill(serverUrl, identityPath, workspacePath);
|
|
231
|
+
if (initResult) {
|
|
232
|
+
spinner.succeed('初始化成功');
|
|
233
|
+
} else {
|
|
234
|
+
spinner.warn('初始化端点不存在,可忽略(不影响 join/命令执行)');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (options.project && options.code) {
|
|
238
|
+
spinner = ora('自动加入微元项目...').start();
|
|
239
|
+
try {
|
|
240
|
+
await runJoin(weiyuanPath, identityPath, options.project, options.code, true);
|
|
241
|
+
spinner.succeed(`已加入项目: ${options.project}`);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
spinner.fail(`自动入组失败: ${error.message}`);
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 打印总结
|
|
249
|
+
printSummary(workspacePath, serverUrl, source.downloadUrl);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function runClean(options) {
|
|
253
|
+
const workspacePath = resolveWorkspacePath(options.workspace);
|
|
254
|
+
|
|
255
|
+
if (!await fs.pathExists(workspacePath)) {
|
|
256
|
+
console.log(chalk.yellow(`工作目录不存在: ${workspacePath}`));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const spinner = ora(`清理工作目录: ${workspacePath}`).start();
|
|
261
|
+
try {
|
|
262
|
+
await fs.remove(workspacePath);
|
|
263
|
+
spinner.succeed(`清理完成`);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
spinner.fail(`清理失败: ${error.message}`);
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function runStatus(options) {
|
|
271
|
+
const workspacePath = resolveWorkspacePath(options.workspace);
|
|
272
|
+
const weiyuanPath = path.join(workspacePath, 'weiyuan');
|
|
273
|
+
const identityPath = path.join(workspacePath, DEFAULT_CONFIG.identityFile);
|
|
274
|
+
|
|
275
|
+
console.log(chalk.cyan('\n' + '='.repeat(60)));
|
|
276
|
+
console.log(chalk.cyan.bold(' Weiyuan Skill 状态'));
|
|
277
|
+
console.log(chalk.cyan('='.repeat(60) + '\n'));
|
|
278
|
+
|
|
279
|
+
// 检查工作目录
|
|
280
|
+
if (await fs.pathExists(workspacePath)) {
|
|
281
|
+
console.log(chalk.green(`✅ 工作目录: ${workspacePath}`));
|
|
282
|
+
} else {
|
|
283
|
+
console.log(chalk.red(`❌ 工作目录不存在: ${workspacePath}`));
|
|
284
|
+
console.log(chalk.gray(' 运行 "openclaw-weiyuan-init init" 创建'));
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 检查 weiyuan 文件夹
|
|
289
|
+
if (await fs.pathExists(weiyuanPath)) {
|
|
290
|
+
const files = await fs.readdir(weiyuanPath);
|
|
291
|
+
console.log(chalk.green(`✅ weiyuan 文件夹: ${files.length} 项`));
|
|
292
|
+
} else {
|
|
293
|
+
console.log(chalk.red(`❌ weiyuan 文件夹不存在`));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 检查身份文件
|
|
297
|
+
if (await fs.pathExists(identityPath)) {
|
|
298
|
+
const identity = await fs.readJson(identityPath);
|
|
299
|
+
const idLabel = identity.lobsterId || identity.device_id || '已配置';
|
|
300
|
+
console.log(chalk.green(`✅ 身份文件: ${idLabel}`));
|
|
301
|
+
} else {
|
|
302
|
+
console.log(chalk.red(`❌ 身份文件不存在`));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// 检查服务器
|
|
306
|
+
const serverUrl = options.server || DEFAULT_CONFIG.serverUrl;
|
|
307
|
+
const serverOk = await checkServer(serverUrl);
|
|
308
|
+
if (serverOk) {
|
|
309
|
+
console.log(chalk.green(`✅ 服务器: ${serverUrl}`));
|
|
310
|
+
} else {
|
|
311
|
+
console.log(chalk.red(`❌ 服务器不可达: ${serverUrl}`));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
console.log('');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
module.exports = { runInit, runClean, runStatus, DEFAULT_CONFIG };
|