ai-yuca 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/.eslintrc.js +25 -0
- package/CONFIG_UPLOAD.md +154 -0
- package/CONTRIBUTING.md +58 -0
- package/INSTALLATION.md +192 -0
- package/README.md +80 -0
- package/bin/cli.js +85 -0
- package/bin/cli.ts +302 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +297 -0
- package/dist/package.json +51 -0
- package/dist/src/config.d.ts +56 -0
- package/dist/src/config.js +101 -0
- package/dist/src/download.d.ts +30 -0
- package/dist/src/download.js +214 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.js +126 -0
- package/dist/src/types/analyze.d.ts +33 -0
- package/dist/src/types/analyze.js +5 -0
- package/dist/src/types/download.d.ts +60 -0
- package/dist/src/types/download.js +2 -0
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.js +28 -0
- package/dist/src/types/upload.d.ts +89 -0
- package/dist/src/types/upload.js +2 -0
- package/dist/src/upload.d.ts +24 -0
- package/dist/src/upload.js +252 -0
- package/dist/src/uploadWithConfig.d.ts +34 -0
- package/dist/src/uploadWithConfig.js +82 -0
- package/dist/src/utils/compression.d.ts +16 -0
- package/dist/src/utils/compression.js +85 -0
- package/dist/test/compression.test.d.ts +1 -0
- package/dist/test/compression.test.js +109 -0
- package/dist/test/download.test.d.ts +1 -0
- package/dist/test/download.test.js +168 -0
- package/dist/test/index.test.d.ts +1 -0
- package/dist/test/index.test.js +33 -0
- package/dist/test/upload.test.d.ts +1 -0
- package/dist/test/upload.test.js +140 -0
- package/docs/usage.md +223 -0
- package/examples/sample.txt +7 -0
- package/examples/upload-example.js +53 -0
- package/out/test.txt +1 -0
- package/package.json +51 -0
- package/src/config.ts +104 -0
- package/src/download.ts +216 -0
- package/src/index.js +88 -0
- package/src/index.ts +98 -0
- package/src/types/analyze.ts +37 -0
- package/src/types/download.ts +67 -0
- package/src/types/index.ts +16 -0
- package/src/types/upload.ts +97 -0
- package/src/upload.js +197 -0
- package/src/upload.ts +254 -0
- package/src/uploadWithConfig.ts +122 -0
- package/src/utils/compression.ts +61 -0
- package/test/compression.test.ts +88 -0
- package/test/download.test.ts +162 -0
- package/test/index.test.js +38 -0
- package/test/index.test.ts +39 -0
- package/test/upload.test.ts +131 -0
- package/tsconfig.json +17 -0
- package/vs.config.json +42 -0
package/bin/cli.ts
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import * as pkg from '../package.json';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { analyze } from '../src/index';
|
|
8
|
+
import { createStorageClient, uploadFiles } from '../src/upload';
|
|
9
|
+
import { downloadFiles } from '../src/download';
|
|
10
|
+
import { uploadFilesWithConfig, getConfigSummary } from '../src/uploadWithConfig';
|
|
11
|
+
import { AnalyzeOptions, UploadFilesResult, UploadCommandOptions, DownloadCommandOptions, UploadWithConfigOptions } from '../src/types';
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
// 设置版本和描述
|
|
16
|
+
program
|
|
17
|
+
.version(pkg.version, '-v, --version')
|
|
18
|
+
.description(pkg.description);
|
|
19
|
+
|
|
20
|
+
// 添加analyze命令
|
|
21
|
+
program
|
|
22
|
+
.command('analyze')
|
|
23
|
+
.description('分析文本内容')
|
|
24
|
+
.option('-f, --file <path>', '指定要分析的文件路径')
|
|
25
|
+
.option('-t, --text <text>', '直接分析提供的文本')
|
|
26
|
+
.action((options: AnalyzeOptions) => {
|
|
27
|
+
analyze(options);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// 使用从types导入的UploadCommandOptions接口
|
|
31
|
+
|
|
32
|
+
// 添加upload命令
|
|
33
|
+
program
|
|
34
|
+
.command('upload')
|
|
35
|
+
.description('上传文件到GCP存储桶')
|
|
36
|
+
.option('-s, --source <paths...>', '指定要上传的文件或目录路径(支持多个)')
|
|
37
|
+
.option('-b, --bucket <name>', 'GCP存储桶名称')
|
|
38
|
+
.option('-d, --destination <path>', '目标路径(存储桶中的路径)')
|
|
39
|
+
.option('-k, --key-file <path>', 'GCP服务账号密钥文件路径(可选,不提供则使用应用默认凭证)')
|
|
40
|
+
.option('-r, --recursive', '递归上传目录中的文件', false)
|
|
41
|
+
.option('-c, --no-compression', '禁用GZIP压缩(默认对js、css、json、html、woff文件启用压缩)')
|
|
42
|
+
.action(async (options: UploadCommandOptions) => {
|
|
43
|
+
try {
|
|
44
|
+
const { source, bucket, destination, keyFile, recursive, compression = true } = options;
|
|
45
|
+
|
|
46
|
+
if (!source || !bucket) {
|
|
47
|
+
console.error('错误: 必须提供源文件路径和存储桶名称');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 创建存储客户端
|
|
52
|
+
const storageClient = keyFile
|
|
53
|
+
? createStorageClient({ keyFilename: keyFile })
|
|
54
|
+
: createStorageClient(); // 使用应用默认凭证
|
|
55
|
+
|
|
56
|
+
console.log('开始上传文件...');
|
|
57
|
+
|
|
58
|
+
// 执行上传
|
|
59
|
+
const results = await uploadFiles({
|
|
60
|
+
bucketName: bucket,
|
|
61
|
+
sourcePath: source,
|
|
62
|
+
destination,
|
|
63
|
+
storageClient,
|
|
64
|
+
recursive,
|
|
65
|
+
enableCompression: compression
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// 输出结果
|
|
69
|
+
console.log('\n上传完成!');
|
|
70
|
+
console.log(`成功: ${results.success.length} 个文件`);
|
|
71
|
+
console.log(`失败: ${results.failed.length} 个文件`);
|
|
72
|
+
|
|
73
|
+
if (results.success.length > 0) {
|
|
74
|
+
console.log('\n成功上传的文件:');
|
|
75
|
+
results.success.forEach(file => {
|
|
76
|
+
console.log(`- ${file.file} (${file.url})`);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (results.failed.length > 0) {
|
|
81
|
+
console.log('\n上传失败的文件:');
|
|
82
|
+
results.failed.forEach(file => {
|
|
83
|
+
console.log(`- ${file.file}: ${file.error}`);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error(`上传错误: ${err instanceof Error ? err.message : String(err)}`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 添加download命令
|
|
93
|
+
program
|
|
94
|
+
.command('download')
|
|
95
|
+
.description('从GCP存储桶下载文件或文件夹')
|
|
96
|
+
.option('-s, --source <path>', '指定要下载的GCP存储桶中的文件或目录路径')
|
|
97
|
+
.option('-b, --bucket <name>', 'GCP存储桶名称')
|
|
98
|
+
.option('-d, --destination <path>', '本地目标路径(下载到本地的路径)')
|
|
99
|
+
.option('-k, --key-file <path>', 'GCP服务账号密钥文件路径(可选,不提供则使用应用默认凭证)')
|
|
100
|
+
.option('-r, --recursive', '递归下载目录中的文件', false)
|
|
101
|
+
.action(async (options: DownloadCommandOptions) => {
|
|
102
|
+
try {
|
|
103
|
+
const { source, bucket, destination, keyFile, recursive } = options;
|
|
104
|
+
|
|
105
|
+
if (!source || !bucket || !destination) {
|
|
106
|
+
console.error('错误: 必须提供源路径、存储桶名称和目标路径');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 创建存储客户端
|
|
111
|
+
const storageClient = keyFile
|
|
112
|
+
? createStorageClient({ keyFilename: keyFile })
|
|
113
|
+
: createStorageClient(); // 使用应用默认凭证
|
|
114
|
+
|
|
115
|
+
console.log('开始下载文件...');
|
|
116
|
+
|
|
117
|
+
// 执行下载
|
|
118
|
+
const results = await downloadFiles({
|
|
119
|
+
bucketName: bucket,
|
|
120
|
+
sourcePath: source,
|
|
121
|
+
destinationPath: destination,
|
|
122
|
+
storageClient,
|
|
123
|
+
recursive
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// 输出结果
|
|
127
|
+
console.log('\n下载完成!');
|
|
128
|
+
console.log(`成功: ${results.success.length} 个文件`);
|
|
129
|
+
console.log(`失败: ${results.failed.length} 个文件`);
|
|
130
|
+
|
|
131
|
+
if (results.success.length > 0) {
|
|
132
|
+
console.log('\n成功下载的文件:');
|
|
133
|
+
results.success.forEach(file => {
|
|
134
|
+
console.log(`- ${file.file} -> ${file.localPath}`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (results.failed.length > 0) {
|
|
139
|
+
console.log('\n下载失败的文件:');
|
|
140
|
+
results.failed.forEach(file => {
|
|
141
|
+
console.log(`- ${file.file}: ${file.error}`);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error(`下载错误: ${err instanceof Error ? err.message : String(err)}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// 添加基于配置文件的上传命令
|
|
151
|
+
program
|
|
152
|
+
.command('upload-config')
|
|
153
|
+
.description('基于vs.config.json配置文件上传文件到GCP存储桶')
|
|
154
|
+
.option('-c, --config <path>', '指定配置文件路径(默认为项目根目录下的vs.config.json)')
|
|
155
|
+
.option('-k, --key-file <path>', 'GCP服务账号密钥文件路径(可选,不提供则使用应用默认凭证)')
|
|
156
|
+
.option('-s, --source <path>', '自定义源路径(覆盖配置文件中的uploadPath)')
|
|
157
|
+
.option('-d, --destination <path>', '自定义目标路径(覆盖配置文件中的目标路径)')
|
|
158
|
+
.option('--no-recursive', '禁用递归上传目录中的文件')
|
|
159
|
+
.option('--no-compression', '禁用GZIP压缩')
|
|
160
|
+
.option('--show-config', '仅显示配置信息,不执行上传')
|
|
161
|
+
.action(async (options: any) => {
|
|
162
|
+
try {
|
|
163
|
+
const {
|
|
164
|
+
config: configPath,
|
|
165
|
+
keyFile,
|
|
166
|
+
source: customSourcePath,
|
|
167
|
+
destination: customDestination,
|
|
168
|
+
recursive = true,
|
|
169
|
+
compression = true,
|
|
170
|
+
showConfig = false
|
|
171
|
+
} = options;
|
|
172
|
+
|
|
173
|
+
// 如果只是显示配置信息
|
|
174
|
+
if (showConfig) {
|
|
175
|
+
try {
|
|
176
|
+
const configSummary = getConfigSummary(configPath);
|
|
177
|
+
console.log('配置信息:');
|
|
178
|
+
console.log(` 桶名称: ${configSummary.bucketName}`);
|
|
179
|
+
console.log(` 源路径: ${configSummary.sourcePath}`);
|
|
180
|
+
console.log(` 目标路径: ${configSummary.destination}`);
|
|
181
|
+
return;
|
|
182
|
+
} catch (err) {
|
|
183
|
+
console.error(`读取配置失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 执行上传
|
|
189
|
+
const uploadOptions: UploadWithConfigOptions = {
|
|
190
|
+
configPath,
|
|
191
|
+
storageClientOptions: keyFile ? { keyFilename: keyFile } : {},
|
|
192
|
+
customSourcePath,
|
|
193
|
+
customDestination,
|
|
194
|
+
recursive,
|
|
195
|
+
enableCompression: compression
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const result = await uploadFilesWithConfig(uploadOptions);
|
|
199
|
+
|
|
200
|
+
if (result.success.length > 0) {
|
|
201
|
+
console.log('\n上传成功的文件:');
|
|
202
|
+
result.success.forEach((file) => {
|
|
203
|
+
console.log(` ✓ ${file.file} -> ${file.url}`);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (result.failed.length > 0) {
|
|
208
|
+
console.log('\n上传失败的文件:');
|
|
209
|
+
result.failed.forEach((file) => {
|
|
210
|
+
console.log(` ✗ ${file.file}: ${file.error}`);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
} catch (err) {
|
|
215
|
+
console.error(`上传错误: ${err instanceof Error ? err.message : String(err)}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// 添加init命令
|
|
221
|
+
program
|
|
222
|
+
.command('init')
|
|
223
|
+
.description('在当前目录生成vs.config.json配置文件')
|
|
224
|
+
.option('-f, --force', '强制覆盖已存在的配置文件')
|
|
225
|
+
.action(async (options: any) => {
|
|
226
|
+
try {
|
|
227
|
+
const { force = false } = options;
|
|
228
|
+
const configPath = path.join(process.cwd(), 'vs.config.json');
|
|
229
|
+
|
|
230
|
+
// 检查文件是否已存在
|
|
231
|
+
if (fs.existsSync(configPath) && !force) {
|
|
232
|
+
console.error('错误: vs.config.json 文件已存在。使用 --force 选项强制覆盖。');
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 默认配置数据
|
|
237
|
+
const defaultConfig = {
|
|
238
|
+
"upload": {
|
|
239
|
+
"uploadPath": "out",
|
|
240
|
+
"s3Static": "static/aiAgent"
|
|
241
|
+
},
|
|
242
|
+
"deploy": {
|
|
243
|
+
"baseUrlExample": "baseUrl: ['/', 'en-us/', 'zh-hk/', 'test/']",
|
|
244
|
+
"baseUrl": [
|
|
245
|
+
"/",
|
|
246
|
+
"en-us/",
|
|
247
|
+
"zh-cn/",
|
|
248
|
+
"de-de/",
|
|
249
|
+
"it-it/",
|
|
250
|
+
"pt-pt/",
|
|
251
|
+
"es-es/",
|
|
252
|
+
"fr-fr/",
|
|
253
|
+
"ru-ru/",
|
|
254
|
+
"error/",
|
|
255
|
+
"download-v2/"
|
|
256
|
+
],
|
|
257
|
+
"host": "https://www.china2u.xyz",
|
|
258
|
+
"testHost": "https://ai.decom.valleysound.xyz"
|
|
259
|
+
},
|
|
260
|
+
"aws": {
|
|
261
|
+
"Bucket": "decom-cdn",
|
|
262
|
+
"prefix": "fed",
|
|
263
|
+
"Region": "us-east-1",
|
|
264
|
+
"HostName": "https://cdn.cn2u.xyz"
|
|
265
|
+
},
|
|
266
|
+
"crowdin": {
|
|
267
|
+
"project": "fed-buy-buy-buy-home",
|
|
268
|
+
"langMap": ["zh-cn","en-us", "de-de", "pt-pt", "fr-fr", "es-es", "it-it", "ru-ru"],
|
|
269
|
+
"workDir": "src",
|
|
270
|
+
"reg": "{#(.+?)#}",
|
|
271
|
+
"keysDir": "src/_i18n",
|
|
272
|
+
"Bucket": "mall-rocket-cdn",
|
|
273
|
+
"prefix": "fed",
|
|
274
|
+
"Region": "us-east-1",
|
|
275
|
+
"FromIni": "mall",
|
|
276
|
+
"HostName": "https://cdn.alvinclub.ca"
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// 写入配置文件
|
|
281
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), 'utf-8');
|
|
282
|
+
|
|
283
|
+
console.log(`✓ 成功生成配置文件: ${configPath}`);
|
|
284
|
+
console.log('\n配置文件内容:');
|
|
285
|
+
console.log(` 桶名称: ${defaultConfig.aws.Bucket}`);
|
|
286
|
+
console.log(` 源路径: ${defaultConfig.upload.uploadPath}`);
|
|
287
|
+
console.log(` 目标路径: ${defaultConfig.aws.prefix}/${defaultConfig.upload.s3Static}`);
|
|
288
|
+
console.log('\n您可以根据需要修改配置文件中的值。');
|
|
289
|
+
|
|
290
|
+
} catch (err) {
|
|
291
|
+
console.error(`生成配置文件失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// 解析命令行参数
|
|
297
|
+
program.parse(process.argv);
|
|
298
|
+
|
|
299
|
+
// 如果没有提供任何命令,显示帮助信息
|
|
300
|
+
if (!process.argv.slice(2).length) {
|
|
301
|
+
program.outputHelp();
|
|
302
|
+
}
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const pkg = __importStar(require("../package.json"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const index_1 = require("../src/index");
|
|
42
|
+
const upload_1 = require("../src/upload");
|
|
43
|
+
const download_1 = require("../src/download");
|
|
44
|
+
const uploadWithConfig_1 = require("../src/uploadWithConfig");
|
|
45
|
+
const program = new commander_1.Command();
|
|
46
|
+
// 设置版本和描述
|
|
47
|
+
program
|
|
48
|
+
.version(pkg.version, '-v, --version')
|
|
49
|
+
.description(pkg.description);
|
|
50
|
+
// 添加analyze命令
|
|
51
|
+
program
|
|
52
|
+
.command('analyze')
|
|
53
|
+
.description('分析文本内容')
|
|
54
|
+
.option('-f, --file <path>', '指定要分析的文件路径')
|
|
55
|
+
.option('-t, --text <text>', '直接分析提供的文本')
|
|
56
|
+
.action((options) => {
|
|
57
|
+
(0, index_1.analyze)(options);
|
|
58
|
+
});
|
|
59
|
+
// 使用从types导入的UploadCommandOptions接口
|
|
60
|
+
// 添加upload命令
|
|
61
|
+
program
|
|
62
|
+
.command('upload')
|
|
63
|
+
.description('上传文件到GCP存储桶')
|
|
64
|
+
.option('-s, --source <paths...>', '指定要上传的文件或目录路径(支持多个)')
|
|
65
|
+
.option('-b, --bucket <name>', 'GCP存储桶名称')
|
|
66
|
+
.option('-d, --destination <path>', '目标路径(存储桶中的路径)')
|
|
67
|
+
.option('-k, --key-file <path>', 'GCP服务账号密钥文件路径(可选,不提供则使用应用默认凭证)')
|
|
68
|
+
.option('-r, --recursive', '递归上传目录中的文件', false)
|
|
69
|
+
.option('-c, --no-compression', '禁用GZIP压缩(默认对js、css、json、html、woff文件启用压缩)')
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
try {
|
|
72
|
+
const { source, bucket, destination, keyFile, recursive, compression = true } = options;
|
|
73
|
+
if (!source || !bucket) {
|
|
74
|
+
console.error('错误: 必须提供源文件路径和存储桶名称');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
// 创建存储客户端
|
|
78
|
+
const storageClient = keyFile
|
|
79
|
+
? (0, upload_1.createStorageClient)({ keyFilename: keyFile })
|
|
80
|
+
: (0, upload_1.createStorageClient)(); // 使用应用默认凭证
|
|
81
|
+
console.log('开始上传文件...');
|
|
82
|
+
// 执行上传
|
|
83
|
+
const results = await (0, upload_1.uploadFiles)({
|
|
84
|
+
bucketName: bucket,
|
|
85
|
+
sourcePath: source,
|
|
86
|
+
destination,
|
|
87
|
+
storageClient,
|
|
88
|
+
recursive,
|
|
89
|
+
enableCompression: compression
|
|
90
|
+
});
|
|
91
|
+
// 输出结果
|
|
92
|
+
console.log('\n上传完成!');
|
|
93
|
+
console.log(`成功: ${results.success.length} 个文件`);
|
|
94
|
+
console.log(`失败: ${results.failed.length} 个文件`);
|
|
95
|
+
if (results.success.length > 0) {
|
|
96
|
+
console.log('\n成功上传的文件:');
|
|
97
|
+
results.success.forEach(file => {
|
|
98
|
+
console.log(`- ${file.file} (${file.url})`);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (results.failed.length > 0) {
|
|
102
|
+
console.log('\n上传失败的文件:');
|
|
103
|
+
results.failed.forEach(file => {
|
|
104
|
+
console.log(`- ${file.file}: ${file.error}`);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
console.error(`上传错误: ${err instanceof Error ? err.message : String(err)}`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// 添加download命令
|
|
114
|
+
program
|
|
115
|
+
.command('download')
|
|
116
|
+
.description('从GCP存储桶下载文件或文件夹')
|
|
117
|
+
.option('-s, --source <path>', '指定要下载的GCP存储桶中的文件或目录路径')
|
|
118
|
+
.option('-b, --bucket <name>', 'GCP存储桶名称')
|
|
119
|
+
.option('-d, --destination <path>', '本地目标路径(下载到本地的路径)')
|
|
120
|
+
.option('-k, --key-file <path>', 'GCP服务账号密钥文件路径(可选,不提供则使用应用默认凭证)')
|
|
121
|
+
.option('-r, --recursive', '递归下载目录中的文件', false)
|
|
122
|
+
.action(async (options) => {
|
|
123
|
+
try {
|
|
124
|
+
const { source, bucket, destination, keyFile, recursive } = options;
|
|
125
|
+
if (!source || !bucket || !destination) {
|
|
126
|
+
console.error('错误: 必须提供源路径、存储桶名称和目标路径');
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
// 创建存储客户端
|
|
130
|
+
const storageClient = keyFile
|
|
131
|
+
? (0, upload_1.createStorageClient)({ keyFilename: keyFile })
|
|
132
|
+
: (0, upload_1.createStorageClient)(); // 使用应用默认凭证
|
|
133
|
+
console.log('开始下载文件...');
|
|
134
|
+
// 执行下载
|
|
135
|
+
const results = await (0, download_1.downloadFiles)({
|
|
136
|
+
bucketName: bucket,
|
|
137
|
+
sourcePath: source,
|
|
138
|
+
destinationPath: destination,
|
|
139
|
+
storageClient,
|
|
140
|
+
recursive
|
|
141
|
+
});
|
|
142
|
+
// 输出结果
|
|
143
|
+
console.log('\n下载完成!');
|
|
144
|
+
console.log(`成功: ${results.success.length} 个文件`);
|
|
145
|
+
console.log(`失败: ${results.failed.length} 个文件`);
|
|
146
|
+
if (results.success.length > 0) {
|
|
147
|
+
console.log('\n成功下载的文件:');
|
|
148
|
+
results.success.forEach(file => {
|
|
149
|
+
console.log(`- ${file.file} -> ${file.localPath}`);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (results.failed.length > 0) {
|
|
153
|
+
console.log('\n下载失败的文件:');
|
|
154
|
+
results.failed.forEach(file => {
|
|
155
|
+
console.log(`- ${file.file}: ${file.error}`);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error(`下载错误: ${err instanceof Error ? err.message : String(err)}`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
// 添加基于配置文件的上传命令
|
|
165
|
+
program
|
|
166
|
+
.command('upload-config')
|
|
167
|
+
.description('基于vs.config.json配置文件上传文件到GCP存储桶')
|
|
168
|
+
.option('-c, --config <path>', '指定配置文件路径(默认为项目根目录下的vs.config.json)')
|
|
169
|
+
.option('-k, --key-file <path>', 'GCP服务账号密钥文件路径(可选,不提供则使用应用默认凭证)')
|
|
170
|
+
.option('-s, --source <path>', '自定义源路径(覆盖配置文件中的uploadPath)')
|
|
171
|
+
.option('-d, --destination <path>', '自定义目标路径(覆盖配置文件中的目标路径)')
|
|
172
|
+
.option('--no-recursive', '禁用递归上传目录中的文件')
|
|
173
|
+
.option('--no-compression', '禁用GZIP压缩')
|
|
174
|
+
.option('--show-config', '仅显示配置信息,不执行上传')
|
|
175
|
+
.action(async (options) => {
|
|
176
|
+
try {
|
|
177
|
+
const { config: configPath, keyFile, source: customSourcePath, destination: customDestination, recursive = true, compression = true, showConfig = false } = options;
|
|
178
|
+
// 如果只是显示配置信息
|
|
179
|
+
if (showConfig) {
|
|
180
|
+
try {
|
|
181
|
+
const configSummary = (0, uploadWithConfig_1.getConfigSummary)(configPath);
|
|
182
|
+
console.log('配置信息:');
|
|
183
|
+
console.log(` 桶名称: ${configSummary.bucketName}`);
|
|
184
|
+
console.log(` 源路径: ${configSummary.sourcePath}`);
|
|
185
|
+
console.log(` 目标路径: ${configSummary.destination}`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
console.error(`读取配置失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// 执行上传
|
|
194
|
+
const uploadOptions = {
|
|
195
|
+
configPath,
|
|
196
|
+
storageClientOptions: keyFile ? { keyFilename: keyFile } : {},
|
|
197
|
+
customSourcePath,
|
|
198
|
+
customDestination,
|
|
199
|
+
recursive,
|
|
200
|
+
enableCompression: compression
|
|
201
|
+
};
|
|
202
|
+
const result = await (0, uploadWithConfig_1.uploadFilesWithConfig)(uploadOptions);
|
|
203
|
+
if (result.success.length > 0) {
|
|
204
|
+
console.log('\n上传成功的文件:');
|
|
205
|
+
result.success.forEach((file) => {
|
|
206
|
+
console.log(` ✓ ${file.file} -> ${file.url}`);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (result.failed.length > 0) {
|
|
210
|
+
console.log('\n上传失败的文件:');
|
|
211
|
+
result.failed.forEach((file) => {
|
|
212
|
+
console.log(` ✗ ${file.file}: ${file.error}`);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
console.error(`上传错误: ${err instanceof Error ? err.message : String(err)}`);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// 添加init命令
|
|
222
|
+
program
|
|
223
|
+
.command('init')
|
|
224
|
+
.description('在当前目录生成vs.config.json配置文件')
|
|
225
|
+
.option('-f, --force', '强制覆盖已存在的配置文件')
|
|
226
|
+
.action(async (options) => {
|
|
227
|
+
try {
|
|
228
|
+
const { force = false } = options;
|
|
229
|
+
const configPath = path.join(process.cwd(), 'vs.config.json');
|
|
230
|
+
// 检查文件是否已存在
|
|
231
|
+
if (fs.existsSync(configPath) && !force) {
|
|
232
|
+
console.error('错误: vs.config.json 文件已存在。使用 --force 选项强制覆盖。');
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
// 默认配置数据
|
|
236
|
+
const defaultConfig = {
|
|
237
|
+
"upload": {
|
|
238
|
+
"uploadPath": "out",
|
|
239
|
+
"s3Static": "static/aiAgent"
|
|
240
|
+
},
|
|
241
|
+
"deploy": {
|
|
242
|
+
"baseUrlExample": "baseUrl: ['/', 'en-us/', 'zh-hk/', 'test/']",
|
|
243
|
+
"baseUrl": [
|
|
244
|
+
"/",
|
|
245
|
+
"en-us/",
|
|
246
|
+
"zh-cn/",
|
|
247
|
+
"de-de/",
|
|
248
|
+
"it-it/",
|
|
249
|
+
"pt-pt/",
|
|
250
|
+
"es-es/",
|
|
251
|
+
"fr-fr/",
|
|
252
|
+
"ru-ru/",
|
|
253
|
+
"error/",
|
|
254
|
+
"download-v2/"
|
|
255
|
+
],
|
|
256
|
+
"host": "https://www.china2u.xyz",
|
|
257
|
+
"testHost": "https://ai.decom.valleysound.xyz"
|
|
258
|
+
},
|
|
259
|
+
"aws": {
|
|
260
|
+
"Bucket": "decom-cdn",
|
|
261
|
+
"prefix": "fed",
|
|
262
|
+
"Region": "us-east-1",
|
|
263
|
+
"HostName": "https://cdn.cn2u.xyz"
|
|
264
|
+
},
|
|
265
|
+
"crowdin": {
|
|
266
|
+
"project": "fed-buy-buy-buy-home",
|
|
267
|
+
"langMap": ["zh-cn", "en-us", "de-de", "pt-pt", "fr-fr", "es-es", "it-it", "ru-ru"],
|
|
268
|
+
"workDir": "src",
|
|
269
|
+
"reg": "{#(.+?)#}",
|
|
270
|
+
"keysDir": "src/_i18n",
|
|
271
|
+
"Bucket": "mall-rocket-cdn",
|
|
272
|
+
"prefix": "fed",
|
|
273
|
+
"Region": "us-east-1",
|
|
274
|
+
"FromIni": "mall",
|
|
275
|
+
"HostName": "https://cdn.alvinclub.ca"
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
// 写入配置文件
|
|
279
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), 'utf-8');
|
|
280
|
+
console.log(`✓ 成功生成配置文件: ${configPath}`);
|
|
281
|
+
console.log('\n配置文件内容:');
|
|
282
|
+
console.log(` 桶名称: ${defaultConfig.aws.Bucket}`);
|
|
283
|
+
console.log(` 源路径: ${defaultConfig.upload.uploadPath}`);
|
|
284
|
+
console.log(` 目标路径: ${defaultConfig.aws.prefix}/${defaultConfig.upload.s3Static}`);
|
|
285
|
+
console.log('\n您可以根据需要修改配置文件中的值。');
|
|
286
|
+
}
|
|
287
|
+
catch (err) {
|
|
288
|
+
console.error(`生成配置文件失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
// 解析命令行参数
|
|
293
|
+
program.parse(process.argv);
|
|
294
|
+
// 如果没有提供任何命令,显示帮助信息
|
|
295
|
+
if (!process.argv.slice(2).length) {
|
|
296
|
+
program.outputHelp();
|
|
297
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-yuca",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "一个实用的AI辅助工具",
|
|
5
|
+
"main": "dist/src/index.js",
|
|
6
|
+
"types": "dist/src/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"ai-yuca": "./dist/bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"directories": {
|
|
11
|
+
"test": "test"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test": "mocha -r ts-node/register 'test/**/*.ts'",
|
|
16
|
+
"start": "ts-node src/index.ts",
|
|
17
|
+
"lint": "eslint . --ext .ts",
|
|
18
|
+
"dev": "ts-node bin/cli.ts",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"tool",
|
|
24
|
+
"utility",
|
|
25
|
+
"cli"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=14.0.0"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@google-cloud/storage": "^7.17.1",
|
|
34
|
+
"commander": "^10.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/chai": "^5.2.2",
|
|
38
|
+
"@types/google-cloud__storage": "^2.3.1",
|
|
39
|
+
"@types/mocha": "^10.0.10",
|
|
40
|
+
"@types/node": "^24.3.1",
|
|
41
|
+
"@types/sinon": "^17.0.4",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.43.0",
|
|
44
|
+
"chai": "^4.3.4",
|
|
45
|
+
"eslint": "^9.35.0",
|
|
46
|
+
"mocha": "^11.7.2",
|
|
47
|
+
"sinon": "^21.0.0",
|
|
48
|
+
"ts-node": "^10.9.2",
|
|
49
|
+
"typescript": "^5.9.2"
|
|
50
|
+
}
|
|
51
|
+
}
|