import { join, resolve, basename, dirname, extname } from 'path' import { readdirSync, mkdirSync, rmdirSync, readFileSync, writeFileSync, appendFileSync, rmSync, copyFileSync, statSync, lstatSync, chmodSync, symlinkSync, readlinkSync, watch, } from 'fs' export const fs = { // Directory operations ls: (path: string) => readdirSync(path), mkdir: (path: string) => mkdirSync(path, { recursive: true }), rmdir: (path: string) => rmdirSync(path === '/' || path === '' ? '/tmp/*' : path, { recursive: true }), pwd: () => process.cwd(), cd: (path: string) => process.chdir(path), // Reading read: (path: string) => readFileSync(path, 'utf-8'), cat: (path: string) => {}, // added below 'read-bytes': (path: string) => [...readFileSync(path)], // Writing write: (path: string, content: string) => writeFileSync(path, content), append: (path: string, content: string) => appendFileSync(path, content), // File operations delete: (path: string) => rmSync(path), rm: (path: string) => {}, // added below copy: (from: string, to: string) => copyFileSync(from, to), move: (from: string, to: string) => { fs.copy(from, to) fs.rm(from) }, mv: (from: string, to: string) => {}, // added below // Path operations basename: (path: string) => basename(path), dirname: (path: string) => dirname(path), extname: (path: string) => extname(path), join: (...paths: string[]) => join(...paths), resolve: (...paths: string[]) => resolve(...paths), // File info stat: (path: string) => { try { const stats = statSync(path) const record = Object.fromEntries(Object.entries(stats)) record['atime'] = record['atimeMs'] record['ctime'] = record['ctimeMs'] record['mtime'] = record['mtimeMs'] delete record['atimeMs'] delete record['ctimeMs'] delete record['mtimeMs'] return record } catch { return {} } }, 'exists?': (path: string) => { try { statSync(path) return true } catch { return false } }, 'file?': (path: string) => { try { return statSync(path).isFile() } catch { return false } }, 'dir?': (path: string) => { try { return statSync(path).isDirectory() } catch { return false } }, 'symlink?': (path: string) => { try { return lstatSync(path).isSymbolicLink() } catch { return false } }, 'exec?': (path: string) => { try { const stats = statSync(path) return !!(stats.mode & 0o111) } catch { return false } }, size: (path: string) => { try { return statSync(path).size } catch { return 0 } }, // Permissions chmod: (path: string, mode: number | string) => { const numMode = typeof mode === 'string' ? parseInt(mode, 8) : mode chmodSync(path, numMode) }, // Symlinks symlink: (target: string, path: string) => symlinkSync(target, path), readlink: (path: string) => readlinkSync(path, 'utf-8'), // Other glob: (pattern: string) => { const dir = pattern.substring(0, pattern.lastIndexOf('/')) const match = pattern.substring(pattern.lastIndexOf('/') + 1) if (!match.includes('*')) throw new Error('only * patterns supported') const ext = match.split('*').pop()! return readdirSync(dir) .filter((f) => f.endsWith(ext)) .map((f) => join(dir, f)) }, watch: (path: string, callback: Function) => watch(path, (event, filename) => callback(event, filename)), } ;(fs as any).cat = fs.read ;(fs as any).mv = fs.move ;(fs as any).cp = fs.copy ;(fs as any).rm = fs.delete