@@ -356,8 +356,9 @@ export const layer = Layer.effect(
356356 )
357357
358358 const scan = Effect . fn ( "File.scan" ) ( function * ( ) {
359- if ( Instance . directory === path . parse ( Instance . directory ) . root ) return
360- const isGlobalHome = Instance . directory === Global . Path . home && Instance . project . id === "global"
359+ const ctx = yield * InstanceState . context
360+ if ( ctx . directory === path . parse ( ctx . directory ) . root ) return
361+ const isGlobalHome = ctx . directory === Global . Path . home && ctx . project . id === "global"
361362 const next : Entry = { files : [ ] , dirs : [ ] }
362363
363364 if ( isGlobalHome ) {
@@ -366,14 +367,14 @@ export const layer = Layer.effect(
366367 const ignoreNested = new Set ( [ "node_modules" , "dist" , "build" , "target" , "vendor" ] )
367368 const shouldIgnoreName = ( name : string ) => name . startsWith ( "." ) || protectedNames . has ( name )
368369 const shouldIgnoreNested = ( name : string ) => name . startsWith ( "." ) || ignoreNested . has ( name )
369- const top = yield * appFs . readDirectoryEntries ( Instance . directory ) . pipe ( Effect . orElseSucceed ( ( ) => [ ] ) )
370+ const top = yield * appFs . readDirectoryEntries ( ctx . directory ) . pipe ( Effect . orElseSucceed ( ( ) => [ ] ) )
370371
371372 for ( const entry of top ) {
372373 if ( entry . type !== "directory" ) continue
373374 if ( shouldIgnoreName ( entry . name ) ) continue
374375 dirs . add ( entry . name + "/" )
375376
376- const base = path . join ( Instance . directory , entry . name )
377+ const base = path . join ( ctx . directory , entry . name )
377378 const children = yield * appFs . readDirectoryEntries ( base ) . pipe ( Effect . orElseSucceed ( ( ) => [ ] ) )
378379 for ( const child of children ) {
379380 if ( child . type !== "directory" ) continue
@@ -384,7 +385,7 @@ export const layer = Layer.effect(
384385
385386 next . dirs = Array . from ( dirs ) . toSorted ( )
386387 } else {
387- const files = yield * rg . files ( { cwd : Instance . directory } ) . pipe (
388+ const files = yield * rg . files ( { cwd : ctx . directory } ) . pipe (
388389 Stream . runCollect ,
389390 Effect . map ( ( chunk ) => [ ...chunk ] ) ,
390391 )
@@ -416,15 +417,16 @@ export const layer = Layer.effect(
416417 } )
417418
418419 const gitText = Effect . fnUntraced ( function * ( args : string [ ] ) {
419- return ( yield * git . run ( args , { cwd : Instance . directory } ) ) . text ( )
420+ return ( yield * git . run ( args , { cwd : ( yield * InstanceState . context ) . directory } ) ) . text ( )
420421 } )
421422
422423 const init = Effect . fn ( "File.init" ) ( function * ( ) {
423424 yield * ensure ( ) . pipe ( Effect . forkIn ( scope ) )
424425 } )
425426
426427 const status = Effect . fn ( "File.status" ) ( function * ( ) {
427- if ( Instance . project . vcs !== "git" ) return [ ]
428+ const ctx = yield * InstanceState . context
429+ if ( ctx . project . vcs !== "git" ) return [ ]
428430
429431 const diffOutput = yield * gitText ( [
430432 "-c" ,
@@ -463,7 +465,7 @@ export const layer = Layer.effect(
463465 if ( untrackedOutput . trim ( ) ) {
464466 for ( const file of untrackedOutput . trim ( ) . split ( "\n" ) ) {
465467 const content = yield * appFs
466- . readFileString ( path . join ( Instance . directory , file ) )
468+ . readFileString ( path . join ( ctx . directory , file ) )
467469 . pipe ( Effect . catch ( ( ) => Effect . succeed < string | undefined > ( undefined ) ) )
468470 if ( content === undefined ) continue
469471 changed . push ( {
@@ -498,19 +500,22 @@ export const layer = Layer.effect(
498500 }
499501
500502 return changed . map ( ( item ) => {
501- const full = path . isAbsolute ( item . path ) ? item . path : path . join ( Instance . directory , item . path )
503+ const full = path . isAbsolute ( item . path ) ? item . path : path . join ( ctx . directory , item . path )
502504 return {
503505 ...item ,
504- path : path . relative ( Instance . directory , full ) ,
506+ path : path . relative ( ctx . directory , full ) ,
505507 }
506508 } )
507509 } )
508510
509511 const read : Interface [ "read" ] = Effect . fn ( "File.read" ) ( function * ( file : string ) {
510512 using _ = log . time ( "read" , { file } )
511- const full = path . join ( Instance . directory , file )
513+ const ctx = yield * InstanceState . context
514+ const full = path . join ( ctx . directory , file )
512515
513- if ( ! Instance . containsPath ( full ) ) throw new Error ( "Access denied: path escapes project directory" )
516+ if ( ! Instance . containsPath ( full , ctx ) ) {
517+ throw new Error ( "Access denied: path escapes project directory" )
518+ }
514519
515520 if ( isImageByExtension ( file ) ) {
516521 const exists = yield * appFs . existsSafe ( full )
@@ -553,13 +558,13 @@ export const layer = Layer.effect(
553558 Effect . catch ( ( ) => Effect . succeed ( "" ) ) ,
554559 )
555560
556- if ( Instance . project . vcs === "git" ) {
561+ if ( ctx . project . vcs === "git" ) {
557562 let diff = yield * gitText ( [ "-c" , "core.fsmonitor=false" , "diff" , "--" , file ] )
558563 if ( ! diff . trim ( ) ) {
559564 diff = yield * gitText ( [ "-c" , "core.fsmonitor=false" , "diff" , "--staged" , "--" , file ] )
560565 }
561566 if ( diff . trim ( ) ) {
562- const original = yield * git . show ( Instance . directory , "HEAD" , file )
567+ const original = yield * git . show ( ctx . directory , "HEAD" , file )
563568 const patch = structuredPatch ( file , file , original , content , "old" , "new" , {
564569 context : Infinity ,
565570 ignoreWhitespace : true ,
@@ -573,29 +578,32 @@ export const layer = Layer.effect(
573578 } )
574579
575580 const list = Effect . fn ( "File.list" ) ( function * ( dir ?: string ) {
581+ const ctx = yield * InstanceState . context
576582 const exclude = [ ".git" , ".DS_Store" ]
577583 let ignored = ( _ : string ) => false
578- if ( Instance . project . vcs === "git" ) {
584+ if ( ctx . project . vcs === "git" ) {
579585 const ig = ignore ( )
580- const gitignore = path . join ( Instance . project . worktree , ".gitignore" )
586+ const gitignore = path . join ( ctx . worktree , ".gitignore" )
581587 const gitignoreText = yield * appFs . readFileString ( gitignore ) . pipe ( Effect . catch ( ( ) => Effect . succeed ( "" ) ) )
582588 if ( gitignoreText ) ig . add ( gitignoreText )
583- const ignoreFile = path . join ( Instance . project . worktree , ".ignore" )
589+ const ignoreFile = path . join ( ctx . worktree , ".ignore" )
584590 const ignoreText = yield * appFs . readFileString ( ignoreFile ) . pipe ( Effect . catch ( ( ) => Effect . succeed ( "" ) ) )
585591 if ( ignoreText ) ig . add ( ignoreText )
586592 ignored = ig . ignores . bind ( ig )
587593 }
588594
589- const resolved = dir ? path . join ( Instance . directory , dir ) : Instance . directory
590- if ( ! Instance . containsPath ( resolved ) ) throw new Error ( "Access denied: path escapes project directory" )
595+ const resolved = dir ? path . join ( ctx . directory , dir ) : ctx . directory
596+ if ( ! Instance . containsPath ( resolved , ctx ) ) {
597+ throw new Error ( "Access denied: path escapes project directory" )
598+ }
591599
592600 const entries = yield * appFs . readDirectoryEntries ( resolved ) . pipe ( Effect . orElseSucceed ( ( ) => [ ] ) )
593601
594602 const nodes : Node [ ] = [ ]
595603 for ( const entry of entries ) {
596604 if ( exclude . includes ( entry . name ) ) continue
597605 const absolute = path . join ( resolved , entry . name )
598- const file = path . relative ( Instance . directory , absolute )
606+ const file = path . relative ( ctx . directory , absolute )
599607 const type = entry . type === "directory" ? "directory" : "file"
600608 nodes . push ( {
601609 name : entry . name ,
0 commit comments