@round2ai/r2-cli 1.0.1 → 1.0.3
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 +1 -1
- package/dist/index.js +842 -230
- package/dist/index.js.map +7 -1
- package/package.json +13 -5
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,236 +1,848 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command8 } from "commander";
|
|
3
5
|
import fse from "fs-extra";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import inquirer from "inquirer";
|
|
6
|
+
import path2 from "node:path";
|
|
7
|
+
import chalk8 from "chalk";
|
|
7
8
|
import figlet from "figlet";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
9
|
+
|
|
10
|
+
// src/commands/setup.ts
|
|
11
|
+
import "commander";
|
|
12
|
+
import chalk7 from "chalk";
|
|
13
|
+
|
|
14
|
+
// src/commands/auth/login.ts
|
|
15
|
+
import { Command } from "commander";
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
|
|
18
|
+
// src/query/executor.ts
|
|
19
|
+
async function* executePollingQuery(query, options) {
|
|
20
|
+
const { interval, timeout, condition, onProgress } = options;
|
|
21
|
+
const startTime = Date.now();
|
|
22
|
+
yield {
|
|
23
|
+
type: "start",
|
|
24
|
+
message: `\u5F00\u59CB\u8F6E\u8BE2: ${query.description}`,
|
|
25
|
+
timestamp: startTime
|
|
26
|
+
};
|
|
27
|
+
let attempts = 0;
|
|
28
|
+
let lastData = null;
|
|
29
|
+
while (Date.now() - startTime < timeout) {
|
|
30
|
+
attempts++;
|
|
31
|
+
if (query.deps.signal?.aborted) {
|
|
32
|
+
throw new Error("\u67E5\u8BE2\u88AB\u4E2D\u6B62");
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const data = await query.execute(query.deps);
|
|
36
|
+
lastData = data;
|
|
37
|
+
const progress = Math.min(
|
|
38
|
+
Math.floor((Date.now() - startTime) / timeout * 100),
|
|
39
|
+
99
|
|
40
|
+
);
|
|
41
|
+
onProgress?.(progress, `\u8F6E\u8BE2\u4E2D... (\u7B2C ${attempts} \u6B21)`);
|
|
42
|
+
yield {
|
|
43
|
+
type: "update",
|
|
44
|
+
message: `\u8F6E\u8BE2\u4E2D... (\u7B2C ${attempts} \u6B21)`,
|
|
45
|
+
progress,
|
|
46
|
+
timestamp: Date.now()
|
|
47
|
+
};
|
|
48
|
+
if (condition(data)) {
|
|
49
|
+
const duration = Date.now() - startTime;
|
|
50
|
+
yield {
|
|
51
|
+
type: "complete",
|
|
52
|
+
message: `\u8F6E\u8BE2\u5B8C\u6210 (\u5171 ${attempts} \u6B21)`,
|
|
53
|
+
progress: 100,
|
|
54
|
+
timestamp: Date.now()
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
data,
|
|
58
|
+
metadata: {
|
|
59
|
+
duration,
|
|
60
|
+
success: true,
|
|
61
|
+
attempts
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
67
|
+
yield {
|
|
68
|
+
type: "error",
|
|
69
|
+
message: `\u8F6E\u8BE2\u9519\u8BEF: ${errorMessage}`,
|
|
70
|
+
timestamp: Date.now()
|
|
71
|
+
};
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
await sleep(interval);
|
|
75
|
+
}
|
|
76
|
+
throw new Error(
|
|
77
|
+
`\u8F6E\u8BE2\u8D85\u65F6: ${query.description} (\u5DF2\u7B49\u5F85 ${timeout}ms, \u5171 ${attempts} \u6B21)`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function sleep(ms) {
|
|
81
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/errors/index.ts
|
|
85
|
+
var R2Error = class _R2Error extends Error {
|
|
86
|
+
constructor(message, code, details) {
|
|
87
|
+
super(message);
|
|
88
|
+
this.code = code;
|
|
89
|
+
this.details = details;
|
|
90
|
+
this.name = "R2Error";
|
|
91
|
+
if (Error.captureStackTrace) {
|
|
92
|
+
Error.captureStackTrace(this, _R2Error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
code;
|
|
96
|
+
details;
|
|
97
|
+
};
|
|
98
|
+
var ApiError = class extends R2Error {
|
|
99
|
+
constructor(message, status, response) {
|
|
100
|
+
super(message, "API_ERROR", response);
|
|
101
|
+
this.status = status;
|
|
102
|
+
this.response = response;
|
|
103
|
+
this.name = "ApiError";
|
|
104
|
+
}
|
|
105
|
+
status;
|
|
106
|
+
response;
|
|
107
|
+
};
|
|
108
|
+
var StorageError = class extends R2Error {
|
|
109
|
+
constructor(message, path3, code) {
|
|
110
|
+
super(message, "STORAGE_ERROR", { path: path3, code });
|
|
111
|
+
this.path = path3;
|
|
112
|
+
this.code = code;
|
|
113
|
+
this.name = "StorageError";
|
|
114
|
+
}
|
|
115
|
+
path;
|
|
116
|
+
code;
|
|
117
|
+
};
|
|
118
|
+
var AuthError = class extends R2Error {
|
|
119
|
+
constructor(message) {
|
|
120
|
+
super(message, "AUTH_ERROR");
|
|
121
|
+
this.name = "AuthError";
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var PollingError = class extends R2Error {
|
|
125
|
+
constructor(message, attempts, timeout) {
|
|
126
|
+
super(message, "POLLING_ERROR", { attempts, timeout });
|
|
127
|
+
this.attempts = attempts;
|
|
128
|
+
this.timeout = timeout;
|
|
129
|
+
this.name = "PollingError";
|
|
130
|
+
}
|
|
131
|
+
attempts;
|
|
132
|
+
timeout;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/services/api/api-client.service.ts
|
|
136
|
+
var R2_API_URL = "https://api.puresnake.com";
|
|
137
|
+
var ApiClientService = class {
|
|
138
|
+
config;
|
|
139
|
+
token = null;
|
|
140
|
+
constructor(config = {}) {
|
|
141
|
+
this.config = {
|
|
142
|
+
baseUrl: config.baseUrl ?? R2_API_URL,
|
|
143
|
+
version: config.version ?? "v3",
|
|
144
|
+
debug: config.debug ?? false
|
|
145
|
+
};
|
|
146
|
+
console.log("this.config", this.config);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 设置认证令牌
|
|
150
|
+
*/
|
|
151
|
+
setToken(token) {
|
|
152
|
+
this.token = token;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 获取认证令牌
|
|
156
|
+
*/
|
|
157
|
+
getToken() {
|
|
158
|
+
return this.token;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 构建 URL
|
|
162
|
+
*/
|
|
163
|
+
buildUrl(path3) {
|
|
164
|
+
const cleanPath = path3.startsWith("/") ? path3.slice(1) : path3;
|
|
165
|
+
return `${this.config.baseUrl}/${this.config.version}/${cleanPath}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 构建 HTTP 头
|
|
169
|
+
*/
|
|
170
|
+
buildHeaders() {
|
|
171
|
+
const headers = {
|
|
172
|
+
"Content-Type": "application/json"
|
|
173
|
+
};
|
|
174
|
+
if (this.token) {
|
|
175
|
+
headers["token"] = this.token;
|
|
176
|
+
}
|
|
177
|
+
return headers;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 处理响应
|
|
181
|
+
*/
|
|
182
|
+
async handleResponse(response) {
|
|
183
|
+
if (!response.ok) {
|
|
184
|
+
const errorText = await response.text();
|
|
185
|
+
throw new ApiError(`HTTP ${response.status}: ${response.statusText} - ${errorText}`, response.status);
|
|
186
|
+
}
|
|
187
|
+
const result = await response.json();
|
|
188
|
+
if (this.config.debug) {
|
|
189
|
+
console.log("[API Response]", result);
|
|
190
|
+
}
|
|
191
|
+
if (!result.success || result.status !== 0) {
|
|
192
|
+
throw new ApiError(`API Error: status=${result.status}, success=${result.success}, message=${result.msg}`, void 0, result);
|
|
193
|
+
}
|
|
194
|
+
return result.data;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 执行请求
|
|
198
|
+
*/
|
|
199
|
+
async request(path3, config) {
|
|
200
|
+
const url = this.buildUrl(path3);
|
|
201
|
+
const { method, headers, body } = config;
|
|
202
|
+
const init = {
|
|
203
|
+
method,
|
|
204
|
+
headers: { ...this.buildHeaders(), ...headers }
|
|
205
|
+
};
|
|
206
|
+
if (body !== void 0) {
|
|
207
|
+
init.body = JSON.stringify(body);
|
|
208
|
+
}
|
|
209
|
+
if (this.config.debug) {
|
|
210
|
+
console.log(`[API ${method}]`, url, body);
|
|
211
|
+
}
|
|
212
|
+
const response = await fetch(url, init);
|
|
213
|
+
return this.handleResponse(response);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* GET 请求
|
|
217
|
+
*/
|
|
218
|
+
async get(path3, params) {
|
|
219
|
+
let url = this.buildUrl(path3);
|
|
220
|
+
if (params && params.size > 0) {
|
|
221
|
+
url += `?${params.toString()}`;
|
|
222
|
+
}
|
|
223
|
+
const init = {
|
|
224
|
+
method: "GET",
|
|
225
|
+
headers: this.buildHeaders()
|
|
226
|
+
};
|
|
227
|
+
if (this.config.debug) {
|
|
228
|
+
console.log(`[API GET]`, url);
|
|
229
|
+
}
|
|
230
|
+
const response = await fetch(url, init);
|
|
231
|
+
return this.handleResponse(response);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* POST 请求
|
|
235
|
+
*/
|
|
236
|
+
async post(path3, body) {
|
|
237
|
+
const config = { method: "POST", body };
|
|
238
|
+
return this.request(path3, config);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* PUT 请求
|
|
242
|
+
*/
|
|
243
|
+
async put(path3, body) {
|
|
244
|
+
const config = { method: "PUT", body };
|
|
245
|
+
return this.request(path3, config);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* DELETE 请求
|
|
249
|
+
*/
|
|
250
|
+
async delete(path3) {
|
|
251
|
+
const config = { method: "DELETE" };
|
|
252
|
+
return this.request(path3, config);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
var QRCodeAuthApiService = class {
|
|
256
|
+
client;
|
|
257
|
+
constructor(client) {
|
|
258
|
+
this.client = client;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* 生成二维码
|
|
262
|
+
*/
|
|
263
|
+
async generateQRCode() {
|
|
264
|
+
return this.client.post("app/qrcode/generate");
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* 查询二维码状态
|
|
268
|
+
*/
|
|
269
|
+
async getQRCodeStatus(qrToken) {
|
|
270
|
+
const params = new URLSearchParams();
|
|
271
|
+
params.append("qrToken", qrToken);
|
|
272
|
+
return this.client.get("app/qrcode/status", params);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* 确认登录
|
|
276
|
+
*/
|
|
277
|
+
async confirmLogin(qrToken) {
|
|
278
|
+
return this.client.post("app/qrcode/confirm", {
|
|
279
|
+
qrToken
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// src/services/storage/index.ts
|
|
285
|
+
import { promises as fs } from "node:fs";
|
|
286
|
+
import path from "node:path";
|
|
287
|
+
import os from "node:os";
|
|
288
|
+
import { stat, mkdir } from "node:fs/promises";
|
|
289
|
+
var CONFIG_FILE_NAME = ".r2-cli";
|
|
290
|
+
var StorageService = class {
|
|
291
|
+
configPath;
|
|
292
|
+
config;
|
|
293
|
+
constructor() {
|
|
294
|
+
const homeDir = os.homedir();
|
|
295
|
+
const configDir = path.join(homeDir, CONFIG_FILE_NAME);
|
|
296
|
+
this.configPath = path.join(configDir, "config.json");
|
|
297
|
+
this.config = { credentials: null };
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* 获取配置文件路径
|
|
301
|
+
*/
|
|
302
|
+
getConfigPath() {
|
|
303
|
+
return this.configPath;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 加载配置
|
|
307
|
+
*/
|
|
308
|
+
async loadConfig() {
|
|
309
|
+
try {
|
|
310
|
+
const content = await fs.readFile(this.configPath, "utf-8");
|
|
311
|
+
const config = JSON.parse(content);
|
|
312
|
+
this.config = config;
|
|
313
|
+
return config;
|
|
314
|
+
} catch (error) {
|
|
315
|
+
if (error.code === "ENOENT") {
|
|
316
|
+
return { credentials: null };
|
|
317
|
+
}
|
|
318
|
+
throw new StorageError(
|
|
319
|
+
"Failed to load config",
|
|
320
|
+
this.configPath,
|
|
321
|
+
error.code
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* 保存配置
|
|
327
|
+
*/
|
|
328
|
+
async saveConfig(config) {
|
|
329
|
+
this.config = config;
|
|
330
|
+
const content = JSON.stringify(config, null, 2);
|
|
331
|
+
const dirPath = path.dirname(this.configPath);
|
|
332
|
+
try {
|
|
333
|
+
await stat(dirPath);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if (error.code === "ENOENT") {
|
|
336
|
+
await mkdir(dirPath, { recursive: true });
|
|
337
|
+
} else {
|
|
338
|
+
throw new StorageError(
|
|
339
|
+
"Failed to create directory",
|
|
340
|
+
dirPath,
|
|
341
|
+
error.code
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
await fs.writeFile(this.configPath, content, "utf-8");
|
|
347
|
+
} catch (error) {
|
|
348
|
+
throw new StorageError(
|
|
349
|
+
"Failed to save config",
|
|
350
|
+
this.configPath,
|
|
351
|
+
error.code
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* 保存登录凭证
|
|
357
|
+
*/
|
|
358
|
+
async saveCredentials(token, userInfo) {
|
|
359
|
+
const credentials = {
|
|
360
|
+
token,
|
|
361
|
+
userInfo,
|
|
362
|
+
timestamp: Date.now()
|
|
363
|
+
};
|
|
364
|
+
let config;
|
|
365
|
+
try {
|
|
366
|
+
config = await this.loadConfig();
|
|
367
|
+
} catch (error) {
|
|
368
|
+
config = { credentials: null };
|
|
369
|
+
}
|
|
370
|
+
config.credentials = credentials;
|
|
371
|
+
await this.saveConfig(config);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 获取登录凭证
|
|
375
|
+
*/
|
|
376
|
+
async getCredentials() {
|
|
377
|
+
const config = await this.loadConfig();
|
|
378
|
+
return config.credentials;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* 清除登录凭证
|
|
382
|
+
*/
|
|
383
|
+
async clearCredentials() {
|
|
384
|
+
const config = await this.loadConfig();
|
|
385
|
+
config.credentials = null;
|
|
386
|
+
await this.saveConfig(config);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* 获取 token
|
|
390
|
+
*/
|
|
391
|
+
async getToken() {
|
|
392
|
+
const credentials = await this.getCredentials();
|
|
393
|
+
return credentials?.token ?? null;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* 获取用户信息
|
|
397
|
+
*/
|
|
398
|
+
async getUserInfo() {
|
|
399
|
+
const credentials = await this.getCredentials();
|
|
400
|
+
return credentials?.userInfo ?? null;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* 检查是否已登录
|
|
404
|
+
*/
|
|
405
|
+
async isLoggedIn() {
|
|
406
|
+
const credentials = await this.getCredentials();
|
|
407
|
+
return credentials !== null;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
function createStorageService() {
|
|
411
|
+
return new StorageService();
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/commands/auth/login.ts
|
|
415
|
+
import { createRequire } from "node:module";
|
|
416
|
+
var require2 = createRequire(import.meta.url);
|
|
417
|
+
var qrcodeTerminal = require2("qrcode-terminal");
|
|
418
|
+
var LoginService = class {
|
|
419
|
+
authApi;
|
|
420
|
+
storage;
|
|
421
|
+
constructor(authApi, storage) {
|
|
422
|
+
this.authApi = authApi ?? new QRCodeAuthApiService(new ApiClientService());
|
|
423
|
+
this.storage = storage ?? createStorageService();
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* 执行扫码登录
|
|
427
|
+
*/
|
|
428
|
+
async login(signal) {
|
|
429
|
+
console.log(chalk.cyan("\n\u{1F510} \u6B63\u5728\u542F\u52A8\u626B\u7801\u767B\u5F55..."));
|
|
430
|
+
const qrData = await this.authApi.generateQRCode();
|
|
431
|
+
console.log(chalk.green("\u2705 \u4E8C\u7EF4\u7801\u5DF2\u751F\u6210\n"));
|
|
432
|
+
this.displayQRCode(qrData);
|
|
433
|
+
const query = {
|
|
434
|
+
id: "qrcode-status-poll",
|
|
435
|
+
description: "\u67E5\u8BE2\u4E8C\u7EF4\u7801\u767B\u5F55\u72B6\u6001",
|
|
436
|
+
deps: {
|
|
437
|
+
signal: signal ?? null,
|
|
438
|
+
uuid: () => Math.random().toString(36),
|
|
439
|
+
api: {
|
|
440
|
+
get: async (url) => {
|
|
441
|
+
return this.authApi.getQRCodeStatus(qrData.qrToken);
|
|
442
|
+
},
|
|
443
|
+
post: async (_url, _body) => {
|
|
444
|
+
throw new Error("Not implemented");
|
|
445
|
+
}
|
|
71
446
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
console.log(chalk.
|
|
172
|
-
console.log(chalk.
|
|
173
|
-
console.log(chalk.
|
|
174
|
-
console.log(chalk.
|
|
175
|
-
console.log(chalk.
|
|
176
|
-
console.log(chalk.
|
|
177
|
-
console.log(chalk.
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
.
|
|
184
|
-
.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
447
|
+
log: {
|
|
448
|
+
info: (msg) => console.log(chalk.blue(`[INFO] ${msg}`)),
|
|
449
|
+
error: (msg) => console.error(chalk.red(`[ERROR] ${msg}`)),
|
|
450
|
+
debug: (msg) => console.log(chalk.gray(`[DEBUG] ${msg}`))
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
execute: async () => {
|
|
454
|
+
return this.authApi.getQRCodeStatus(qrData.qrToken);
|
|
455
|
+
},
|
|
456
|
+
options: {
|
|
457
|
+
timeout: Number.parseInt(qrData.expireTime, 10),
|
|
458
|
+
enableProgress: true
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
try {
|
|
462
|
+
const result = await this.pollLoginStatus(query, qrData);
|
|
463
|
+
if (result.data.token && result.data.userInfo) {
|
|
464
|
+
await this.saveCredentials(result.data.token, result.data.userInfo);
|
|
465
|
+
console.log(chalk.green("\n\u2705 \u767B\u5F55\u6210\u529F\uFF01\n"));
|
|
466
|
+
this.displayUserInfo(result.data.userInfo);
|
|
467
|
+
return {
|
|
468
|
+
userInfo: result.data.userInfo,
|
|
469
|
+
token: result.data.token
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
throw new AuthError("\u767B\u5F55\u5931\u8D25: \u672A\u83B7\u53D6\u5230\u51ED\u8BC1");
|
|
473
|
+
} catch (error) {
|
|
474
|
+
console.log("error", error);
|
|
475
|
+
console.log(chalk.red("\n\u274C \u767B\u5F55\u5931\u8D25\n"));
|
|
476
|
+
if (error instanceof Error) {
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
throw new AuthError("\u767B\u5F55\u5931\u8D25: \u672A\u77E5\u9519\u8BEF");
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* 显示二维码
|
|
484
|
+
*/
|
|
485
|
+
displayQRCode(qrData) {
|
|
486
|
+
console.log(chalk.yellow("\u{1F4F1} \u8BF7\u4F7F\u7528 \u7B2C\u4E8C\u56DE\u5408APP \u626B\u63CF\u4E8C\u7EF4\u7801\u767B\u5F55\n"));
|
|
487
|
+
qrcodeTerminal.generate(`r2://auth/login?qrToken=${qrData.qrContent}`, { small: true });
|
|
488
|
+
const expireTimeMs = Number.parseInt(qrData.expireTime, 10);
|
|
489
|
+
const pollIntervalMs = Number.parseInt(qrData.pollInterval, 10);
|
|
490
|
+
console.log(chalk.yellow("\n\u23F3 \u7B49\u5F85\u626B\u7801..."));
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* 轮询登录状态
|
|
494
|
+
*/
|
|
495
|
+
async pollLoginStatus(query, qrData) {
|
|
496
|
+
let lastStatus = "waiting";
|
|
497
|
+
const expireTimeMs = Number.parseInt(qrData.expireTime, 10);
|
|
498
|
+
const pollIntervalMs = Number.parseInt(qrData.pollInterval, 10);
|
|
499
|
+
const pollingIterator = executePollingQuery(query, {
|
|
500
|
+
interval: pollIntervalMs,
|
|
501
|
+
timeout: expireTimeMs,
|
|
502
|
+
condition: (data) => {
|
|
503
|
+
if (data.status !== lastStatus) {
|
|
504
|
+
lastStatus = data.status;
|
|
505
|
+
switch (data.status) {
|
|
506
|
+
case "scanned":
|
|
507
|
+
console.log(chalk.cyan(`
|
|
508
|
+
\u{1F50D} \u5DF2\u626B\u7801: ${data.userInfo?.nickname || "\u672A\u77E5\u7528\u6237"}`));
|
|
509
|
+
console.log(chalk.yellow("\u8BF7\u5728 APP \u4E0A\u786E\u8BA4\u767B\u5F55"));
|
|
510
|
+
break;
|
|
511
|
+
case "confirmed":
|
|
512
|
+
console.log(chalk.green("\n\u2705 \u7528\u6237\u5DF2\u786E\u8BA4\u767B\u5F55"));
|
|
513
|
+
break;
|
|
514
|
+
case "expired":
|
|
515
|
+
console.log(chalk.red("\n\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F"));
|
|
516
|
+
break;
|
|
517
|
+
case "canceled":
|
|
518
|
+
console.log(chalk.red("\n\u{1F6AB} \u7528\u6237\u5DF2\u53D6\u6D88\u767B\u5F55"));
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return data.status === "confirmed";
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
let result = null;
|
|
526
|
+
let done = false;
|
|
527
|
+
while (!done) {
|
|
528
|
+
const { value, done: iterationDone } = await pollingIterator.next();
|
|
529
|
+
done = iterationDone ?? true;
|
|
530
|
+
if (done) {
|
|
531
|
+
if (value && "data" in value) {
|
|
532
|
+
result = { data: value.data };
|
|
533
|
+
}
|
|
534
|
+
} else {
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (result) {
|
|
538
|
+
return result;
|
|
539
|
+
}
|
|
540
|
+
throw new PollingError("\u8F6E\u8BE2\u5F02\u5E38\u7EC8\u6B62");
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* 显示用户信息
|
|
544
|
+
*/
|
|
545
|
+
displayUserInfo(userInfo) {
|
|
546
|
+
console.log(chalk.white("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
547
|
+
console.log(chalk.cyan("\u7528\u6237\u4FE1\u606F:"));
|
|
548
|
+
console.log(chalk.white(" \u7528\u6237\u540D: ") + chalk.yellow(userInfo.username));
|
|
549
|
+
console.log(chalk.white(" \u6635\u79F0: ") + chalk.yellow(userInfo.nickname));
|
|
550
|
+
console.log(chalk.white(" \u624B\u673A\u53F7: ") + chalk.yellow(userInfo.mobile));
|
|
551
|
+
console.log(chalk.white(" \u7528\u6237ID: ") + chalk.yellow(userInfo.userId.toString()));
|
|
552
|
+
console.log(chalk.white("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* 保存登录凭证
|
|
556
|
+
*/
|
|
557
|
+
async saveCredentials(token, userInfo) {
|
|
558
|
+
await this.storage.saveCredentials(token, userInfo);
|
|
559
|
+
const credentials = await this.storage.getCredentials();
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* 登出
|
|
563
|
+
*/
|
|
564
|
+
async logout() {
|
|
565
|
+
console.log(chalk.cyan("\n\u{1F6AA} \u6B63\u5728\u9000\u51FA\u767B\u5F55..."));
|
|
566
|
+
await this.clearCredentials();
|
|
567
|
+
console.log(chalk.green("\u2705 \u5DF2\u9000\u51FA\u767B\u5F55\n"));
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* 查看登录状态
|
|
571
|
+
*/
|
|
572
|
+
async status() {
|
|
573
|
+
console.log(chalk.cyan("\n\u{1F4CA} \u67E5\u770B\u767B\u5F55\u72B6\u6001...\n"));
|
|
574
|
+
const isLoggedIn = await this.storage.isLoggedIn();
|
|
575
|
+
if (!isLoggedIn) {
|
|
576
|
+
console.log(chalk.yellow("\u26A0\uFE0F \u5C1A\u672A\u767B\u5F55\u6216\u51ED\u8BC1\u5DF2\u8FC7\u671F\n"));
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const credentials = await this.storage.getCredentials();
|
|
580
|
+
const userInfo = credentials.userInfo;
|
|
581
|
+
const lastLogin = new Date(credentials.timestamp);
|
|
582
|
+
const daysSinceLogin = Math.floor((Date.now() - credentials.timestamp) / (1e3 * 60 * 60 * 24));
|
|
583
|
+
console.log(chalk.green("\u2705 \u5DF2\u767B\u5F55\n"));
|
|
584
|
+
this.displayUserInfo(userInfo);
|
|
585
|
+
console.log(chalk.gray("\n\u{1F4C5} \u6700\u540E\u767B\u5F55: " + lastLogin.toLocaleString()));
|
|
586
|
+
console.log(chalk.gray(" \u8DDD\u79BB\u4ECA\u5929: " + daysSinceLogin + " \u5929\u524D"));
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* 清除登录凭证
|
|
590
|
+
*/
|
|
591
|
+
async clearCredentials() {
|
|
592
|
+
await this.storage.clearCredentials();
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
function createLoginCommand() {
|
|
596
|
+
const command = new Command("login");
|
|
597
|
+
command.description("\u626B\u7801\u767B\u5F55 Round2AI \u8D26\u6237");
|
|
598
|
+
command.option("--timeout <ms>", "\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09", "300000");
|
|
599
|
+
command.option("--debug", "\u542F\u7528\u8C03\u8BD5\u6A21\u5F0F", false);
|
|
600
|
+
command.action(async (options) => {
|
|
601
|
+
try {
|
|
602
|
+
const loginService = new LoginService();
|
|
603
|
+
const controller = new AbortController();
|
|
604
|
+
const timeout = setTimeout(
|
|
605
|
+
() => {
|
|
606
|
+
controller.abort();
|
|
191
607
|
},
|
|
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
|
-
|
|
608
|
+
Number.parseInt(options.timeout ?? "300000", 10)
|
|
609
|
+
);
|
|
610
|
+
await loginService.login(controller.signal);
|
|
611
|
+
clearTimeout(timeout);
|
|
612
|
+
} catch (error) {
|
|
613
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
614
|
+
console.error(chalk.red(`\u274C ${errorMessage}`));
|
|
615
|
+
process.exit(1);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
return command;
|
|
619
|
+
}
|
|
620
|
+
function createLogoutCommand() {
|
|
621
|
+
const command = new Command("logout");
|
|
622
|
+
command.description("\u9000\u51FA\u767B\u5F55");
|
|
623
|
+
command.action(async () => {
|
|
624
|
+
try {
|
|
625
|
+
const loginService = new LoginService();
|
|
626
|
+
await loginService.logout();
|
|
627
|
+
} catch (error) {
|
|
628
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
629
|
+
console.error(chalk.red(`\u274C ${errorMessage}`));
|
|
630
|
+
process.exit(1);
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
return command;
|
|
634
|
+
}
|
|
635
|
+
function createStatusCommand() {
|
|
636
|
+
const command = new Command("status");
|
|
637
|
+
command.description("\u67E5\u770B\u767B\u5F55\u72B6\u6001");
|
|
638
|
+
command.action(async () => {
|
|
639
|
+
try {
|
|
640
|
+
const loginService = new LoginService();
|
|
641
|
+
await loginService.status();
|
|
642
|
+
} catch (error) {
|
|
643
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
644
|
+
console.error(chalk.red(`\u274C ${errorMessage}`));
|
|
645
|
+
process.exit(1);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
return command;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/commands/business/pricing.ts
|
|
652
|
+
import { Command as Command2 } from "commander";
|
|
653
|
+
import chalk2 from "chalk";
|
|
654
|
+
function createPricingCommand() {
|
|
655
|
+
const command = new Command2("pricing");
|
|
656
|
+
command.description("\u57FA\u4E8E\u771F\u5B9E\u6210\u4EA4\u6570\u636E\u7ED9\u51FA\u6536\u8D27\u4EF7\u4E0E\u552E\u5356\u4EF7\u5EFA\u8BAE");
|
|
657
|
+
command.option("--sku <sku>", "\u5546\u54C1SKU");
|
|
658
|
+
command.option("--condition <condition>", "\u5546\u54C1\u6210\u8272");
|
|
659
|
+
command.action((options) => {
|
|
660
|
+
console.log(chalk2.blue("\u6B63\u5728\u5206\u6790\u4EF7\u683C\u6570\u636E..."));
|
|
661
|
+
console.log(chalk2.green(`SKU: ${options.sku || "\u5168\u90E8"}`));
|
|
662
|
+
console.log(chalk2.green(`\u6210\u8272: ${options.condition || "\u5168\u65B0"}`));
|
|
663
|
+
console.log(chalk2.yellow("\u{1F4B0} \u5EFA\u8BAE\u6536\u8D27\u4EF7: \xA58000"));
|
|
664
|
+
console.log(chalk2.yellow("\u{1F4B8} \u5EFA\u8BAE\u552E\u5356\u4EF7: \xA512000"));
|
|
665
|
+
console.log(chalk2.blue("\u4EF7\u683C\u5206\u6790\u5B8C\u6210\uFF01"));
|
|
666
|
+
});
|
|
667
|
+
return command;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/commands/business/report.ts
|
|
671
|
+
import { Command as Command3 } from "commander";
|
|
672
|
+
import chalk3 from "chalk";
|
|
673
|
+
function createReportCommand() {
|
|
674
|
+
const command = new Command3("report");
|
|
675
|
+
command.description("\u751F\u6210\u7ECF\u8425\u65E5\u62A5/\u5468\u62A5");
|
|
676
|
+
command.option("--type <type>", "\u62A5\u544A\u7C7B\u578B: daily, weekly", "daily");
|
|
677
|
+
command.action((options) => {
|
|
678
|
+
console.log(chalk3.blue(`\u751F\u6210${options.type === "daily" ? "\u65E5\u62A5" : "\u5468\u62A5"}...`));
|
|
679
|
+
console.log(chalk3.green("\u{1F4CA} \u9500\u552E\u6570\u636E"));
|
|
680
|
+
console.log(chalk3.green("\u{1F4C8} \u6BDB\u5229\u5206\u6790"));
|
|
681
|
+
console.log(chalk3.green("\u23F0 \u5E93\u9F84\u5206\u6790"));
|
|
682
|
+
console.log(chalk3.green("\u26A0\uFE0F \u5F02\u5E38\u6CE2\u52A8"));
|
|
683
|
+
console.log(chalk3.blue(`${options.type === "daily" ? "\u65E5\u62A5" : "\u5468\u62A5"}\u751F\u6210\u5B8C\u6210\uFF01`));
|
|
684
|
+
});
|
|
685
|
+
return command;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// src/commands/inventory/risk.ts
|
|
689
|
+
import { Command as Command4 } from "commander";
|
|
690
|
+
import chalk4 from "chalk";
|
|
691
|
+
function createRiskCommand() {
|
|
692
|
+
const command = new Command4("risk");
|
|
693
|
+
command.description("\u5E93\u5B58\u98CE\u9669\u8BC6\u522B");
|
|
694
|
+
command.option("--warehouse <warehouse>", "\u4ED3\u5E93\u4EE3\u7801");
|
|
695
|
+
command.action((options) => {
|
|
696
|
+
console.log(chalk4.blue("\u6B63\u5728\u8BC6\u522B\u5E93\u5B58\u98CE\u9669..."));
|
|
697
|
+
console.log(chalk4.green(`\u4ED3\u5E93: ${options.warehouse || "\u5168\u90E8"}`));
|
|
698
|
+
console.log(chalk4.yellow("\u26A0\uFE0F \u6EDE\u9500\u9884\u8B66: 15 \u4EF6\u5546\u54C1"));
|
|
699
|
+
console.log(chalk4.yellow("\u{1F4C9} \u8D2C\u503C\u901A\u9053: 8 \u4EF6\u5546\u54C1"));
|
|
700
|
+
console.log(chalk4.yellow("\u23F0 \u5E93\u9F84\u8D85\u671F: 5 \u4EF6\u5546\u54C1"));
|
|
701
|
+
console.log(chalk4.blue("\u5E93\u5B58\u98CE\u9669\u8BC6\u522B\u5B8C\u6210\uFF01"));
|
|
702
|
+
});
|
|
703
|
+
return command;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// src/commands/ai/chat.ts
|
|
707
|
+
import { Command as Command5 } from "commander";
|
|
708
|
+
import chalk5 from "chalk";
|
|
709
|
+
function createChatCommand() {
|
|
710
|
+
const command = new Command5("chat");
|
|
711
|
+
command.description("\u4E0E AI \u52A9\u624B\u804A\u5929\uFF0C\u83B7\u53D6\u7ECF\u8425\u5EFA\u8BAE");
|
|
712
|
+
command.action(() => {
|
|
713
|
+
console.log(chalk5.blue("\u6B63\u5728\u8FDE\u63A5 AI \u52A9\u624B..."));
|
|
714
|
+
console.log(chalk5.green("\u2705 \u5DF2\u8FDE\u63A5 Claude AI"));
|
|
715
|
+
console.log(chalk5.yellow("\u{1F4AC} \u8BF7\u8F93\u5165\u60A8\u7684\u95EE\u9898..."));
|
|
716
|
+
console.log(chalk5.gray("\u793A\u4F8B\uFF1A\u5206\u6790\u672C\u5468\u9500\u552E\u6570\u636E"));
|
|
717
|
+
console.log(chalk5.blue("AI \u804A\u5929\u529F\u80FD\u5F00\u53D1\u4E2D..."));
|
|
718
|
+
});
|
|
719
|
+
return command;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// src/commands/ai/skills.ts
|
|
723
|
+
import { Command as Command6 } from "commander";
|
|
724
|
+
import chalk6 from "chalk";
|
|
725
|
+
function createSkillsCommand() {
|
|
726
|
+
const command = new Command6("skills");
|
|
727
|
+
command.description("AI Agent \u6280\u80FD\u7BA1\u7406");
|
|
728
|
+
command.action(() => {
|
|
729
|
+
console.log(chalk6.blue("AI Agent \u6280\u80FD\u7BA1\u7406"));
|
|
730
|
+
console.log(chalk6.green("\u{1F527} \u5DF2\u5B89\u88C5\u7684\u6280\u80FD:"));
|
|
731
|
+
console.log(chalk6.green(" - \u7ECF\u8425\u5206\u6790"));
|
|
732
|
+
console.log(chalk6.green(" - \u4EF7\u683C\u67E5\u8BE2"));
|
|
733
|
+
console.log(chalk6.green(" - \u5E93\u5B58\u7BA1\u7406"));
|
|
734
|
+
console.log(chalk6.yellow("\u{1F4A1} \u4F7F\u7528 'r2 ai chat' \u5F00\u59CB\u5BF9\u8BDD"));
|
|
735
|
+
});
|
|
736
|
+
return command;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// src/commands/setup.ts
|
|
740
|
+
function setupCommands(program2) {
|
|
741
|
+
const authCommand = program2.command("auth").description("\u6388\u6743\u7BA1\u7406");
|
|
742
|
+
authCommand.addCommand(createLoginCommand());
|
|
743
|
+
authCommand.addCommand(createLogoutCommand());
|
|
744
|
+
authCommand.addCommand(createStatusCommand());
|
|
745
|
+
program2.command("ingest").description("\u5BF9\u63A5\u4E3B\u6D41 ERP\uFF0C\u7EDF\u4E00\u591A\u6E20\u9053\u7ECF\u8425\u6570\u636E").action(() => {
|
|
746
|
+
console.log(chalk7.blue("\u6B63\u5728\u5BF9\u63A5 ERP \u6570\u636E..."));
|
|
747
|
+
console.log(chalk7.green("\u2705 \u5DF2\u5BF9\u63A5\u7EBF\u4E0A\u7535\u5546\u6570\u636E"));
|
|
748
|
+
console.log(chalk7.green("\u2705 \u5DF2\u5BF9\u63A5\u7EBF\u4E0B\u95E8\u5E97\u6570\u636E"));
|
|
749
|
+
console.log(chalk7.green("\u2705 \u5DF2\u5BF9\u63A5\u4ED3\u50A8\u5C65\u7EA6\u6570\u636E"));
|
|
750
|
+
console.log(chalk7.blue("\u6570\u636E\u5BF9\u63A5\u5B8C\u6210\uFF01"));
|
|
751
|
+
});
|
|
752
|
+
const reportCommand = program2.command("report").description("\u751F\u6210\u7ECF\u8425\u65E5\u62A5/\u5468\u62A5");
|
|
753
|
+
reportCommand.addCommand(createReportCommand());
|
|
754
|
+
program2.command("ask").description("\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2\u7ECF\u8425\u6570\u636E").action(() => {
|
|
755
|
+
console.log("\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2\u529F\u80FD\u5F00\u53D1\u4E2D...");
|
|
756
|
+
});
|
|
757
|
+
const demandCommand = program2.command("demand").description("\u626B\u63CF\u5E02\u573A\u9700\u6C42\u70ED\u5EA6\u4E0E\u4F9B\u9700\u7F3A\u53E3");
|
|
758
|
+
demandCommand.option("--sku <sku>", "\u5546\u54C1SKU").option("--region <region>", "\u533A\u57DF").action((options) => {
|
|
759
|
+
console.log(chalk7.blue("\u6B63\u5728\u626B\u63CF\u5E02\u573A\u9700\u6C42..."));
|
|
760
|
+
console.log(chalk7.green(`SKU: ${options.sku || "\u5168\u90E8"}`));
|
|
761
|
+
console.log(chalk7.green(`\u533A\u57DF: ${options.region || "\u5168\u56FD"}`));
|
|
762
|
+
console.log(chalk7.yellow("\u{1F525} \u9700\u6C42\u70ED\u5EA6: \u9AD8"));
|
|
763
|
+
console.log(chalk7.yellow("\u{1F4C8} \u4F9B\u9700\u7F3A\u53E3: 20%"));
|
|
764
|
+
console.log(chalk7.blue("\u5E02\u573A\u9700\u6C42\u5206\u6790\u5B8C\u6210\uFF01"));
|
|
765
|
+
});
|
|
766
|
+
const pricingCommand = program2.command("pricing").description("\u57FA\u4E8E\u771F\u5B9E\u6210\u4EA4\u6570\u636E\u7ED9\u51FA\u6536\u8D27\u4EF7\u4E0E\u552E\u5356\u4EF7\u5EFA\u8BAE");
|
|
767
|
+
pricingCommand.addCommand(createPricingCommand());
|
|
768
|
+
const inventoryCommand = program2.command("inventory").description("\u5E93\u5B58\u7BA1\u7406");
|
|
769
|
+
inventoryCommand.addCommand(createRiskCommand());
|
|
770
|
+
program2.command("fulfillment").description("\u5C65\u7EA6\u5168\u94FE\u8DEF\u8FFD\u8E2A").action(() => {
|
|
771
|
+
console.log(chalk7.blue("\u6B63\u5728\u8FFD\u8E2A\u5C65\u7EA6\u5168\u94FE\u8DEF..."));
|
|
772
|
+
console.log(chalk7.green("\u{1F4E6} \u6536\u8D27: \u5B8C\u6210"));
|
|
773
|
+
console.log(chalk7.green("\u{1F50D} \u8D28\u68C0: \u5B8C\u6210"));
|
|
774
|
+
console.log(chalk7.green("\u{1F3E0} \u5165\u5E93: \u5B8C\u6210"));
|
|
775
|
+
console.log(chalk7.green("\u{1F69A} \u53D1\u8D27: \u8FDB\u884C\u4E2D"));
|
|
776
|
+
console.log(chalk7.blue("\u5C65\u7EA6\u8FFD\u8E2A\u5B8C\u6210\uFF01"));
|
|
777
|
+
});
|
|
778
|
+
const aiCommand = program2.command("ai").description("AI \u76F8\u5173\u529F\u80FD");
|
|
779
|
+
aiCommand.addCommand(createChatCommand());
|
|
780
|
+
aiCommand.addCommand(createSkillsCommand());
|
|
781
|
+
const simulateCommand = program2.command("simulate").description("\u7ADE\u4EF7\u6210\u4EA4\u6A21\u62DF");
|
|
782
|
+
simulateCommand.option("--sku <sku>", "\u5546\u54C1SKU").option("--price <price>", "\u51FA\u4EF7").action((options) => {
|
|
783
|
+
console.log(chalk7.blue("\u6B63\u5728\u6A21\u62DF\u7ADE\u4EF7\u6210\u4EA4..."));
|
|
784
|
+
console.log(chalk7.green(`SKU: ${options.sku}`));
|
|
785
|
+
console.log(chalk7.green(`\u51FA\u4EF7: \xA5${options.price}`));
|
|
786
|
+
console.log(chalk7.yellow("\u{1F4CA} \u9884\u4F30\u6210\u4EA4\u7387: 85%"));
|
|
787
|
+
console.log(chalk7.yellow("\u{1F4B0} \u9884\u4F30\u5229\u6DA6\u7A7A\u95F4: 15%"));
|
|
788
|
+
console.log(chalk7.blue("\u7ADE\u4EF7\u6A21\u62DF\u5B8C\u6210\uFF01"));
|
|
789
|
+
});
|
|
790
|
+
program2.command("bidding-strategy").description("\u57FA\u4E8E\u9884\u7B97\u4E0E\u54C1\u7C7B\u751F\u6210\u7ADE\u4EF7\u7B56\u7565\u5EFA\u8BAE").action(() => {
|
|
791
|
+
console.log(chalk7.blue("\u6B63\u5728\u751F\u6210\u7ADE\u4EF7\u7B56\u7565..."));
|
|
792
|
+
console.log(chalk7.green("\u{1F3AF} \u7B56\u7565\u76EE\u6807: \u6700\u5927\u5316\u6210\u4EA4\u7387"));
|
|
793
|
+
console.log(chalk7.green("\u{1F4B8} \u9884\u7B97\u5206\u914D: \u9AD8\u9700\u6C42\u54C1\u7C7B 60%\uFF0C\u4E2D\u9700\u6C42\u54C1\u7C7B 30%\uFF0C\u4F4E\u9700\u6C42\u54C1\u7C7B 10%"));
|
|
794
|
+
console.log(chalk7.yellow("\u{1F4C8} \u5EFA\u8BAE\u51FA\u4EF7\u533A\u95F4: \xA5800-\xA51200"));
|
|
795
|
+
console.log(chalk7.blue("\u7ADE\u4EF7\u7B56\u7565\u751F\u6210\u5B8C\u6210\uFF01"));
|
|
796
|
+
});
|
|
797
|
+
const decideCommand = program2.command("decide").description("\u7EFC\u5408\u6570\u636E\u8F93\u51FA\u7ECF\u8425\u52A8\u4F5C\u5EFA\u8BAE");
|
|
798
|
+
decideCommand.option("--store <store>", "\u5E97\u94FA\u4EE3\u7801").option("--horizon <horizon>", "\u9884\u6D4B\u5468\u671F").action((options) => {
|
|
799
|
+
console.log(chalk7.blue("\u6B63\u5728\u5206\u6790\u7ECF\u8425\u6570\u636E..."));
|
|
800
|
+
console.log(chalk7.green(`\u5E97\u94FA: ${options.store || "\u5168\u90E8"}`));
|
|
801
|
+
console.log(chalk7.green(`\u9884\u6D4B\u5468\u671F: ${options.horizon || "7d"}`));
|
|
802
|
+
console.log(chalk7.yellow("\u{1F4C8} \u8865\u8D27\u5EFA\u8BAE: Air Jordan 1 Retro High OG (20 \u53CC)"));
|
|
803
|
+
console.log(chalk7.yellow("\u{1F4C9} \u6E05\u4ED3\u5EFA\u8BAE: Louis Vuitton Neverfull (5 \u4E2A)"));
|
|
804
|
+
console.log(chalk7.yellow("\u{1F4B0} \u8C03\u8C03\u4EF7\u5EFA\u8BAE: Chanel Classic Flap (\u4E0A\u8C03 5%)"));
|
|
805
|
+
console.log(chalk7.yellow("\u26A0\uFE0F \u98CE\u63A7\u5EFA\u8BAE: \u52A0\u5F3A\u9AD8\u4EF7\u503C\u5546\u54C1\u7684\u8D28\u68C0\u6D41\u7A0B"));
|
|
806
|
+
console.log(chalk7.blue("\u7ECF\u8425\u51B3\u7B56\u5EFA\u8BAE\u751F\u6210\u5B8C\u6210\uFF01"));
|
|
807
|
+
});
|
|
808
|
+
program2.command("agent").description("AI Agent \u96C6\u6210").action(() => {
|
|
809
|
+
console.log(chalk7.blue("AI Agent \u96C6\u6210"));
|
|
810
|
+
console.log(chalk7.green("\u{1F527} \u652F\u6301\u7684 AI Agent \u6846\u67B6:"));
|
|
811
|
+
console.log(chalk7.green(" - Claude Code"));
|
|
812
|
+
console.log(chalk7.green(" - OpenClaw"));
|
|
813
|
+
console.log(chalk7.green(" - Codex"));
|
|
814
|
+
console.log(chalk7.blue("\u5B89\u88C5 Agent Skills:"));
|
|
815
|
+
console.log(chalk7.yellow("npx skills add Round2AI/r2-cli --all -y"));
|
|
816
|
+
console.log(chalk7.blue("AI Agent \u96C6\u6210\u5B8C\u6210\uFF01"));
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/index.ts
|
|
821
|
+
function displayWelcomeMessage() {
|
|
822
|
+
console.log(
|
|
823
|
+
chalk8.cyan(
|
|
824
|
+
figlet.textSync("R2-CLI", {
|
|
825
|
+
font: "Standard",
|
|
826
|
+
horizontalLayout: "full"
|
|
827
|
+
})
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
console.log(chalk8.gray("\u5411 AI \u5F00\u653E\u4E8C\u624B\u6F6E\u5962\u4EA4\u6613\u5168\u94FE\u8DEF\u80FD\u529B\n"));
|
|
831
|
+
}
|
|
832
|
+
function setupCliApp() {
|
|
833
|
+
displayWelcomeMessage();
|
|
834
|
+
const pkgJson = fse.readJSONSync(path2.join(import.meta.dirname, "../package.json"));
|
|
835
|
+
const program2 = new Command8();
|
|
836
|
+
program2.name("r2").description("R2-CLI\uFF0C\u5411 AI \u5F00\u653E\u4E8C\u624B\u6F6E\u5962\u4EA4\u6613\u5168\u94FE\u8DEF\u80FD\u529B").version(pkgJson.version, "-v, --version");
|
|
837
|
+
program2.configureOutput({
|
|
230
838
|
writeErr: (str) => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
|
|
839
|
+
const error = str.replace("error:", "").trim();
|
|
840
|
+
console.error(`\u274C \u9519\u8BEF: ${error}`);
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
setupCommands(program2);
|
|
844
|
+
return program2;
|
|
845
|
+
}
|
|
846
|
+
var program = setupCliApp();
|
|
847
|
+
program.parse(process.argv);
|
|
848
|
+
//# sourceMappingURL=index.js.map
|