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.
Files changed (75) hide show
  1. package/README.md +400 -0
  2. package/index.js +51 -21
  3. package/package.json +1 -1
  4. package/commands/log/core/constants.js +0 -237
  5. package/commands/log/core/display.js +0 -370
  6. package/commands/log/core/search.js +0 -330
  7. package/commands/log/core/tail.js +0 -216
  8. package/commands/log/core/utils.js +0 -424
  9. package/commands/log.js +0 -298
  10. package/commands/sandbox/core/log-bridge.js +0 -119
  11. package/commands/sandbox/core/replay/analyzer.js +0 -311
  12. package/commands/sandbox/core/replay/batch-orchestrator.js +0 -536
  13. package/commands/sandbox/core/replay/batch-task.js +0 -369
  14. package/commands/sandbox/core/replay/concurrent-display.js +0 -70
  15. package/commands/sandbox/core/replay/concurrent-orchestrator.js +0 -170
  16. package/commands/sandbox/core/replay/data-source.js +0 -86
  17. package/commands/sandbox/core/replay/display.js +0 -231
  18. package/commands/sandbox/core/replay/executor.js +0 -634
  19. package/commands/sandbox/core/replay/history-fetcher.js +0 -124
  20. package/commands/sandbox/core/replay/index.js +0 -338
  21. package/commands/sandbox/core/replay/loghouse-data-source.js +0 -177
  22. package/commands/sandbox/core/replay/pid-mapping.js +0 -26
  23. package/commands/sandbox/core/replay/request.js +0 -109
  24. package/commands/sandbox/core/replay/worker.js +0 -166
  25. package/commands/sandbox/core/session.js +0 -346
  26. package/commands/sandbox/log-bridge.js +0 -2
  27. package/commands/sandbox/ray.js +0 -2
  28. package/commands/sandbox/replay/analyzer.js +0 -311
  29. package/commands/sandbox/replay/batch-orchestrator.js +0 -536
  30. package/commands/sandbox/replay/batch-task.js +0 -369
  31. package/commands/sandbox/replay/concurrent-display.js +0 -70
  32. package/commands/sandbox/replay/concurrent-orchestrator.js +0 -170
  33. package/commands/sandbox/replay/display.js +0 -231
  34. package/commands/sandbox/replay/executor.js +0 -634
  35. package/commands/sandbox/replay/history-fetcher.js +0 -118
  36. package/commands/sandbox/replay/index.js +0 -338
  37. package/commands/sandbox/replay/pid-mapping.js +0 -26
  38. package/commands/sandbox/replay/request.js +0 -109
  39. package/commands/sandbox/replay/worker.js +0 -166
  40. package/commands/sandbox/replay.js +0 -2
  41. package/commands/sandbox/session.js +0 -2
  42. package/commands/sandbox-original.js +0 -1393
  43. package/commands/sandbox.js +0 -499
  44. package/help/help.json +0 -1071
  45. package/help/middleware.js +0 -71
  46. package/help/renderer.js +0 -800
  47. package/lib/plugin-context.js +0 -40
  48. package/sdks/sandbox/core/client.js +0 -845
  49. package/sdks/sandbox/core/config.js +0 -70
  50. package/sdks/sandbox/core/types.js +0 -74
  51. package/sdks/sandbox/httpLogger.js +0 -251
  52. package/sdks/sandbox/index.js +0 -9
  53. package/utils/asciiArt.js +0 -138
  54. package/utils/bun-compat.js +0 -59
  55. package/utils/ciPipelines.js +0 -138
  56. package/utils/cli.js +0 -17
  57. package/utils/command-router.js +0 -79
  58. package/utils/configManager.js +0 -503
  59. package/utils/dependency-resolver.js +0 -135
  60. package/utils/eagleeye_traceid.js +0 -151
  61. package/utils/envDetector.js +0 -78
  62. package/utils/execution_logger.js +0 -415
  63. package/utils/featureManager.js +0 -68
  64. package/utils/firstTimeTip.js +0 -44
  65. package/utils/hook-manager.js +0 -125
  66. package/utils/http-logger.js +0 -264
  67. package/utils/i18n.js +0 -139
  68. package/utils/image-progress.js +0 -159
  69. package/utils/logger.js +0 -154
  70. package/utils/plugin-loader.js +0 -124
  71. package/utils/plugin-manager.js +0 -348
  72. package/utils/ray_cli_wrapper.js +0 -746
  73. package/utils/sandbox-client.js +0 -419
  74. package/utils/terminal.js +0 -32
  75. 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 };
@@ -1,9 +0,0 @@
1
- // Sandbox SDK - Core implementation (Open Source)
2
- const { SandboxClient } = require('./core/client');
3
- const { SandboxConfig } = require('./core/config');
4
-
5
- module.exports = {
6
- // Core exports (Open Source)
7
- SandboxClient,
8
- SandboxConfig,
9
- };
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
- };
@@ -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 };