/** * E2B provider for the filesystem capability seam. Paths, contents, and * atomic staging files remain inside the shared remote sandbox. * @module @deepseek-ai/dsh-fs-e2b */ import { createHash, randomUUID } from 'node:crypto' import { Buffer } from 'node:buffer' import { posix } from 'node:path' import { FileSystem, FsError, FsTargetKey, FsVersion } from '@deepseek-ai/dsh-fs' import type { FsDirEntry, FsEditOutcome, FsEditRequest, FsInfo, FsPathInfo, FsTarget, FsWriteIntent, FsWriteOutcome, } from '@deepseek-ai/dsh-fs' import { CommandExitError, e2bControlEnvs, FileNotFoundError, FileType, quoteE2BShellArg, } from '@deepseek-ai/dsh-e2b' import type { EntryInfo, Sandbox } from '@deepseek-ai/dsh-e2b' const VERSION_METADATA_KEY = 'dsh-version' const BINARY_SAMPLE_BYTES = 8192 const BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/ function assertNotAborted(signal: AbortSignal | undefined, operation: string): void { if (signal?.aborted === true) throw new FsError(`${operation} aborted`, 'FS_ABORTED') } function normalizeLineEndings(value: string): string { return value.replaceAll('\r\n', '\n') } function detectsCrlf(value: string): boolean { const sample = value.slice(0, 4096) const crlf = sample.split('\r\n').length - 1 const lf = sample.split('\n').length - 1 - crlf return crlf > lf } function restoreLineEndings(value: string, crlf: boolean): string { return crlf ? normalizeLineEndings(value).replaceAll('\n', '\r\n') : value } function decodeText(bytes: Uint8Array, displayPath: string, binarySampleBytes: number): string { if (bytes.subarray(0, binarySampleBytes).includes(0)) { throw new FsError(`cannot read "${displayPath}": binary file`, 'FS_NOT_TEXT') } try { return new TextDecoder('utf-8', { fatal: true }).decode(bytes) } catch (error: unknown) { throw new FsError(`cannot read "${displayPath}": invalid UTF-8 text`, 'FS_NOT_TEXT', { cause: error }) } } function decodeCanonicalPath(encoded: string): string { if (encoded.length === 0 || !BASE64.test(encoded)) { throw new Error('fs-e2b: canonical path transport returned invalid base64') } const framed = Buffer.from(encoded, 'base64') if (framed.toString('base64') !== encoded || framed.length < 2 || framed.at(-1) !== 0 || framed.subarray(0, -1).includes(0)) { throw new Error('fs-e2b: canonical path transport returned invalid NUL framing') } let path: string try { path = new TextDecoder('utf-8', { fatal: true }).decode(framed.subarray(0, -1)) } catch (error: unknown) { throw new Error('fs-e2b: canonical path is not valid UTF-8', { cause: error }) } if (!posix.isAbsolute(path)) throw new Error('fs-e2b: canonical path is not absolute') return path } function signalOpts(signal: AbortSignal | undefined): { signal?: AbortSignal } { return signal === undefined ? {} : { signal } } function commandOpts(signal: AbortSignal | undefined): { envs: Record; signal?: AbortSignal } { return { envs: e2bControlEnvs(), ...signalOpts(signal) } } async function openReadStream( sandbox: Sandbox, target: FsTarget, signal: AbortSignal | undefined, ): Promise> { try { // The pinned SDK's stream overload lies for empty files: content-length 0 // returns '' instead of a ReadableStream. const read = await sandbox.files.read(String(target.targetKey), { format: 'stream', ...signalOpts(signal) }) as ReadableStream | string return typeof read === 'string' ? new ReadableStream({ start(controller) { controller.close() } }) : read } catch (error: unknown) { throw mapError(error, 'read', target.displayPath, signal) } } function entryType(entry: EntryInfo): FsInfo['type'] { switch (entry.type) { case FileType.FILE: return 'file' case FileType.DIR: return 'directory' default: return 'other' } } function entryVersion(entry: EntryInfo): ReturnType { const facts = JSON.stringify([ entry.metadata?.[VERSION_METADATA_KEY], entry.path, entry.type, entry.size, entry.mode, entry.modifiedTime?.toISOString(), entry.symlinkTarget, ]) return FsVersion(`e2b:${createHash('sha256').update(facts).digest('hex')}`) } function mapError(error: unknown, operation: string, displayPath: string, signal?: AbortSignal): FsError { if (error instanceof FsError) return error if (signal?.aborted === true || (error instanceof DOMException && error.name === 'AbortError')) { return new FsError(`${operation} aborted`, 'FS_ABORTED', { cause: error }) } if (error instanceof FileNotFoundError) { return new FsError(`cannot ${operation} "${displayPath}": not found`, 'FS_NOT_FOUND', { cause: error }) } if (/permission denied|operation not permitted/i.test(String(error))) { return new FsError(`cannot ${operation} "${displayPath}": permission denied`, 'FS_PERMISSION_DENIED', { cause: error }) } return new FsError(`cannot ${operation} "${displayPath}": ${String(error)}`, 'FS_IO_ERROR', { cause: error }) } function literalEdit(content: string, request: FsEditRequest, displayPath: string): string { const oldString = normalizeLineEndings(request.oldString) const newString = normalizeLineEndings(request.newString) if (oldString.length === 0) { throw new FsError(`cannot edit "${displayPath}": old_string must be non-empty`, 'FS_EDIT_NOT_FOUND') } let matches = 0 let offset = 0 while (true) { const found = content.indexOf(oldString, offset) if (found < 0) break matches += 1 offset = found + oldString.length } if (matches === 0) throw new FsError(`cannot edit "${displayPath}": old_string was not found`, 'FS_EDIT_NOT_FOUND') if (!request.replaceAll && matches !== 1) { throw new FsError(`cannot edit "${displayPath}": old_string matched ${matches} times`, 'FS_AMBIGUOUS_EDIT') } return request.replaceAll ? content.split(oldString).join(newString) : content.replace(oldString, newString) } /** Remote filesystem backend sharing the sandbox owned by `ctx.e2b`. */ export class E2BFileSystem extends FileSystem { static inject = ['e2b'] private readonly locks = new Map>() override async resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise { assertNotAborted(opts?.signal, 'resolve') if (path.trim().length === 0) throw new FsError('file_path must be a non-empty string', 'FS_NOT_FOUND') const displayPath = posix.resolve(opts?.cwd ?? this.ctx.e2b.cwd, path) try { const sandbox = await this.ctx.e2b.getSandbox() const targetKey = await this.canonicalPath(sandbox, displayPath, opts?.signal) assertNotAborted(opts?.signal, 'resolve') return { targetKey: FsTargetKey(targetKey), displayPath } } catch (error: unknown) { throw mapError(error, 'resolve', displayPath, opts?.signal) } } override processPath(target: FsTarget): string { return String(target.targetKey) } override fileUrl(target: FsTarget): string { const path = this.processPath(target) if (!posix.isAbsolute(path)) throw new Error(`fs-e2b: expected an absolute process path: ${JSON.stringify(path)}`) return `file://${path.split('/').map(segment => encodeURIComponent(segment)).join('/')}` } override contains(parent: FsTarget, child: FsTarget): boolean { const relative = posix.relative(this.processPath(parent), this.processPath(child)) return relative === '' || (relative !== '..' && !relative.startsWith('../') && !posix.isAbsolute(relative)) } override async stat(target: FsTarget, signal?: AbortSignal): Promise { assertNotAborted(signal, 'stat') const entry = await this.probe(String(target.targetKey), target.displayPath, signal) if (entry === undefined) return undefined return { version: entryVersion(entry), type: entryType(entry), ...(entry.type === FileType.FILE ? { size: entry.size } : {}), } } override async lstat(path: string, opts?: { cwd?: string }, signal?: AbortSignal): Promise { assertNotAborted(signal, 'lstat') if (path.trim().length === 0) throw new FsError('file_path must be a non-empty string', 'FS_NOT_FOUND') const displayPath = posix.resolve(opts?.cwd ?? this.ctx.e2b.cwd, path) const entry = await this.probe(displayPath, displayPath, signal) if (entry === undefined) return undefined const type = entry.symlinkTarget !== undefined ? 'symlink' as const : entry.type === FileType.FILE ? 'file' as const : entry.type === FileType.DIR ? 'directory' as const : 'other' as const return { version: entryVersion(entry), type, ...(entry.type === FileType.FILE ? { size: entry.size } : {}), } } override async readText(target: FsTarget, signal?: AbortSignal): Promise { const sandbox = await this.ctx.e2b.getSandbox() await this.requireRegular(target, signal) try { const bytes = await sandbox.files.read(String(target.targetKey), { format: 'bytes', ...signalOpts(signal) }) assertNotAborted(signal, 'read') return decodeText(bytes, target.displayPath, BINARY_SAMPLE_BYTES) } catch (error: unknown) { throw mapError(error, 'read', target.displayPath, signal) } } override async readBytes(target: FsTarget, signal: AbortSignal | undefined, maxBytes: number): Promise { const sandbox = await this.ctx.e2b.getSandbox() const info = await this.requireRegular(target, signal) if (info.size !== undefined && info.size > maxBytes) { throw new FsError(`cannot read "${target.displayPath}": ${info.size} bytes exceeds the ${maxBytes}-byte limit`, 'FS_TOO_LARGE') } const stream = await openReadStream(sandbox, target, signal) const reader = stream.getReader() const chunks: Uint8Array[] = [] let bytes = 0 let completed = false try { while (true) { assertNotAborted(signal, 'read') const next = await reader.read() if (next.done) break // The stat preflight covers the at-rest case; this streamed bound stops // a post-stat grower without transferring past the first overflowing chunk. bytes += next.value.byteLength if (bytes > maxBytes) { throw new FsError(`cannot read "${target.displayPath}": content exceeds the ${maxBytes}-byte limit`, 'FS_TOO_LARGE') } chunks.push(next.value) } completed = true } catch (error: unknown) { throw mapError(error, 'read', target.displayPath, signal) } finally { if (!completed) { try { await reader.cancel() } catch (_streamCancellationFailure) { // The read already failed; a cancellation failure on the abandoned // remote stream adds nothing actionable for the caller. } } reader.releaseLock() } const whole = new Uint8Array(bytes) let offset = 0 for (const chunk of chunks) { whole.set(chunk, offset) offset += chunk.byteLength } return whole } override async streamText(target: FsTarget, signal?: AbortSignal): Promise> { const sandbox = await this.ctx.e2b.getSandbox() await this.requireRegular(target, signal) const stream = await openReadStream(sandbox, target, signal) const displayPath = target.displayPath return { async *[Symbol.asyncIterator](): AsyncGenerator { const reader = stream.getReader() const decoder = new TextDecoder('utf-8', { fatal: true }) let sampledBytes = 0 let completed = false try { while (true) { assertNotAborted(signal, 'read') const next = await reader.read() if (next.done) break if (sampledBytes < BINARY_SAMPLE_BYTES) { const sample = next.value.subarray(0, BINARY_SAMPLE_BYTES - sampledBytes) if (sample.includes(0)) throw new FsError(`cannot read "${displayPath}": binary file`, 'FS_NOT_TEXT') sampledBytes += sample.length } let text: string try { text = decoder.decode(next.value, { stream: true }) } catch (error: unknown) { throw new FsError(`cannot read "${displayPath}": invalid UTF-8 text`, 'FS_NOT_TEXT', { cause: error }) } if (text.length > 0) yield text } try { decoder.decode() } catch (error: unknown) { throw new FsError(`cannot read "${displayPath}": invalid UTF-8 text`, 'FS_NOT_TEXT', { cause: error }) } completed = true } catch (error: unknown) { throw mapError(error, 'read', displayPath, signal) } finally { if (!completed) { try { await reader.cancel() } catch (_streamCancellationFailure) { // The primary read outcome owns the result; cancellation is best-effort after early stop. } } reader.releaseLock() } }, } } override async listDir(target: FsTarget, signal?: AbortSignal): Promise { const info = await this.stat(target, signal) if (info === undefined) throw new FsError(`cannot list "${target.displayPath}": not found`, 'FS_NOT_FOUND') if (info.type !== 'directory') throw new FsError(`cannot list "${target.displayPath}": not a directory`, 'FS_NOT_DIRECTORY') try { const sandbox = await this.ctx.e2b.getSandbox() const listed = await sandbox.files.list(String(target.targetKey), { depth: 1, ...signalOpts(signal) }) const entries: FsDirEntry[] = [] for (const entry of listed) { const displayPath = posix.join(target.displayPath, entry.name) const canonical = entry.symlinkTarget === undefined ? entry.path : await this.canonicalPath(sandbox, entry.path, signal) const resolved = entry.symlinkTarget === undefined ? entry : await this.probe(canonical, displayPath, signal) entries.push({ name: entry.name, type: resolved === undefined ? 'other' : entryType(resolved), target: { targetKey: FsTargetKey(canonical), displayPath }, ...(resolved !== undefined ? { version: entryVersion(resolved) } : {}), ...(resolved?.type === FileType.FILE ? { size: resolved.size } : {}), }) } return entries.sort((left, right) => left.name.localeCompare(right.name)) } catch (error: unknown) { throw mapError(error, 'list', target.displayPath, signal) } } override async writeText( target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal, ): Promise { return this.withLock(String(target.targetKey), async () => { const existing = await this.probe(String(target.targetKey), target.displayPath, signal) if (existing !== undefined && entryType(existing) !== 'file') { throw new FsError(`cannot write "${target.displayPath}": not a regular file`, 'FS_NOT_REGULAR_FILE') } this.checkWriteIntent(existing, expected, target) const before = existing === undefined ? null : await this.readForDiff(target, signal) const version = await this.writeAtomic( target, content, existing, expected?.kind === 'createIfAbsent', signal, ) return { operation: existing === undefined ? 'create' : 'update', version, before, after: normalizeLineEndings(content), } }) } override async editText( target: FsTarget, edit: FsEditRequest, expected?: { version: ReturnType }, signal?: AbortSignal, ): Promise { return this.withLock(String(target.targetKey), async () => { const existing = await this.probe(String(target.targetKey), target.displayPath, signal) if (existing === undefined) { throw new FsError(`cannot edit "${target.displayPath}": file changed since it was read`, 'FS_STALE_VERSION') } if (entryType(existing) !== 'file') { throw new FsError(`cannot edit "${target.displayPath}": not a regular file`, 'FS_NOT_REGULAR_FILE') } if (expected !== undefined && entryVersion(existing) !== expected.version) { throw new FsError(`cannot edit "${target.displayPath}": file changed since it was read`, 'FS_STALE_VERSION') } const raw = await this.readForEdit(target, signal) const before = normalizeLineEndings(raw) const after = literalEdit(before, edit, target.displayPath) const storage = restoreLineEndings(after, detectsCrlf(raw)) const version = await this.writeAtomic(target, storage, existing, false, signal) return { version, before, after } }) } private async withLock(targetKey: string, operation: () => Promise): Promise { const prior = this.locks.get(targetKey) ?? Promise.resolve() const run = prior.then(operation, operation) const tail = run.then(() => undefined, () => undefined) this.locks.set(targetKey, tail) try { return await run } finally { if (this.locks.get(targetKey) === tail) this.locks.delete(targetKey) } } private async canonicalPath(sandbox: Sandbox, path: string, signal?: AbortSignal): Promise { try { const result = await sandbox.commands.run( `set -o pipefail; realpath -mz -- ${quoteE2BShellArg(path)} | base64 -w0`, commandOpts(signal), ) return decodeCanonicalPath(result.stdout) } catch (error: unknown) { if (error instanceof CommandExitError) throw new Error(error.stderr || error.message, { cause: error }) throw error } } private async probe(path: string, displayPath: string, signal?: AbortSignal): Promise { assertNotAborted(signal, 'stat') try { const sandbox = await this.ctx.e2b.getSandbox() const entry = await sandbox.files.getInfo(path, signalOpts(signal)) assertNotAborted(signal, 'stat') return entry } catch (error: unknown) { if (error instanceof FileNotFoundError) return undefined throw mapError(error, 'stat', displayPath, signal) } } private async requireRegular(target: FsTarget, signal?: AbortSignal): Promise { const info = await this.stat(target, signal) if (info === undefined) throw new FsError(`cannot read "${target.displayPath}": not found`, 'FS_NOT_FOUND') if (info.type !== 'file') throw new FsError(`cannot read "${target.displayPath}": not a regular file`, 'FS_NOT_REGULAR_FILE') return info } private checkWriteIntent(existing: EntryInfo | undefined, expected: FsWriteIntent | undefined, target: FsTarget): void { if (expected?.kind === 'createIfAbsent' && existing !== undefined) { throw new FsError(`cannot overwrite existing "${target.displayPath}" without reading it first`, 'FS_NOT_OBSERVED') } if (expected?.kind === 'replaceIfVersion') { if (existing === undefined || entryVersion(existing) !== expected.version) { throw new FsError(`cannot write "${target.displayPath}": file changed since it was read`, 'FS_STALE_VERSION') } } } private async readForDiff(target: FsTarget, signal?: AbortSignal): Promise { try { const sandbox = await this.ctx.e2b.getSandbox() const bytes = await sandbox.files.read(String(target.targetKey), { format: 'bytes', ...signalOpts(signal) }) assertNotAborted(signal, 'read') return normalizeLineEndings(decodeText(bytes, target.displayPath, bytes.length)) } catch (error: unknown) { if (error instanceof FsError && error.code === 'FS_NOT_TEXT') return null throw mapError(error, 'read', target.displayPath, signal) } } private async readForEdit(target: FsTarget, signal?: AbortSignal): Promise { try { const sandbox = await this.ctx.e2b.getSandbox() const bytes = await sandbox.files.read(String(target.targetKey), { format: 'bytes', ...signalOpts(signal) }) assertNotAborted(signal, 'edit') return decodeText(bytes, target.displayPath, bytes.length) } catch (error: unknown) { throw mapError(error, 'edit', target.displayPath, signal) } } private async writeAtomic( target: FsTarget, content: string, existing: EntryInfo | undefined, createIfAbsent: boolean, signal?: AbortSignal, ): Promise> { assertNotAborted(signal, 'write') const sandbox = await this.ctx.e2b.getSandbox() const targetPath = String(target.targetKey) const versionId = randomUUID() const stagingDirectory = posix.join(posix.dirname(targetPath), `.dsh-${randomUUID()}.tmp`) const temporary = posix.join(stagingDirectory, 'content') let stagingDirectoryCreated = false try { const created = await sandbox.files.makeDir(stagingDirectory, signalOpts(signal)) if (!created) throw new Error('private staging directory already exists') stagingDirectoryCreated = true await sandbox.commands.run(`chmod 700 -- ${quoteE2BShellArg(stagingDirectory)}`, commandOpts(signal)) assertNotAborted(signal, 'write') await sandbox.files.write(temporary, content, { metadata: { [VERSION_METADATA_KEY]: versionId }, ...signalOpts(signal), }) assertNotAborted(signal, 'write') const mode = existing === undefined ? 0o600 : existing.mode & 0o777 await sandbox.commands.run( `chmod ${mode.toString(8)} -- ${quoteE2BShellArg(temporary)}`, commandOpts(signal), ) assertNotAborted(signal, 'write') let committed: EntryInfo if (createIfAbsent) { const staged = await sandbox.files.getInfo(temporary, signalOpts(signal)) assertNotAborted(signal, 'write') const targetArg = quoteE2BShellArg(targetPath) const publication = await sandbox.commands.run( `if ln -T -- ${quoteE2BShellArg(temporary)} ${targetArg}; then printf created; elif test -e ${targetArg} || test -L ${targetArg}; then printf exists; else exit 1; fi`, commandOpts(undefined), ) if (publication.stdout === 'exists') { throw new FsError( `cannot overwrite existing "${target.displayPath}" without reading it first`, 'FS_NOT_OBSERVED', ) } if (publication.stdout !== 'created') { throw new Error('guarded create returned an invalid publication result') } committed = { ...staged, name: posix.basename(targetPath), path: targetPath } } else { committed = await sandbox.files.rename(temporary, targetPath) } try { await sandbox.files.remove(stagingDirectory) } catch (_committedStagingCleanupFailure) { // The target is already committed; an empty private directory cannot turn that write into a failure. } return entryVersion(committed) } catch (error: unknown) { if (stagingDirectoryCreated) { try { await sandbox.files.remove(stagingDirectory) } catch (_stagingDirectoryAlreadyAbsentOrCleanupFailed) { // Only the private staging directory is swallowed; the original failure owns the operation. } } throw mapError(error, 'write', target.displayPath, signal) } } } export default E2BFileSystem