@cloudflare/sandbox 0.13.0-next.776.1 → 0.13.0-next.797.1

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 (33) hide show
  1. package/dist/bridge/index.js +24 -8
  2. package/dist/bridge/index.js.map +1 -1
  3. package/dist/{dist-Duor5GbS.js → dist-n_eniPAR.js} +8 -46
  4. package/dist/dist-n_eniPAR.js.map +1 -0
  5. package/dist/extensions/index.d.ts +2 -2
  6. package/dist/extensions/index.js +2 -2
  7. package/dist/{extensions-CFB2xHqY.js → extensions-Be5HnDGt.js} +2 -2
  8. package/dist/{extensions-CFB2xHqY.js.map → extensions-Be5HnDGt.js.map} +1 -1
  9. package/dist/{filesystem-BWAZCZER.d.ts → filesystem-Y5aF3nmJ.d.ts} +7 -3
  10. package/dist/filesystem-Y5aF3nmJ.d.ts.map +1 -0
  11. package/dist/git/index.d.ts +2 -2
  12. package/dist/git/index.js +2 -2
  13. package/dist/{index-Bs4bqXDR.d.ts → index-DfXx3uZL.d.ts} +2 -2
  14. package/dist/{index-Bs4bqXDR.d.ts.map → index-DfXx3uZL.d.ts.map} +1 -1
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +3 -3
  18. package/dist/interpreter/index.d.ts +2 -2
  19. package/dist/interpreter/index.js +2 -2
  20. package/dist/openai/index.d.ts +2 -2
  21. package/dist/openai/index.d.ts.map +1 -1
  22. package/dist/openai/index.js +10 -34
  23. package/dist/openai/index.js.map +1 -1
  24. package/dist/opencode/index.d.ts +2 -2
  25. package/dist/opencode/index.js +2 -2
  26. package/dist/{sandbox-cmlgGVYX.js → sandbox-BEhPgFZx.js} +127 -48
  27. package/dist/sandbox-BEhPgFZx.js.map +1 -0
  28. package/dist/{sandbox-BbAabq93.d.ts → sandbox-CBkS3tGv.d.ts} +2 -2
  29. package/dist/{sandbox-BbAabq93.d.ts.map → sandbox-CBkS3tGv.d.ts.map} +1 -1
  30. package/package.json +1 -1
  31. package/dist/dist-Duor5GbS.js.map +0 -1
  32. package/dist/filesystem-BWAZCZER.d.ts.map +0 -1
  33. package/dist/sandbox-cmlgGVYX.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["sandbox: ISandbox","output: ShellResult['output']","exitCode: number | null","outcome: ShellOutputResult['outcome']","error: unknown","root: string","result: FileOperationResult","original: string","stack: string[]"],"sources":["../../src/openai/index.ts"],"sourcesContent":["/**\n * OpenAI Agents adapters for executing shell commands and file operations\n * inside a Cloudflare Sandbox.\n */\nimport {\n type ApplyPatchOperation,\n type ApplyPatchResult,\n applyDiff,\n type Editor as OpenAIEeditor,\n type Shell as OpenAIShell,\n type ShellAction,\n type ShellOutputResult,\n type ShellResult\n} from '@openai/agents';\n\n// Command result for API responses\nexport interface CommandResult {\n command: string;\n stdout: string;\n stderr: string;\n exitCode: number | null;\n timestamp: number;\n}\n\n// File operation result for API responses\nexport interface FileOperationResult {\n operation: 'create' | 'update' | 'delete';\n path: string;\n status: 'completed' | 'failed';\n output: string;\n error?: string;\n timestamp: number;\n}\n\nimport { createLogger, type ISandbox, type Logger } from '@repo/shared';\n\n// Helper functions for error handling\nfunction isErrorWithProperties(error: unknown): error is {\n message?: string;\n exitCode?: number;\n stdout?: string;\n stderr?: string;\n status?: number;\n stack?: string;\n} {\n return typeof error === 'object' && error !== null;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isErrorWithProperties(error) && typeof error.message === 'string') {\n return error.message;\n }\n return String(error);\n}\n\n/**\n * Convert unknown values to Error instances when possible so downstream\n * loggers can include stack traces without losing type safety.\n */\nfunction toError(error: unknown): Error | undefined {\n return error instanceof Error ? error : undefined;\n}\n\n/**\n * Shell implementation that adapts Cloudflare Sandbox exec calls to the\n * OpenAI Agents `Shell` contract, including structured result collection.\n */\nexport class Shell implements OpenAIShell {\n private cwd: string = '/workspace';\n public results: CommandResult[] = [];\n private readonly logger: Logger;\n\n constructor(private readonly sandbox: ISandbox) {\n this.logger = createLogger({\n component: 'sandbox-do',\n operation: 'openai-shell'\n });\n }\n\n async run(action: ShellAction): Promise<ShellResult> {\n this.logger.debug('SandboxShell.run called', {\n commands: action.commands,\n timeout: action.timeoutMs\n });\n const output: ShellResult['output'] = [];\n\n for (const command of action.commands) {\n this.logger.debug('Executing command', { command, cwd: this.cwd });\n let stdout = '';\n let stderr = '';\n let exitCode: number | null = 0;\n let outcome: ShellOutputResult['outcome'] = {\n type: 'exit',\n exitCode: 0\n };\n try {\n const proc = await this.sandbox.exec(['/bin/bash', '-lc', command], {\n timeout: action.timeoutMs,\n cwd: this.cwd\n });\n const out = await proc.output();\n stdout = new TextDecoder().decode(out.stdout);\n stderr = new TextDecoder().decode(out.stderr);\n exitCode = out.exitCode;\n // Timeout would be indicated by a specific error or exit code\n outcome = { type: 'exit', exitCode };\n\n this.logger.debug('Command executed successfully', {\n command,\n exitCode,\n stdoutLength: stdout.length,\n stderrLength: stderr.length\n });\n\n // Log warnings for non-zero exit codes or stderr output\n if (exitCode !== 0) {\n this.logger.warn(`Command failed with exit code ${exitCode}`, {\n command,\n stderr\n });\n } else if (stderr) {\n this.logger.warn(`Command produced stderr output`, {\n command,\n stderr\n });\n } else {\n this.logger.info(`Command completed successfully`, { command });\n }\n } catch (error: unknown) {\n // Handle network/HTTP errors or timeout errors\n const errorObj = isErrorWithProperties(error) ? error : {};\n exitCode =\n typeof errorObj.exitCode === 'number' ? errorObj.exitCode : null;\n stdout = typeof errorObj.stdout === 'string' ? errorObj.stdout : '';\n stderr = typeof errorObj.stderr === 'string' ? errorObj.stderr : '';\n\n // Check if it's a timeout error\n const errorMessage = getErrorMessage(error);\n if (\n errorMessage.includes('timeout') ||\n errorMessage.includes('Timeout') ||\n errorMessage.includes('timed out')\n ) {\n this.logger.error(`Command timed out`, undefined, {\n command,\n timeout: action.timeoutMs\n });\n outcome = { type: 'timeout' };\n } else {\n this.logger.error(`Error executing command`, toError(error), {\n command,\n error: errorMessage || error,\n exitCode\n });\n outcome = { type: 'exit', exitCode: exitCode ?? 1 };\n }\n }\n output.push({\n command,\n stdout,\n stderr,\n outcome\n });\n\n // Collect results for API responses\n const collectedExitCode =\n outcome.type === 'exit' ? outcome.exitCode : null;\n const timestamp = Date.now();\n this.results.push({\n command: String(command),\n stdout: String(stdout),\n stderr: String(stderr),\n exitCode: collectedExitCode,\n timestamp\n });\n this.logger.debug('Result collected', {\n command,\n exitCode: collectedExitCode,\n timestamp\n });\n\n if (outcome.type === 'timeout') {\n this.logger.warn('Breaking command loop due to timeout');\n break;\n }\n }\n\n this.logger.debug('SandboxShell.run completed', {\n totalCommands: action.commands.length,\n resultsCount: this.results.length\n });\n return {\n output,\n providerData: {\n working_directory: this.cwd\n }\n };\n }\n}\n\n/**\n * Editor implementation that projects applyPatch operations from Agents\n * into calls against the sandbox filesystem APIs.\n */\nexport class Editor implements OpenAIEeditor {\n public results: FileOperationResult[] = [];\n private readonly logger: Logger;\n\n constructor(\n private readonly sandbox: ISandbox,\n private readonly root: string = '/workspace'\n ) {\n this.logger = createLogger({\n component: 'sandbox-do',\n operation: 'openai-editor'\n });\n }\n\n /**\n * Create a new file inside the sandbox by applying the provided diff.\n */\n async createFile(\n operation: Extract<ApplyPatchOperation, { type: 'create_file' }>\n ): Promise<ApplyPatchResult | undefined> {\n const targetPath = this.resolve(operation.path);\n this.logger.debug('WorkspaceEditor.createFile called', {\n path: operation.path,\n targetPath\n });\n\n try {\n // Create parent directory if needed\n const dirPath = this.getDirname(targetPath);\n if (dirPath !== this.root && dirPath !== '/') {\n this.logger.debug('Creating parent directory', { dirPath });\n await this.sandbox.mkdir(dirPath, { recursive: true });\n }\n\n const content = applyDiff('', operation.diff, 'create');\n this.logger.debug('Writing file content', {\n path: targetPath,\n contentLength: content.length\n });\n await this.sandbox.writeFile(targetPath, content, { encoding: 'utf-8' });\n const timestamp = Date.now();\n const result: FileOperationResult = {\n operation: 'create',\n path: operation.path,\n status: 'completed',\n output: `Created ${operation.path}`,\n timestamp\n };\n this.results.push(result);\n this.logger.info('File created successfully', {\n path: operation.path,\n timestamp\n });\n return { status: 'completed', output: `Created ${operation.path}` };\n } catch (error: unknown) {\n const timestamp = Date.now();\n const errorMessage = getErrorMessage(error);\n const result: FileOperationResult = {\n operation: 'create',\n path: operation.path,\n status: 'failed',\n output: `Failed to create ${operation.path}`,\n error: errorMessage,\n timestamp\n };\n this.results.push(result);\n this.logger.error('Failed to create file', toError(error), {\n path: operation.path,\n error: errorMessage\n });\n throw error;\n }\n }\n\n /**\n * Update an existing file by reading its content, applying a diff, and\n * writing the patched output back to the sandbox.\n */\n async updateFile(\n operation: Extract<ApplyPatchOperation, { type: 'update_file' }>\n ): Promise<ApplyPatchResult | undefined> {\n const targetPath = this.resolve(operation.path);\n this.logger.debug('WorkspaceEditor.updateFile called', {\n path: operation.path,\n targetPath\n });\n\n try {\n let original: string;\n try {\n this.logger.debug('Reading original file', { path: targetPath });\n const fileInfo = await this.sandbox.readFile(targetPath, {\n encoding: 'utf-8'\n });\n original = fileInfo.content;\n this.logger.debug('Original file read', {\n path: targetPath,\n originalLength: original.length\n });\n } catch (error: unknown) {\n // Sandbox API may throw errors for missing files\n const errorObj = isErrorWithProperties(error) ? error : {};\n const errorMessage = getErrorMessage(error);\n if (\n errorMessage.includes('not found') ||\n errorMessage.includes('ENOENT') ||\n errorObj.status === 404\n ) {\n this.logger.error('Cannot update missing file', undefined, {\n path: operation.path\n });\n throw new Error(`Cannot update missing file: ${operation.path}`);\n }\n this.logger.error('Error reading file', toError(error), {\n path: operation.path,\n error: errorMessage\n });\n throw error;\n }\n\n const patched = applyDiff(original, operation.diff);\n this.logger.debug('Applied diff', {\n path: targetPath,\n originalLength: original.length,\n patchedLength: patched.length\n });\n await this.sandbox.writeFile(targetPath, patched, { encoding: 'utf-8' });\n const timestamp = Date.now();\n const result: FileOperationResult = {\n operation: 'update',\n path: operation.path,\n status: 'completed',\n output: `Updated ${operation.path}`,\n timestamp\n };\n this.results.push(result);\n this.logger.info('File updated successfully', {\n path: operation.path,\n timestamp\n });\n return { status: 'completed', output: `Updated ${operation.path}` };\n } catch (error: unknown) {\n const timestamp = Date.now();\n const errorMessage = getErrorMessage(error);\n const result: FileOperationResult = {\n operation: 'update',\n path: operation.path,\n status: 'failed',\n output: `Failed to update ${operation.path}`,\n error: errorMessage,\n timestamp\n };\n this.results.push(result);\n this.logger.error('Failed to update file', toError(error), {\n path: operation.path,\n error: errorMessage\n });\n throw error;\n }\n }\n\n /**\n * Delete a file that was previously created through applyPatch calls.\n */\n async deleteFile(\n operation: Extract<ApplyPatchOperation, { type: 'delete_file' }>\n ): Promise<ApplyPatchResult | undefined> {\n const targetPath = this.resolve(operation.path);\n this.logger.debug('WorkspaceEditor.deleteFile called', {\n path: operation.path,\n targetPath\n });\n\n try {\n await this.sandbox.deleteFile(targetPath);\n const timestamp = Date.now();\n const result: FileOperationResult = {\n operation: 'delete',\n path: operation.path,\n status: 'completed',\n output: `Deleted ${operation.path}`,\n timestamp\n };\n this.results.push(result);\n this.logger.info('File deleted successfully', {\n path: operation.path,\n timestamp\n });\n return { status: 'completed', output: `Deleted ${operation.path}` };\n } catch (error: unknown) {\n const timestamp = Date.now();\n const errorMessage = getErrorMessage(error);\n const result: FileOperationResult = {\n operation: 'delete',\n path: operation.path,\n status: 'failed',\n output: `Failed to delete ${operation.path}`,\n error: errorMessage,\n timestamp\n };\n this.results.push(result);\n this.logger.error('Failed to delete file', toError(error), {\n path: operation.path,\n error: errorMessage\n });\n throw error;\n }\n }\n\n private resolve(relativePath: string): string {\n // If the path already starts with the root, strip it to get the relative part\n let pathToProcess = relativePath;\n if (relativePath.startsWith(this.root)) {\n pathToProcess = relativePath.slice(this.root.length);\n // Remove leading slash if present after stripping root\n pathToProcess = pathToProcess.replace(/^\\//, '');\n }\n\n // Remove leading ./ or / if present, then join with root\n const normalized = pathToProcess.replace(/^\\.\\//, '').replace(/^\\//, '');\n const resolved = normalized ? `${this.root}/${normalized}` : this.root;\n\n // Normalize path separators first\n const pathWithNormalizedSeparators = resolved.replace(/\\/+/g, '/');\n\n // Normalize .. segments by processing path segments\n const segments = pathWithNormalizedSeparators\n .split('/')\n .filter((s) => s && s !== '.');\n const stack: string[] = [];\n\n for (const segment of segments) {\n if (segment === '..') {\n if (stack.length === 0) {\n throw new Error(`Operation outside workspace: ${relativePath}`);\n }\n stack.pop();\n } else {\n stack.push(segment);\n }\n }\n\n const normalizedPath = `/${stack.join('/')}`;\n\n // Ensure the resolved path is within the workspace\n if (!normalizedPath.startsWith(this.root)) {\n throw new Error(`Operation outside workspace: ${relativePath}`);\n }\n\n return normalizedPath;\n }\n\n private getDirname(filePath: string): string {\n const lastSlash = filePath.lastIndexOf('/');\n if (lastSlash === -1) {\n return '/';\n }\n return filePath.substring(0, lastSlash) || '/';\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["sandbox: ISandbox","output: ShellResult['output']","exitCode: number | null","outcome: ShellOutputResult['outcome']","error: unknown","root: string","result: FileOperationResult","original: string","stack: string[]"],"sources":["../../src/openai/index.ts"],"sourcesContent":["/**\n * OpenAI Agents adapters for executing shell commands and file operations\n * inside a Cloudflare Sandbox.\n */\nimport {\n type ApplyPatchOperation,\n type ApplyPatchResult,\n applyDiff,\n type Editor as OpenAIEeditor,\n type Shell as OpenAIShell,\n type ShellAction,\n type ShellOutputResult,\n type ShellResult\n} from '@openai/agents';\n\n// Command result for API responses\nexport interface CommandResult {\n command: string;\n stdout: string;\n stderr: string;\n exitCode: number | null;\n timestamp: number;\n}\n\n// File operation result for API responses\nexport interface FileOperationResult {\n operation: 'create' | 'update' | 'delete';\n path: string;\n status: 'completed' | 'failed';\n output: string;\n error?: string;\n timestamp: number;\n}\n\nimport { createLogger, type ISandbox, type Logger } from '@repo/shared';\n\n// Helper functions for error handling\nfunction isErrorWithProperties(error: unknown): error is {\n message?: string;\n exitCode?: number;\n stdout?: string;\n stderr?: string;\n status?: number;\n stack?: string;\n} {\n return typeof error === 'object' && error !== null;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isErrorWithProperties(error) && typeof error.message === 'string') {\n return error.message;\n }\n return String(error);\n}\n\n/**\n * Convert unknown values to Error instances when possible so downstream\n * loggers can include stack traces without losing type safety.\n */\nfunction toError(error: unknown): Error | undefined {\n return error instanceof Error ? error : undefined;\n}\n\n/**\n * Shell implementation that adapts Cloudflare Sandbox exec calls to the\n * OpenAI Agents `Shell` contract, including structured result collection.\n */\nexport class Shell implements OpenAIShell {\n private cwd: string = '/workspace';\n public results: CommandResult[] = [];\n private readonly logger: Logger;\n\n constructor(private readonly sandbox: ISandbox) {\n this.logger = createLogger({\n component: 'sandbox-do',\n operation: 'openai-shell'\n });\n }\n\n async run(action: ShellAction): Promise<ShellResult> {\n this.logger.debug('SandboxShell.run called', {\n commandCount: action.commands.length,\n timeout: action.timeoutMs\n });\n const output: ShellResult['output'] = [];\n\n for (const command of action.commands) {\n this.logger.debug('Executing command', { cwd: this.cwd });\n let stdout = '';\n let stderr = '';\n let exitCode: number | null = 0;\n let outcome: ShellOutputResult['outcome'] = {\n type: 'exit',\n exitCode: 0\n };\n try {\n const proc = await this.sandbox.exec(['/bin/bash', '-lc', command], {\n timeout: action.timeoutMs,\n cwd: this.cwd\n });\n const out = await proc.output();\n stdout = new TextDecoder().decode(out.stdout);\n stderr = new TextDecoder().decode(out.stderr);\n exitCode = out.exitCode;\n // Timeout would be indicated by a specific error or exit code\n outcome = { type: 'exit', exitCode };\n\n this.logger.debug('Command executed successfully', {\n exitCode,\n stdoutLength: stdout.length,\n stderrLength: stderr.length\n });\n\n // Log warnings for non-zero exit codes or stderr output\n if (exitCode !== 0) {\n this.logger.warn(`Command failed with exit code ${exitCode}`, {\n stderrLength: stderr.length\n });\n } else if (stderr) {\n this.logger.warn(`Command produced stderr output`, {\n stderrLength: stderr.length\n });\n } else {\n this.logger.info(`Command completed successfully`);\n }\n } catch (error: unknown) {\n // Handle network/HTTP errors or timeout errors\n const errorObj = isErrorWithProperties(error) ? error : {};\n exitCode =\n typeof errorObj.exitCode === 'number' ? errorObj.exitCode : null;\n stdout = typeof errorObj.stdout === 'string' ? errorObj.stdout : '';\n stderr = typeof errorObj.stderr === 'string' ? errorObj.stderr : '';\n\n // Check if it's a timeout error\n const errorMessage = getErrorMessage(error);\n if (\n errorMessage.includes('timeout') ||\n errorMessage.includes('Timeout') ||\n errorMessage.includes('timed out')\n ) {\n this.logger.error(`Command timed out`, undefined, {\n timeout: action.timeoutMs\n });\n outcome = { type: 'timeout' };\n } else {\n this.logger.error(`Error executing command`, toError(error), {\n exitCode\n });\n outcome = { type: 'exit', exitCode: exitCode ?? 1 };\n }\n }\n output.push({\n command,\n stdout,\n stderr,\n outcome\n });\n\n // Collect results for API responses\n const collectedExitCode =\n outcome.type === 'exit' ? outcome.exitCode : null;\n const timestamp = Date.now();\n this.results.push({\n command: String(command),\n stdout: String(stdout),\n stderr: String(stderr),\n exitCode: collectedExitCode,\n timestamp\n });\n this.logger.debug('Result collected', {\n exitCode: collectedExitCode,\n timestamp\n });\n\n if (outcome.type === 'timeout') {\n this.logger.warn('Breaking command loop due to timeout');\n break;\n }\n }\n\n this.logger.debug('SandboxShell.run completed', {\n totalCommands: action.commands.length,\n resultsCount: this.results.length\n });\n return {\n output,\n providerData: {\n working_directory: this.cwd\n }\n };\n }\n}\n\n/**\n * Editor implementation that projects applyPatch operations from Agents\n * into calls against the sandbox filesystem APIs.\n */\nexport class Editor implements OpenAIEeditor {\n public results: FileOperationResult[] = [];\n private readonly logger: Logger;\n\n constructor(\n private readonly sandbox: ISandbox,\n private readonly root: string = '/workspace'\n ) {\n this.logger = createLogger({\n component: 'sandbox-do',\n operation: 'openai-editor'\n });\n }\n\n /**\n * Create a new file inside the sandbox by applying the provided diff.\n */\n async createFile(\n operation: Extract<ApplyPatchOperation, { type: 'create_file' }>\n ): Promise<ApplyPatchResult | undefined> {\n const targetPath = this.resolve(operation.path);\n this.logger.debug('WorkspaceEditor.createFile called', {\n path: operation.path,\n targetPath\n });\n\n try {\n // Create parent directory if needed\n const dirPath = this.getDirname(targetPath);\n if (dirPath !== this.root && dirPath !== '/') {\n this.logger.debug('Creating parent directory', { dirPath });\n await this.sandbox.mkdir(dirPath, { recursive: true });\n }\n\n const content = applyDiff('', operation.diff, 'create');\n this.logger.debug('Writing file content', {\n path: targetPath,\n contentLength: content.length\n });\n await this.sandbox.writeFile(targetPath, content, { encoding: 'utf-8' });\n const timestamp = Date.now();\n const result: FileOperationResult = {\n operation: 'create',\n path: operation.path,\n status: 'completed',\n output: `Created ${operation.path}`,\n timestamp\n };\n this.results.push(result);\n this.logger.info('File created successfully', {\n path: operation.path,\n timestamp\n });\n return { status: 'completed', output: `Created ${operation.path}` };\n } catch (error: unknown) {\n const timestamp = Date.now();\n const errorMessage = getErrorMessage(error);\n const result: FileOperationResult = {\n operation: 'create',\n path: operation.path,\n status: 'failed',\n output: `Failed to create ${operation.path}`,\n error: errorMessage,\n timestamp\n };\n this.results.push(result);\n // applyDiff errors quote patch lines, which can hold file contents.\n // The caller still gets the full error.\n this.logger.error('Failed to create file', undefined, {\n path: operation.path\n });\n throw error;\n }\n }\n\n /**\n * Update an existing file by reading its content, applying a diff, and\n * writing the patched output back to the sandbox.\n */\n async updateFile(\n operation: Extract<ApplyPatchOperation, { type: 'update_file' }>\n ): Promise<ApplyPatchResult | undefined> {\n const targetPath = this.resolve(operation.path);\n this.logger.debug('WorkspaceEditor.updateFile called', {\n path: operation.path,\n targetPath\n });\n\n try {\n let original: string;\n try {\n this.logger.debug('Reading original file', { path: targetPath });\n const fileInfo = await this.sandbox.readFile(targetPath, {\n encoding: 'utf-8'\n });\n original = fileInfo.content;\n this.logger.debug('Original file read', {\n path: targetPath,\n originalLength: original.length\n });\n } catch (error: unknown) {\n // Sandbox API may throw errors for missing files\n const errorObj = isErrorWithProperties(error) ? error : {};\n const errorMessage = getErrorMessage(error);\n if (\n errorMessage.includes('not found') ||\n errorMessage.includes('ENOENT') ||\n errorObj.status === 404\n ) {\n this.logger.error('Cannot update missing file', undefined, {\n path: operation.path\n });\n throw new Error(`Cannot update missing file: ${operation.path}`);\n }\n this.logger.error('Error reading file', toError(error), {\n path: operation.path,\n error: errorMessage\n });\n throw error;\n }\n\n const patched = applyDiff(original, operation.diff);\n this.logger.debug('Applied diff', {\n path: targetPath,\n originalLength: original.length,\n patchedLength: patched.length\n });\n await this.sandbox.writeFile(targetPath, patched, { encoding: 'utf-8' });\n const timestamp = Date.now();\n const result: FileOperationResult = {\n operation: 'update',\n path: operation.path,\n status: 'completed',\n output: `Updated ${operation.path}`,\n timestamp\n };\n this.results.push(result);\n this.logger.info('File updated successfully', {\n path: operation.path,\n timestamp\n });\n return { status: 'completed', output: `Updated ${operation.path}` };\n } catch (error: unknown) {\n const timestamp = Date.now();\n const errorMessage = getErrorMessage(error);\n const result: FileOperationResult = {\n operation: 'update',\n path: operation.path,\n status: 'failed',\n output: `Failed to update ${operation.path}`,\n error: errorMessage,\n timestamp\n };\n this.results.push(result);\n // applyDiff errors quote patch lines, which can hold file contents.\n // The caller still gets the full error.\n this.logger.error('Failed to update file', undefined, {\n path: operation.path\n });\n throw error;\n }\n }\n\n /**\n * Delete a file that was previously created through applyPatch calls.\n */\n async deleteFile(\n operation: Extract<ApplyPatchOperation, { type: 'delete_file' }>\n ): Promise<ApplyPatchResult | undefined> {\n const targetPath = this.resolve(operation.path);\n this.logger.debug('WorkspaceEditor.deleteFile called', {\n path: operation.path,\n targetPath\n });\n\n try {\n await this.sandbox.deleteFile(targetPath);\n const timestamp = Date.now();\n const result: FileOperationResult = {\n operation: 'delete',\n path: operation.path,\n status: 'completed',\n output: `Deleted ${operation.path}`,\n timestamp\n };\n this.results.push(result);\n this.logger.info('File deleted successfully', {\n path: operation.path,\n timestamp\n });\n return { status: 'completed', output: `Deleted ${operation.path}` };\n } catch (error: unknown) {\n const timestamp = Date.now();\n const errorMessage = getErrorMessage(error);\n const result: FileOperationResult = {\n operation: 'delete',\n path: operation.path,\n status: 'failed',\n output: `Failed to delete ${operation.path}`,\n error: errorMessage,\n timestamp\n };\n this.results.push(result);\n this.logger.error('Failed to delete file', toError(error), {\n path: operation.path,\n error: errorMessage\n });\n throw error;\n }\n }\n\n private resolve(relativePath: string): string {\n // If the path already starts with the root, strip it to get the relative part\n let pathToProcess = relativePath;\n if (relativePath.startsWith(this.root)) {\n pathToProcess = relativePath.slice(this.root.length);\n // Remove leading slash if present after stripping root\n pathToProcess = pathToProcess.replace(/^\\//, '');\n }\n\n // Remove leading ./ or / if present, then join with root\n const normalized = pathToProcess.replace(/^\\.\\//, '').replace(/^\\//, '');\n const resolved = normalized ? `${this.root}/${normalized}` : this.root;\n\n // Normalize path separators first\n const pathWithNormalizedSeparators = resolved.replace(/\\/+/g, '/');\n\n // Normalize .. segments by processing path segments\n const segments = pathWithNormalizedSeparators\n .split('/')\n .filter((s) => s && s !== '.');\n const stack: string[] = [];\n\n for (const segment of segments) {\n if (segment === '..') {\n if (stack.length === 0) {\n throw new Error(`Operation outside workspace: ${relativePath}`);\n }\n stack.pop();\n } else {\n stack.push(segment);\n }\n }\n\n const normalizedPath = `/${stack.join('/')}`;\n\n // Ensure the resolved path is within the workspace\n if (!normalizedPath.startsWith(this.root)) {\n throw new Error(`Operation outside workspace: ${relativePath}`);\n }\n\n return normalizedPath;\n }\n\n private getDirname(filePath: string): string {\n const lastSlash = filePath.lastIndexOf('/');\n if (lastSlash === -1) {\n return '/';\n }\n return filePath.substring(0, lastSlash) || '/';\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { D as OpenCodeStartupContext } from "../contexts-1EsLHByO.js";
2
2
  import "../process-types-GStiZ8f8.js";
3
- import "../filesystem-BWAZCZER.js";
4
- import { c as SandboxExtension, l as SandboxLike } from "../index-Bs4bqXDR.js";
3
+ import "../filesystem-Y5aF3nmJ.js";
4
+ import { c as SandboxExtension, l as SandboxLike } from "../index-DfXx3uZL.js";
5
5
  import { OpencodeClient } from "@opencode-ai/sdk/v2/client";
6
6
  import { Config } from "@opencode-ai/sdk/v2";
7
7
 
@@ -1,7 +1,7 @@
1
1
  import { i as ErrorCode } from "../errors-CXR0xBpw.js";
2
2
  import "../errors-QYlSkVGz.js";
3
- import { r as createLogger } from "../dist-Duor5GbS.js";
4
- import { n as createExtensionProcessSandbox, t as SandboxExtension } from "../extensions-CFB2xHqY.js";
3
+ import { r as createLogger } from "../dist-n_eniPAR.js";
4
+ import { n as createExtensionProcessSandbox, t as SandboxExtension } from "../extensions-Be5HnDGt.js";
5
5
 
6
6
  //#region ../../extensions/opencode/src/client.ts
7
7
  let createSDKClient;
@@ -1,7 +1,7 @@
1
1
  import { i as ErrorCode, n as getSuggestion, r as getHttpStatus } from "./errors-CXR0xBpw.js";
2
2
  import { $ as TerminalControlError, G as BackupRestoreError, H as BackupCreateError, Q as StaleTerminalHandleError, U as BackupExpiredError, W as BackupNotFoundError, X as OperationInterruptedError, Z as RPCTransportError, _ as StaleProcessHandleError, n as RuntimeIdentityInactiveError, p as ProcessNotFoundError, q as InvalidBackupConfigError, r as RuntimeControlProtocolError, t as createErrorFromResponse, tt as SandboxError, v as CustomDomainRequiredError } from "./errors-QYlSkVGz.js";
3
- import { a as TraceContext, d as partitionEnvVars, i as createNoOpLogger, o as logCanonicalEvent, r as createLogger, t as parseSSEFrames, u as getEnvString } from "./dist-Duor5GbS.js";
4
- import { a as PullSubscriptionTarget, i as createSandboxProcess, o as openRemoteSubscription, r as sandboxRuntimeCall, s as translateRPCError, t as SandboxExtension } from "./extensions-CFB2xHqY.js";
3
+ import { a as TraceContext, d as partitionEnvVars, i as createNoOpLogger, o as logCanonicalEvent, r as createLogger, t as parseSSEFrames, u as getEnvString } from "./dist-n_eniPAR.js";
4
+ import { a as PullSubscriptionTarget, i as createSandboxProcess, o as openRemoteSubscription, r as sandboxRuntimeCall, s as translateRPCError, t as SandboxExtension } from "./extensions-Be5HnDGt.js";
5
5
  import { Container, ContainerProxy, getContainer, switchPort } from "@cloudflare/containers";
6
6
  import { RpcTarget } from "cloudflare:workers";
7
7
  import { AwsClient } from "aws4fetch";
@@ -161,6 +161,19 @@ function isDurableObjectCodeUpdateReset(error) {
161
161
  return false;
162
162
  }
163
163
  /**
164
+ * Whether an error was raised because the Durable Object itself was reset, by
165
+ * a code update or a storage startup failure, rather than by the operation
166
+ * that observed it.
167
+ */
168
+ function isDurableObjectReset(error) {
169
+ for (const candidate of selfAndCauses(error)) {
170
+ const message = errorMessageOf(candidate);
171
+ if (SUPERSEDED_ISOLATE_PATTERN.test(message)) return true;
172
+ if (DO_STORAGE_STARTUP_RESET_PATTERN.test(message)) return true;
173
+ }
174
+ return false;
175
+ }
176
+ /**
164
177
  * Whether an error represents a transient platform lifecycle/storage failure,
165
178
  * not an application-level sandbox failure.
166
179
  */
@@ -2003,6 +2016,8 @@ const DEFAULT_POLL_INTERVAL_MS = 1e3;
2003
2016
  const DEFAULT_ECHO_SUPPRESS_TTL_MS = 2e3;
2004
2017
  const MAX_BACKOFF_MS = 3e4;
2005
2018
  const SYNC_CONCURRENCY = 5;
2019
+ const STREAM_TO_CONTAINER_THRESHOLD_BYTES = 4 * 1024 * 1024;
2020
+ const UPLOAD_DEBOUNCE_MS = 1500;
2006
2021
  /**
2007
2022
  * Manages bidirectional sync between an R2 binding and a container directory.
2008
2023
  *
@@ -2020,7 +2035,9 @@ var LocalMountSyncManager = class {
2020
2035
  pollIntervalMs;
2021
2036
  echoSuppressTtlMs;
2022
2037
  snapshot = /* @__PURE__ */ new Map();
2023
- echoSuppressSet = /* @__PURE__ */ new Set();
2038
+ echoSuppressTimers = /* @__PURE__ */ new Map();
2039
+ uploadTimers = /* @__PURE__ */ new Map();
2040
+ containerToR2Queue = Promise.resolve();
2024
2041
  pollTimer = null;
2025
2042
  watchReconnectTimer = null;
2026
2043
  watchAbortController = null;
@@ -2071,9 +2088,10 @@ var LocalMountSyncManager = class {
2071
2088
  this.interrupt();
2072
2089
  const pollCycle = this.activePollCycle;
2073
2090
  const watchLoop = this.activeWatchLoop;
2074
- await Promise.allSettled([pollCycle, watchLoop].filter(isPromise));
2091
+ await Promise.allSettled([...[pollCycle, watchLoop].filter(isPromise), this.containerToR2Queue]);
2092
+ for (const timer of this.echoSuppressTimers.values()) clearTimeout(timer);
2093
+ this.echoSuppressTimers.clear();
2075
2094
  this.snapshot.clear();
2076
- this.echoSuppressSet.clear();
2077
2095
  this.logger.info("Local mount sync stopped", { mountPath: this.mountPath });
2078
2096
  }
2079
2097
  interrupt() {
@@ -2090,6 +2108,8 @@ var LocalMountSyncManager = class {
2090
2108
  this.watchAbortController.abort();
2091
2109
  this.watchAbortController = null;
2092
2110
  }
2111
+ for (const timer of this.uploadTimers.values()) clearTimeout(timer);
2112
+ this.uploadTimers.clear();
2093
2113
  if (!this.runtimeHoldReleased) {
2094
2114
  this.runtimeHoldReleased = true;
2095
2115
  this.runtimeHold.release();
@@ -2163,6 +2183,7 @@ var LocalMountSyncManager = class {
2163
2183
  if (!this.isCurrentGeneration(generation)) return;
2164
2184
  this.suppressEcho(containerPath);
2165
2185
  await this.transferR2ObjectToContainer(key, containerPath, generation);
2186
+ this.suppressEcho(containerPath);
2166
2187
  this.logger.debug("R2 -> Container: synced object", {
2167
2188
  key,
2168
2189
  action
@@ -2206,6 +2227,15 @@ var LocalMountSyncManager = class {
2206
2227
  async transferR2ObjectToContainer(key, containerPath, generation) {
2207
2228
  const obj = await this.bucket.get(key);
2208
2229
  if (!obj) return;
2230
+ if (obj.size > STREAM_TO_CONTAINER_THRESHOLD_BYTES) {
2231
+ try {
2232
+ await this.runRuntimeCallIfCurrent(generation, "mount.local.writeFileStream", (control) => control.files.writeFileStream(containerPath, obj.body));
2233
+ } catch (error) {
2234
+ await obj.body.cancel().catch(() => {});
2235
+ throw error;
2236
+ }
2237
+ return;
2238
+ }
2209
2239
  const arrayBuffer = await obj.arrayBuffer();
2210
2240
  const base64 = uint8ArrayToBase64(new Uint8Array(arrayBuffer));
2211
2241
  await this.runRuntimeCallIfCurrent(generation, "mount.local.writeFile", (control) => control.files.writeFile(containerPath, base64, { encoding: "base64" }));
@@ -2265,48 +2295,89 @@ var LocalMountSyncManager = class {
2265
2295
  if (event.type !== "event") continue;
2266
2296
  if (event.isDirectory) continue;
2267
2297
  const containerPath = event.path;
2268
- if (this.echoSuppressSet.has(containerPath)) continue;
2298
+ if (this.echoSuppressTimers.has(containerPath)) continue;
2269
2299
  const r2Key = this.containerPathToR2Key(containerPath);
2270
2300
  if (!r2Key) continue;
2271
- try {
2272
- switch (event.eventType) {
2273
- case "create":
2274
- case "modify":
2275
- case "move_to":
2276
- await this.uploadFileToR2(containerPath, r2Key, generation);
2277
- this.logger.debug("Container -> R2: synced file", {
2278
- path: containerPath,
2279
- key: r2Key,
2280
- action: event.eventType
2281
- });
2282
- break;
2283
- case "delete":
2284
- case "move_from":
2285
- if (!this.isCurrentGeneration(generation)) break;
2301
+ switch (event.eventType) {
2302
+ case "create":
2303
+ case "modify":
2304
+ case "move_to":
2305
+ this.scheduleUpload(containerPath, r2Key, generation);
2306
+ break;
2307
+ case "delete":
2308
+ case "move_from":
2309
+ this.cancelScheduledUpload(containerPath);
2310
+ this.enqueueContainerToR2(containerPath, generation, async () => {
2286
2311
  await this.bucket.delete(r2Key);
2287
- if (!this.isCurrentGeneration(generation)) break;
2312
+ if (!this.isCurrentGeneration(generation)) return;
2288
2313
  this.snapshot.delete(r2Key);
2289
2314
  this.logger.debug("Container -> R2: deleted object", {
2290
2315
  path: containerPath,
2291
2316
  key: r2Key
2292
2317
  });
2293
- break;
2294
- }
2295
- } catch (error) {
2296
- this.logger.error(`Container -> R2 sync failed for ${containerPath}`, error instanceof Error ? error : new Error(String(error)));
2318
+ });
2319
+ break;
2297
2320
  }
2298
2321
  }
2299
2322
  });
2300
2323
  }
2301
2324
  /**
2302
- * Read a container file and upload it to R2, then update the local
2303
- * snapshot so the next poll cycle doesn't echo the write back.
2325
+ * Upload a changed file once its burst of watch events settles. Each new
2326
+ * event for the path restarts the wait.
2327
+ */
2328
+ scheduleUpload(containerPath, r2Key, generation) {
2329
+ this.cancelScheduledUpload(containerPath);
2330
+ const timer = setTimeout(() => {
2331
+ this.uploadTimers.delete(containerPath);
2332
+ this.enqueueContainerToR2(containerPath, generation, async () => {
2333
+ await this.uploadFileToR2(containerPath, r2Key, generation);
2334
+ this.logger.debug("Container -> R2: synced file", {
2335
+ path: containerPath,
2336
+ key: r2Key
2337
+ });
2338
+ });
2339
+ }, UPLOAD_DEBOUNCE_MS);
2340
+ this.uploadTimers.set(containerPath, timer);
2341
+ }
2342
+ cancelScheduledUpload(containerPath) {
2343
+ const timer = this.uploadTimers.get(containerPath);
2344
+ if (timer !== void 0) {
2345
+ clearTimeout(timer);
2346
+ this.uploadTimers.delete(containerPath);
2347
+ }
2348
+ }
2349
+ enqueueContainerToR2(containerPath, generation, operation) {
2350
+ this.containerToR2Queue = this.containerToR2Queue.then(async () => {
2351
+ if (!this.isCurrentGeneration(generation)) return;
2352
+ try {
2353
+ await operation();
2354
+ } catch (error) {
2355
+ if (!this.isCurrentGeneration(generation)) return;
2356
+ this.logger.error(`Container -> R2 sync failed for ${containerPath}`, error instanceof Error ? error : new Error(String(error)));
2357
+ }
2358
+ });
2359
+ }
2360
+ /**
2361
+ * Stream a container file into R2, then update the local snapshot so the
2362
+ * next poll cycle doesn't echo the write back.
2304
2363
  */
2305
2364
  async uploadFileToR2(containerPath, r2Key, generation) {
2306
- const result = await this.runRuntimeCallIfCurrent(generation, "mount.local.readFile", (control) => control.files.readFile(containerPath, { encoding: "base64" }));
2307
- if (!this.isCurrentOrUnscoped(generation)) return;
2308
- const bytes = base64ToUint8Array(result.content);
2309
- await this.bucket.put(r2Key, bytes);
2365
+ await this.runRuntimeCallIfCurrent(generation, "mount.local.readFile", async (control) => {
2366
+ const file = await control.files.readFile(containerPath, { encoding: "none" });
2367
+ if (!this.isCurrentOrUnscoped(generation)) {
2368
+ await file.content.cancel();
2369
+ return;
2370
+ }
2371
+ const sized = new FixedLengthStream(file.size);
2372
+ const pipeAbort = new AbortController();
2373
+ file.content.pipeTo(sized.writable, { signal: pipeAbort.signal }).catch(() => {});
2374
+ try {
2375
+ await this.bucket.put(r2Key, sized.readable);
2376
+ } catch (error) {
2377
+ pipeAbort.abort(error);
2378
+ throw error;
2379
+ }
2380
+ });
2310
2381
  if (!this.isCurrentOrUnscoped(generation)) return;
2311
2382
  const head = await this.bucket.head(r2Key);
2312
2383
  if (head) this.snapshot.set(r2Key, {
@@ -2328,10 +2399,10 @@ var LocalMountSyncManager = class {
2328
2399
  return this.running && this.generation === generation;
2329
2400
  }
2330
2401
  suppressEcho(containerPath) {
2331
- this.echoSuppressSet.add(containerPath);
2332
- setTimeout(() => {
2333
- this.echoSuppressSet.delete(containerPath);
2334
- }, this.echoSuppressTtlMs);
2402
+ clearTimeout(this.echoSuppressTimers.get(containerPath));
2403
+ this.echoSuppressTimers.set(containerPath, setTimeout(() => {
2404
+ this.echoSuppressTimers.delete(containerPath);
2405
+ }, this.echoSuppressTtlMs));
2335
2406
  }
2336
2407
  r2KeyToContainerPath(key) {
2337
2408
  let relativePath = key;
@@ -2353,9 +2424,6 @@ function isPromise(value) {
2353
2424
  function uint8ArrayToBase64(bytes) {
2354
2425
  return Buffer.from(bytes).toString("base64");
2355
2426
  }
2356
- function base64ToUint8Array(base64) {
2357
- return new Uint8Array(Buffer.from(base64, "base64"));
2358
- }
2359
2427
 
2360
2428
  //#endregion
2361
2429
  //#region src/storage-mount/operations/local-sync-mount.ts
@@ -4546,8 +4614,13 @@ async function forwardPreviewRequest(tcpPort, request, lease) {
4546
4614
  };
4547
4615
  } catch (error) {
4548
4616
  release();
4617
+ if (interruptedError) throw interruptedError;
4618
+ if (isDurableObjectReset(error)) throw error;
4549
4619
  if (error instanceof Error && error.message.includes("Network connection lost.")) return { status: "network-lost" };
4550
- throw error;
4620
+ return {
4621
+ status: "failed",
4622
+ error
4623
+ };
4551
4624
  }
4552
4625
  }
4553
4626
  function retainPreviewBody(body, release, bindInterrupt) {
@@ -4699,10 +4772,6 @@ function buildPreviewProxyRequest(request, { port, sandboxId, sandboxName }) {
4699
4772
  headers.set("X-Forwarded-Host", url.hostname);
4700
4773
  headers.set("X-Forwarded-Proto", url.protocol.replace(":", ""));
4701
4774
  headers.set("X-Sandbox-Name", sandboxName ?? sandboxId);
4702
- if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") return new Request(request, {
4703
- headers,
4704
- redirect: "manual"
4705
- });
4706
4775
  return new Request(proxyURL, {
4707
4776
  method: request.method,
4708
4777
  headers,
@@ -5036,6 +5105,13 @@ var PreviewService = class {
5036
5105
  if (!container?.running) return this.stalePreviewURLResponse();
5037
5106
  const result = await forwardPreviewRequest(container.getTcpPort(port), request, lease);
5038
5107
  if (result.status === "network-lost") return this.stalePreviewURLResponse();
5108
+ if (result.status === "failed") {
5109
+ this.deps.logger.error("Preview request to container port failed", result.error instanceof Error ? result.error : new Error(String(result.error)), {
5110
+ port,
5111
+ method: request.method
5112
+ });
5113
+ return new Response(`Could not reach port ${port} in the container`, { status: 502 });
5114
+ }
5039
5115
  return result.response;
5040
5116
  }
5041
5117
  async validatePreviewURLForRuntime(port, token) {
@@ -9670,7 +9746,10 @@ var Sandbox = class extends Container {
9670
9746
  async exec(command, options = {}) {
9671
9747
  const argv = validateExecArgv(command);
9672
9748
  const startTime = Date.now();
9673
- const commandText = argv.join(" ");
9749
+ const commandSummary = {
9750
+ argv0: argv[0],
9751
+ argCount: argv.length - 1
9752
+ };
9674
9753
  const launchOptions = (options.env === void 0 || isPlainObject(options.env)) && (Object.keys(this.envVars).length > 0 || options.env !== void 0) ? {
9675
9754
  ...options,
9676
9755
  env: mergeExecEnvironment(this.envVars, options.env ?? {})
@@ -9683,7 +9762,7 @@ var Sandbox = class extends Container {
9683
9762
  logCanonicalEvent(this.logger, {
9684
9763
  event: "sandbox.exec",
9685
9764
  outcome: "success",
9686
- command: commandText,
9765
+ ...commandSummary,
9687
9766
  processId: descriptor.id,
9688
9767
  pid: descriptor.pid,
9689
9768
  durationMs: Date.now() - startTime,
@@ -9695,7 +9774,7 @@ var Sandbox = class extends Container {
9695
9774
  logCanonicalEvent(this.logger, {
9696
9775
  event: "sandbox.exec",
9697
9776
  outcome: "error",
9698
- command: commandText,
9777
+ ...commandSummary,
9699
9778
  durationMs: Date.now() - startTime,
9700
9779
  origin: "user",
9701
9780
  error: execError,
@@ -10053,4 +10132,4 @@ var Sandbox = class extends Container {
10053
10132
 
10054
10133
  //#endregion
10055
10134
  export { proxyTerminal as _, responseToAsyncIterable as a, collectFile as b, BucketUnmountError as c, S3FSMountError as d, parsePreviewRoute as f, validateTunnelName as g, validatePort as h, parseSSEStream as i, InvalidMountConfigError as l, SandboxSecurityError as m, getSandbox as n, ContainerProxy$1 as o, withPreviewProxyMetadata as p, asyncIterableToSSEStream as r, BucketMountError as s, Sandbox as t, MissingCredentialsError as u, isDurableObjectCodeUpdateReset as v, streamFile as x, isPlatformTransientError as y };
10056
- //# sourceMappingURL=sandbox-cmlgGVYX.js.map
10135
+ //# sourceMappingURL=sandbox-BEhPgFZx.js.map