rl-rockcli 0.0.2 → 0.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 +400 -0
- package/index.js +51 -21
- package/package.json +1 -1
- 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,70 +0,0 @@
|
|
|
1
|
-
const logger = require('../../../utils/logger');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Internal sandbox configuration defaults
|
|
7
|
-
* Loaded from config/internal_sandbox_config.json for internal environment
|
|
8
|
-
*/
|
|
9
|
-
const internalConfigPath = path.join(__dirname, '../../../config/internal_sandbox_config.json');
|
|
10
|
-
let internalConfig = null;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Get internal sandbox configuration defaults
|
|
14
|
-
* This function loads internal-only defaults from config file
|
|
15
|
-
* @returns {Object|null} Internal sandbox config or null if not available
|
|
16
|
-
*/
|
|
17
|
-
function getInternalSandboxConfig() {
|
|
18
|
-
if (internalConfig === null) {
|
|
19
|
-
try {
|
|
20
|
-
if (fs.existsSync(internalConfigPath)) {
|
|
21
|
-
internalConfig = JSON.parse(fs.readFileSync(internalConfigPath, 'utf8'));
|
|
22
|
-
} else {
|
|
23
|
-
internalConfig = {};
|
|
24
|
-
}
|
|
25
|
-
} catch (error) {
|
|
26
|
-
logger.debug(`Failed to load internal sandbox config: ${error.message}`);
|
|
27
|
-
internalConfig = {};
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return internalConfig;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Sandbox configuration class
|
|
35
|
-
* Note: This class does not contain internal-specific defaults.
|
|
36
|
-
* Internal defaults are loaded from config/internal_sandbox_config.json via getInternalSandboxConfig()
|
|
37
|
-
*/
|
|
38
|
-
class SandboxConfig {
|
|
39
|
-
constructor(options = {}) {
|
|
40
|
-
// Technical defaults (not environment-specific)
|
|
41
|
-
this.autoClearSeconds = options.autoClearSeconds || 300; // 5 minutes
|
|
42
|
-
this.startupTimeout = options.startupTimeout || 120; // 2 minutes
|
|
43
|
-
this.memory = options.memory || '8g';
|
|
44
|
-
this.cpus = options.cpus !== undefined ? options.cpus : 2.0;
|
|
45
|
-
|
|
46
|
-
// Environment-specific settings (no defaults, must be provided)
|
|
47
|
-
this.baseUrl = options.baseUrl;
|
|
48
|
-
this.xrlAuthorization = options.xrlAuthorization;
|
|
49
|
-
this.image = options.image;
|
|
50
|
-
this.cluster = options.cluster;
|
|
51
|
-
this.namespace = options.namespace || null;
|
|
52
|
-
this.userId = options.userId || null;
|
|
53
|
-
this.experimentId = options.experimentId || null;
|
|
54
|
-
this.extraHeaders = options.extraHeaders || {};
|
|
55
|
-
this.waitForAlive = options.waitForAlive !== undefined ? options.waitForAlive : false;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
validate(options = {}) {
|
|
59
|
-
const { requireImage = true } = options;
|
|
60
|
-
|
|
61
|
-
if (!this.baseUrl) {
|
|
62
|
-
throw new Error('baseUrl is required');
|
|
63
|
-
}
|
|
64
|
-
if (requireImage && !this.image) {
|
|
65
|
-
throw new Error('image is required');
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
module.exports = { SandboxConfig, getInternalSandboxConfig };
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sandbox SDK Response Types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {Object} IsAliveResponse
|
|
7
|
-
* @property {boolean} isAlive - Whether the sandbox is alive
|
|
8
|
-
* @property {string} message - Additional message
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {Object} SandboxStatus
|
|
13
|
-
* @property {string} sandbox_id - Sandbox ID
|
|
14
|
-
* @property {Object} status - Status details by stage
|
|
15
|
-
* @property {Object} port_mapping - Port mappings
|
|
16
|
-
* @property {string|null} host_name - Host name
|
|
17
|
-
* @property {string|null} host_ip - Host IP
|
|
18
|
-
* @property {boolean} is_alive - Whether alive
|
|
19
|
-
* @property {string|null} image - Image name
|
|
20
|
-
* @property {string|null} gateway_version - Gateway version
|
|
21
|
-
* @property {string|null} swe_rex_version - SWE Rex version
|
|
22
|
-
* @property {string|null} user_id - User ID
|
|
23
|
-
* @property {string|null} experiment_id - Experiment ID
|
|
24
|
-
* @property {string|null} namespace - Namespace
|
|
25
|
-
* @property {number|null} cpus - CPU count
|
|
26
|
-
* @property {string|null} memory - Memory allocation
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {Object} CommandResponse
|
|
31
|
-
* @property {string} stdout - Standard output
|
|
32
|
-
* @property {string} stderr - Standard error
|
|
33
|
-
* @property {number|null} exit_code - Exit code
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @typedef {Object} Observation
|
|
38
|
-
* @property {string} output - Command output
|
|
39
|
-
* @property {number|null} exit_code - Exit code
|
|
40
|
-
* @property {string} failure_reason - Failure reason if any
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @typedef {Object} CreateSessionResponse
|
|
45
|
-
* @property {string} output - Session output
|
|
46
|
-
* @property {number|null} exit_code - Exit code
|
|
47
|
-
* @property {string|null} failure_reason - Failure reason
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @typedef {Object} WriteFileResponse
|
|
52
|
-
* @property {boolean} success - Whether write succeeded
|
|
53
|
-
* @property {string} message - Result message
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @typedef {Object} ReadFileResponse
|
|
58
|
-
* @property {string} content - File content
|
|
59
|
-
*/
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @typedef {Object} FileUploadResponse
|
|
63
|
-
* @property {boolean} success - Whether upload succeeded
|
|
64
|
-
* @property {string} message - Result message
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @typedef {Object} StartResponse
|
|
69
|
-
* @property {string} sandboxId - Sandbox ID
|
|
70
|
-
* @property {string} hostName - Host name
|
|
71
|
-
* @property {string} hostIp - Host IP
|
|
72
|
-
*/
|
|
73
|
-
|
|
74
|
-
module.exports = {};
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP Logger - Event emitter for HTTP request/response logging
|
|
3
|
-
*
|
|
4
|
-
* Log format: [HH:mm:ss.SSS] [LEVEL] [ACTION] [traceId] msg
|
|
5
|
-
*
|
|
6
|
-
* This module provides a centralized way to log HTTP requests and responses.
|
|
7
|
-
* InkREPL's console can subscribe to these events to display them.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const EventEmitter = require('events');
|
|
11
|
-
|
|
12
|
-
// Action types
|
|
13
|
-
const ACTION = {
|
|
14
|
-
SESSION: 'SESSION',
|
|
15
|
-
HTTP_REQ: 'HTTP_REQ',
|
|
16
|
-
HTTP_RES: 'HTTP_RES',
|
|
17
|
-
HTTP_ERR: 'HTTP_ERR',
|
|
18
|
-
CMD: 'CMD',
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Log levels
|
|
22
|
-
const LEVEL = {
|
|
23
|
-
DEBUG: 'DEBUG',
|
|
24
|
-
INFO: 'INFO',
|
|
25
|
-
WARN: 'WARN',
|
|
26
|
-
ERROR: 'ERROR',
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
class HttpLogger extends EventEmitter {
|
|
30
|
-
constructor() {
|
|
31
|
-
super();
|
|
32
|
-
this.enabled = false;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Enable HTTP logging
|
|
37
|
-
*/
|
|
38
|
-
enable() {
|
|
39
|
-
this.enabled = true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Disable HTTP logging
|
|
44
|
-
*/
|
|
45
|
-
disable() {
|
|
46
|
-
this.enabled = false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Format timestamp with milliseconds
|
|
51
|
-
*/
|
|
52
|
-
_formatTime(date) {
|
|
53
|
-
const pad = (n, len = 2) => String(n).padStart(len, '0');
|
|
54
|
-
return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Format log message
|
|
59
|
-
* Format: [HH:mm:ss.SSS] [LEVEL] [ACTION] [traceId] msg
|
|
60
|
-
*/
|
|
61
|
-
_formatMessage(level, action, traceId, msg) {
|
|
62
|
-
const time = this._formatTime(new Date());
|
|
63
|
-
const tid = traceId || '-';
|
|
64
|
-
return `[${time}] [${level.padEnd(5)}] [${action.padEnd(8)}] [${tid}] ${msg}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Truncate and format JSON for logging
|
|
69
|
-
*/
|
|
70
|
-
_formatBody(data, maxLen = 200) {
|
|
71
|
-
if (!data) return null;
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
let json = JSON.stringify(data);
|
|
75
|
-
if (json.length > maxLen) {
|
|
76
|
-
json = json.slice(0, maxLen) + '...';
|
|
77
|
-
}
|
|
78
|
-
return json;
|
|
79
|
-
} catch {
|
|
80
|
-
return String(data).slice(0, maxLen);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Log an HTTP request
|
|
86
|
-
* @param {string} method - HTTP method (GET, POST, etc.)
|
|
87
|
-
* @param {string} url - Request URL
|
|
88
|
-
* @param {Object} data - Request body (optional)
|
|
89
|
-
*/
|
|
90
|
-
logRequest(method, url, data = null) {
|
|
91
|
-
if (!this.enabled) return;
|
|
92
|
-
|
|
93
|
-
const urlPath = this._extractPath(url);
|
|
94
|
-
const msg = `${method} ${urlPath}`;
|
|
95
|
-
const message = this._formatMessage(LEVEL.DEBUG, ACTION.HTTP_REQ, null, msg);
|
|
96
|
-
|
|
97
|
-
const event = {
|
|
98
|
-
type: 'request',
|
|
99
|
-
level: LEVEL.DEBUG,
|
|
100
|
-
action: ACTION.HTTP_REQ,
|
|
101
|
-
method,
|
|
102
|
-
url: urlPath,
|
|
103
|
-
data,
|
|
104
|
-
message,
|
|
105
|
-
timestamp: new Date(),
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
this.emit('request', event);
|
|
109
|
-
|
|
110
|
-
// Log request body as separate debug entry
|
|
111
|
-
if (data) {
|
|
112
|
-
const bodyJson = this._formatBody(data);
|
|
113
|
-
const fullBody = this._formatBody(data, Infinity); // Full body for copying
|
|
114
|
-
if (bodyJson) {
|
|
115
|
-
const bodyMsg = this._formatMessage(LEVEL.DEBUG, ACTION.HTTP_REQ, null, `body: ${bodyJson}`);
|
|
116
|
-
this.emit('request', {
|
|
117
|
-
...event,
|
|
118
|
-
message: bodyMsg,
|
|
119
|
-
fullMessage: `body: ${fullBody}`, // Store full message for copying
|
|
120
|
-
isBody: true,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Log an HTTP response
|
|
128
|
-
* @param {string} method - HTTP method
|
|
129
|
-
* @param {string} url - Request URL
|
|
130
|
-
* @param {number} status - HTTP status code
|
|
131
|
-
* @param {number} duration - Request duration in ms
|
|
132
|
-
* @param {Object} data - Response data (optional)
|
|
133
|
-
* @param {string} traceId - Trace ID from response headers (optional)
|
|
134
|
-
*/
|
|
135
|
-
logResponse(method, url, status, duration, data = null, traceId = null) {
|
|
136
|
-
if (!this.enabled) return;
|
|
137
|
-
|
|
138
|
-
const urlPath = this._extractPath(url);
|
|
139
|
-
const statusText = status >= 200 && status < 300 ? 'OK' : 'FAIL';
|
|
140
|
-
const level = status >= 400 ? LEVEL.WARN : LEVEL.INFO;
|
|
141
|
-
|
|
142
|
-
const msg = `${method} ${urlPath} ${status} ${statusText} ${duration}ms`;
|
|
143
|
-
const message = this._formatMessage(level, ACTION.HTTP_RES, traceId, msg);
|
|
144
|
-
|
|
145
|
-
const event = {
|
|
146
|
-
type: 'response',
|
|
147
|
-
level,
|
|
148
|
-
action: ACTION.HTTP_RES,
|
|
149
|
-
method,
|
|
150
|
-
url: urlPath,
|
|
151
|
-
status,
|
|
152
|
-
duration,
|
|
153
|
-
data,
|
|
154
|
-
traceId,
|
|
155
|
-
message,
|
|
156
|
-
timestamp: new Date(),
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
this.emit('response', event);
|
|
160
|
-
|
|
161
|
-
// Log response body as separate debug entry
|
|
162
|
-
if (data) {
|
|
163
|
-
const bodyJson = this._formatBody(data);
|
|
164
|
-
const fullBody = this._formatBody(data, Infinity); // Full body for copying
|
|
165
|
-
if (bodyJson) {
|
|
166
|
-
const bodyMsg = this._formatMessage(LEVEL.DEBUG, ACTION.HTTP_RES, traceId, `body: ${bodyJson}`);
|
|
167
|
-
this.emit('response', {
|
|
168
|
-
...event,
|
|
169
|
-
level: LEVEL.DEBUG,
|
|
170
|
-
message: bodyMsg,
|
|
171
|
-
fullMessage: `body: ${fullBody}`, // Store full message for copying
|
|
172
|
-
isBody: true,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Log an HTTP error
|
|
180
|
-
* @param {string} method - HTTP method
|
|
181
|
-
* @param {string} url - Request URL
|
|
182
|
-
* @param {Error} error - Error object
|
|
183
|
-
* @param {number} duration - Request duration in ms
|
|
184
|
-
* @param {string} traceId - Trace ID from response headers (optional)
|
|
185
|
-
*/
|
|
186
|
-
logError(method, url, error, duration, traceId = null) {
|
|
187
|
-
if (!this.enabled) return;
|
|
188
|
-
|
|
189
|
-
const urlPath = this._extractPath(url);
|
|
190
|
-
const msg = `${method} ${urlPath} ERROR: ${error.message} ${duration}ms`;
|
|
191
|
-
const message = this._formatMessage(LEVEL.ERROR, ACTION.HTTP_ERR, traceId, msg);
|
|
192
|
-
|
|
193
|
-
this.emit('error', {
|
|
194
|
-
type: 'error',
|
|
195
|
-
level: LEVEL.ERROR,
|
|
196
|
-
action: ACTION.HTTP_ERR,
|
|
197
|
-
method,
|
|
198
|
-
url: urlPath,
|
|
199
|
-
error: error.message,
|
|
200
|
-
duration,
|
|
201
|
-
traceId,
|
|
202
|
-
message,
|
|
203
|
-
timestamp: new Date(),
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Log a generic message (for session, cmd, etc.)
|
|
209
|
-
* @param {string} level - Log level
|
|
210
|
-
* @param {string} action - Action type
|
|
211
|
-
* @param {string} msg - Message
|
|
212
|
-
* @param {string} traceId - Trace ID (optional)
|
|
213
|
-
*/
|
|
214
|
-
log(level, action, msg, traceId = null) {
|
|
215
|
-
if (!this.enabled) return;
|
|
216
|
-
|
|
217
|
-
const message = this._formatMessage(level, action, traceId, msg);
|
|
218
|
-
|
|
219
|
-
this.emit('log', {
|
|
220
|
-
type: 'log',
|
|
221
|
-
level,
|
|
222
|
-
action,
|
|
223
|
-
traceId,
|
|
224
|
-
message,
|
|
225
|
-
timestamp: new Date(),
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Extract path from full URL
|
|
231
|
-
*/
|
|
232
|
-
_extractPath(url) {
|
|
233
|
-
try {
|
|
234
|
-
const urlObj = new URL(url);
|
|
235
|
-
return urlObj.pathname;
|
|
236
|
-
} catch {
|
|
237
|
-
// If URL parsing fails, try to extract path manually
|
|
238
|
-
const match = url.match(/\/apis\/.*$/);
|
|
239
|
-
return match ? match[0] : url;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Export constants
|
|
245
|
-
HttpLogger.ACTION = ACTION;
|
|
246
|
-
HttpLogger.LEVEL = LEVEL;
|
|
247
|
-
|
|
248
|
-
// Singleton instance
|
|
249
|
-
const httpLogger = new HttpLogger();
|
|
250
|
-
|
|
251
|
-
module.exports = { httpLogger, HttpLogger };
|
package/sdks/sandbox/index.js
DELETED
package/utils/asciiArt.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ASCII 艺术字工具
|
|
3
|
-
* 提供 ROCK CLI 的 ASCII 艺术字显示功能(统一管理)
|
|
4
|
-
*
|
|
5
|
-
* 与 install.sh 保持一致的 Logo 格式和配色
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// 渐变色(与 install.sh 一致:蓝色到紫色)
|
|
9
|
-
const GRADIENT_COLORS = ['#2563EB', '#3B82F6', '#4F46E5', '#6366F1', '#7C3AED', '#8B5CF6'];
|
|
10
|
-
|
|
11
|
-
// Unicode 版 Logo(与 install.sh 保持一致的紧凑格式)
|
|
12
|
-
const UNICODE_LOGO_LINES = [
|
|
13
|
-
' ██████╗ ██████╗ ██████╗██╗ ██╗ ██████╗██╗ ██╗',
|
|
14
|
-
' ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝ ██╔════╝██║ ██║',
|
|
15
|
-
' ██████╔╝██║ ██║██║ █████╔╝ ██║ ██║ ██║',
|
|
16
|
-
' ██╔══██╗██║ ██║██║ ██╔═██╗ ██║ ██║ ██║',
|
|
17
|
-
' ██║ ██║╚██████╔╝╚██████╗██║ ██╗ ╚██████╗███████╗██║',
|
|
18
|
-
' ╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝',
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
// 简单 ASCII 版 Logo(兼容老终端)
|
|
22
|
-
const SIMPLE_LOGO_LINES = [
|
|
23
|
-
'____ ___ ____ _ __ ____ _ ___ ',
|
|
24
|
-
'| _ \\ / _ \\ / ___| |/ / / ___| | |_ _|',
|
|
25
|
-
'| |_) | | | | | | \' / | | | | | | ',
|
|
26
|
-
'| _ <| |_| | |___| . \\ | |___| |___ | | ',
|
|
27
|
-
'|_| \\_\\\\___/ \\____|_|\\_\\ \\____|_____|___|',
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 检测终端能力
|
|
32
|
-
* @returns {{ supportsUnicode: boolean, colorLevel: number }}
|
|
33
|
-
* colorLevel: 0=无颜色, 1=16色, 2=256色, 3=24-bit
|
|
34
|
-
*/
|
|
35
|
-
function detectTerminalCapabilities() {
|
|
36
|
-
const term = process.env.TERM || '';
|
|
37
|
-
|
|
38
|
-
// 用户强制覆盖(优先级最高)
|
|
39
|
-
if (process.env.ROCK_ASCII_UNICODE === '1') {
|
|
40
|
-
return { supportsUnicode: true, colorLevel: 3 };
|
|
41
|
-
}
|
|
42
|
-
if (process.env.ROCK_ASCII_SIMPLE === '1') {
|
|
43
|
-
return { supportsUnicode: false, colorLevel: 1 };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 只有明确不支持的终端才降级(TERM 检查优先)
|
|
47
|
-
if (term === 'linux' || term === 'dumb') {
|
|
48
|
-
return { supportsUnicode: false, colorLevel: term === 'dumb' ? 0 : 1 };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 非 TTY(管道/重定向)→ 无颜色,但保持 Unicode
|
|
52
|
-
if (!process.stdout.isTTY) {
|
|
53
|
-
return { supportsUnicode: true, colorLevel: 0 };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 用户明确禁用颜色
|
|
57
|
-
if (process.env.NO_COLOR) {
|
|
58
|
-
return { supportsUnicode: true, colorLevel: 0 };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 默认启用 Box Drawing(与 install.sh 一致)
|
|
62
|
-
return { supportsUnicode: true, colorLevel: 3 };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 获取 Logo 行数组(用于 TUI 逐行渲染)
|
|
67
|
-
* @returns {string[]} Logo 行数组
|
|
68
|
-
*/
|
|
69
|
-
function getLogoLines() {
|
|
70
|
-
const { supportsUnicode } = detectTerminalCapabilities();
|
|
71
|
-
return supportsUnicode ? UNICODE_LOGO_LINES : SIMPLE_LOGO_LINES;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* 获取渐变颜色数组
|
|
76
|
-
* @returns {string[]} 渐变颜色数组(hex 格式)
|
|
77
|
-
*/
|
|
78
|
-
function getGradientColors() {
|
|
79
|
-
return GRADIENT_COLORS;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 将 hex 颜色转换为 ANSI 24-bit 颜色代码
|
|
84
|
-
*/
|
|
85
|
-
function hexToAnsi24bit(hex) {
|
|
86
|
-
const r = parseInt(hex.slice(1, 3), 16);
|
|
87
|
-
const g = parseInt(hex.slice(3, 5), 16);
|
|
88
|
-
const b = parseInt(hex.slice(5, 7), 16);
|
|
89
|
-
return `\x1b[38;2;${r};${g};${b}m`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 显示 ROCK CLI 的 ASCII 艺术字(智能降级)
|
|
94
|
-
* @returns {string} ASCII 艺术字符串(可直接 console.log)
|
|
95
|
-
*/
|
|
96
|
-
function showAsciiArt() {
|
|
97
|
-
const { supportsUnicode, colorLevel } = detectTerminalCapabilities();
|
|
98
|
-
const lines = supportsUnicode ? UNICODE_LOGO_LINES : SIMPLE_LOGO_LINES;
|
|
99
|
-
const reset = '\x1b[0m';
|
|
100
|
-
const bold = '\x1b[1m';
|
|
101
|
-
|
|
102
|
-
let result = '\n';
|
|
103
|
-
for (let i = 0; i < lines.length; i++) {
|
|
104
|
-
let colorCode = '';
|
|
105
|
-
|
|
106
|
-
if (colorLevel === 3) {
|
|
107
|
-
// 24-bit 渐变色
|
|
108
|
-
colorCode = hexToAnsi24bit(GRADIENT_COLORS[i % GRADIENT_COLORS.length]);
|
|
109
|
-
} else if (colorLevel >= 1) {
|
|
110
|
-
// 16 色降级
|
|
111
|
-
colorCode = `\x1b[${ANSI_16_COLORS[i % ANSI_16_COLORS.length]}m`;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (colorLevel > 0) {
|
|
115
|
-
result += `${colorCode}${bold}${lines[i]}${reset}\n`;
|
|
116
|
-
} else {
|
|
117
|
-
result += `${lines[i]}\n`;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* 获取无颜色的 Logo 字符串
|
|
125
|
-
* @returns {string} 无颜色 Logo 字符串
|
|
126
|
-
*/
|
|
127
|
-
function getPlainLogo() {
|
|
128
|
-
return getLogoLines().join('\n');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
module.exports = {
|
|
132
|
-
showAsciiArt,
|
|
133
|
-
getLogoLines,
|
|
134
|
-
getGradientColors,
|
|
135
|
-
getPlainLogo,
|
|
136
|
-
UNICODE_LOGO_LINES,
|
|
137
|
-
GRADIENT_COLORS,
|
|
138
|
-
};
|
package/utils/bun-compat.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bun runtime compatibility patcher
|
|
3
|
-
*
|
|
4
|
-
* Patches follow-redirects module to fix:
|
|
5
|
-
* "First argument must be an Error object" error in Bun
|
|
6
|
-
*
|
|
7
|
-
* Issue: https://github.com/oven-sh/bun/issues/15750
|
|
8
|
-
*
|
|
9
|
-
* This must be imported BEFORE any module that uses axios/follow-redirects
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
// Check if running in Bun
|
|
16
|
-
const isBun = typeof Bun !== 'undefined' || process.versions?.bun;
|
|
17
|
-
|
|
18
|
-
if (isBun) {
|
|
19
|
-
try {
|
|
20
|
-
const followRedirectsPath = require.resolve('follow-redirects');
|
|
21
|
-
const indexJsPath = path.join(path.dirname(followRedirectsPath), 'index.js');
|
|
22
|
-
|
|
23
|
-
if (fs.existsSync(indexJsPath)) {
|
|
24
|
-
let content = fs.readFileSync(indexJsPath, 'utf-8');
|
|
25
|
-
|
|
26
|
-
// Check if already patched
|
|
27
|
-
if (!content.includes('// BUN_COMPAT_PATCH')) {
|
|
28
|
-
// Patch: Wrap Error.captureStackTrace call to handle non-Error objects
|
|
29
|
-
const originalCode = `if (isFunction(Error.captureStackTrace)) {
|
|
30
|
-
Error.captureStackTrace(this, this.constructor);
|
|
31
|
-
}`;
|
|
32
|
-
|
|
33
|
-
const patchedCode = `// BUN_COMPAT_PATCH: Handle Bun runtime compatibility
|
|
34
|
-
if (isFunction(Error.captureStackTrace)) {
|
|
35
|
-
try {
|
|
36
|
-
Error.captureStackTrace(this, this.constructor);
|
|
37
|
-
} catch (e) {
|
|
38
|
-
// Ignore captureStackTrace errors in Bun runtime
|
|
39
|
-
// The error object is still valid without stack trace capture
|
|
40
|
-
}
|
|
41
|
-
}`;
|
|
42
|
-
|
|
43
|
-
content = content.replace(originalCode, patchedCode);
|
|
44
|
-
|
|
45
|
-
if (content.includes('// BUN_COMPAT_PATCH')) {
|
|
46
|
-
fs.writeFileSync(indexJsPath, content);
|
|
47
|
-
// Only log in debug mode to avoid cluttering output
|
|
48
|
-
if (process.env.DEBUG) {
|
|
49
|
-
console.log('[bun-compat] Patched follow-redirects for Bun compatibility');
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
} catch (e) {
|
|
55
|
-
// follow-redirects not found or patch failed, ignore silently
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
module.exports = { isBun };
|