rl-rockcli 0.0.8 → 0.0.10
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/commands/attach/basic-repl.js +212 -0
- package/commands/attach/cleanup-history.js +189 -0
- package/commands/attach/cleanup-manager.js +163 -0
- package/commands/attach/copy-ui/copyRepl.js +195 -0
- package/commands/attach/copy-ui/index.js +7 -0
- package/commands/attach/copy-ui/render/outputBlock.js +25 -0
- package/commands/attach/copy-ui/viewport/viewport.js +23 -0
- package/commands/attach/copy-ui/viewport/wheel.js +14 -0
- package/commands/attach/history-manager.js +507 -0
- package/commands/attach/history-session.js +48 -0
- package/commands/attach/ink-repl/InkREPL.js +1507 -0
- package/commands/attach/ink-repl/builtinCommands.js +1253 -0
- package/commands/attach/ink-repl/components/ConnectingScreen.js +76 -0
- package/commands/attach/ink-repl/components/Console.js +191 -0
- package/commands/attach/ink-repl/components/DetailView.js +148 -0
- package/commands/attach/ink-repl/components/DropdownMenu.js +86 -0
- package/commands/attach/ink-repl/components/InputArea.js +125 -0
- package/commands/attach/ink-repl/components/InputLine.js +18 -0
- package/commands/attach/ink-repl/components/OutputArea.js +22 -0
- package/commands/attach/ink-repl/components/OutputItem.js +96 -0
- package/commands/attach/ink-repl/components/ShellLayout.js +61 -0
- package/commands/attach/ink-repl/components/Spinner.js +79 -0
- package/commands/attach/ink-repl/components/StatusBar.js +106 -0
- package/commands/attach/ink-repl/components/WelcomeBanner.js +48 -0
- package/commands/attach/ink-repl/contexts/LayoutContext.js +12 -0
- package/commands/attach/ink-repl/contexts/ThemeContext.js +43 -0
- package/commands/attach/ink-repl/hooks/useFunctionKeys.js +70 -0
- package/commands/attach/ink-repl/hooks/useMouse.js +162 -0
- package/commands/attach/ink-repl/hooks/useResources.js +132 -0
- package/commands/attach/ink-repl/hooks/useSpinner.js +49 -0
- package/commands/attach/ink-repl/index.js +112 -0
- package/commands/attach/ink-repl/package.json +3 -0
- package/commands/attach/ink-repl/replState.js +947 -0
- package/commands/attach/ink-repl/shortcuts/defaultKeybindings.js +138 -0
- package/commands/attach/ink-repl/shortcuts/index.js +332 -0
- package/commands/attach/ink-repl/themes/defaultDark.js +18 -0
- package/commands/attach/ink-repl/themes/defaultLight.js +18 -0
- package/commands/attach/ink-repl/themes/index.js +4 -0
- package/commands/attach/ink-repl/themes/themeManager.js +45 -0
- package/commands/attach/ink-repl/themes/themeTokens.js +15 -0
- package/commands/attach/ink-repl/utils/atCompletion.js +346 -0
- package/commands/attach/ink-repl/utils/clipboard.js +50 -0
- package/commands/attach/ink-repl/utils/consoleLogger.js +81 -0
- package/commands/attach/ink-repl/utils/exitCodeHandler.js +49 -0
- package/commands/attach/ink-repl/utils/exitCodeTips.js +56 -0
- package/commands/attach/ink-repl/utils/formatTime.js +12 -0
- package/commands/attach/ink-repl/utils/outputSelection.js +120 -0
- package/commands/attach/ink-repl/utils/outputViewport.js +77 -0
- package/commands/attach/ink-repl/utils/paginatedFileLoading.js +76 -0
- package/commands/attach/ink-repl/utils/paramHint.js +60 -0
- package/commands/attach/ink-repl/utils/parseError.js +174 -0
- package/commands/attach/ink-repl/utils/pathCompletion.js +167 -0
- package/commands/attach/ink-repl/utils/remotePathSafety.js +56 -0
- package/commands/attach/ink-repl/utils/replSelection.js +205 -0
- package/commands/attach/ink-repl/utils/responseFormatter.js +127 -0
- package/commands/attach/ink-repl/utils/textWrap.js +117 -0
- package/commands/attach/ink-repl/utils/truncate.js +115 -0
- package/commands/attach/opentui-repl/App.tsx +891 -0
- package/commands/attach/opentui-repl/builtinCommands.ts +80 -0
- package/commands/attach/opentui-repl/components/ConfirmDialog.tsx +116 -0
- package/commands/attach/opentui-repl/components/ConnectingScreen.tsx +131 -0
- package/commands/attach/opentui-repl/components/Console.tsx +73 -0
- package/commands/attach/opentui-repl/components/DetailView.tsx +45 -0
- package/commands/attach/opentui-repl/components/DropdownMenu.tsx +130 -0
- package/commands/attach/opentui-repl/components/ExecutionStatus.tsx +66 -0
- package/commands/attach/opentui-repl/components/Header.tsx +24 -0
- package/commands/attach/opentui-repl/components/OutputArea.tsx +25 -0
- package/commands/attach/opentui-repl/components/OutputBlock.tsx +108 -0
- package/commands/attach/opentui-repl/components/PromptInput.tsx +109 -0
- package/commands/attach/opentui-repl/components/StatusBar.tsx +63 -0
- package/commands/attach/opentui-repl/components/Toast.tsx +65 -0
- package/commands/attach/opentui-repl/components/WelcomeBanner.tsx +41 -0
- package/commands/attach/opentui-repl/contexts/ReplContext.tsx +137 -0
- package/commands/attach/opentui-repl/contexts/SessionContext.tsx +32 -0
- package/commands/attach/opentui-repl/contexts/ThemeContext.tsx +70 -0
- package/commands/attach/opentui-repl/contexts/ToastContext.tsx +69 -0
- package/commands/attach/opentui-repl/contexts/toast-logic.js +71 -0
- package/commands/attach/opentui-repl/hooks/useResources.ts +102 -0
- package/commands/attach/opentui-repl/hooks/useSpinner.ts +46 -0
- package/commands/attach/opentui-repl/index.js +99 -0
- package/commands/attach/opentui-repl/keybindings.ts +39 -0
- package/commands/attach/opentui-repl/package.json +3 -0
- package/commands/attach/opentui-repl/render.tsx +72 -0
- package/commands/attach/opentui-repl/tsconfig.json +12 -0
- package/commands/attach/repl.js +791 -0
- package/commands/attach/sandbox-id-resolver.js +56 -0
- package/commands/attach/session-manager.js +307 -0
- package/commands/attach/ui-mode.js +146 -0
- package/commands/log/core/constants.js +237 -0
- package/commands/log/core/display.js +370 -0
- package/commands/log/core/search.js +330 -0
- package/commands/log/core/tail.js +216 -0
- package/commands/log/core/utils.js +424 -0
- package/commands/log.js +298 -0
- package/commands/sandbox/core/log-bridge.js +119 -0
- package/commands/sandbox/core/replay/analyzer.js +311 -0
- package/commands/sandbox/core/replay/batch-orchestrator.js +536 -0
- package/commands/sandbox/core/replay/batch-task.js +369 -0
- package/commands/sandbox/core/replay/concurrent-display.js +70 -0
- package/commands/sandbox/core/replay/concurrent-orchestrator.js +170 -0
- package/commands/sandbox/core/replay/data-source.js +86 -0
- package/commands/sandbox/core/replay/display.js +231 -0
- package/commands/sandbox/core/replay/executor.js +634 -0
- package/commands/sandbox/core/replay/history-fetcher.js +124 -0
- package/commands/sandbox/core/replay/index.js +338 -0
- package/commands/sandbox/core/replay/loghouse-data-source.js +177 -0
- package/commands/sandbox/core/replay/pid-mapping.js +26 -0
- package/commands/sandbox/core/replay/request.js +109 -0
- package/commands/sandbox/core/replay/worker.js +166 -0
- package/commands/sandbox/core/session.js +346 -0
- package/commands/sandbox/log-bridge.js +2 -0
- package/commands/sandbox/ray.js +2 -0
- package/commands/sandbox/replay/analyzer.js +311 -0
- package/commands/sandbox/replay/batch-orchestrator.js +536 -0
- package/commands/sandbox/replay/batch-task.js +369 -0
- package/commands/sandbox/replay/concurrent-display.js +70 -0
- package/commands/sandbox/replay/concurrent-orchestrator.js +170 -0
- package/commands/sandbox/replay/display.js +231 -0
- package/commands/sandbox/replay/executor.js +634 -0
- package/commands/sandbox/replay/history-fetcher.js +118 -0
- package/commands/sandbox/replay/index.js +338 -0
- package/commands/sandbox/replay/pid-mapping.js +26 -0
- package/commands/sandbox/replay/request.js +109 -0
- package/commands/sandbox/replay/worker.js +166 -0
- package/commands/sandbox/replay.js +2 -0
- package/commands/sandbox/session.js +2 -0
- package/commands/sandbox-original.js +1393 -0
- package/commands/sandbox.js +499 -0
- package/help/help.json +1071 -0
- package/help/middleware.js +71 -0
- package/help/renderer.js +800 -0
- package/index.js +5 -15
- package/lib/plugin-context.js +40 -0
- package/package.json +2 -2
- package/sdks/sandbox/core/client.js +845 -0
- package/sdks/sandbox/core/config.js +70 -0
- package/sdks/sandbox/core/types.js +74 -0
- package/sdks/sandbox/httpLogger.js +251 -0
- package/sdks/sandbox/index.js +9 -0
- package/utils/asciiArt.js +138 -0
- package/utils/bun-compat.js +59 -0
- package/utils/ciPipelines.js +138 -0
- package/utils/cli.js +17 -0
- package/utils/command-router.js +79 -0
- package/utils/configManager.js +503 -0
- package/utils/dependency-resolver.js +135 -0
- package/utils/eagleeye_traceid.js +151 -0
- package/utils/envDetector.js +78 -0
- package/utils/execution_logger.js +415 -0
- package/utils/featureManager.js +68 -0
- package/utils/firstTimeTip.js +44 -0
- package/utils/hook-manager.js +125 -0
- package/utils/http-logger.js +264 -0
- package/utils/i18n.js +139 -0
- package/utils/image-progress.js +159 -0
- package/utils/logger.js +154 -0
- package/utils/plugin-loader.js +124 -0
- package/utils/plugin-manager.js +348 -0
- package/utils/ray_cli_wrapper.js +746 -0
- package/utils/sandbox-client.js +419 -0
- package/utils/terminal.js +32 -0
- package/utils/tips.js +106 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
const { SandboxClient, SandboxConfig } = require('../utils/sandbox-client');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const logger = require('../utils/logger');
|
|
5
|
+
const { routeSandboxCommand, showDeprecatedWarning } = require('../utils/command-router');
|
|
6
|
+
const { handleSandboxLogSearch, handleSandboxLogTail } = require('./sandbox/log-bridge');
|
|
7
|
+
const { gracefulExit } = require('../utils/execution_logger');
|
|
8
|
+
const configManager = require('../utils/configManager');
|
|
9
|
+
const { printNextStep, TIPS } = require('../utils/tips');
|
|
10
|
+
|
|
11
|
+
const isOpenSource = process.env.ROCKCLI_MODE === 'opensource';
|
|
12
|
+
const DEFAULT_OPEN_SOURCE_BASE_URL = 'http://127.0.0.1:8080';
|
|
13
|
+
const DEFAULT_OPEN_SOURCE_IMAGE = 'python:3.11';
|
|
14
|
+
|
|
15
|
+
// Import existing sandbox.js handlers
|
|
16
|
+
const sandboxOriginal = require('./sandbox-original');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 读取配置文件中的 sandbox 配置
|
|
20
|
+
* @param {Object} argv - Command line arguments
|
|
21
|
+
* @returns {Object} - Sandbox config with proper priority for all parameters
|
|
22
|
+
*/
|
|
23
|
+
function readSandboxConfig(argv = {}) {
|
|
24
|
+
const config = configManager.readConfig();
|
|
25
|
+
const sandboxConfig = config?.sandbox || {};
|
|
26
|
+
const envBaseUrl = process.env.ROCKCLI_BASE_URL;
|
|
27
|
+
|
|
28
|
+
const baseUrl =
|
|
29
|
+
argv.baseUrl ||
|
|
30
|
+
envBaseUrl ||
|
|
31
|
+
sandboxConfig.base_url ||
|
|
32
|
+
(isOpenSource ? DEFAULT_OPEN_SOURCE_BASE_URL : 'http://127.0.0.1:8080');
|
|
33
|
+
|
|
34
|
+
// Get default image from internal config or use open source default
|
|
35
|
+
let defaultImage;
|
|
36
|
+
if (isOpenSource) {
|
|
37
|
+
defaultImage = DEFAULT_OPEN_SOURCE_IMAGE;
|
|
38
|
+
} else {
|
|
39
|
+
const { getInternalSandboxConfig } = require('../sdks/sandbox/core/config');
|
|
40
|
+
const internalDefaults = getInternalSandboxConfig();
|
|
41
|
+
defaultImage = internalDefaults.image;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
base_url: baseUrl,
|
|
46
|
+
image: defaultImage,
|
|
47
|
+
api_key: configManager.getApiKeyWithPriority(argv),
|
|
48
|
+
cluster: configManager.getClusterWithPriority(argv),
|
|
49
|
+
user_id: configManager.getUserIdWithPriority(argv),
|
|
50
|
+
experiment_id: configManager.getExperimentIdWithPriority(argv),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Sandbox command module for yargs - NEW FORMAT
|
|
55
|
+
const sandboxExports = module.exports = {
|
|
56
|
+
command: 'sandbox [id] [command]',
|
|
57
|
+
describe: 'Sandbox instance management',
|
|
58
|
+
builder: (yargs) => {
|
|
59
|
+
return yargs
|
|
60
|
+
.positional('id', {
|
|
61
|
+
describe: 'Sandbox ID (for operations on existing sandbox)',
|
|
62
|
+
type: 'string',
|
|
63
|
+
})
|
|
64
|
+
.positional('command', {
|
|
65
|
+
describe: 'Sandbox command to perform',
|
|
66
|
+
type: 'string',
|
|
67
|
+
})
|
|
68
|
+
.strict(false) // Allow unknown options (they will be passed to subcommands like log search)
|
|
69
|
+
.option('api-key', {
|
|
70
|
+
describe: 'API key for authentication',
|
|
71
|
+
type: 'string',
|
|
72
|
+
group: 'Command Options:'
|
|
73
|
+
})
|
|
74
|
+
.option('base-url', {
|
|
75
|
+
describe: 'Base URL for sandbox service',
|
|
76
|
+
type: 'string',
|
|
77
|
+
group: 'Command Options:'
|
|
78
|
+
})
|
|
79
|
+
.option('image', {
|
|
80
|
+
describe: 'Docker image to use',
|
|
81
|
+
type: 'string',
|
|
82
|
+
group: 'Command Options:'
|
|
83
|
+
})
|
|
84
|
+
.option('memory', {
|
|
85
|
+
describe: 'Memory limit',
|
|
86
|
+
type: 'string',
|
|
87
|
+
default: '8g',
|
|
88
|
+
group: 'Command Options:'
|
|
89
|
+
})
|
|
90
|
+
.option('cpus', {
|
|
91
|
+
describe: 'CPU limit',
|
|
92
|
+
type: 'number',
|
|
93
|
+
default: 2.0,
|
|
94
|
+
group: 'Command Options:'
|
|
95
|
+
})
|
|
96
|
+
.option('timeout', {
|
|
97
|
+
describe: 'Startup timeout in seconds',
|
|
98
|
+
type: 'number',
|
|
99
|
+
default: 120,
|
|
100
|
+
group: 'Command Options:'
|
|
101
|
+
})
|
|
102
|
+
.option('auto-clear', {
|
|
103
|
+
describe: 'Auto clear time in seconds',
|
|
104
|
+
type: 'number',
|
|
105
|
+
default: 300,
|
|
106
|
+
group: 'Command Options:'
|
|
107
|
+
})
|
|
108
|
+
.option('cluster', {
|
|
109
|
+
alias: 'c',
|
|
110
|
+
describe: 'Cluster ID (sets X-Cluster header)',
|
|
111
|
+
type: 'string',
|
|
112
|
+
group: 'Command Options:'
|
|
113
|
+
})
|
|
114
|
+
.option('experiment-id', {
|
|
115
|
+
describe: 'Experiment ID (sets X-Experiment-Id header)',
|
|
116
|
+
type: 'string',
|
|
117
|
+
group: 'Command Options:'
|
|
118
|
+
})
|
|
119
|
+
.option('user-id', {
|
|
120
|
+
describe: 'User ID (sets X-User-Id header)',
|
|
121
|
+
type: 'string',
|
|
122
|
+
group: 'Command Options:'
|
|
123
|
+
})
|
|
124
|
+
.option('extra-header', {
|
|
125
|
+
alias: 'H',
|
|
126
|
+
type: 'array',
|
|
127
|
+
description: 'Extra HTTP headers in format "Key=value". Can be used multiple times.',
|
|
128
|
+
group: 'Command Options:',
|
|
129
|
+
coerce: (headers) => {
|
|
130
|
+
const result = {};
|
|
131
|
+
if (headers) {
|
|
132
|
+
headers.forEach(header => {
|
|
133
|
+
if (header.includes('=')) {
|
|
134
|
+
const [key, value] = header.split('=', 2);
|
|
135
|
+
result[key.trim()] = value.trim();
|
|
136
|
+
} else {
|
|
137
|
+
logger.warn(`Invalid header format: ${header}. Expected format: 'Key=Value'`);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
.option('wait-for-alive', {
|
|
145
|
+
describe: 'Wait for sandbox to be alive before returning',
|
|
146
|
+
type: 'boolean',
|
|
147
|
+
default: false,
|
|
148
|
+
group: 'Command Options:'
|
|
149
|
+
})
|
|
150
|
+
.option('n', {
|
|
151
|
+
alias: 'lines',
|
|
152
|
+
describe: 'Number of recent log lines to display (default: 10)',
|
|
153
|
+
type: 'number',
|
|
154
|
+
default: 10,
|
|
155
|
+
group: 'Log Options:'
|
|
156
|
+
})
|
|
157
|
+
.option('f', {
|
|
158
|
+
alias: 'follow',
|
|
159
|
+
describe: 'Follow mode: continuously monitor logs (like tail -f)',
|
|
160
|
+
type: 'boolean',
|
|
161
|
+
default: false,
|
|
162
|
+
group: 'Log Options:'
|
|
163
|
+
})
|
|
164
|
+
.option('sleep-interval', {
|
|
165
|
+
alias: 'i',
|
|
166
|
+
describe: 'Refresh interval in seconds for follow mode (default: 5)',
|
|
167
|
+
type: 'number',
|
|
168
|
+
default: 5,
|
|
169
|
+
group: 'Log Options:'
|
|
170
|
+
})
|
|
171
|
+
.option('q', {
|
|
172
|
+
alias: 'quiet',
|
|
173
|
+
describe: 'Quiet mode: hide internal fields (timestamp, time_iso8601, etc.)',
|
|
174
|
+
type: 'boolean',
|
|
175
|
+
default: false,
|
|
176
|
+
group: 'Log Options:'
|
|
177
|
+
})
|
|
178
|
+
.option('keyword', {
|
|
179
|
+
alias: 'k',
|
|
180
|
+
describe: 'Filter logs by keyword',
|
|
181
|
+
type: 'string',
|
|
182
|
+
group: 'Log Options:'
|
|
183
|
+
})
|
|
184
|
+
.option('log-file', {
|
|
185
|
+
describe: 'Filter by log file name',
|
|
186
|
+
type: 'string',
|
|
187
|
+
group: 'Log Options:'
|
|
188
|
+
})
|
|
189
|
+
.option('debug', {
|
|
190
|
+
describe: 'Enable debug mode to display SQL query',
|
|
191
|
+
type: 'boolean',
|
|
192
|
+
default: false,
|
|
193
|
+
group: 'Log Options:'
|
|
194
|
+
})
|
|
195
|
+
.option('raw', {
|
|
196
|
+
describe: 'Display raw output (flatten to single line)',
|
|
197
|
+
type: 'boolean',
|
|
198
|
+
default: false,
|
|
199
|
+
group: 'Log Options:'
|
|
200
|
+
})
|
|
201
|
+
.option('multilines', {
|
|
202
|
+
describe: 'Display multi-line logs with separators',
|
|
203
|
+
type: 'boolean',
|
|
204
|
+
default: false,
|
|
205
|
+
group: 'Log Options:'
|
|
206
|
+
})
|
|
207
|
+
.option('highlight', {
|
|
208
|
+
describe: 'Enable keyword highlighting (default: true)',
|
|
209
|
+
type: 'boolean',
|
|
210
|
+
default: true,
|
|
211
|
+
group: 'Log Options:'
|
|
212
|
+
})
|
|
213
|
+
.example([
|
|
214
|
+
['$0 sandbox start --image python:3.11', 'Start a new sandbox'],
|
|
215
|
+
['$0 sandbox <id> status', 'Get sandbox status'],
|
|
216
|
+
['$0 sandbox <id> attach', 'Attach to sandbox (interactive REPL)'],
|
|
217
|
+
['$0 sandbox <id> exec -- ls -la', 'Execute command in sandbox'],
|
|
218
|
+
]);
|
|
219
|
+
},
|
|
220
|
+
handler: async (argv) => {
|
|
221
|
+
try {
|
|
222
|
+
// Rebuild argv._ from process.argv to preserve all original arguments
|
|
223
|
+
// This is needed because yargs parses positional parameters separately
|
|
224
|
+
const rawArgs = process.argv.slice(2);
|
|
225
|
+
|
|
226
|
+
// Filter out options (args starting with -) from argv._
|
|
227
|
+
// This is needed because global options like -vvv should not be treated as positional args
|
|
228
|
+
argv._ = rawArgs.filter(arg => !arg.startsWith('-'));
|
|
229
|
+
|
|
230
|
+
const commandType = routeSandboxCommand(argv);
|
|
231
|
+
|
|
232
|
+
if (commandType === 'help') {
|
|
233
|
+
const { renderHelp } = require('../help/renderer');
|
|
234
|
+
console.log(renderHelp(['sandbox']));
|
|
235
|
+
gracefulExit(0);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (commandType === 'sandbox-start') {
|
|
240
|
+
// Handle start command
|
|
241
|
+
await sandboxOriginal.handler({
|
|
242
|
+
...argv,
|
|
243
|
+
action: 'start'
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (commandType === 'sandbox-id-first') {
|
|
249
|
+
// Handle <id> <command> format
|
|
250
|
+
const id = argv.id;
|
|
251
|
+
if (!id) {
|
|
252
|
+
console.error('Error: Sandbox ID is required');
|
|
253
|
+
gracefulExit(1);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const command = argv.command;
|
|
258
|
+
if (!command) {
|
|
259
|
+
console.error('Error: Command is required');
|
|
260
|
+
gracefulExit(1);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Route to appropriate handler
|
|
265
|
+
await handleIdFirstCommand(id, command, argv);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (commandType === 'sandbox-session') {
|
|
270
|
+
// Handle session commands (deprecated)
|
|
271
|
+
showDeprecatedWarning('sandbox session', 'sandbox <id> exec --session <action>');
|
|
272
|
+
|
|
273
|
+
// Use original handler for now
|
|
274
|
+
await sandboxOriginal.handler(argv);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Default: use original handler
|
|
279
|
+
await sandboxOriginal.handler(argv);
|
|
280
|
+
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error.response && error.response.status === 401) {
|
|
283
|
+
logger.error('Authentication failed: Invalid or missing API key');
|
|
284
|
+
console.error('\n💡 Please configure your API key:');
|
|
285
|
+
console.error(' Option 1: export ROCK_API_KEY=<your-key>');
|
|
286
|
+
console.error(' Option 2: Use --api-key flag: rc sandbox --id <id> --api-key <your-key>\n');
|
|
287
|
+
} else {
|
|
288
|
+
logger.error(`Sandbox action failed: ${error.message}`);
|
|
289
|
+
}
|
|
290
|
+
gracefulExit(1);
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Handle <id> <command> format
|
|
297
|
+
* @param {string} id - Sandbox ID
|
|
298
|
+
* @param {string} command - Command to execute
|
|
299
|
+
* @param {Object} argv - Command line arguments
|
|
300
|
+
*/
|
|
301
|
+
async function handleIdFirstCommand(id, command, argv) {
|
|
302
|
+
// Set sandboxId in argv
|
|
303
|
+
argv.sandboxId = id;
|
|
304
|
+
argv.id = id;
|
|
305
|
+
|
|
306
|
+
switch (command) {
|
|
307
|
+
case 'status':
|
|
308
|
+
await sandboxOriginal.handler({
|
|
309
|
+
...argv,
|
|
310
|
+
action: 'status',
|
|
311
|
+
sandboxId: id
|
|
312
|
+
});
|
|
313
|
+
break;
|
|
314
|
+
|
|
315
|
+
case 'stop':
|
|
316
|
+
await sandboxOriginal.handler({
|
|
317
|
+
...argv,
|
|
318
|
+
action: 'stop',
|
|
319
|
+
sandboxId: id
|
|
320
|
+
});
|
|
321
|
+
break;
|
|
322
|
+
|
|
323
|
+
case 'attach':
|
|
324
|
+
// Route to attach command
|
|
325
|
+
const { handler: attachHandler } = require('./attach');
|
|
326
|
+
await attachHandler({
|
|
327
|
+
...argv,
|
|
328
|
+
sandboxId: id
|
|
329
|
+
});
|
|
330
|
+
break;
|
|
331
|
+
|
|
332
|
+
case 'exec':
|
|
333
|
+
case 'execute':
|
|
334
|
+
// Extract command arguments from process.argv
|
|
335
|
+
// This is needed because yargs parses options like -l separately
|
|
336
|
+
const execRawArgs = process.argv.slice(2); // Skip 'node' and script path
|
|
337
|
+
const execSandboxIndex = execRawArgs.indexOf('sandbox');
|
|
338
|
+
const execIndex = execRawArgs.indexOf('exec');
|
|
339
|
+
|
|
340
|
+
if (execIndex !== -1) {
|
|
341
|
+
// Get all arguments after 'exec'
|
|
342
|
+
const execArgs = execRawArgs.slice(execIndex + 1);
|
|
343
|
+
|
|
344
|
+
// Parse --session parameter from exec args
|
|
345
|
+
let sessionName = null;
|
|
346
|
+
let commandArgs = [];
|
|
347
|
+
|
|
348
|
+
for (let i = 0; i < execArgs.length; i++) {
|
|
349
|
+
if (execArgs[i] === '--session' && i + 1 < execArgs.length) {
|
|
350
|
+
sessionName = execArgs[i + 1];
|
|
351
|
+
i++; // Skip session value
|
|
352
|
+
} else if (execArgs[i] && !execArgs[i].startsWith('-')) {
|
|
353
|
+
commandArgs.push(execArgs[i]);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const command = commandArgs.join(' ');
|
|
358
|
+
|
|
359
|
+
if (sessionName) {
|
|
360
|
+
// Auto-create session before running command
|
|
361
|
+
const sessionHandler = require('./sandbox/session');
|
|
362
|
+
|
|
363
|
+
// Try to create session (ignore errors - session may already exist or sandbox may not be running)
|
|
364
|
+
await sessionHandler.handler({
|
|
365
|
+
...argv,
|
|
366
|
+
subaction: 'create',
|
|
367
|
+
sandboxId: id,
|
|
368
|
+
session: sessionName,
|
|
369
|
+
envEnable: true,
|
|
370
|
+
}).catch(() => {
|
|
371
|
+
// Ignore errors from create
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Run command in session
|
|
375
|
+
await sessionHandler.handler({
|
|
376
|
+
...argv,
|
|
377
|
+
subaction: 'run',
|
|
378
|
+
sandboxId: id,
|
|
379
|
+
session: sessionName,
|
|
380
|
+
command: command,
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
await sandboxOriginal.handler({
|
|
384
|
+
...argv,
|
|
385
|
+
action: 'execute',
|
|
386
|
+
sandboxId: id,
|
|
387
|
+
command: command || undefined
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
await sandboxOriginal.handler({
|
|
392
|
+
...argv,
|
|
393
|
+
action: 'execute',
|
|
394
|
+
sandboxId: id
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
398
|
+
|
|
399
|
+
case 'upload':
|
|
400
|
+
await sandboxOriginal.handler({
|
|
401
|
+
...argv,
|
|
402
|
+
action: 'upload',
|
|
403
|
+
sandboxId: id
|
|
404
|
+
});
|
|
405
|
+
break;
|
|
406
|
+
|
|
407
|
+
case 'download':
|
|
408
|
+
await sandboxOriginal.handler({
|
|
409
|
+
...argv,
|
|
410
|
+
action: 'download',
|
|
411
|
+
sandboxId: id
|
|
412
|
+
});
|
|
413
|
+
break;
|
|
414
|
+
|
|
415
|
+
case 'history':
|
|
416
|
+
// History is the same as log history
|
|
417
|
+
const { handleLogHistory } = require('./log/history');
|
|
418
|
+
await handleLogHistory({
|
|
419
|
+
...argv,
|
|
420
|
+
sandboxId: id
|
|
421
|
+
});
|
|
422
|
+
break;
|
|
423
|
+
|
|
424
|
+
case 'log':
|
|
425
|
+
// Log operations require additional handling
|
|
426
|
+
const logSubcommand = argv._[argv._.indexOf('log') + 1];
|
|
427
|
+
|
|
428
|
+
// Extract additional arguments from process.argv (beyond yargs parsing)
|
|
429
|
+
const rawArgs = process.argv.slice(2);
|
|
430
|
+
const sandboxIndex = rawArgs.indexOf('sandbox');
|
|
431
|
+
|
|
432
|
+
// Find the log file name (first non-option argument after 'log' or after 'tail')
|
|
433
|
+
let logFile = null;
|
|
434
|
+
let foundLog = false;
|
|
435
|
+
let foundTail = false;
|
|
436
|
+
|
|
437
|
+
for (let i = sandboxIndex + 1; i < rawArgs.length; i++) {
|
|
438
|
+
const arg = rawArgs[i];
|
|
439
|
+
|
|
440
|
+
if (arg === 'log') {
|
|
441
|
+
foundLog = true;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (foundLog && arg === 'tail') {
|
|
446
|
+
foundTail = true;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (foundTail && !arg.startsWith('-')) {
|
|
451
|
+
logFile = arg;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (logFile) {
|
|
457
|
+
argv.logFile = logFile;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (logSubcommand === 'search') {
|
|
461
|
+
await handleSandboxLogSearch({
|
|
462
|
+
...argv,
|
|
463
|
+
sandboxId: id
|
|
464
|
+
});
|
|
465
|
+
} else if (logSubcommand === 'tail') {
|
|
466
|
+
await handleSandboxLogTail({
|
|
467
|
+
...argv,
|
|
468
|
+
sandboxId: id
|
|
469
|
+
});
|
|
470
|
+
} else {
|
|
471
|
+
console.error(`错误:缺少 log 子命令\n`);
|
|
472
|
+
console.error(`可用的子命令:`);
|
|
473
|
+
console.error(` search - 搜索日志`);
|
|
474
|
+
console.error(` tail - 实时监控日志\n`);
|
|
475
|
+
console.error(`使用示例:`);
|
|
476
|
+
console.error(` rockcli sandbox ${id} log search -k "error"`);
|
|
477
|
+
console.error(` rockcli sandbox ${id} log tail -f\n`);
|
|
478
|
+
console.error(`查看帮助:`);
|
|
479
|
+
console.error(` rockcli sandbox --help`);
|
|
480
|
+
gracefulExit(1);
|
|
481
|
+
}
|
|
482
|
+
break;
|
|
483
|
+
|
|
484
|
+
default:
|
|
485
|
+
console.error(`Unknown command: ${command}`);
|
|
486
|
+
gracefulExit(1);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Export internal functions for testing
|
|
491
|
+
sandboxExports.readSandboxConfig = readSandboxConfig;
|
|
492
|
+
|
|
493
|
+
// Re-export functions from backup module for backward compatibility
|
|
494
|
+
if (sandboxOriginal.getRemoteFileList) {
|
|
495
|
+
sandboxExports.getRemoteFileList = sandboxOriginal.getRemoteFileList;
|
|
496
|
+
}
|
|
497
|
+
if (sandboxOriginal.validateAuth) {
|
|
498
|
+
sandboxExports.validateAuth = sandboxOriginal.validateAuth;
|
|
499
|
+
}
|