@@ -24,22 +24,31 @@ export type FileOperationResult = {
2424
2525export class Filesystem {
2626 private synapse : Synapse ;
27+ private workDir : string ;
2728 private folderWatchers : Map < string , fsSync . FSWatcher > = new Map ( ) ;
2829
2930 /**
3031 * Creates a new Filesystem instance
3132 * @param synapse - The Synapse instance to use
3233 */
33- constructor ( synapse : Synapse ) {
34+ constructor ( synapse : Synapse , workDir ?: string ) {
3435 this . synapse = synapse ;
3536 this . synapse . setFilesystem ( this ) ;
37+ this . workDir = workDir ?? process . cwd ( ) ;
3638 }
3739
3840 private log ( message : string ) : void {
3941 const timestamp = new Date ( ) . toISOString ( ) ;
4042 console . log ( `[Filesystem][${ timestamp } ] ${ message } ` ) ;
4143 }
4244
45+ private resolvePath ( inputPath : string ) : string {
46+ if ( path . isAbsolute ( inputPath ) ) {
47+ return inputPath ;
48+ }
49+ return path . join ( this . workDir , inputPath ) ;
50+ }
51+
4352 /**
4453 * Creates a new file at the specified path with optional content.
4554 * Fails if the file already exists.
@@ -52,7 +61,7 @@ export class Filesystem {
5261 filePath : string ,
5362 content : string = "" ,
5463 ) : Promise < FileOperationResult > {
55- const fullPath = path . join ( this . synapse . workDir , filePath ) ;
64+ const fullPath = this . resolvePath ( filePath ) ;
5665
5766 try {
5867 await fs . access ( fullPath , fsConstants . F_OK ) ;
@@ -111,7 +120,7 @@ export class Filesystem {
111120 */
112121 async getFile ( filePath : string ) : Promise < FileOperationResult > {
113122 try {
114- const fullPath = path . join ( this . synapse . workDir , filePath ) ;
123+ const fullPath = this . resolvePath ( filePath ) ;
115124
116125 const data = await fs . readFile ( fullPath , "utf-8" ) ;
117126
@@ -140,7 +149,7 @@ export class Filesystem {
140149 ) : Promise < FileOperationResult > {
141150 try {
142151 this . log ( `Updating file at path: ${ filePath } ` ) ;
143- const fullPath = path . join ( this . synapse . workDir , filePath ) ;
152+ const fullPath = this . resolvePath ( filePath ) ;
144153 const dirPath = path . dirname ( filePath ) ;
145154
146155 await this . createFolder ( dirPath ) ;
@@ -170,7 +179,7 @@ export class Filesystem {
170179 content : string ,
171180 ) : Promise < FileOperationResult > {
172181 try {
173- const fullPath = path . join ( this . synapse . workDir , filePath ) ;
182+ const fullPath = this . resolvePath ( filePath ) ;
174183 await fs . appendFile ( fullPath , content ) ;
175184 return { success : true } ;
176185 } catch ( error ) {
@@ -197,8 +206,8 @@ export class Filesystem {
197206 ) : Promise < FileOperationResult > {
198207 try {
199208 this . log ( `Moving file from ${ oldPath } to ${ newPath } ` ) ;
200- const fullOldPath = path . join ( this . synapse . workDir , oldPath ) ;
201- const fullNewPath = path . join ( this . synapse . workDir , newPath ) ;
209+ const fullOldPath = this . resolvePath ( oldPath ) ;
210+ const fullNewPath = this . resolvePath ( newPath ) ;
202211
203212 await fs . rename ( fullOldPath , fullNewPath ) ;
204213
@@ -223,7 +232,7 @@ export class Filesystem {
223232 async deleteFile ( filePath : string ) : Promise < FileOperationResult > {
224233 try {
225234 this . log ( `Deleting file at path: ${ filePath } ` ) ;
226- const fullPath = path . join ( this . synapse . workDir , filePath ) ;
235+ const fullPath = this . resolvePath ( filePath ) ;
227236
228237 await fs . unlink ( fullPath ) ;
229238
@@ -246,13 +255,13 @@ export class Filesystem {
246255 * @throws Error if directory creation fails
247256 */
248257 async createFolder ( dirPath : string ) : Promise < FileOperationResult > {
258+ const fullPath = this . resolvePath ( dirPath ) ;
259+
249260 if ( dirPath === "." || dirPath === "" || dirPath === "/" ) {
250261 // Skip creation for root or relative '.' path
251262 return { success : true } ;
252263 }
253264
254- const fullPath = path . join ( this . synapse . workDir , dirPath ) ;
255-
256265 try {
257266 await fs . mkdir ( fullPath , { recursive : true } ) ;
258267
@@ -279,7 +288,7 @@ export class Filesystem {
279288 async getFolder ( dirPath : string ) : Promise < FileItemResult > {
280289 try {
281290 this . log ( `Reading directory at path: ${ dirPath } ` ) ;
282- const fullPath = path . join ( this . synapse . workDir , dirPath ) ;
291+ const fullPath = this . resolvePath ( dirPath ) ;
283292
284293 const items = await fs . readdir ( fullPath , { withFileTypes : true } ) ;
285294 const data : FileItem [ ] = items . map ( ( item ) => ( {
@@ -312,7 +321,7 @@ export class Filesystem {
312321 ) : Promise < FileOperationResult > {
313322 try {
314323 this . log ( `Renaming folder at ${ dirPath } to ${ name } ` ) ;
315- const fullPath = path . join ( this . synapse . workDir , dirPath ) ;
324+ const fullPath = this . resolvePath ( dirPath ) ;
316325
317326 const dir = path . dirname ( fullPath ) ;
318327 const newPath = path . join ( dir , name ) ;
@@ -344,8 +353,8 @@ export class Filesystem {
344353 ) : Promise < FileOperationResult > {
345354 try {
346355 this . log ( `Moving folder from ${ oldPath } to ${ newPath } ` ) ;
347- const fullOldPath = path . join ( this . synapse . workDir , oldPath ) ;
348- const fullNewPath = path . join ( this . synapse . workDir , newPath ) ;
356+ const fullOldPath = this . resolvePath ( oldPath ) ;
357+ const fullNewPath = this . resolvePath ( newPath ) ;
349358
350359 await fs . rename ( fullOldPath , fullNewPath ) ;
351360
@@ -370,7 +379,7 @@ export class Filesystem {
370379 async deleteFolder ( dirPath : string ) : Promise < FileOperationResult > {
371380 try {
372381 this . log ( `Deleting folder at path: ${ dirPath } ` ) ;
373- const fullPath = path . join ( this . synapse . workDir , dirPath ) ;
382+ const fullPath = this . resolvePath ( dirPath ) ;
374383
375384 await fs . rm ( fullPath , { recursive : true } ) ;
376385
@@ -393,15 +402,15 @@ export class Filesystem {
393402 watchWorkDir (
394403 onChange : ( result : { path : string ; content : string | null } ) => void ,
395404 ) : void {
396- const fullPath = path . join ( this . synapse . workDir ) ;
405+ const fullPath = this . resolvePath ( this . workDir ) ;
397406 if ( this . folderWatchers . has ( fullPath ) ) {
398407 return ;
399408 }
400409
401410 // Read and parse .gitignore from the root of the workspace
402411 let ig : ReturnType < typeof ignore > | null = null ;
403412 try {
404- const gitignorePath = path . join ( this . synapse . workDir , ".gitignore" ) ;
413+ const gitignorePath = this . resolvePath ( ".gitignore" ) ;
405414 const gitignoreContent = fsSync . existsSync ( gitignorePath )
406415 ? fsSync . readFileSync ( gitignorePath , "utf-8" )
407416 : "" ;
@@ -422,7 +431,7 @@ export class Filesystem {
422431 return ; // ignore this change
423432 }
424433 const changedPath = path . join ( "/" , filename ) ; // relative to workDir
425- const absPath = path . join ( this . synapse . workDir , filename ) ;
434+ const absPath = path . join ( this . workDir , filename ) ;
426435
427436 try {
428437 const stat = await fs . lstat ( absPath ) ;
@@ -447,7 +456,7 @@ export class Filesystem {
447456 * Stops watching a directory for changes.
448457 */
449458 unwatchWorkDir ( ) : void {
450- const fullPath = path . join ( this . synapse . workDir ) ;
459+ const fullPath = this . resolvePath ( this . workDir ) ;
451460 const watcher = this . folderWatchers . get ( fullPath ) ;
452461 if ( watcher ) {
453462 watcher . close ( ) ;
0 commit comments