@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.
- package/dist/bridge/index.js +24 -8
- package/dist/bridge/index.js.map +1 -1
- package/dist/{dist-Duor5GbS.js → dist-n_eniPAR.js} +8 -46
- package/dist/dist-n_eniPAR.js.map +1 -0
- package/dist/extensions/index.d.ts +2 -2
- package/dist/extensions/index.js +2 -2
- package/dist/{extensions-CFB2xHqY.js → extensions-Be5HnDGt.js} +2 -2
- package/dist/{extensions-CFB2xHqY.js.map → extensions-Be5HnDGt.js.map} +1 -1
- package/dist/{filesystem-BWAZCZER.d.ts → filesystem-Y5aF3nmJ.d.ts} +7 -3
- package/dist/filesystem-Y5aF3nmJ.d.ts.map +1 -0
- package/dist/git/index.d.ts +2 -2
- package/dist/git/index.js +2 -2
- package/dist/{index-Bs4bqXDR.d.ts → index-DfXx3uZL.d.ts} +2 -2
- package/dist/{index-Bs4bqXDR.d.ts.map → index-DfXx3uZL.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/interpreter/index.d.ts +2 -2
- package/dist/interpreter/index.js +2 -2
- package/dist/openai/index.d.ts +2 -2
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +10 -34
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +2 -2
- package/dist/opencode/index.js +2 -2
- package/dist/{sandbox-cmlgGVYX.js → sandbox-BEhPgFZx.js} +127 -48
- package/dist/sandbox-BEhPgFZx.js.map +1 -0
- package/dist/{sandbox-BbAabq93.d.ts → sandbox-CBkS3tGv.d.ts} +2 -2
- package/dist/{sandbox-BbAabq93.d.ts.map → sandbox-CBkS3tGv.d.ts.map} +1 -1
- package/package.json +1 -1
- package/dist/dist-Duor5GbS.js.map +0 -1
- package/dist/filesystem-BWAZCZER.d.ts.map +0 -1
- package/dist/sandbox-cmlgGVYX.js.map +0 -1
package/dist/openai/index.js.map
CHANGED
|
@@ -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":";;;;;;;;;AAqCA,SAAS,sBAAsB,OAO7B;AACA,QAAO,OAAO,UAAU,YAAY,UAAU;;AAGhD,SAAS,gBAAgB,OAAwB;AAC/C,KAAI,sBAAsB,MAAM,IAAI,OAAO,MAAM,YAAY,SAC3D,QAAO,MAAM;AAEf,QAAO,OAAO,MAAM;;;;;;AAOtB,SAAS,QAAQ,OAAmC;AAClD,QAAO,iBAAiB,QAAQ,QAAQ;;;;;;AAO1C,IAAa,QAAb,MAA0C;CACxC,AAAQ,MAAc;CACtB,AAAO,UAA2B,EAAE;CACpC,AAAiB;CAEjB,YAAY,AAAiBA,SAAmB;EAAnB;AAC3B,OAAK,SAAS,aAAa;GACzB,WAAW;GACX,WAAW;GACZ,CAAC;;CAGJ,MAAM,IAAI,QAA2C;AACnD,OAAK,OAAO,MAAM,2BAA2B;GAC3C,UAAU,OAAO;GACjB,SAAS,OAAO;GACjB,CAAC;EACF,MAAMC,SAAgC,EAAE;AAExC,OAAK,MAAM,WAAW,OAAO,UAAU;AACrC,QAAK,OAAO,MAAM,qBAAqB;IAAE;IAAS,KAAK,KAAK;IAAK,CAAC;GAClE,IAAI,SAAS;GACb,IAAI,SAAS;GACb,IAAIC,WAA0B;GAC9B,IAAIC,UAAwC;IAC1C,MAAM;IACN,UAAU;IACX;AACD,OAAI;IAKF,MAAM,MAAM,OAJC,MAAM,KAAK,QAAQ,KAAK;KAAC;KAAa;KAAO;KAAQ,EAAE;KAClE,SAAS,OAAO;KAChB,KAAK,KAAK;KACX,CAAC,EACqB,QAAQ;AAC/B,aAAS,IAAI,aAAa,CAAC,OAAO,IAAI,OAAO;AAC7C,aAAS,IAAI,aAAa,CAAC,OAAO,IAAI,OAAO;AAC7C,eAAW,IAAI;AAEf,cAAU;KAAE,MAAM;KAAQ;KAAU;AAEpC,SAAK,OAAO,MAAM,iCAAiC;KACjD;KACA;KACA,cAAc,OAAO;KACrB,cAAc,OAAO;KACtB,CAAC;AAGF,QAAI,aAAa,EACf,MAAK,OAAO,KAAK,iCAAiC,YAAY;KAC5D;KACA;KACD,CAAC;aACO,OACT,MAAK,OAAO,KAAK,kCAAkC;KACjD;KACA;KACD,CAAC;QAEF,MAAK,OAAO,KAAK,kCAAkC,EAAE,SAAS,CAAC;YAE1DC,OAAgB;IAEvB,MAAM,WAAW,sBAAsB,MAAM,GAAG,QAAQ,EAAE;AAC1D,eACE,OAAO,SAAS,aAAa,WAAW,SAAS,WAAW;AAC9D,aAAS,OAAO,SAAS,WAAW,WAAW,SAAS,SAAS;AACjE,aAAS,OAAO,SAAS,WAAW,WAAW,SAAS,SAAS;IAGjE,MAAM,eAAe,gBAAgB,MAAM;AAC3C,QACE,aAAa,SAAS,UAAU,IAChC,aAAa,SAAS,UAAU,IAChC,aAAa,SAAS,YAAY,EAClC;AACA,UAAK,OAAO,MAAM,qBAAqB,QAAW;MAChD;MACA,SAAS,OAAO;MACjB,CAAC;AACF,eAAU,EAAE,MAAM,WAAW;WACxB;AACL,UAAK,OAAO,MAAM,2BAA2B,QAAQ,MAAM,EAAE;MAC3D;MACA,OAAO,gBAAgB;MACvB;MACD,CAAC;AACF,eAAU;MAAE,MAAM;MAAQ,UAAU,YAAY;MAAG;;;AAGvD,UAAO,KAAK;IACV;IACA;IACA;IACA;IACD,CAAC;GAGF,MAAM,oBACJ,QAAQ,SAAS,SAAS,QAAQ,WAAW;GAC/C,MAAM,YAAY,KAAK,KAAK;AAC5B,QAAK,QAAQ,KAAK;IAChB,SAAS,OAAO,QAAQ;IACxB,QAAQ,OAAO,OAAO;IACtB,QAAQ,OAAO,OAAO;IACtB,UAAU;IACV;IACD,CAAC;AACF,QAAK,OAAO,MAAM,oBAAoB;IACpC;IACA,UAAU;IACV;IACD,CAAC;AAEF,OAAI,QAAQ,SAAS,WAAW;AAC9B,SAAK,OAAO,KAAK,uCAAuC;AACxD;;;AAIJ,OAAK,OAAO,MAAM,8BAA8B;GAC9C,eAAe,OAAO,SAAS;GAC/B,cAAc,KAAK,QAAQ;GAC5B,CAAC;AACF,SAAO;GACL;GACA,cAAc,EACZ,mBAAmB,KAAK,KACzB;GACF;;;;;;;AAQL,IAAa,SAAb,MAA6C;CAC3C,AAAO,UAAiC,EAAE;CAC1C,AAAiB;CAEjB,YACE,AAAiBJ,SACjB,AAAiBK,OAAe,cAChC;EAFiB;EACA;AAEjB,OAAK,SAAS,aAAa;GACzB,WAAW;GACX,WAAW;GACZ,CAAC;;;;;CAMJ,MAAM,WACJ,WACuC;EACvC,MAAM,aAAa,KAAK,QAAQ,UAAU,KAAK;AAC/C,OAAK,OAAO,MAAM,qCAAqC;GACrD,MAAM,UAAU;GAChB;GACD,CAAC;AAEF,MAAI;GAEF,MAAM,UAAU,KAAK,WAAW,WAAW;AAC3C,OAAI,YAAY,KAAK,QAAQ,YAAY,KAAK;AAC5C,SAAK,OAAO,MAAM,6BAA6B,EAAE,SAAS,CAAC;AAC3D,UAAM,KAAK,QAAQ,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;;GAGxD,MAAM,UAAU,UAAU,IAAI,UAAU,MAAM,SAAS;AACvD,QAAK,OAAO,MAAM,wBAAwB;IACxC,MAAM;IACN,eAAe,QAAQ;IACxB,CAAC;AACF,SAAM,KAAK,QAAQ,UAAU,YAAY,SAAS,EAAE,UAAU,SAAS,CAAC;GACxE,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAMC,SAA8B;IAClC,WAAW;IACX,MAAM,UAAU;IAChB,QAAQ;IACR,QAAQ,WAAW,UAAU;IAC7B;IACD;AACD,QAAK,QAAQ,KAAK,OAAO;AACzB,QAAK,OAAO,KAAK,6BAA6B;IAC5C,MAAM,UAAU;IAChB;IACD,CAAC;AACF,UAAO;IAAE,QAAQ;IAAa,QAAQ,WAAW,UAAU;IAAQ;WAC5DF,OAAgB;GACvB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,eAAe,gBAAgB,MAAM;GAC3C,MAAME,SAA8B;IAClC,WAAW;IACX,MAAM,UAAU;IAChB,QAAQ;IACR,QAAQ,oBAAoB,UAAU;IACtC,OAAO;IACP;IACD;AACD,QAAK,QAAQ,KAAK,OAAO;AACzB,QAAK,OAAO,MAAM,yBAAyB,QAAQ,MAAM,EAAE;IACzD,MAAM,UAAU;IAChB,OAAO;IACR,CAAC;AACF,SAAM;;;;;;;CAQV,MAAM,WACJ,WACuC;EACvC,MAAM,aAAa,KAAK,QAAQ,UAAU,KAAK;AAC/C,OAAK,OAAO,MAAM,qCAAqC;GACrD,MAAM,UAAU;GAChB;GACD,CAAC;AAEF,MAAI;GACF,IAAIC;AACJ,OAAI;AACF,SAAK,OAAO,MAAM,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAIhE,gBAHiB,MAAM,KAAK,QAAQ,SAAS,YAAY,EACvD,UAAU,SACX,CAAC,EACkB;AACpB,SAAK,OAAO,MAAM,sBAAsB;KACtC,MAAM;KACN,gBAAgB,SAAS;KAC1B,CAAC;YACKH,OAAgB;IAEvB,MAAM,WAAW,sBAAsB,MAAM,GAAG,QAAQ,EAAE;IAC1D,MAAM,eAAe,gBAAgB,MAAM;AAC3C,QACE,aAAa,SAAS,YAAY,IAClC,aAAa,SAAS,SAAS,IAC/B,SAAS,WAAW,KACpB;AACA,UAAK,OAAO,MAAM,8BAA8B,QAAW,EACzD,MAAM,UAAU,MACjB,CAAC;AACF,WAAM,IAAI,MAAM,+BAA+B,UAAU,OAAO;;AAElE,SAAK,OAAO,MAAM,sBAAsB,QAAQ,MAAM,EAAE;KACtD,MAAM,UAAU;KAChB,OAAO;KACR,CAAC;AACF,UAAM;;GAGR,MAAM,UAAU,UAAU,UAAU,UAAU,KAAK;AACnD,QAAK,OAAO,MAAM,gBAAgB;IAChC,MAAM;IACN,gBAAgB,SAAS;IACzB,eAAe,QAAQ;IACxB,CAAC;AACF,SAAM,KAAK,QAAQ,UAAU,YAAY,SAAS,EAAE,UAAU,SAAS,CAAC;GACxE,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAME,SAA8B;IAClC,WAAW;IACX,MAAM,UAAU;IAChB,QAAQ;IACR,QAAQ,WAAW,UAAU;IAC7B;IACD;AACD,QAAK,QAAQ,KAAK,OAAO;AACzB,QAAK,OAAO,KAAK,6BAA6B;IAC5C,MAAM,UAAU;IAChB;IACD,CAAC;AACF,UAAO;IAAE,QAAQ;IAAa,QAAQ,WAAW,UAAU;IAAQ;WAC5DF,OAAgB;GACvB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,eAAe,gBAAgB,MAAM;GAC3C,MAAME,SAA8B;IAClC,WAAW;IACX,MAAM,UAAU;IAChB,QAAQ;IACR,QAAQ,oBAAoB,UAAU;IACtC,OAAO;IACP;IACD;AACD,QAAK,QAAQ,KAAK,OAAO;AACzB,QAAK,OAAO,MAAM,yBAAyB,QAAQ,MAAM,EAAE;IACzD,MAAM,UAAU;IAChB,OAAO;IACR,CAAC;AACF,SAAM;;;;;;CAOV,MAAM,WACJ,WACuC;EACvC,MAAM,aAAa,KAAK,QAAQ,UAAU,KAAK;AAC/C,OAAK,OAAO,MAAM,qCAAqC;GACrD,MAAM,UAAU;GAChB;GACD,CAAC;AAEF,MAAI;AACF,SAAM,KAAK,QAAQ,WAAW,WAAW;GACzC,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAMA,SAA8B;IAClC,WAAW;IACX,MAAM,UAAU;IAChB,QAAQ;IACR,QAAQ,WAAW,UAAU;IAC7B;IACD;AACD,QAAK,QAAQ,KAAK,OAAO;AACzB,QAAK,OAAO,KAAK,6BAA6B;IAC5C,MAAM,UAAU;IAChB;IACD,CAAC;AACF,UAAO;IAAE,QAAQ;IAAa,QAAQ,WAAW,UAAU;IAAQ;WAC5DF,OAAgB;GACvB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,eAAe,gBAAgB,MAAM;GAC3C,MAAME,SAA8B;IAClC,WAAW;IACX,MAAM,UAAU;IAChB,QAAQ;IACR,QAAQ,oBAAoB,UAAU;IACtC,OAAO;IACP;IACD;AACD,QAAK,QAAQ,KAAK,OAAO;AACzB,QAAK,OAAO,MAAM,yBAAyB,QAAQ,MAAM,EAAE;IACzD,MAAM,UAAU;IAChB,OAAO;IACR,CAAC;AACF,SAAM;;;CAIV,AAAQ,QAAQ,cAA8B;EAE5C,IAAI,gBAAgB;AACpB,MAAI,aAAa,WAAW,KAAK,KAAK,EAAE;AACtC,mBAAgB,aAAa,MAAM,KAAK,KAAK,OAAO;AAEpD,mBAAgB,cAAc,QAAQ,OAAO,GAAG;;EAIlD,MAAM,aAAa,cAAc,QAAQ,SAAS,GAAG,CAAC,QAAQ,OAAO,GAAG;EAOxE,MAAM,YANW,aAAa,GAAG,KAAK,KAAK,GAAG,eAAe,KAAK,MAGpB,QAAQ,QAAQ,IAAI,CAI/D,MAAM,IAAI,CACV,QAAQ,MAAM,KAAK,MAAM,IAAI;EAChC,MAAME,QAAkB,EAAE;AAE1B,OAAK,MAAM,WAAW,SACpB,KAAI,YAAY,MAAM;AACpB,OAAI,MAAM,WAAW,EACnB,OAAM,IAAI,MAAM,gCAAgC,eAAe;AAEjE,SAAM,KAAK;QAEX,OAAM,KAAK,QAAQ;EAIvB,MAAM,iBAAiB,IAAI,MAAM,KAAK,IAAI;AAG1C,MAAI,CAAC,eAAe,WAAW,KAAK,KAAK,CACvC,OAAM,IAAI,MAAM,gCAAgC,eAAe;AAGjE,SAAO;;CAGT,AAAQ,WAAW,UAA0B;EAC3C,MAAM,YAAY,SAAS,YAAY,IAAI;AAC3C,MAAI,cAAc,GAChB,QAAO;AAET,SAAO,SAAS,UAAU,GAAG,UAAU,IAAI"}
|
|
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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"}
|
package/dist/opencode/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { D as OpenCodeStartupContext } from "../contexts-1EsLHByO.js";
|
|
2
2
|
import "../process-types-GStiZ8f8.js";
|
|
3
|
-
import "../filesystem-
|
|
4
|
-
import { c as SandboxExtension, l as SandboxLike } from "../index-
|
|
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
|
|
package/dist/opencode/index.js
CHANGED
|
@@ -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-
|
|
4
|
-
import { n as createExtensionProcessSandbox, t as SandboxExtension } from "../extensions-
|
|
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-
|
|
4
|
-
import { a as PullSubscriptionTarget, i as createSandboxProcess, o as openRemoteSubscription, r as sandboxRuntimeCall, s as translateRPCError, t as SandboxExtension } from "./extensions-
|
|
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
|
-
|
|
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.
|
|
2298
|
+
if (this.echoSuppressTimers.has(containerPath)) continue;
|
|
2269
2299
|
const r2Key = this.containerPathToR2Key(containerPath);
|
|
2270
2300
|
if (!r2Key) continue;
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
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))
|
|
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
|
-
|
|
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
|
-
*
|
|
2303
|
-
*
|
|
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
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
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.
|
|
2332
|
-
setTimeout(() => {
|
|
2333
|
-
this.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
10135
|
+
//# sourceMappingURL=sandbox-BEhPgFZx.js.map
|