11import { FragmentSchema } from '@/lib/schema'
22import { ExecutionResultInterpreter , ExecutionResultWeb } from '@/lib/types'
33import { Sandbox } from '@e2b/code-interpreter'
4+ import { FileSystemNode } from '@/components/file-tree'
45
56const sandboxTimeout = 10 * 60 * 1000
67
8+ async function fetchSandboxFiles ( sbx : Sandbox ) : Promise < FileSystemNode [ ] > {
9+ try {
10+ const result = await sbx . commands . run (
11+ 'find /home/user -type f -o -type d 2>/dev/null | grep -v "node_modules" | sort'
12+ )
13+
14+ if ( result . exitCode !== 0 ) {
15+ console . error ( 'Error listing files:' , result . stderr )
16+ return [ ]
17+ }
18+
19+ return parseFileTree ( result . stdout )
20+ } catch ( error ) {
21+ console . error ( 'Error fetching sandbox files:' , error )
22+ return [ ]
23+ }
24+ }
25+
26+ function parseFileTree ( output : string ) : FileSystemNode [ ] {
27+ const lines = output . trim ( ) . split ( '\n' ) . filter ( line => line . trim ( ) )
28+ const root : FileSystemNode [ ] = [ ]
29+ const nodeMap = new Map < string , FileSystemNode > ( )
30+
31+ const paths = lines
32+ . map ( line => line . trim ( ) )
33+ . filter ( path => path . startsWith ( '/home/user/' ) )
34+ . sort ( )
35+
36+ for ( const fullPath of paths ) {
37+ const relativePath = fullPath . replace ( '/home/user/' , '' )
38+ if ( ! relativePath ) continue
39+
40+ const parts = relativePath . split ( '/' )
41+ const name = parts [ parts . length - 1 ]
42+ const parentPath = parts . slice ( 0 , - 1 ) . join ( '/' )
43+
44+ const node : FileSystemNode = {
45+ name,
46+ isDirectory : false ,
47+ path : `/${ relativePath } ` ,
48+ children : [ ]
49+ }
50+
51+ nodeMap . set ( relativePath , node )
52+
53+ if ( parentPath === '' ) {
54+ root . push ( node )
55+ } else {
56+ const parent = nodeMap . get ( parentPath )
57+ if ( parent ) {
58+ if ( ! parent . children ) {
59+ parent . children = [ ]
60+ }
61+ parent . children . push ( node )
62+ parent . isDirectory = true
63+ }
64+ }
65+ }
66+
67+ return root
68+ }
69+
770export const maxDuration = 60
871export const runtime = 'nodejs'
972export const dynamic = 'force-dynamic'
@@ -97,6 +160,9 @@ export async function POST(req: Request) {
97160 if ( fragment . template === 'code-interpreter-v1' ) {
98161 const { logs, error, results } = await sbx . runCode ( fragment . code || '' )
99162
163+ // Fetch file tree after execution
164+ const files = await fetchSandboxFiles ( sbx )
165+
100166 return new Response (
101167 JSON . stringify ( {
102168 sbxId : sbx ?. sandboxId ,
@@ -105,6 +171,7 @@ export async function POST(req: Request) {
105171 stderr : logs . stderr ,
106172 runtimeError : error ,
107173 cellResults : results ,
174+ files,
108175 } as ExecutionResultInterpreter ) ,
109176 { headers : { 'Content-Type' : 'application/json' } }
110177 )
@@ -116,11 +183,15 @@ export async function POST(req: Request) {
116183 } ,
117184 } )
118185
186+ // Fetch file tree after project setup
187+ const files = await fetchSandboxFiles ( sbx )
188+
119189 return new Response (
120190 JSON . stringify ( {
121191 sbxId : sbx ?. sandboxId ,
122192 template : fragment . template ,
123193 url : `https://${ sbx ?. getHost ( fragment . port || 80 ) } ` ,
194+ files,
124195 } as ExecutionResultWeb ) ,
125196 { headers : { 'Content-Type' : 'application/json' } }
126197 )
0 commit comments