@cloudflare/sandbox 0.5.1 → 0.5.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.
@@ -1,15 +1,23 @@
1
1
 
2
- > @cloudflare/sandbox@0.5.1 build
2
+ > @cloudflare/sandbox@0.5.3 build
3
3
  > rm -rf dist && tsdown --config tsdown.config.ts
4
4
 
5
- ℹ tsdown v0.16.4 powered by rolldown v1.0.0-beta.50
5
+ ℹ tsdown v0.16.6 powered by rolldown v1.0.0-beta.51
6
6
  ℹ Using tsdown config: /home/runner/work/sandbox-sdk/sandbox-sdk/packages/sandbox/tsdown.config.ts
7
- ℹ entry: src/index.ts
7
+ ℹ entry: src/index.ts, src/openai/index.ts
8
8
  ℹ tsconfig: tsconfig.json
9
9
  ℹ Build start
10
- ℹ dist/index.js 118.95 kB │ gzip: 28.12 kB
11
- ℹ dist/index.js.map 247.16 kB │ gzip: 56.13 kB
12
- ℹ dist/index.d.ts.map  72.87 kB │ gzip: 20.09 kB
13
- ℹ dist/index.d.ts  58.32 kB │ gzip: 13.36 kB
14
- ℹ 4 files, total: 497.30 kB
15
- ✔ Build complete in 2409ms
10
+ ℹ dist/index.js 102.82 kB │ gzip: 23.33 kB
11
+ ℹ dist/openai/index.js  10.42 kB │ gzip: 2.63 kB
12
+ ℹ dist/index.js.map 219.05 kB │ gzip: 48.46 kB
13
+ ℹ dist/sandbox-HQazw9bn.d.ts.map  61.69 kB │ gzip: 16.89 kB
14
+ ℹ dist/dist-gVyG2H2h.js.map  30.14 kB │ gzip: 8.31 kB
15
+ ℹ dist/openai/index.js.map  21.00 kB │ gzip: 5.13 kB
16
+ ℹ dist/dist-gVyG2H2h.js  17.03 kB │ gzip: 5.39 kB
17
+ ℹ dist/index.d.ts.map  9.22 kB │ gzip: 2.82 kB
18
+ ℹ dist/openai/index.d.ts.map  0.72 kB │ gzip: 0.37 kB
19
+ ℹ dist/index.d.ts  11.11 kB │ gzip: 3.32 kB
20
+ ℹ dist/openai/index.d.ts  2.10 kB │ gzip: 0.81 kB
21
+ ℹ dist/sandbox-HQazw9bn.d.ts  51.36 kB │ gzip: 11.79 kB
22
+ ℹ 12 files, total: 536.66 kB
23
+ ✔ Build complete in 3733ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @cloudflare/sandbox
2
2
 
