@fastcar/cli 0.0.7 → 0.1.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/README.md +259 -21
- package/bin/cli.js +202 -32
- package/package.json +3 -3
- package/skills/fastcar-database/SKILL.md +374 -0
- package/skills/fastcar-framework/SKILL.md +661 -0
- package/skills/fastcar-framework/assets/project-template/package.json +24 -0
- package/skills/fastcar-framework/assets/project-template/resource/application.yml +14 -0
- package/skills/fastcar-framework/assets/project-template/src/app.ts +18 -0
- package/skills/fastcar-framework/assets/project-template/src/component/StartupRunner.ts +15 -0
- package/skills/fastcar-framework/assets/project-template/src/controller/HelloController.ts +21 -0
- package/skills/fastcar-framework/assets/project-template/src/service/HelloService.ts +12 -0
- package/skills/fastcar-framework/assets/project-template/tsconfig.json +21 -0
- package/skills/fastcar-framework/references/api-reference.md +353 -0
- package/skills/fastcar-rpc-microservices/SKILL.md +311 -0
- package/skills/fastcar-serverless/SKILL.md +211 -0
- package/skills/fastcar-toolkit/SKILL.md +282 -0
- package/src/init.js +615 -201
- package/src/pack.js +204 -0
- package/src/reverse.js +204 -0
- package/src/skill-targets.js +74 -0
- package/src/skill.js +362 -0
- package/src/templates.json +32 -0
- package/src/utils.js +51 -66
package/src/skill.js
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { getTarget, getGlobalPath, getLocalPath, getAllTargets, getTargetNames } = require('./skill-targets');
|
|
5
|
+
|
|
6
|
+
const fsPromises = fs.promises;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 获取包根目录
|
|
10
|
+
*/
|
|
11
|
+
function getPackageRoot() {
|
|
12
|
+
return path.join(__dirname, '..');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 获取 skills 目录
|
|
17
|
+
*/
|
|
18
|
+
function getSkillsDir() {
|
|
19
|
+
return path.join(getPackageRoot(), 'skills');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 检查路径是否存在
|
|
24
|
+
*/
|
|
25
|
+
async function pathExists(checkPath) {
|
|
26
|
+
try {
|
|
27
|
+
await fsPromises.access(checkPath);
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 列出可用的 skills
|
|
36
|
+
*/
|
|
37
|
+
async function listAvailableSkills() {
|
|
38
|
+
const skillsDir = getSkillsDir();
|
|
39
|
+
if (!(await pathExists(skillsDir))) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const items = await fsPromises.readdir(skillsDir);
|
|
45
|
+
const skills = [];
|
|
46
|
+
|
|
47
|
+
for (const item of items) {
|
|
48
|
+
const skillPath = path.join(skillsDir, item);
|
|
49
|
+
const stat = await fsPromises.stat(skillPath);
|
|
50
|
+
if (stat.isDirectory()) {
|
|
51
|
+
skills.push(item);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return skills;
|
|
56
|
+
} catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 获取 skill 目录
|
|
63
|
+
*/
|
|
64
|
+
async function getSkillDir(skillName) {
|
|
65
|
+
const skillsDir = getSkillsDir();
|
|
66
|
+
const skillPath = path.join(skillsDir, skillName);
|
|
67
|
+
|
|
68
|
+
if (await pathExists(skillPath)) {
|
|
69
|
+
return skillPath;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 递归复制目录
|
|
76
|
+
*/
|
|
77
|
+
async function copyDir(src, dest) {
|
|
78
|
+
await fsPromises.mkdir(dest, { recursive: true });
|
|
79
|
+
const entries = await fsPromises.readdir(src, { withFileTypes: true });
|
|
80
|
+
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
const srcPath = path.join(src, entry.name);
|
|
83
|
+
const destPath = path.join(dest, entry.name);
|
|
84
|
+
|
|
85
|
+
if (entry.isDirectory()) {
|
|
86
|
+
await copyDir(srcPath, destPath);
|
|
87
|
+
} else {
|
|
88
|
+
await fsPromises.copyFile(srcPath, destPath);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 删除目录
|
|
95
|
+
*/
|
|
96
|
+
async function removeDir(dirPath) {
|
|
97
|
+
if (await pathExists(dirPath)) {
|
|
98
|
+
await fsPromises.rm(dirPath, { recursive: true, force: true });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 提示选择安装模式
|
|
104
|
+
*/
|
|
105
|
+
async function promptMode(action = 'install') {
|
|
106
|
+
const { mode } = await inquirer.prompt([{
|
|
107
|
+
type: 'list',
|
|
108
|
+
name: 'mode',
|
|
109
|
+
message: `选择 ${action} 位置:`,
|
|
110
|
+
choices: [
|
|
111
|
+
{
|
|
112
|
+
name: `全局 (Global) - 所有项目可用`,
|
|
113
|
+
value: 'global'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: `本地 (Local) - 仅当前项目可用`,
|
|
117
|
+
value: 'local'
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
default: 'global'
|
|
121
|
+
}]);
|
|
122
|
+
|
|
123
|
+
return mode;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 安装 skill
|
|
128
|
+
*/
|
|
129
|
+
async function installSkill(skillName, options = {}) {
|
|
130
|
+
try {
|
|
131
|
+
// 检查 skill 是否存在
|
|
132
|
+
const skillDir = await getSkillDir(skillName);
|
|
133
|
+
if (!skillDir) {
|
|
134
|
+
const availableSkills = await listAvailableSkills();
|
|
135
|
+
console.log(`❌ Skill "${skillName}" 不存在`);
|
|
136
|
+
console.log(`可用的 skills: ${availableSkills.join(', ') || '无'}`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 确定安装模式
|
|
141
|
+
let mode = 'global';
|
|
142
|
+
if (options.local) {
|
|
143
|
+
mode = 'local';
|
|
144
|
+
} else if (options.global) {
|
|
145
|
+
mode = 'global';
|
|
146
|
+
} else {
|
|
147
|
+
mode = await promptMode('install');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 确定目标
|
|
151
|
+
const target = options.target || 'kimi';
|
|
152
|
+
|
|
153
|
+
// 确定目标路径
|
|
154
|
+
let targetPath;
|
|
155
|
+
if (mode === 'local') {
|
|
156
|
+
targetPath = getLocalPath(target);
|
|
157
|
+
} else {
|
|
158
|
+
targetPath = getGlobalPath(target);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!targetPath) {
|
|
162
|
+
console.log('❌ 无法确定安装路径');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 确保目标目录存在
|
|
167
|
+
await fsPromises.mkdir(targetPath, { recursive: true });
|
|
168
|
+
|
|
169
|
+
// 检查是否已存在
|
|
170
|
+
const destPath = path.join(targetPath, skillName);
|
|
171
|
+
const exists = await pathExists(destPath);
|
|
172
|
+
|
|
173
|
+
if (exists) {
|
|
174
|
+
const { overwrite } = await inquirer.prompt([{
|
|
175
|
+
type: 'confirm',
|
|
176
|
+
name: 'overwrite',
|
|
177
|
+
message: `Skill "${skillName}" 已存在,是否覆盖?`,
|
|
178
|
+
default: false
|
|
179
|
+
}]);
|
|
180
|
+
|
|
181
|
+
if (!overwrite) {
|
|
182
|
+
console.log('⚠️ 已取消安装');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 删除旧的
|
|
187
|
+
await removeDir(destPath);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 复制 skill 文件
|
|
191
|
+
console.log(`📦 正在安装 ${skillName}...`);
|
|
192
|
+
await copyDir(skillDir, destPath);
|
|
193
|
+
|
|
194
|
+
// 验证安装
|
|
195
|
+
if (await pathExists(destPath)) {
|
|
196
|
+
const modeText = mode === 'global' ? '全局' : '本地';
|
|
197
|
+
console.log(`✅ 成功 ${modeText} 安装 ${skillName}`);
|
|
198
|
+
console.log(` 位置: ${destPath}`);
|
|
199
|
+
console.log();
|
|
200
|
+
console.log('提示:');
|
|
201
|
+
console.log(' 1. 重启你的 AI agent 以使用 skill');
|
|
202
|
+
console.log(` 2. 在对话中询问关于 "${skillName}" 的内容`);
|
|
203
|
+
} else {
|
|
204
|
+
console.log('❌ 安装验证失败');
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.log(`❌ 错误: ${error.message}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* 卸载 skill
|
|
213
|
+
*/
|
|
214
|
+
async function uninstallSkill(skillName, options = {}) {
|
|
215
|
+
try {
|
|
216
|
+
// 确定安装模式
|
|
217
|
+
let mode = 'global';
|
|
218
|
+
if (options.local) {
|
|
219
|
+
mode = 'local';
|
|
220
|
+
} else if (options.global) {
|
|
221
|
+
mode = 'global';
|
|
222
|
+
} else {
|
|
223
|
+
mode = await promptMode('uninstall');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 确定目标
|
|
227
|
+
const target = options.target || 'kimi';
|
|
228
|
+
|
|
229
|
+
// 确定目标路径
|
|
230
|
+
let targetPath;
|
|
231
|
+
if (mode === 'local') {
|
|
232
|
+
targetPath = getLocalPath(target);
|
|
233
|
+
} else {
|
|
234
|
+
targetPath = getGlobalPath(target);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const skillPath = path.join(targetPath, skillName);
|
|
238
|
+
|
|
239
|
+
// 检查是否存在
|
|
240
|
+
if (!(await pathExists(skillPath))) {
|
|
241
|
+
console.log(`⚠️ Skill "${skillName}" 不存在于 ${skillPath}`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// 确认卸载
|
|
246
|
+
const { confirm } = await inquirer.prompt([{
|
|
247
|
+
type: 'confirm',
|
|
248
|
+
name: 'confirm',
|
|
249
|
+
message: `确认卸载 "${skillName}"?`,
|
|
250
|
+
default: false
|
|
251
|
+
}]);
|
|
252
|
+
|
|
253
|
+
if (!confirm) {
|
|
254
|
+
console.log('⚠️ 已取消卸载');
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// 删除 skill
|
|
259
|
+
console.log(`🗑️ 正在卸载 ${skillName}...`);
|
|
260
|
+
await removeDir(skillPath);
|
|
261
|
+
|
|
262
|
+
console.log(`✅ 成功卸载 ${skillName}`);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.log(`❌ 错误: ${error.message}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 列出可用的 skills
|
|
270
|
+
*/
|
|
271
|
+
async function listSkills() {
|
|
272
|
+
try {
|
|
273
|
+
const skills = await listAvailableSkills();
|
|
274
|
+
|
|
275
|
+
if (skills.length === 0) {
|
|
276
|
+
console.log('⚠️ 没有可用的 skills');
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log('📚 可用的 FastCar Skills:');
|
|
281
|
+
console.log();
|
|
282
|
+
|
|
283
|
+
for (const skill of skills) {
|
|
284
|
+
const skillDir = await getSkillDir(skill);
|
|
285
|
+
const skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
286
|
+
|
|
287
|
+
let description = '';
|
|
288
|
+
if (await pathExists(skillMdPath)) {
|
|
289
|
+
const content = await fsPromises.readFile(skillMdPath, 'utf-8');
|
|
290
|
+
const match = content.match(/description:\s*(.+)/);
|
|
291
|
+
if (match) {
|
|
292
|
+
description = match[1].trim();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log(` • ${skill}`);
|
|
297
|
+
if (description) {
|
|
298
|
+
console.log(` ${description}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
console.log();
|
|
303
|
+
console.log('安装命令: fastcar-cli skill install <skill-name>');
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.log(`❌ 错误: ${error.message}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 列出支持的目标 agents
|
|
311
|
+
*/
|
|
312
|
+
function listTargets() {
|
|
313
|
+
const targets = getAllTargets();
|
|
314
|
+
|
|
315
|
+
console.log('🤖 支持的 AI Agents:');
|
|
316
|
+
console.log();
|
|
317
|
+
|
|
318
|
+
for (const [key, config] of Object.entries(targets)) {
|
|
319
|
+
const globalPath = getGlobalPath(key);
|
|
320
|
+
const localPath = getLocalPath(key);
|
|
321
|
+
|
|
322
|
+
console.log(` • ${config.name} (${key})`);
|
|
323
|
+
console.log(` ${config.description}`);
|
|
324
|
+
console.log(` 全局: ${globalPath}`);
|
|
325
|
+
console.log(` 本地: ${localPath}`);
|
|
326
|
+
console.log();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* 初始化项目级配置
|
|
332
|
+
*/
|
|
333
|
+
async function initSkill(options = {}) {
|
|
334
|
+
try {
|
|
335
|
+
const target = options.target || 'kimi';
|
|
336
|
+
const localPath = getLocalPath(target);
|
|
337
|
+
|
|
338
|
+
console.log(`🔧 正在初始化 ${target} 配置...`);
|
|
339
|
+
|
|
340
|
+
if (await pathExists(localPath)) {
|
|
341
|
+
console.log(`⚠️ 目录已存在: ${localPath}`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
await fsPromises.mkdir(localPath, { recursive: true });
|
|
346
|
+
|
|
347
|
+
console.log(`✅ 已创建 ${localPath}`);
|
|
348
|
+
console.log();
|
|
349
|
+
console.log('下一步:');
|
|
350
|
+
console.log(` fastcar-cli skill install <skill-name> --local`);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
console.log(`❌ 错误: ${error.message}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
module.exports = {
|
|
357
|
+
installSkill,
|
|
358
|
+
uninstallSkill,
|
|
359
|
+
listSkills,
|
|
360
|
+
listTargets,
|
|
361
|
+
initSkill
|
|
362
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"web": {
|
|
3
|
+
"name": "web",
|
|
4
|
+
"description": "Web 应用模板 - 适用于构建 Web 服务端应用",
|
|
5
|
+
"package": "@fastcar/template-web",
|
|
6
|
+
"tags": ["web", "server", "http"]
|
|
7
|
+
},
|
|
8
|
+
"rpc": {
|
|
9
|
+
"name": "rpc",
|
|
10
|
+
"description": "RPC 服务模板 - 适用于构建微服务 RPC 节点",
|
|
11
|
+
"package": "@fastcar/template-rpc",
|
|
12
|
+
"tags": ["rpc", "microservice"]
|
|
13
|
+
},
|
|
14
|
+
"cos": {
|
|
15
|
+
"name": "cos",
|
|
16
|
+
"description": "COS 存储模板 - 适用于对象存储服务",
|
|
17
|
+
"package": "@fastcar/template-cos",
|
|
18
|
+
"tags": ["cos", "storage"]
|
|
19
|
+
},
|
|
20
|
+
"micro": {
|
|
21
|
+
"name": "micro",
|
|
22
|
+
"description": "微服务模板 - 适用于构建完整的微服务架构",
|
|
23
|
+
"package": "@fastcar/template-microservices",
|
|
24
|
+
"tags": ["microservices", "fullstack"]
|
|
25
|
+
},
|
|
26
|
+
"static": {
|
|
27
|
+
"name": "static",
|
|
28
|
+
"description": "静态资源模板 - 适用于静态网站或资源服务",
|
|
29
|
+
"package": "@fastcar/template-static",
|
|
30
|
+
"tags": ["static", "assets"]
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/utils.js
CHANGED
|
@@ -1,96 +1,81 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const compressing = require("compressing");
|
|
4
|
-
const util = require("util");
|
|
5
4
|
const yaml = require("yaml");
|
|
6
5
|
|
|
7
6
|
//复制文件
|
|
8
7
|
function copyDirectory(src, dest) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
if (!fs.existsSync(dest)) {
|
|
9
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
if (!fs.existsSync(src)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let dirs = fs.readdirSync(src);
|
|
16
|
+
dirs.forEach((item) => {
|
|
17
|
+
let item_path = path.join(src, item);
|
|
18
|
+
let temp = fs.statSync(item_path);
|
|
19
|
+
|
|
20
|
+
if (temp.isFile()) {
|
|
21
|
+
fs.copyFileSync(item_path, path.join(dest, item));
|
|
22
|
+
} else if (temp.isDirectory()) {
|
|
23
|
+
copyDirectory(item_path, path.join(dest, item));
|
|
17
24
|
}
|
|
25
|
+
});
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
dirs.forEach((item) => {
|
|
21
|
-
|
|
22
|
-
let item_path = path.join(src, item);
|
|
23
|
-
let temp = fs.statSync(item_path);
|
|
24
|
-
|
|
25
|
-
if (temp.isFile()) {
|
|
26
|
-
|
|
27
|
-
fs.copyFileSync(item_path, path.join(dest, item));
|
|
28
|
-
} else if (temp.isDirectory()) {
|
|
29
|
-
|
|
30
|
-
copyDirectory(item_path, path.join(dest, item));
|
|
31
|
-
}
|
|
32
|
-
});
|
|
27
|
+
return true;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
//递归删除文件夹
|
|
36
31
|
function delDirEctory(src) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
if (!fs.existsSync(src)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let srcstats = fs.statSync(src);
|
|
37
|
+
if (srcstats.isFile()) {
|
|
38
|
+
fs.rmSync(src);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let dirs = fs.readdirSync(src);
|
|
43
|
+
dirs.forEach((item) => {
|
|
44
|
+
let item_path = path.join(src, item);
|
|
45
|
+
let temp = fs.statSync(item_path);
|
|
46
|
+
|
|
47
|
+
if (temp.isFile()) {
|
|
48
|
+
fs.rmSync(item_path);
|
|
49
|
+
} else if (temp.isDirectory()) {
|
|
50
|
+
delDirEctory(item_path);
|
|
41
51
|
}
|
|
52
|
+
});
|
|
42
53
|
|
|
43
|
-
|
|
44
|
-
if (srcstats.isFile()) {
|
|
45
|
-
|
|
46
|
-
fs.rmSync(src);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let dirs = fs.readdirSync(src);
|
|
51
|
-
dirs.forEach((item) => {
|
|
52
|
-
|
|
53
|
-
let item_path = path.join(src, item);
|
|
54
|
-
let temp = fs.statSync(item_path);
|
|
55
|
-
|
|
56
|
-
if (temp.isFile()) {
|
|
57
|
-
|
|
58
|
-
fs.rmSync(item_path);
|
|
59
|
-
} else if (temp.isDirectory()) {
|
|
60
|
-
|
|
61
|
-
delDirEctory(item_path);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
fs.rmdirSync(src);
|
|
54
|
+
fs.rmdirSync(src);
|
|
66
55
|
}
|
|
67
56
|
|
|
68
57
|
async function unzipFile(src, dest) {
|
|
69
|
-
|
|
70
|
-
await compressing.zip.uncompress(src, dest);
|
|
58
|
+
await compressing.zip.uncompress(src, dest);
|
|
71
59
|
}
|
|
72
60
|
|
|
73
61
|
async function zipFile(src, dest) {
|
|
74
|
-
|
|
75
|
-
await compressing.zip.compressDir(src, dest);
|
|
62
|
+
await compressing.zip.compressDir(src, dest);
|
|
76
63
|
}
|
|
77
64
|
|
|
78
65
|
function readYaml(fp) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return yaml.parse(content);
|
|
66
|
+
let content = fs.readFileSync(fp, "utf-8");
|
|
67
|
+
return yaml.parse(content);
|
|
82
68
|
}
|
|
83
69
|
|
|
84
70
|
function writeYaml(fp, obj) {
|
|
85
|
-
|
|
86
|
-
fs.writeFileSync(fp, yaml.stringify(obj));
|
|
71
|
+
fs.writeFileSync(fp, yaml.stringify(obj));
|
|
87
72
|
}
|
|
88
73
|
|
|
89
74
|
module.exports = {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
75
|
+
copyDirectory,
|
|
76
|
+
delDirEctory,
|
|
77
|
+
unzipFile,
|
|
78
|
+
zipFile,
|
|
79
|
+
readYaml,
|
|
80
|
+
writeYaml,
|
|
81
|
+
};
|