rl-rockcli 0.0.1
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/LICENSE +21 -0
- package/bin/rockcli.js +40 -0
- package/package.json +62 -0
- package/src/core/commands/attach/index.js +242 -0
- package/src/core/commands/log/constants.js +20 -0
- package/src/core/commands/log/index.js +94 -0
- package/src/core/commands/log/search.js +106 -0
- package/src/core/commands/sandbox/index.js +428 -0
- package/src/core/config/index.js +77 -0
- package/src/core/display/constants.js +59 -0
- package/src/core/display/format.js +178 -0
- package/src/core/display/highlight.js +34 -0
- package/src/core/index.js +55 -0
- package/src/core/providers/index.js +9 -0
- package/src/core/providers/log-provider.js +79 -0
- package/src/core/sdks/sandbox/client.js +472 -0
- package/src/core/sdks/sandbox/config.js +57 -0
- package/src/core/sdks/sandbox/index.js +13 -0
- package/src/core/sdks/sandbox/types.js +5 -0
- package/src/core/utils/index.js +9 -0
- package/src/core/utils/logger.js +106 -0
- package/src/core/utils/time.js +52 -0
- package/src/plugins/oss-file-log/file-client.js +186 -0
- package/src/plugins/oss-file-log/index.js +18 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sandbox 命令实现
|
|
3
|
+
* 开源版 sandbox 命令
|
|
4
|
+
* 格式: rockcli sandbox <id> <command>
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { SandboxClient, SandboxConfig, getOpenSourceSandboxConfig } = require('../../sdks/sandbox');
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const logger = require('../../utils/logger');
|
|
11
|
+
|
|
12
|
+
// 配置文件路径
|
|
13
|
+
const CONFIG_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.rock');
|
|
14
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'settings.json');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 读取配置文件
|
|
18
|
+
*/
|
|
19
|
+
function readConfig() {
|
|
20
|
+
try {
|
|
21
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
22
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
23
|
+
}
|
|
24
|
+
} catch (error) {
|
|
25
|
+
logger.debug(`Failed to read config: ${error.message}`);
|
|
26
|
+
}
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 获取 API Key(优先级:参数 > 环境变量 > 配置文件)
|
|
32
|
+
*/
|
|
33
|
+
function getApiKey(argv) {
|
|
34
|
+
return argv.apiKey || process.env.ROCK_API_KEY || readConfig()?.sandbox?.api_key;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 读取 sandbox 配置
|
|
39
|
+
* 优先级:环境变量 > argv > 配置文件 > 默认值
|
|
40
|
+
*/
|
|
41
|
+
function readSandboxConfig(argv = {}) {
|
|
42
|
+
const config = readConfig();
|
|
43
|
+
const sandboxConfig = config?.sandbox || {};
|
|
44
|
+
const defaults = getOpenSourceSandboxConfig();
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
// 环境变量优先于 argv(yargs 默认值)
|
|
48
|
+
base_url: process.env.ROCK_BASE_URL || argv.baseUrl || sandboxConfig.base_url || defaults.baseUrl,
|
|
49
|
+
api_key: getApiKey(argv),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 创建 SandboxClient
|
|
55
|
+
* @param {Object} argv - 命令行参数
|
|
56
|
+
* @param {Object} options - 可选配置
|
|
57
|
+
* @param {boolean} options.requireImage - 是否要求 image 参数(默认 true)
|
|
58
|
+
*/
|
|
59
|
+
function createClient(argv, options = {}) {
|
|
60
|
+
const config = readSandboxConfig(argv);
|
|
61
|
+
const sdkConfig = new SandboxConfig({
|
|
62
|
+
baseUrl: config.base_url,
|
|
63
|
+
xrlAuthorization: config.api_key,
|
|
64
|
+
image: argv.image,
|
|
65
|
+
memory: argv.memory,
|
|
66
|
+
cpus: argv.cpus,
|
|
67
|
+
startupTimeout: argv.timeout,
|
|
68
|
+
autoClearSeconds: argv.autoClear,
|
|
69
|
+
waitForAlive: argv.waitForAlive,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return new SandboxClient(sdkConfig, { requireImage: options.requireImage !== false });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* sandbox 命令模块
|
|
77
|
+
* 格式: rockcli sandbox <id> <command>
|
|
78
|
+
*/
|
|
79
|
+
module.exports = {
|
|
80
|
+
command: 'sandbox [id] [subcommand]',
|
|
81
|
+
describe: 'Sandbox instance management',
|
|
82
|
+
builder: (yargs) => {
|
|
83
|
+
return yargs
|
|
84
|
+
.positional('id', {
|
|
85
|
+
describe: 'Sandbox ID (for operations on existing sandbox)',
|
|
86
|
+
type: 'string',
|
|
87
|
+
})
|
|
88
|
+
.positional('subcommand', {
|
|
89
|
+
describe: 'Sandbox command to perform (status, stop, exec, upload, download, log)',
|
|
90
|
+
type: 'string',
|
|
91
|
+
})
|
|
92
|
+
.option('api-key', {
|
|
93
|
+
describe: 'API key for authentication',
|
|
94
|
+
type: 'string',
|
|
95
|
+
})
|
|
96
|
+
.option('base-url', {
|
|
97
|
+
describe: 'Base URL for sandbox service',
|
|
98
|
+
type: 'string',
|
|
99
|
+
default: 'http://localhost:8080',
|
|
100
|
+
})
|
|
101
|
+
.option('image', {
|
|
102
|
+
describe: 'Docker image to use (for start)',
|
|
103
|
+
type: 'string',
|
|
104
|
+
})
|
|
105
|
+
.option('memory', {
|
|
106
|
+
describe: 'Memory limit',
|
|
107
|
+
type: 'string',
|
|
108
|
+
default: '8g',
|
|
109
|
+
})
|
|
110
|
+
.option('cpus', {
|
|
111
|
+
describe: 'CPU limit',
|
|
112
|
+
type: 'number',
|
|
113
|
+
default: 2.0,
|
|
114
|
+
})
|
|
115
|
+
.option('timeout', {
|
|
116
|
+
describe: 'Startup timeout in seconds',
|
|
117
|
+
type: 'number',
|
|
118
|
+
default: 120,
|
|
119
|
+
})
|
|
120
|
+
.option('auto-clear', {
|
|
121
|
+
describe: 'Auto clear time in seconds',
|
|
122
|
+
type: 'number',
|
|
123
|
+
default: 300,
|
|
124
|
+
})
|
|
125
|
+
.option('wait-for-alive', {
|
|
126
|
+
describe: 'Wait for sandbox to be alive before returning',
|
|
127
|
+
type: 'boolean',
|
|
128
|
+
default: false,
|
|
129
|
+
})
|
|
130
|
+
.option('command', {
|
|
131
|
+
describe: 'Command to execute (for exec)',
|
|
132
|
+
type: 'string',
|
|
133
|
+
})
|
|
134
|
+
.option('file', {
|
|
135
|
+
describe: 'File path for upload/download',
|
|
136
|
+
type: 'string',
|
|
137
|
+
})
|
|
138
|
+
.option('target-path', {
|
|
139
|
+
describe: 'Target path for upload',
|
|
140
|
+
type: 'string',
|
|
141
|
+
})
|
|
142
|
+
.option('session', {
|
|
143
|
+
describe: 'Session name',
|
|
144
|
+
type: 'string',
|
|
145
|
+
})
|
|
146
|
+
.strict(false) // Allow unknown options for subcommands
|
|
147
|
+
.example([
|
|
148
|
+
['$0 sandbox start', 'Start a new sandbox (default: python:3.11)'],
|
|
149
|
+
['$0 sandbox start --image node:18', 'Start a new sandbox with custom image'],
|
|
150
|
+
['$0 sandbox <id> status', 'Get sandbox status'],
|
|
151
|
+
['$0 sandbox <id> stop', 'Stop sandbox'],
|
|
152
|
+
['$0 sandbox <id> exec --command "ls -la"', 'Execute command in sandbox'],
|
|
153
|
+
['$0 sandbox <id> upload --file ./local.txt --target-path /remote.txt', 'Upload file'],
|
|
154
|
+
]);
|
|
155
|
+
},
|
|
156
|
+
handler: async (argv) => {
|
|
157
|
+
try {
|
|
158
|
+
// Rebuild argv._ from process.argv to preserve all original arguments
|
|
159
|
+
const rawArgs = process.argv.slice(2);
|
|
160
|
+
argv._ = rawArgs.filter(arg => !arg.startsWith('-'));
|
|
161
|
+
|
|
162
|
+
const id = argv.id;
|
|
163
|
+
const subcommand = argv.subcommand;
|
|
164
|
+
|
|
165
|
+
// 特殊处理:如果 id 是 "start",则识别为 start 命令
|
|
166
|
+
if (id === 'start' && !subcommand) {
|
|
167
|
+
await handleStart(argv);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 判断命令格式
|
|
172
|
+
if (!id) {
|
|
173
|
+
// 无 ID 参数,检查是否是 start 命令
|
|
174
|
+
const firstArg = rawArgs[rawArgs.indexOf('sandbox') + 1];
|
|
175
|
+
if (firstArg === 'start') {
|
|
176
|
+
await handleStart(argv);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// 显示帮助
|
|
180
|
+
console.log('Sandbox commands:');
|
|
181
|
+
console.log(' rockcli sandbox start Start a new sandbox (default: python:3.11)');
|
|
182
|
+
console.log(' rockcli sandbox start --image <image> Start a new sandbox with custom image');
|
|
183
|
+
console.log(' rockcli sandbox <id> status Get sandbox status');
|
|
184
|
+
console.log(' rockcli sandbox <id> stop Stop sandbox');
|
|
185
|
+
console.log(' rockcli sandbox <id> exec --command "cmd" Execute command');
|
|
186
|
+
console.log(' rockcli sandbox <id> upload --file <file> Upload file');
|
|
187
|
+
console.log(' rockcli sandbox <id> download --file <file> Download file');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 有 ID 参数,执行对应的子命令
|
|
192
|
+
switch (subcommand) {
|
|
193
|
+
case 'status':
|
|
194
|
+
await handleStatus(argv, id);
|
|
195
|
+
break;
|
|
196
|
+
case 'stop':
|
|
197
|
+
await handleStop(argv, id);
|
|
198
|
+
break;
|
|
199
|
+
case 'exec':
|
|
200
|
+
case 'execute':
|
|
201
|
+
await handleExec(argv, id);
|
|
202
|
+
break;
|
|
203
|
+
case 'upload':
|
|
204
|
+
await handleUpload(argv, id);
|
|
205
|
+
break;
|
|
206
|
+
case 'download':
|
|
207
|
+
await handleDownload(argv, id);
|
|
208
|
+
break;
|
|
209
|
+
case 'session':
|
|
210
|
+
await handleSession(argv, id);
|
|
211
|
+
break;
|
|
212
|
+
case 'replay':
|
|
213
|
+
await handleReplay(argv, id);
|
|
214
|
+
break;
|
|
215
|
+
case 'log':
|
|
216
|
+
await handleLog(argv, id);
|
|
217
|
+
break;
|
|
218
|
+
case 'start':
|
|
219
|
+
// start 命令不应该有 ID
|
|
220
|
+
await handleStart(argv);
|
|
221
|
+
break;
|
|
222
|
+
default:
|
|
223
|
+
if (subcommand) {
|
|
224
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
225
|
+
} else {
|
|
226
|
+
console.log(`Sandbox ID: ${id}`);
|
|
227
|
+
console.log('Available commands: status, stop, exec, upload, download, log');
|
|
228
|
+
}
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
} catch (error) {
|
|
232
|
+
logger.error(`Sandbox action failed: ${error.message}`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 处理 start 命令
|
|
240
|
+
* 与内网版保持一致:默认镜像通过 getOpenSourceSandboxConfig() 获取
|
|
241
|
+
*/
|
|
242
|
+
async function handleStart(argv) {
|
|
243
|
+
const { getOpenSourceSandboxConfig } = require('../../sdks/sandbox/config');
|
|
244
|
+
const defaults = getOpenSourceSandboxConfig();
|
|
245
|
+
const image = argv.image || defaults.image;
|
|
246
|
+
|
|
247
|
+
const client = createClient({ ...argv, image });
|
|
248
|
+
const result = await client.start();
|
|
249
|
+
|
|
250
|
+
console.log('Sandbox started successfully');
|
|
251
|
+
console.log(`Sandbox ID: ${result.sandboxId}`);
|
|
252
|
+
console.log(`Image: ${image}`);
|
|
253
|
+
console.log(`Host: ${result.hostName || result.hostIp || 'N/A'}`);
|
|
254
|
+
console.log(`Status: ${result.isAlive ? 'ready' : 'starting'}`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 处理 stop 命令
|
|
259
|
+
*/
|
|
260
|
+
async function handleStop(argv, sandboxId) {
|
|
261
|
+
if (!sandboxId) {
|
|
262
|
+
throw new Error('Sandbox ID is required for stop');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const client = createClient(argv, { requireImage: false });
|
|
266
|
+
client._sandboxId = sandboxId;
|
|
267
|
+
await client.stop();
|
|
268
|
+
|
|
269
|
+
console.log(`Sandbox ${sandboxId} stopped successfully`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 处理 status 命令
|
|
274
|
+
*/
|
|
275
|
+
async function handleStatus(argv, sandboxId) {
|
|
276
|
+
if (!sandboxId) {
|
|
277
|
+
throw new Error('Sandbox ID is required for status');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const client = createClient(argv, { requireImage: false });
|
|
281
|
+
client._sandboxId = sandboxId;
|
|
282
|
+
const status = await client.getStatus();
|
|
283
|
+
|
|
284
|
+
console.log(JSON.stringify(status, null, 2));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* 处理 exec 命令
|
|
289
|
+
*/
|
|
290
|
+
async function handleExec(argv, sandboxId) {
|
|
291
|
+
const command = argv.command;
|
|
292
|
+
|
|
293
|
+
if (!sandboxId) {
|
|
294
|
+
throw new Error('Sandbox ID is required for exec');
|
|
295
|
+
}
|
|
296
|
+
if (!command) {
|
|
297
|
+
throw new Error('--command is required for exec');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const client = createClient(argv, { requireImage: false });
|
|
301
|
+
client._sandboxId = sandboxId;
|
|
302
|
+
const result = await client.execute(command);
|
|
303
|
+
|
|
304
|
+
if (result.stdout) console.log(result.stdout);
|
|
305
|
+
if (result.stderr) console.error(result.stderr);
|
|
306
|
+
process.exit(result.exit_code || 0);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 处理 upload 命令
|
|
311
|
+
*/
|
|
312
|
+
async function handleUpload(argv, sandboxId) {
|
|
313
|
+
const localPath = argv.file;
|
|
314
|
+
const targetPath = argv.targetPath;
|
|
315
|
+
|
|
316
|
+
if (!sandboxId || !localPath || !targetPath) {
|
|
317
|
+
throw new Error('Sandbox ID, --file, and --target-path are required for upload');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const client = createClient(argv, { requireImage: false });
|
|
321
|
+
client._sandboxId = sandboxId;
|
|
322
|
+
const result = await client.uploadFile(localPath, targetPath);
|
|
323
|
+
|
|
324
|
+
if (result.success) {
|
|
325
|
+
console.log(result.message);
|
|
326
|
+
} else {
|
|
327
|
+
throw new Error(result.message);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* 处理 download 命令
|
|
333
|
+
*/
|
|
334
|
+
async function handleDownload(argv, sandboxId) {
|
|
335
|
+
const filePath = argv.file;
|
|
336
|
+
|
|
337
|
+
if (!sandboxId || !filePath) {
|
|
338
|
+
throw new Error('Sandbox ID and --file are required for download');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const client = createClient(argv, { requireImage: false });
|
|
342
|
+
client._sandboxId = sandboxId;
|
|
343
|
+
const result = await client.downloadFile(filePath);
|
|
344
|
+
|
|
345
|
+
console.log(result.content || JSON.stringify(result, null, 2));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* 处理 session 命令
|
|
350
|
+
*/
|
|
351
|
+
async function handleSession(argv, sandboxId) {
|
|
352
|
+
const sessionName = argv.session || 'default';
|
|
353
|
+
|
|
354
|
+
if (!sandboxId) {
|
|
355
|
+
throw new Error('Sandbox ID is required for session');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const client = createClient(argv, { requireImage: false });
|
|
359
|
+
client._sandboxId = sandboxId;
|
|
360
|
+
|
|
361
|
+
// 简化版:创建 session
|
|
362
|
+
const result = await client.createSession({ session: sessionName });
|
|
363
|
+
console.log(`Session '${sessionName}' created`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 处理 replay 命令
|
|
368
|
+
*/
|
|
369
|
+
async function handleReplay(argv, sandboxId) {
|
|
370
|
+
if (!sandboxId) {
|
|
371
|
+
throw new Error('Sandbox ID is required for replay');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// 从 stdin 读取 JSON
|
|
375
|
+
const readline = require('readline');
|
|
376
|
+
const rl = readline.createInterface({
|
|
377
|
+
input: process.stdin,
|
|
378
|
+
terminal: false,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
const requests = [];
|
|
382
|
+
for await (const line of rl) {
|
|
383
|
+
try {
|
|
384
|
+
requests.push(JSON.parse(line));
|
|
385
|
+
} catch (e) {
|
|
386
|
+
// 跳过无效行
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (requests.length === 0) {
|
|
391
|
+
throw new Error('No valid requests found in stdin');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const client = createClient(argv, { requireImage: false });
|
|
395
|
+
client._sandboxId = sandboxId;
|
|
396
|
+
|
|
397
|
+
console.log(`Replaying ${requests.length} requests...`);
|
|
398
|
+
|
|
399
|
+
for (let i = 0; i < requests.length; i++) {
|
|
400
|
+
const req = requests[i];
|
|
401
|
+
console.log(`[${i + 1}/${requests.length}] ${req.method} ${req.uri}`);
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
const result = await client.makeRequest(req);
|
|
405
|
+
console.log(` Status: ${result.status}`);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.error(` Error: ${error.message}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
console.log('Replay completed');
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* 处理 log 命令
|
|
416
|
+
*/
|
|
417
|
+
async function handleLog(argv, sandboxId) {
|
|
418
|
+
if (!sandboxId) {
|
|
419
|
+
throw new Error('Sandbox ID is required for log');
|
|
420
|
+
}
|
|
421
|
+
// 日志功能通过 log 命令实现
|
|
422
|
+
console.log(`Log command for sandbox ${sandboxId}`);
|
|
423
|
+
console.log('Use: rockcli log search --sandbox-id ' + sandboxId);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// 导出辅助函数
|
|
427
|
+
module.exports.readSandboxConfig = readSandboxConfig;
|
|
428
|
+
module.exports.createClient = createClient;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 开源版配置模块
|
|
3
|
+
* 管理配置文件和环境变量
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
// 配置路径
|
|
10
|
+
const CONFIG_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '/tmp', '.rock');
|
|
11
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'settings.json');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 读取配置文件
|
|
15
|
+
* @returns {Object} 配置对象
|
|
16
|
+
*/
|
|
17
|
+
function readConfig() {
|
|
18
|
+
try {
|
|
19
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
20
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
// 忽略错误,返回空配置
|
|
24
|
+
}
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 写入配置文件
|
|
30
|
+
* @param {Object} config - 配置对象
|
|
31
|
+
*/
|
|
32
|
+
function writeConfig(config) {
|
|
33
|
+
fs.ensureDirSync(CONFIG_DIR);
|
|
34
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 获取 API Key
|
|
39
|
+
* 优先级:参数 > 环境变量 > 配置文件
|
|
40
|
+
* @param {Object} argv - 命令行参数
|
|
41
|
+
* @returns {string|null}
|
|
42
|
+
*/
|
|
43
|
+
function getApiKey(argv = {}) {
|
|
44
|
+
return argv.apiKey || process.env.ROCK_API_KEY || readConfig()?.sandbox?.api_key || null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 获取 Base URL
|
|
49
|
+
* 优先级:参数 > 环境变量 > 配置文件 > 默认值
|
|
50
|
+
* @param {Object} argv - 命令行参数
|
|
51
|
+
* @returns {string}
|
|
52
|
+
*/
|
|
53
|
+
function getBaseUrl(argv = {}) {
|
|
54
|
+
return argv.baseUrl || process.env.ROCK_BASE_URL || readConfig()?.sandbox?.base_url || 'http://localhost:8080';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 获取 Sandbox 配置
|
|
59
|
+
* @param {Object} argv - 命令行参数
|
|
60
|
+
* @returns {Object}
|
|
61
|
+
*/
|
|
62
|
+
function getSandboxConfig(argv = {}) {
|
|
63
|
+
return {
|
|
64
|
+
base_url: getBaseUrl(argv),
|
|
65
|
+
api_key: getApiKey(argv),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
CONFIG_DIR,
|
|
71
|
+
CONFIG_FILE,
|
|
72
|
+
readConfig,
|
|
73
|
+
writeConfig,
|
|
74
|
+
getApiKey,
|
|
75
|
+
getBaseUrl,
|
|
76
|
+
getSandboxConfig,
|
|
77
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 展示层常量定义
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 默认显示字段(通用字段)
|
|
6
|
+
const DISPLAY_FIELDS = [
|
|
7
|
+
'timestamp',
|
|
8
|
+
'time_iso8601',
|
|
9
|
+
'level',
|
|
10
|
+
'sandbox_id',
|
|
11
|
+
'trace_id',
|
|
12
|
+
'request_id',
|
|
13
|
+
'method',
|
|
14
|
+
'url',
|
|
15
|
+
'status',
|
|
16
|
+
'message',
|
|
17
|
+
'event',
|
|
18
|
+
'content',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// 字段颜色映射(ANSI 颜色代码)
|
|
22
|
+
const FIELD_COLOR_MAP = {
|
|
23
|
+
// 时间/级别/消息: 高亮
|
|
24
|
+
timestamp: '\x1b[1;36m',
|
|
25
|
+
time_iso8601: '\x1b[1;36m',
|
|
26
|
+
level: '\x1b[1;36m',
|
|
27
|
+
message: '\x1b[1;36m',
|
|
28
|
+
// 错误/异常: 红色
|
|
29
|
+
error: '\x1b[1;31m',
|
|
30
|
+
exception: '\x1b[1;31m',
|
|
31
|
+
// 其它常用上下文字段
|
|
32
|
+
sandbox_id: '\x1b[0;36m',
|
|
33
|
+
trace_id: '\x1b[0;36m',
|
|
34
|
+
request_id: '\x1b[0;36m',
|
|
35
|
+
method: '\x1b[0;36m',
|
|
36
|
+
url: '\x1b[0;36m',
|
|
37
|
+
status: '\x1b[0;36m',
|
|
38
|
+
event: '\x1b[0;36m',
|
|
39
|
+
content: '\x1b[0;36m',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// 默认字段颜色
|
|
43
|
+
const DEFAULT_FIELD_COLOR = '\x1b[0;90m';
|
|
44
|
+
|
|
45
|
+
// 需要截断的字段
|
|
46
|
+
const TRUNCATE_FIELDS = ['message', 'content', 'event'];
|
|
47
|
+
|
|
48
|
+
// ANSI 颜色控制码
|
|
49
|
+
const ANSI_COLORS = {
|
|
50
|
+
RESET: '\x1b[0m',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
DISPLAY_FIELDS,
|
|
55
|
+
FIELD_COLOR_MAP,
|
|
56
|
+
DEFAULT_FIELD_COLOR,
|
|
57
|
+
TRUNCATE_FIELDS,
|
|
58
|
+
ANSI_COLORS,
|
|
59
|
+
};
|