3
+ ## 0.5.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#204](https://github.com/cloudflare/sandbox-sdk/pull/204) [`55981f8`](https://github.com/cloudflare/sandbox-sdk/commit/55981f8802b4e0d3b65b947ef8ba7ae2bae183d7) Thanks [@whoiskatrin](https://github.com/whoiskatrin)! - add environment variables and working directory support to command exec
8
+
9
+ ## 0.5.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [#234](https://github.com/cloudflare/sandbox-sdk/pull/234) [`d4cee5e`](https://github.com/cloudflare/sandbox-sdk/commit/d4cee5e4617db205c9c1ca714e25493de7ea24ce) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Remove unused logging infrastructure (getLogger, runWithLogger) that was never called
14
+
15
+ - [#224](https://github.com/cloudflare/sandbox-sdk/pull/224) [`71e86f4`](https://github.com/cloudflare/sandbox-sdk/commit/71e86f42c3b98424db79c268d55f2d5be5e495b3) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix memory leaks from listener accumulation, unbounded process storage, and stale DO state
16
+
17
+ - [#221](https://github.com/cloudflare/sandbox-sdk/pull/221) [`3aba9e8`](https://github.com/cloudflare/sandbox-sdk/commit/3aba9e8da6e2e6acd7b40076cc0920a69cb02775) Thanks [@threepointone](https://github.com/threepointone)! - Add OpenAI Agents adapters
18
+
19
+ Add OpenAI Agents adapters (`Shell` and `Editor`) that integrate Cloudflare Sandbox with the OpenAI Agents SDK. These adapters enable AI agents to execute shell commands and perform file operations (create, update, delete) inside sandboxed environments. Both adapters automatically collect and timestamp results from operations, making it easy to track command execution and file modifications during agent sessions. The adapters are exported from `@cloudflare/sandbox/openai` and implement the OpenAI Agents `Shell` and `Editor` interfaces.
20
+
3
21
  ## 0.5.1
4
22
 
5
23
  ### Patch Changes
@@ -0,0 +1,612 @@
1
+ //#region ../shared/dist/env.js
2
+ /**
3
+ * Safely extract a string value from an environment object
4
+ *
5
+ * @param env - Environment object with dynamic keys
6
+ * @param key - The environment variable key to access
7
+ * @returns The string value if present and is a string, undefined otherwise
8
+ */
9
+ function getEnvString(env, key) {
10
+ const value = env?.[key];
11
+ return typeof value === "string" ? value : void 0;
12
+ }
13
+
14
+ //#endregion
15
+ //#region ../shared/dist/git.js
16
+ /**
17
+ * Redact credentials from URLs for secure logging
18
+ *
19
+ * Replaces any credentials (username:password, tokens, etc.) embedded
20
+ * in URLs with ****** to prevent sensitive data exposure in logs.
21
+ * Works with URLs embedded in text (e.g., "Error: https://token@github.com/repo.git failed")
22
+ *
23
+ * @param text - String that may contain URLs with credentials
24
+ * @returns String with credentials redacted from any URLs
25
+ */
26
+ function redactCredentials(text) {
27
+ let result = text;
28
+ let pos = 0;
29
+ while (pos < result.length) {
30
+ const httpPos = result.indexOf("http://", pos);
31
+ const httpsPos = result.indexOf("https://", pos);
32
+ let protocolPos = -1;
33
+ let protocolLen = 0;
34
+ if (httpPos === -1 && httpsPos === -1) break;
35
+ if (httpPos !== -1 && (httpsPos === -1 || httpPos < httpsPos)) {
36
+ protocolPos = httpPos;
37
+ protocolLen = 7;
38
+ } else {
39
+ protocolPos = httpsPos;
40
+ protocolLen = 8;
41
+ }
42
+ const searchStart = protocolPos + protocolLen;
43
+ const atPos = result.indexOf("@", searchStart);
44
+ let urlEnd = searchStart;
45
+ while (urlEnd < result.length) {
46
+ const char = result[urlEnd];
47
+ if (/[\s"'`<>,;{}[\]]/.test(char)) break;
48
+ urlEnd++;
49
+ }
50
+ if (atPos !== -1 && atPos < urlEnd) {
51
+ result = `${result.substring(0, searchStart)}******${result.substring(atPos)}`;
52
+ pos = searchStart + 6;
53
+ } else pos = protocolPos + protocolLen;
54
+ }
55
+ return result;
56
+ }
57
+ /**
58
+ * Sanitize data by redacting credentials from any strings
59
+ * Recursively processes objects and arrays to ensure credentials are never leaked
60
+ */
61
+ function sanitizeGitData(data) {
62
+ if (typeof data === "string") return redactCredentials(data);
63
+ if (data === null || data === void 0) return data;
64
+ if (Array.isArray(data)) return data.map((item) => sanitizeGitData(item));
65
+ if (typeof data === "object") {
66
+ const result = {};
67
+ for (const [key, value] of Object.entries(data)) result[key] = sanitizeGitData(value);
68
+ return result;
69
+ }
70
+ return data;
71
+ }
72
+ /**
73
+ * Logger wrapper that automatically sanitizes git credentials
74
+ */
75
+ var GitLogger = class GitLogger {
76
+ baseLogger;
77
+ constructor(baseLogger) {
78
+ this.baseLogger = baseLogger;
79
+ }
80
+ sanitizeContext(context) {
81
+ return context ? sanitizeGitData(context) : context;
82
+ }
83
+ sanitizeError(error) {
84
+ if (!error) return error;
85
+ const sanitized = new Error(redactCredentials(error.message));
86
+ sanitized.name = error.name;
87
+ if (error.stack) sanitized.stack = redactCredentials(error.stack);
88
+ const sanitizedRecord = sanitized;
89
+ const errorRecord = error;
90
+ for (const key of Object.keys(error)) if (key !== "message" && key !== "stack" && key !== "name") sanitizedRecord[key] = sanitizeGitData(errorRecord[key]);
91
+ return sanitized;
92
+ }
93
+ debug(message, context) {
94
+ this.baseLogger.debug(message, this.sanitizeContext(context));
95
+ }
96
+ info(message, context) {
97
+ this.baseLogger.info(message, this.sanitizeContext(context));
98
+ }
99
+ warn(message, context) {
100
+ this.baseLogger.warn(message, this.sanitizeContext(context));
101
+ }
102
+ error(message, error, context) {
103
+ this.baseLogger.error(message, this.sanitizeError(error), this.sanitizeContext(context));
104
+ }
105
+ child(context) {
106
+ const sanitized = sanitizeGitData(context);
107
+ return new GitLogger(this.baseLogger.child(sanitized));
108
+ }
109
+ };
110
+
111
+ //#endregion
112
+ //#region ../shared/dist/interpreter-types.js
113
+ var Execution = class {
114
+ code;
115
+ context;
116
+ /**
117
+ * All results from the execution
118
+ */
119
+ results = [];
120
+ /**
121
+ * Accumulated stdout and stderr
122
+ */
123
+ logs = {
124
+ stdout: [],
125
+ stderr: []
126
+ };
127
+ /**
128
+ * Execution error if any
129
+ */
130
+ error;
131
+ /**
132
+ * Execution count (for interpreter)
133
+ */
134
+ executionCount;
135
+ constructor(code, context) {
136
+ this.code = code;
137
+ this.context = context;
138
+ }
139
+ /**
140
+ * Convert to a plain object for serialization
141
+ */
142
+ toJSON() {
143
+ return {
144
+ code: this.code,
145
+ logs: this.logs,
146
+ error: this.error,
147
+ executionCount: this.executionCount,
148
+ results: this.results.map((result) => ({
149
+ text: result.text,
150
+ html: result.html,
151
+ png: result.png,
152
+ jpeg: result.jpeg,
153
+ svg: result.svg,
154
+ latex: result.latex,
155
+ markdown: result.markdown,
156
+ javascript: result.javascript,
157
+ json: result.json,
158
+ chart: result.chart,
159
+ data: result.data
160
+ }))
161
+ };
162
+ }
163
+ };
164
+ var ResultImpl = class {
165
+ raw;
166
+ constructor(raw) {
167
+ this.raw = raw;
168
+ }
169
+ get text() {
170
+ return this.raw.text || this.raw.data?.["text/plain"];
171
+ }
172
+ get html() {
173
+ return this.raw.html || this.raw.data?.["text/html"];
174
+ }
175
+ get png() {
176
+ return this.raw.png || this.raw.data?.["image/png"];
177
+ }
178
+ get jpeg() {
179
+ return this.raw.jpeg || this.raw.data?.["image/jpeg"];
180
+ }
181
+ get svg() {
182
+ return this.raw.svg || this.raw.data?.["image/svg+xml"];
183
+ }
184
+ get latex() {
185
+ return this.raw.latex || this.raw.data?.["text/latex"];
186
+ }
187
+ get markdown() {
188
+ return this.raw.markdown || this.raw.data?.["text/markdown"];
189
+ }
190
+ get javascript() {
191
+ return this.raw.javascript || this.raw.data?.["application/javascript"];
192
+ }
193
+ get json() {
194
+ return this.raw.json || this.raw.data?.["application/json"];
195
+ }
196
+ get chart() {
197
+ return this.raw.chart;
198
+ }
199
+ get data() {
200
+ return this.raw.data;
201
+ }
202
+ formats() {
203
+ const formats = [];
204
+ if (this.text) formats.push("text");
205
+ if (this.html) formats.push("html");
206
+ if (this.png) formats.push("png");
207
+ if (this.jpeg) formats.push("jpeg");
208
+ if (this.svg) formats.push("svg");
209
+ if (this.latex) formats.push("latex");
210
+ if (this.markdown) formats.push("markdown");
211
+ if (this.javascript) formats.push("javascript");
212
+ if (this.json) formats.push("json");
213
+ if (this.chart) formats.push("chart");
214
+ return formats;
215
+ }
216
+ };
217
+
218
+ //#endregion
219
+ //#region ../shared/dist/logger/types.js
220
+ /**
221
+ * Logger types for Cloudflare Sandbox SDK
222
+ *
223
+ * Provides structured, trace-aware logging across Worker, Durable Object, and Container.
224
+ */
225
+ /**
226
+ * Log levels (from most to least verbose)
227
+ */
228
+ var LogLevel;
229
+ (function(LogLevel$1) {
230
+ LogLevel$1[LogLevel$1["DEBUG"] = 0] = "DEBUG";
231
+ LogLevel$1[LogLevel$1["INFO"] = 1] = "INFO";
232
+ LogLevel$1[LogLevel$1["WARN"] = 2] = "WARN";
233
+ LogLevel$1[LogLevel$1["ERROR"] = 3] = "ERROR";
234
+ })(LogLevel || (LogLevel = {}));
235
+
236
+ //#endregion
237
+ //#region ../shared/dist/logger/logger.js
238
+ /**
239
+ * Logger implementation
240
+ */
241
+ /**
242
+ * ANSI color codes for terminal output
243
+ */
244
+ const COLORS = {
245
+ reset: "\x1B[0m",
246
+ debug: "\x1B[36m",
247
+ info: "\x1B[32m",
248
+ warn: "\x1B[33m",
249
+ error: "\x1B[31m",
250
+ dim: "\x1B[2m"
251
+ };
252
+ /**
253
+ * CloudflareLogger implements structured logging with support for
254
+ * both JSON output (production) and pretty printing (development).
255
+ */
256
+ var CloudflareLogger = class CloudflareLogger {
257
+ baseContext;
258
+ minLevel;
259
+ pretty;
260
+ /**
261
+ * Create a new CloudflareLogger
262
+ *
263
+ * @param baseContext Base context included in all log entries
264
+ * @param minLevel Minimum log level to output (default: INFO)
265
+ * @param pretty Enable pretty printing for human-readable output (default: false)
266
+ */
267
+ constructor(baseContext, minLevel = LogLevel.INFO, pretty = false) {
268
+ this.baseContext = baseContext;
269
+ this.minLevel = minLevel;
270
+ this.pretty = pretty;
271
+ }
272
+ /**
273
+ * Log debug-level message
274
+ */
275
+ debug(message, context) {
276
+ if (this.shouldLog(LogLevel.DEBUG)) {
277
+ const logData = this.buildLogData("debug", message, context);
278
+ this.output(console.log, logData);
279
+ }
280
+ }
281
+ /**
282
+ * Log info-level message
283
+ */
284
+ info(message, context) {
285
+ if (this.shouldLog(LogLevel.INFO)) {
286
+ const logData = this.buildLogData("info", message, context);
287
+ this.output(console.log, logData);
288
+ }
289
+ }
290
+ /**
291
+ * Log warning-level message
292
+ */
293
+ warn(message, context) {
294
+ if (this.shouldLog(LogLevel.WARN)) {
295
+ const logData = this.buildLogData("warn", message, context);
296
+ this.output(console.warn, logData);
297
+ }
298
+ }
299
+ /**
300
+ * Log error-level message
301
+ */
302
+ error(message, error, context) {
303
+ if (this.shouldLog(LogLevel.ERROR)) {
304
+ const logData = this.buildLogData("error", message, context, error);
305
+ this.output(console.error, logData);
306
+ }
307
+ }
308
+ /**
309
+ * Create a child logger with additional context
310
+ */
311
+ child(context) {
312
+ return new CloudflareLogger({
313
+ ...this.baseContext,
314
+ ...context
315
+ }, this.minLevel, this.pretty);
316
+ }
317
+ /**
318
+ * Check if a log level should be output
319
+ */
320
+ shouldLog(level) {
321
+ return level >= this.minLevel;
322
+ }
323
+ /**
324
+ * Build log data object
325
+ */
326
+ buildLogData(level, message, context, error) {
327
+ const logData = {
328
+ level,
329
+ msg: message,
330
+ ...this.baseContext,
331
+ ...context,
332
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
333
+ };
334
+ if (error) logData.error = {
335
+ message: error.message,
336
+ stack: error.stack,
337
+ name: error.name
338
+ };
339
+ return logData;
340
+ }
341
+ /**
342
+ * Output log data to console (pretty or JSON)
343
+ */
344
+ output(consoleFn, data) {
345
+ if (this.pretty) this.outputPretty(consoleFn, data);
346
+ else this.outputJson(consoleFn, data);
347
+ }
348
+ /**
349
+ * Output as JSON (production)
350
+ */
351
+ outputJson(consoleFn, data) {
352
+ consoleFn(JSON.stringify(data));
353
+ }
354
+ /**
355
+ * Output as pretty-printed, colored text (development)
356
+ *
357
+ * Format: LEVEL [component] message (trace: tr_...) {context}
358
+ * Example: INFO [sandbox-do] Command started (trace: tr_7f3a9b2c) {commandId: "cmd-123"}
359
+ */
360
+ outputPretty(consoleFn, data) {
361
+ const { level, msg, timestamp, traceId, component, sandboxId, sessionId, processId, commandId, operation, duration, error, ...rest } = data;
362
+ const levelStr = String(level || "INFO").toUpperCase();
363
+ const levelColor = this.getLevelColor(levelStr);
364
+ const componentBadge = component ? `[${component}]` : "";
365
+ const traceIdShort = traceId ? String(traceId).substring(0, 12) : "";
366
+ let logLine = `${levelColor}${levelStr.padEnd(5)}${COLORS.reset} ${componentBadge} ${msg}`;
367
+ if (traceIdShort) logLine += ` ${COLORS.dim}(trace: ${traceIdShort})${COLORS.reset}`;
368
+ const contextFields = [];
369
+ if (operation) contextFields.push(`operation: ${operation}`);
370
+ if (commandId) contextFields.push(`commandId: ${String(commandId).substring(0, 12)}`);
371
+ if (sandboxId) contextFields.push(`sandboxId: ${sandboxId}`);
372
+ if (sessionId) contextFields.push(`sessionId: ${String(sessionId).substring(0, 12)}`);
373
+ if (processId) contextFields.push(`processId: ${processId}`);
374
+ if (duration !== void 0) contextFields.push(`duration: ${duration}ms`);
375
+ if (contextFields.length > 0) logLine += ` ${COLORS.dim}{${contextFields.join(", ")}}${COLORS.reset}`;
376
+ consoleFn(logLine);
377
+ if (error && typeof error === "object") {
378
+ const errorObj = error;
379
+ if (errorObj.message) consoleFn(` ${COLORS.error}Error: ${errorObj.message}${COLORS.reset}`);
380
+ if (errorObj.stack) consoleFn(` ${COLORS.dim}${errorObj.stack}${COLORS.reset}`);
381
+ }
382
+ if (Object.keys(rest).length > 0) consoleFn(` ${COLORS.dim}${JSON.stringify(rest, null, 2)}${COLORS.reset}`);
383
+ }
384
+ /**
385
+ * Get ANSI color code for log level
386
+ */
387
+ getLevelColor(level) {
388
+ switch (level.toLowerCase()) {
389
+ case "debug": return COLORS.debug;
390
+ case "info": return COLORS.info;
391
+ case "warn": return COLORS.warn;
392
+ case "error": return COLORS.error;
393
+ default: return COLORS.reset;
394
+ }
395
+ }
396
+ };
397
+
398
+ //#endregion
399
+ //#region ../shared/dist/logger/trace-context.js
400
+ /**
401
+ * Trace context utilities for request correlation
402
+ *
403
+ * Trace IDs enable correlating logs across distributed components:
404
+ * Worker → Durable Object → Container → back
405
+ *
406
+ * The trace ID is propagated via the X-Trace-Id HTTP header.
407
+ */
408
+ /**
409
+ * Utility for managing trace context across distributed components
410
+ */
411
+ var TraceContext = class TraceContext {
412
+ /**
413
+ * HTTP header name for trace ID propagation
414
+ */
415
+ static TRACE_HEADER = "X-Trace-Id";
416
+ /**
417
+ * Generate a new trace ID
418
+ *
419
+ * Format: "tr_" + 16 random hex characters
420
+ * Example: "tr_7f3a9b2c4e5d6f1a"
421
+ *
422
+ * @returns Newly generated trace ID
423
+ */
424
+ static generate() {
425
+ return `tr_${crypto.randomUUID().replace(/-/g, "").substring(0, 16)}`;
426
+ }
427
+ /**
428
+ * Extract trace ID from HTTP request headers
429
+ *
430
+ * @param headers Request headers
431
+ * @returns Trace ID if present, null otherwise
432
+ */
433
+ static fromHeaders(headers) {
434
+ return headers.get(TraceContext.TRACE_HEADER);
435
+ }
436
+ /**
437
+ * Create headers object with trace ID for outgoing requests
438
+ *
439
+ * @param traceId Trace ID to include
440
+ * @returns Headers object with X-Trace-Id set
441
+ */
442
+ static toHeaders(traceId) {
443
+ return { [TraceContext.TRACE_HEADER]: traceId };
444
+ }
445
+ /**
446
+ * Get the header name used for trace ID propagation
447
+ *
448
+ * @returns Header name ("X-Trace-Id")
449
+ */
450
+ static getHeaderName() {
451
+ return TraceContext.TRACE_HEADER;
452
+ }
453
+ };
454
+
455
+ //#endregion
456
+ //#region ../shared/dist/logger/index.js
457
+ /**
458
+ * Logger module
459
+ *
460
+ * Provides structured, trace-aware logging with:
461
+ * - Explicit logger passing via constructor injection
462
+ * - Pretty printing for local development
463
+ * - JSON output for production
464
+ * - Environment auto-detection
465
+ * - Log level configuration
466
+ *
467
+ * Usage:
468
+ *
469
+ * ```typescript
470
+ * // Create a logger at entry point
471
+ * const logger = createLogger({ component: 'sandbox-do', traceId: 'tr_abc123' });
472
+ *
473
+ * // Pass to classes via constructor
474
+ * const service = new MyService(logger);
475
+ *
476
+ * // Create child loggers for additional context
477
+ * const execLogger = logger.child({ operation: 'exec', commandId: 'cmd-456' });
478
+ * execLogger.info('Operation started');
479
+ * ```
480
+ */
481
+ /**
482
+ * Create a no-op logger for testing
483
+ *
484
+ * Returns a logger that implements the Logger interface but does nothing.
485
+ * Useful for tests that don't need actual logging output.
486
+ *
487
+ * @returns No-op logger instance
488
+ *
489
+ * @example
490
+ * ```typescript
491
+ * // In tests
492
+ * const client = new HttpClient({
493
+ * baseUrl: 'http://test.com',
494
+ * logger: createNoOpLogger() // Optional - tests can enable real logging if needed
495
+ * });
496
+ * ```
497
+ */
498
+ function createNoOpLogger() {
499
+ return {
500
+ debug: () => {},
501
+ info: () => {},
502
+ warn: () => {},
503
+ error: () => {},
504
+ child: () => createNoOpLogger()
505
+ };
506
+ }
507
+ /**
508
+ * Create a new logger instance
509
+ *
510
+ * @param context Base context for the logger. Must include 'component'.
511
+ * TraceId will be auto-generated if not provided.
512
+ * @returns New logger instance
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * // In Durable Object
517
+ * const logger = createLogger({
518
+ * component: 'sandbox-do',
519
+ * traceId: TraceContext.fromHeaders(request.headers) || TraceContext.generate(),
520
+ * sandboxId: this.id
521
+ * });
522
+ *
523
+ * // In Container
524
+ * const logger = createLogger({
525
+ * component: 'container',
526
+ * traceId: TraceContext.fromHeaders(request.headers)!,
527
+ * sessionId: this.id
528
+ * });
529
+ * ```
530
+ */
531
+ function createLogger(context) {
532
+ const minLevel = getLogLevelFromEnv();
533
+ const pretty = isPrettyPrintEnabled();
534
+ return new CloudflareLogger({
535
+ ...context,
536
+ traceId: context.traceId || TraceContext.generate(),
537
+ component: context.component
538
+ }, minLevel, pretty);
539
+ }
540
+ /**
541
+ * Get log level from environment variable
542
+ *
543
+ * Checks SANDBOX_LOG_LEVEL env var, falls back to default based on environment.
544
+ * Default: 'debug' for development, 'info' for production
545
+ */
546
+ function getLogLevelFromEnv() {
547
+ switch ((getEnvVar("SANDBOX_LOG_LEVEL") || "info").toLowerCase()) {
548
+ case "debug": return LogLevel.DEBUG;
549
+ case "info": return LogLevel.INFO;
550
+ case "warn": return LogLevel.WARN;
551
+ case "error": return LogLevel.ERROR;
552
+ default: return LogLevel.INFO;
553
+ }
554
+ }
555
+ /**
556
+ * Check if pretty printing should be enabled
557
+ *
558
+ * Checks SANDBOX_LOG_FORMAT env var, falls back to auto-detection:
559
+ * - Local development: pretty (colored, human-readable)
560
+ * - Production: json (structured)
561
+ */
562
+ function isPrettyPrintEnabled() {
563
+ const format = getEnvVar("SANDBOX_LOG_FORMAT");
564
+ if (format) return format.toLowerCase() === "pretty";
565
+ return false;
566
+ }
567
+ /**
568
+ * Get environment variable value
569
+ *
570
+ * Supports both Node.js (process.env) and Bun (Bun.env)
571
+ */
572
+ function getEnvVar(name) {
573
+ if (typeof process !== "undefined" && process.env) return process.env[name];
574
+ if (typeof Bun !== "undefined") {
575
+ const bunEnv = Bun.env;
576
+ if (bunEnv) return bunEnv[name];
577
+ }
578
+ }
579
+
580
+ //#endregion
581
+ //#region ../shared/dist/shell-escape.js
582
+ /**
583
+ * Escapes a string for safe use in shell commands using POSIX single-quote escaping.
584
+ * Prevents command injection by wrapping the string in single quotes and escaping
585
+ * any single quotes within the string.
586
+ */
587
+ function shellEscape(str) {
588
+ return `'${str.replace(/'/g, "'\\''")}'`;
589
+ }
590
+
591
+ //#endregion
592
+ //#region ../shared/dist/types.js
593
+ function isExecResult(value) {
594
+ return value && typeof value.success === "boolean" && typeof value.exitCode === "number" && typeof value.stdout === "string" && typeof value.stderr === "string";
595
+ }
596
+ function isProcess(value) {
597
+ return value && typeof value.id === "string" && typeof value.command === "string" && typeof value.status === "string";
598
+ }
599
+ function isProcessStatus(value) {
600
+ return [
601
+ "starting",
602
+ "running",
603
+ "completed",
604
+ "failed",
605
+ "killed",
606
+ "error"
607
+ ].includes(value);
608
+ }
609
+
610
+ //#endregion
611
+ export { createLogger as a, Execution as c, getEnvString as d, shellEscape as i, ResultImpl as l, isProcess as n, createNoOpLogger as o, isProcessStatus as r, TraceContext as s, isExecResult as t, GitLogger as u };
612
+ //# sourceMappingURL=dist-gVyG2H2h.js.map