rl-rockcli 0.0.2 → 0.0.4
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 +400 -0
- package/index.js +51 -21
- package/package.json +3 -2
- package/commands/log/core/constants.js +0 -237
- package/commands/log/core/display.js +0 -370
- package/commands/log/core/search.js +0 -330
- package/commands/log/core/tail.js +0 -216
- package/commands/log/core/utils.js +0 -424
- package/commands/log.js +0 -298
- package/commands/sandbox/core/log-bridge.js +0 -119
- package/commands/sandbox/core/replay/analyzer.js +0 -311
- package/commands/sandbox/core/replay/batch-orchestrator.js +0 -536
- package/commands/sandbox/core/replay/batch-task.js +0 -369
- package/commands/sandbox/core/replay/concurrent-display.js +0 -70
- package/commands/sandbox/core/replay/concurrent-orchestrator.js +0 -170
- package/commands/sandbox/core/replay/data-source.js +0 -86
- package/commands/sandbox/core/replay/display.js +0 -231
- package/commands/sandbox/core/replay/executor.js +0 -634
- package/commands/sandbox/core/replay/history-fetcher.js +0 -124
- package/commands/sandbox/core/replay/index.js +0 -338
- package/commands/sandbox/core/replay/loghouse-data-source.js +0 -177
- package/commands/sandbox/core/replay/pid-mapping.js +0 -26
- package/commands/sandbox/core/replay/request.js +0 -109
- package/commands/sandbox/core/replay/worker.js +0 -166
- package/commands/sandbox/core/session.js +0 -346
- package/commands/sandbox/log-bridge.js +0 -2
- package/commands/sandbox/ray.js +0 -2
- package/commands/sandbox/replay/analyzer.js +0 -311
- package/commands/sandbox/replay/batch-orchestrator.js +0 -536
- package/commands/sandbox/replay/batch-task.js +0 -369
- package/commands/sandbox/replay/concurrent-display.js +0 -70
- package/commands/sandbox/replay/concurrent-orchestrator.js +0 -170
- package/commands/sandbox/replay/display.js +0 -231
- package/commands/sandbox/replay/executor.js +0 -634
- package/commands/sandbox/replay/history-fetcher.js +0 -118
- package/commands/sandbox/replay/index.js +0 -338
- package/commands/sandbox/replay/pid-mapping.js +0 -26
- package/commands/sandbox/replay/request.js +0 -109
- package/commands/sandbox/replay/worker.js +0 -166
- package/commands/sandbox/replay.js +0 -2
- package/commands/sandbox/session.js +0 -2
- package/commands/sandbox-original.js +0 -1393
- package/commands/sandbox.js +0 -499
- package/help/help.json +0 -1071
- package/help/middleware.js +0 -71
- package/help/renderer.js +0 -800
- package/lib/plugin-context.js +0 -40
- package/sdks/sandbox/core/client.js +0 -845
- package/sdks/sandbox/core/config.js +0 -70
- package/sdks/sandbox/core/types.js +0 -74
- package/sdks/sandbox/httpLogger.js +0 -251
- package/sdks/sandbox/index.js +0 -9
- package/utils/asciiArt.js +0 -138
- package/utils/bun-compat.js +0 -59
- package/utils/ciPipelines.js +0 -138
- package/utils/cli.js +0 -17
- package/utils/command-router.js +0 -79
- package/utils/configManager.js +0 -503
- package/utils/dependency-resolver.js +0 -135
- package/utils/eagleeye_traceid.js +0 -151
- package/utils/envDetector.js +0 -78
- package/utils/execution_logger.js +0 -415
- package/utils/featureManager.js +0 -68
- package/utils/firstTimeTip.js +0 -44
- package/utils/hook-manager.js +0 -125
- package/utils/http-logger.js +0 -264
- package/utils/i18n.js +0 -139
- package/utils/image-progress.js +0 -159
- package/utils/logger.js +0 -154
- package/utils/plugin-loader.js +0 -124
- package/utils/plugin-manager.js +0 -348
- package/utils/ray_cli_wrapper.js +0 -746
- package/utils/sandbox-client.js +0 -419
- package/utils/terminal.js +0 -32
- package/utils/tips.js +0 -106
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 请求分类常量
|
|
3
|
-
*/
|
|
4
|
-
const RequestCategory = {
|
|
5
|
-
STARTUP: 'startup', // start_async
|
|
6
|
-
STARTUP_POLLING: 'startup_polling', // get_status after start
|
|
7
|
-
SESSION: 'session', // create_session, close_session
|
|
8
|
-
NOHUP_COMMAND: 'nohup_command', // nohup xxx &
|
|
9
|
-
PROCESS_CHECK: 'process_check', // kill -0 {pid}
|
|
10
|
-
LOG_QUERY: 'log_query', // head -c xxx file
|
|
11
|
-
UPLOAD: 'upload', // upload file
|
|
12
|
-
STOP: 'stop', // stop sandbox
|
|
13
|
-
OTHER: 'other' // other commands
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* 处理动作常量
|
|
18
|
-
*/
|
|
19
|
-
const RequestAction = {
|
|
20
|
-
EXECUTE: 'execute', // 执行
|
|
21
|
-
SKIP: 'skip', // 跳过
|
|
22
|
-
MERGE: 'merge', // 合并到等待逻辑
|
|
23
|
-
EXECUTE_WITH_PROCESS_WAIT: 'execute_with_process_wait' // 执行 nohup 并等待进程结束
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* 单个回放请求
|
|
28
|
-
*/
|
|
29
|
-
class ReplayRequest {
|
|
30
|
-
constructor(raw, index) {
|
|
31
|
-
this.index = index;
|
|
32
|
-
this.method = raw.method;
|
|
33
|
-
this.uri = raw.uri;
|
|
34
|
-
this.requestBody = raw.requestBody || {};
|
|
35
|
-
this.headers = raw.headers || {};
|
|
36
|
-
this.responseTime = raw.responseTime ? new Date(raw.responseTime) : null;
|
|
37
|
-
|
|
38
|
-
// 分析后填充的字段
|
|
39
|
-
this.category = null; // 请求分类
|
|
40
|
-
this.action = null; // 处理动作
|
|
41
|
-
this.skipReason = null; // 跳过原因
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 获取命令(如果是 run_in_session 请求)
|
|
46
|
-
*/
|
|
47
|
-
getCommand() {
|
|
48
|
-
return this.requestBody?.command || '';
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 获取简短描述
|
|
53
|
-
*/
|
|
54
|
-
getShortDescription(maxLen = 60) {
|
|
55
|
-
const command = this.getCommand();
|
|
56
|
-
if (command) {
|
|
57
|
-
if (command.length > maxLen) {
|
|
58
|
-
return command.substring(0, maxLen - 3) + '...';
|
|
59
|
-
}
|
|
60
|
-
return command;
|
|
61
|
-
}
|
|
62
|
-
return this.uri.split('?')[0].split('/').pop();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* 回放计划
|
|
68
|
-
*/
|
|
69
|
-
class ReplayPlan {
|
|
70
|
-
constructor() {
|
|
71
|
-
this.originalCount = 0; // 原始请求数
|
|
72
|
-
this.requests = []; // 待执行的请求列表
|
|
73
|
-
this.skippedRequests = []; // 被跳过的请求列表
|
|
74
|
-
this.mergedRequests = []; // 被合并的请求列表
|
|
75
|
-
|
|
76
|
-
// 统计信息
|
|
77
|
-
this.stats = {
|
|
78
|
-
startup: 0,
|
|
79
|
-
startupPolling: 0,
|
|
80
|
-
session: 0,
|
|
81
|
-
nohupCommand: 0,
|
|
82
|
-
processCheck: 0,
|
|
83
|
-
logQuery: 0,
|
|
84
|
-
upload: 0,
|
|
85
|
-
stop: 0,
|
|
86
|
-
other: 0
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
get skippedCount() {
|
|
92
|
-
return this.skippedRequests.length;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
get mergedCount() {
|
|
96
|
-
return this.mergedRequests.length;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
get executeCount() {
|
|
100
|
-
return this.requests.length;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
module.exports = {
|
|
105
|
-
RequestCategory,
|
|
106
|
-
RequestAction,
|
|
107
|
-
ReplayRequest,
|
|
108
|
-
ReplayPlan
|
|
109
|
-
};
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const { SandboxClient, SandboxConfig } = require('../../../../sdks/sandbox');
|
|
3
|
-
const { ReplayExecutor } = require('./executor');
|
|
4
|
-
const { ReplayRequest, ReplayPlan } = require('./request');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 单个沙箱回放工作者
|
|
8
|
-
* 封装独立的 SandboxClient 和 ReplayExecutor
|
|
9
|
-
*/
|
|
10
|
-
class ReplayWorker {
|
|
11
|
-
/**
|
|
12
|
-
* @param {number} workerId - 工作者 ID(1-based)
|
|
13
|
-
* @param {SandboxConfig} config - 沙箱配置
|
|
14
|
-
* @param {ReplayPlan} plan - 回放计划(会被深拷贝)
|
|
15
|
-
* @param {Object} options - 回放选项
|
|
16
|
-
* @param {string} options.timing - 时间控制
|
|
17
|
-
* @param {number} options.interval - 固定间隔
|
|
18
|
-
* @param {string} options.logFile - 日志文件基础路径
|
|
19
|
-
*/
|
|
20
|
-
constructor(workerId, config, plan, options = {}) {
|
|
21
|
-
this.workerId = workerId;
|
|
22
|
-
this.config = config;
|
|
23
|
-
this.plan = this.deepClonePlan(plan);
|
|
24
|
-
this.options = options;
|
|
25
|
-
|
|
26
|
-
// 独立的沙箱客户端和执行器
|
|
27
|
-
this.client = null;
|
|
28
|
-
this.executor = null;
|
|
29
|
-
|
|
30
|
-
// 执行状态
|
|
31
|
-
this.status = 'pending'; // pending | running | completed | failed
|
|
32
|
-
this.error = null;
|
|
33
|
-
this.results = null;
|
|
34
|
-
this.startTime = null;
|
|
35
|
-
this.endTime = null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* 深拷贝回放计划
|
|
40
|
-
* 确保每个 worker 有独立的请求对象(requestBody 可能被修改)
|
|
41
|
-
* @param {ReplayPlan} plan
|
|
42
|
-
* @returns {ReplayPlan}
|
|
43
|
-
*/
|
|
44
|
-
deepClonePlan(plan) {
|
|
45
|
-
const cloned = new ReplayPlan();
|
|
46
|
-
cloned.originalCount = plan.originalCount;
|
|
47
|
-
cloned.stats = { ...plan.stats };
|
|
48
|
-
cloned.pidAssociations = new Map(plan.pidAssociations);
|
|
49
|
-
|
|
50
|
-
// 深拷贝请求列表
|
|
51
|
-
cloned.requests = plan.requests.map(req => this.cloneRequest(req));
|
|
52
|
-
cloned.skippedRequests = plan.skippedRequests.map(req => this.cloneRequest(req));
|
|
53
|
-
cloned.mergedRequests = plan.mergedRequests.map(req => this.cloneRequest(req));
|
|
54
|
-
|
|
55
|
-
return cloned;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 深拷贝单个请求
|
|
60
|
-
* @param {ReplayRequest} req
|
|
61
|
-
* @returns {ReplayRequest}
|
|
62
|
-
*/
|
|
63
|
-
cloneRequest(req) {
|
|
64
|
-
const cloned = new ReplayRequest({
|
|
65
|
-
method: req.method,
|
|
66
|
-
uri: req.uri,
|
|
67
|
-
requestBody: JSON.parse(JSON.stringify(req.requestBody || {})),
|
|
68
|
-
headers: JSON.parse(JSON.stringify(req.headers || {})),
|
|
69
|
-
responseTime: req.responseTime
|
|
70
|
-
}, req.index);
|
|
71
|
-
|
|
72
|
-
cloned.category = req.category;
|
|
73
|
-
cloned.action = req.action;
|
|
74
|
-
cloned.originalPid = req.originalPid;
|
|
75
|
-
cloned.skipReason = req.skipReason;
|
|
76
|
-
|
|
77
|
-
return cloned;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 获取 worker 专属的日志文件名
|
|
82
|
-
* @returns {string}
|
|
83
|
-
*/
|
|
84
|
-
getLogFileName() {
|
|
85
|
-
const baseLogFile = this.options.logFile || 'replay.log';
|
|
86
|
-
const ext = path.extname(baseLogFile);
|
|
87
|
-
const base = path.basename(baseLogFile, ext);
|
|
88
|
-
const dir = path.dirname(baseLogFile);
|
|
89
|
-
return path.join(dir, `${base}-worker${this.workerId}${ext}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 执行回放
|
|
94
|
-
* @returns {Promise<WorkerResult>}
|
|
95
|
-
*/
|
|
96
|
-
async execute() {
|
|
97
|
-
this.status = 'running';
|
|
98
|
-
this.startTime = Date.now();
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
// 创建独立的 SandboxClient
|
|
102
|
-
this.client = new SandboxClient(this.config);
|
|
103
|
-
|
|
104
|
-
// 创建独立的 ReplayExecutor
|
|
105
|
-
this.executor = new ReplayExecutor(this.client, {
|
|
106
|
-
timing: this.options.timing,
|
|
107
|
-
interval: this.options.interval,
|
|
108
|
-
quiet: true, // 并发模式下强制静默,由 orchestrator 统一输出
|
|
109
|
-
logFile: this.getLogFileName(),
|
|
110
|
-
plan: this.plan,
|
|
111
|
-
workerId: this.workerId
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// 执行回放
|
|
115
|
-
this.results = await this.executor.execute(this.plan);
|
|
116
|
-
this.status = 'completed';
|
|
117
|
-
|
|
118
|
-
} catch (error) {
|
|
119
|
-
this.status = 'failed';
|
|
120
|
-
this.error = error;
|
|
121
|
-
this.results = {
|
|
122
|
-
total: this.plan.requests.length,
|
|
123
|
-
success: 0,
|
|
124
|
-
failed: this.plan.requests.length,
|
|
125
|
-
skipped: 0
|
|
126
|
-
};
|
|
127
|
-
} finally {
|
|
128
|
-
this.endTime = Date.now();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return this.getWorkerResult();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* 获取工作者执行结果
|
|
136
|
-
* @returns {WorkerResult}
|
|
137
|
-
*/
|
|
138
|
-
getWorkerResult() {
|
|
139
|
-
return {
|
|
140
|
-
workerId: this.workerId,
|
|
141
|
-
status: this.status,
|
|
142
|
-
sandboxId: this.executor?.currentSandboxId || null,
|
|
143
|
-
results: this.results,
|
|
144
|
-
error: this.error?.message || null,
|
|
145
|
-
duration: this.endTime - this.startTime,
|
|
146
|
-
logFile: this.getLogFileName()
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* 获取当前进度
|
|
152
|
-
* @returns {Object}
|
|
153
|
-
*/
|
|
154
|
-
getProgress() {
|
|
155
|
-
return {
|
|
156
|
-
workerId: this.workerId,
|
|
157
|
-
status: this.status,
|
|
158
|
-
sandboxId: this.executor?.currentSandboxId?.substring(0, 8) || null,
|
|
159
|
-
success: this.executor?.results?.success || 0,
|
|
160
|
-
failed: this.executor?.results?.failed || 0,
|
|
161
|
-
total: this.plan.requests.length
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
module.exports = { ReplayWorker };
|
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
const { createInternalSandboxClient, SandboxConfig, getInternalSandboxConfig } = require('../../../sdks/sandbox');
|
|
2
|
-
const logger = require('../../../utils/logger');
|
|
3
|
-
const configManager = require('../../../utils/configManager');
|
|
4
|
-
const { gracefulExit } = require('../../../utils/execution_logger');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 读取配置文件中的 sandbox 配置
|
|
8
|
-
* @param {Object} [argv] - CLI 参数,用于解析 API key
|
|
9
|
-
*/
|
|
10
|
-
function readSandboxConfig(argv = {}) {
|
|
11
|
-
const config = configManager.readConfig();
|
|
12
|
-
const sandboxConfig = config?.sandbox || {};
|
|
13
|
-
const internalDefaults = getInternalSandboxConfig();
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
base_url: argv.baseUrl || sandboxConfig.base_url || internalDefaults.baseUrl,
|
|
17
|
-
cluster: argv.cluster || sandboxConfig.cluster || internalDefaults.cluster,
|
|
18
|
-
...sandboxConfig,
|
|
19
|
-
api_key: configManager.getApiKeyWithPriority(argv),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Session command module for yargs
|
|
24
|
-
module.exports = {
|
|
25
|
-
command: 'session <subaction>',
|
|
26
|
-
describe: 'Session operations:\n' +
|
|
27
|
-
' create 创建 session\n' +
|
|
28
|
-
' run 在 session 中执行命令\n' +
|
|
29
|
-
' close 关闭 session',
|
|
30
|
-
builder: (yargs) => {
|
|
31
|
-
return yargs
|
|
32
|
-
.positional('subaction', {
|
|
33
|
-
describe: 'Session action to perform',
|
|
34
|
-
type: 'string',
|
|
35
|
-
choices: ['create', 'run', 'close'],
|
|
36
|
-
})
|
|
37
|
-
.option('sandbox-id', {
|
|
38
|
-
alias: 'id',
|
|
39
|
-
describe: 'Sandbox ID (required)',
|
|
40
|
-
type: 'string',
|
|
41
|
-
demandOption: true,
|
|
42
|
-
group: 'Command Options:'
|
|
43
|
-
})
|
|
44
|
-
.option('session', {
|
|
45
|
-
describe: 'Session name',
|
|
46
|
-
type: 'string',
|
|
47
|
-
default: 'default',
|
|
48
|
-
group: 'Command Options:'
|
|
49
|
-
})
|
|
50
|
-
.option('command', {
|
|
51
|
-
describe: 'Command to execute (for run action)',
|
|
52
|
-
type: 'string',
|
|
53
|
-
group: 'Command Options:'
|
|
54
|
-
})
|
|
55
|
-
.option('startup-source', {
|
|
56
|
-
describe: 'Startup source files for session (comma-separated)',
|
|
57
|
-
type: 'string',
|
|
58
|
-
group: 'Command Options:'
|
|
59
|
-
})
|
|
60
|
-
.option('startup-timeout', {
|
|
61
|
-
describe: 'Startup timeout for session in seconds',
|
|
62
|
-
type: 'number',
|
|
63
|
-
group: 'Command Options:'
|
|
64
|
-
})
|
|
65
|
-
.option('session-type', {
|
|
66
|
-
describe: 'Session type (default: bash)',
|
|
67
|
-
type: 'string',
|
|
68
|
-
default: 'bash',
|
|
69
|
-
group: 'Command Options:'
|
|
70
|
-
})
|
|
71
|
-
.option('env', {
|
|
72
|
-
describe: 'Environment variables as JSON string',
|
|
73
|
-
type: 'string',
|
|
74
|
-
group: 'Command Options:'
|
|
75
|
-
})
|
|
76
|
-
.option('env-enable', {
|
|
77
|
-
describe: 'Enable environment variables from parent process',
|
|
78
|
-
type: 'boolean',
|
|
79
|
-
default: false,
|
|
80
|
-
group: 'Command Options:'
|
|
81
|
-
})
|
|
82
|
-
.option('timeout', {
|
|
83
|
-
describe: 'Command execution timeout in seconds',
|
|
84
|
-
type: 'number',
|
|
85
|
-
group: 'Command Options:'
|
|
86
|
-
})
|
|
87
|
-
.option('is-interactive', {
|
|
88
|
-
describe: 'Is interactive command',
|
|
89
|
-
type: 'boolean',
|
|
90
|
-
default: false,
|
|
91
|
-
group: 'Command Options:'
|
|
92
|
-
})
|
|
93
|
-
.option('expect', {
|
|
94
|
-
describe: 'Expected output patterns for interactive commands (comma-separated)',
|
|
95
|
-
type: 'string',
|
|
96
|
-
group: 'Command Options:'
|
|
97
|
-
})
|
|
98
|
-
.option('check', {
|
|
99
|
-
describe: 'Exit check mode: raise (default), silent, ignore',
|
|
100
|
-
type: 'string',
|
|
101
|
-
default: 'raise',
|
|
102
|
-
choices: ['raise', 'silent', 'ignore'],
|
|
103
|
-
group: 'Command Options:'
|
|
104
|
-
})
|
|
105
|
-
.option('cluster', {
|
|
106
|
-
describe: 'Cluster ID (sets X-Cluster header)',
|
|
107
|
-
type: 'string',
|
|
108
|
-
group: 'Command Options:'
|
|
109
|
-
})
|
|
110
|
-
.option('experiment-id', {
|
|
111
|
-
describe: 'Experiment ID (sets X-Experiment-Id header)',
|
|
112
|
-
type: 'string',
|
|
113
|
-
group: 'Command Options:'
|
|
114
|
-
})
|
|
115
|
-
.option('user-id', {
|
|
116
|
-
describe: 'User ID (sets X-User-Id header)',
|
|
117
|
-
type: 'string',
|
|
118
|
-
group: 'Command Options:'
|
|
119
|
-
})
|
|
120
|
-
.option('extra-header', {
|
|
121
|
-
alias: 'H',
|
|
122
|
-
type: 'array',
|
|
123
|
-
description: 'Extra HTTP headers in format "Key=Value". Can be used multiple times.',
|
|
124
|
-
group: 'Command Options:',
|
|
125
|
-
coerce: (headers) => {
|
|
126
|
-
const result = {};
|
|
127
|
-
if (headers) {
|
|
128
|
-
headers.forEach(header => {
|
|
129
|
-
if (header.includes('=')) {
|
|
130
|
-
const [key, value] = header.split('=', 2);
|
|
131
|
-
result[key.trim()] = value.trim();
|
|
132
|
-
} else {
|
|
133
|
-
logger.warn(`Invalid header format: ${header}. Expected format: 'Key=Value'`);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
return result;
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
.example([
|
|
141
|
-
['$0 sandbox session create --id <sandbox-id>', 'Create a session'],
|
|
142
|
-
['$0 sandbox session run --id <sandbox-id> --command "ls -la"', 'Run command in session'],
|
|
143
|
-
['$0 sandbox session run --id <sandbox-id> -- ls -la', 'Run command in session (alternative)'],
|
|
144
|
-
['$0 sandbox session close --id <sandbox-id>', 'Close a session'],
|
|
145
|
-
]);
|
|
146
|
-
},
|
|
147
|
-
handler: async (argv) => {
|
|
148
|
-
try {
|
|
149
|
-
switch (argv.subaction) {
|
|
150
|
-
case 'create':
|
|
151
|
-
await handleSessionCreate(argv);
|
|
152
|
-
break;
|
|
153
|
-
case 'run':
|
|
154
|
-
await handleSessionRun(argv);
|
|
155
|
-
break;
|
|
156
|
-
case 'close':
|
|
157
|
-
await handleSessionClose(argv);
|
|
158
|
-
break;
|
|
159
|
-
default:
|
|
160
|
-
console.error(`Unknown session action: ${argv.subaction}`);
|
|
161
|
-
gracefulExit(1);
|
|
162
|
-
}
|
|
163
|
-
} catch (error) {
|
|
164
|
-
logger.error(`Session action failed: ${error.message}`);
|
|
165
|
-
gracefulExit(1);
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Handle session create action
|
|
172
|
-
*/
|
|
173
|
-
async function handleSessionCreate(argv) {
|
|
174
|
-
const sandboxConfig = readSandboxConfig(argv);
|
|
175
|
-
const baseUrl = argv.baseUrl || sandboxConfig.base_url;
|
|
176
|
-
const apiKey = argv.apiKey || sandboxConfig.api_key;
|
|
177
|
-
const cluster = argv.cluster || sandboxConfig.cluster;
|
|
178
|
-
const userId = argv.userId || sandboxConfig.user_id;
|
|
179
|
-
const experimentId = argv.experimentId || sandboxConfig.experiment_id;
|
|
180
|
-
|
|
181
|
-
if (!baseUrl) {
|
|
182
|
-
throw new Error('base-url is required (use --base-url or run "rock-cli login" first)');
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const config = new SandboxConfig({
|
|
186
|
-
baseUrl: baseUrl,
|
|
187
|
-
xrlAuthorization: apiKey,
|
|
188
|
-
cluster: cluster,
|
|
189
|
-
userId: userId,
|
|
190
|
-
experimentId: experimentId,
|
|
191
|
-
extraHeaders: argv.extraHeader || {},
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
const client = createInternalSandboxClient(config, { requireImage: false });
|
|
195
|
-
client._sandboxId = argv.sandboxId;
|
|
196
|
-
|
|
197
|
-
const options = {
|
|
198
|
-
session: argv.session || 'default',
|
|
199
|
-
startupSource: argv.startupSource ? argv.startupSource.split(',') : [],
|
|
200
|
-
envEnable: argv.envEnable || false,
|
|
201
|
-
env: argv.env ? JSON.parse(argv.env) : null,
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
if (argv.startupTimeout) {
|
|
205
|
-
options.startupTimeout = argv.startupTimeout;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (!argv.raw) {
|
|
209
|
-
console.log(`Creating session: ${options.session}...`);
|
|
210
|
-
}
|
|
211
|
-
const result = await client.createSession(options);
|
|
212
|
-
|
|
213
|
-
if (argv.raw) {
|
|
214
|
-
console.log(JSON.stringify({
|
|
215
|
-
output: result.output || '',
|
|
216
|
-
exit_code: result.exit_code !== undefined ? result.exit_code : 0,
|
|
217
|
-
success: true,
|
|
218
|
-
}));
|
|
219
|
-
} else {
|
|
220
|
-
console.log('✅ Session created successfully!');
|
|
221
|
-
if (result.output) {
|
|
222
|
-
console.log('Output:');
|
|
223
|
-
console.log(result.output);
|
|
224
|
-
}
|
|
225
|
-
if (result.exit_code !== undefined && result.exit_code !== null) {
|
|
226
|
-
console.log(`Exit code: ${result.exit_code}`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Handle session run action
|
|
233
|
-
*/
|
|
234
|
-
async function handleSessionRun(argv) {
|
|
235
|
-
let command = argv.command;
|
|
236
|
-
if (!command) {
|
|
237
|
-
const separatorIndex = process.argv.indexOf('--');
|
|
238
|
-
if (separatorIndex !== -1 && separatorIndex < process.argv.length - 1) {
|
|
239
|
-
command = process.argv.slice(separatorIndex + 1).join(' ');
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (!command) {
|
|
244
|
-
throw new Error('command is required. Use --command "your command" or: rock-cli sandbox session run --id <id> -- your command');
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const sandboxConfig = readSandboxConfig(argv);
|
|
248
|
-
const baseUrl = argv.baseUrl || sandboxConfig.base_url;
|
|
249
|
-
const apiKey = argv.apiKey || sandboxConfig.api_key;
|
|
250
|
-
const cluster = argv.cluster || sandboxConfig.cluster;
|
|
251
|
-
const userId = argv.userId || sandboxConfig.user_id;
|
|
252
|
-
const experimentId = argv.experimentId || sandboxConfig.experiment_id;
|
|
253
|
-
|
|
254
|
-
if (!baseUrl) {
|
|
255
|
-
throw new Error('base-url is required (use --base-url or run "rock-cli login" first)');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const config = new SandboxConfig({
|
|
259
|
-
baseUrl: baseUrl,
|
|
260
|
-
xrlAuthorization: apiKey,
|
|
261
|
-
cluster: cluster,
|
|
262
|
-
userId: userId,
|
|
263
|
-
experimentId: experimentId,
|
|
264
|
-
extraHeaders: argv.extraHeader || {},
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
const client = createInternalSandboxClient(config, { requireImage: false });
|
|
268
|
-
client._sandboxId = argv.sandboxId;
|
|
269
|
-
|
|
270
|
-
const action = {
|
|
271
|
-
session: argv.session || 'default',
|
|
272
|
-
command: command,
|
|
273
|
-
check: argv.check || 'raise',
|
|
274
|
-
timeout: argv.timeout ? argv.timeout * 1000 : null,
|
|
275
|
-
isInteractiveCommand: argv.isInteractive || false,
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
if (argv.expect) {
|
|
279
|
-
action.expect = argv.expect.split(',');
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (!argv.raw) {
|
|
283
|
-
console.log(`Running command in session ${action.session}: ${command}`);
|
|
284
|
-
}
|
|
285
|
-
const result = await client.runInSession(action);
|
|
286
|
-
|
|
287
|
-
if (argv.raw) {
|
|
288
|
-
console.log(JSON.stringify({
|
|
289
|
-
output: result.output || '',
|
|
290
|
-
exit_code: result.exit_code !== undefined ? result.exit_code : 0,
|
|
291
|
-
success: true,
|
|
292
|
-
}));
|
|
293
|
-
} else {
|
|
294
|
-
if (result.output) {
|
|
295
|
-
console.log('Output:');
|
|
296
|
-
console.log(result.output);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (result.exit_code !== undefined && result.exit_code !== null) {
|
|
300
|
-
console.log(`Exit code: ${result.exit_code}`);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (result.exit_code !== undefined && result.exit_code !== 0 && action.check === 'raise') {
|
|
305
|
-
gracefulExit(1);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Handle session close action
|
|
311
|
-
*/
|
|
312
|
-
async function handleSessionClose(argv) {
|
|
313
|
-
const sandboxConfig = readSandboxConfig(argv);
|
|
314
|
-
const baseUrl = argv.baseUrl || sandboxConfig.base_url;
|
|
315
|
-
const apiKey = argv.apiKey || sandboxConfig.api_key;
|
|
316
|
-
const cluster = argv.cluster || sandboxConfig.cluster;
|
|
317
|
-
const userId = argv.userId || sandboxConfig.user_id;
|
|
318
|
-
const experimentId = argv.experimentId || sandboxConfig.experiment_id;
|
|
319
|
-
|
|
320
|
-
if (!baseUrl) {
|
|
321
|
-
throw new Error('base-url is required (use --base-url or run "rock-cli login" first)');
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const config = new SandboxConfig({
|
|
325
|
-
baseUrl: baseUrl,
|
|
326
|
-
xrlAuthorization: apiKey,
|
|
327
|
-
cluster: cluster,
|
|
328
|
-
userId: userId,
|
|
329
|
-
experimentId: experimentId,
|
|
330
|
-
extraHeaders: argv.extraHeader || {},
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
const client = createInternalSandboxClient(config, { requireImage: false });
|
|
334
|
-
client._sandboxId = argv.sandboxId;
|
|
335
|
-
|
|
336
|
-
const session = argv.session || 'default';
|
|
337
|
-
|
|
338
|
-
console.log(`Closing session: ${session}...`);
|
|
339
|
-
const result = await client.closeSession(session);
|
|
340
|
-
|
|
341
|
-
console.log('✅ Session closed successfully!');
|
|
342
|
-
if (result && result.output) {
|
|
343
|
-
console.log('Output:');
|
|
344
|
-
console.log(result.output);
|
|
345
|
-
}
|
|
346
|
-
}
|
package/commands/sandbox/ray.js
DELETED