Pure Bun-native filesystem utilities from @sidequest/core/fs. Use when you need command-injection-safe filesystem operations, prefer Bun over node:fs, or want token-efficient fs helpers. All functions use Bun.spawn, Bun.file(), or Bun.write() - no node:fs dependencies.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Pure Bun-native filesystem utilities from @sidequest/core/fs - zero node:fs dependencies, command-injection safe.
import { pathExists, pathExistsSync } from "@sidequest/core/fs";
// Async
if (await pathExists("/path/to/file")) { }
// Sync
if (pathExistsSync("/path/to/file")) { }
Implementation: Uses Bun.file().exists() (async) or test -e command (sync)
import { readTextFile, readTextFileSync, readJsonFile, readJsonFileSync } from "@sidequest/core/fs";
// Async text
const content = await readTextFile("/path/to/file.txt");
// Sync text
const content = readTextFileSync("/path/to/file.txt");
// Async JSON
const data = await readJsonFile<MyType>("/path/to/data.json");
// Sync JSON
const data = readJsonFileSync<MyType>("/path/to/data.json");
Implementation: Uses Bun.file().text() (async) or cat command (sync)
import { writeTextFile, writeTextFileSync, writeJsonFile, writeJsonFileSync } from "@sidequest/core/fs";
// Async text
await writeTextFile("/path/to/file.txt", "content");
// Sync text
writeTextFileSync("/path/to/file.txt", "content");
// Async JSON
await writeJsonFile("/path/to/data.json", { foo: "bar" }, 2);
// Sync JSON
writeJsonFileSync("/path/to/data.json", { foo: "bar" }, 2);
Implementation: Uses Bun.write() (async) or printf via shell (sync)
import { ensureDir, ensureDirSync, readDir, readDirAsync } from "@sidequest/core/fs";
// Create directory (recursive)
await ensureDir("/path/to/nested/dir");
ensureDirSync("/path/to/nested/dir");
// List directory contents
const files = readDir("/path/to/dir"); // Sync
const files = await readDirAsync("/path/to/dir"); // Async
Implementation: Uses mkdir -p command, ls -1 command
import { copyFile, moveFile, rename, unlink, unlinkSync } from "@sidequest/core/fs";
// Copy file
await copyFile("/source.txt", "/dest.txt");
// Move file (copy + delete)
await moveFile("/source.txt", "/dest.txt");
// Rename/move atomically
await rename("/old-path.txt", "/new-path.txt");
// Delete file
await unlink("/path/to/file.txt");
unlinkSync("/path/to/file.txt");
Implementation: Uses Bun.write() for copy, mv command for rename, rm command for delete
import { stat } from "@sidequest/core/fs";
const stats = await stat("/path/to/file.txt");
console.log(stats.size); // File size in bytes
console.log(stats.mtimeMs); // Last modified timestamp
Implementation: Uses Bun.file().size and Bun.file().lastModified
Use case: TOCTOU protection - check file before AND after operations
import { sha256, sha256File, fastHash } from "@sidequest/core/fs";
// Hash string
const hash = sha256("content"); // Hex string (64 chars)
// Hash file
const hash = await sha256File("/path/to/file.pdf");
// Fast non-cryptographic hash (cache keys)
const hash = fastHash("content"); // bigint or number
Implementation: Uses Bun.CryptoHasher (SHA256) or Bun.hash (xxHash64)
import { deepEquals } from "@sidequest/core/fs";
const equal = deepEquals(obj1, obj2); // Loose mode
const equal = deepEquals(obj1, obj2, true); // Strict mode
Implementation: Uses Bun.deepEquals()
✅ Command injection safe - All shell commands use array arguments:
// Safe - array args prevent injection
Bun.spawnSync(["mkdir", "-p", userInput]);
// Never - string interpolation allows injection
Bun.spawnSync(`mkdir -p ${userInput}`); // ❌ DON'T DO THIS
✅ TOCTOU protection - Use stat() before AND after file operations to detect tampering
// Before (node:fs)
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
existsSync("/path");
mkdirSync("/path", { recursive: true });
readFileSync("/path", "utf8");
writeFileSync("/path", "content", "utf8");
// After (@sidequest/core/fs)
import { pathExistsSync, ensureDirSync, readTextFileSync, writeTextFileSync } from "@sidequest/core/fs";
pathExistsSync("/path");
ensureDirSync("/path");
readTextFileSync("/path");
writeTextFileSync("/path", "content");
| Operation | Speed | Notes |
|---|---|---|
pathExists | ~1ms | Bun.file().exists() |
pathExistsSync | ~2ms | test -e command |
readTextFile | ~5-50ms | Depends on file size |
writeTextFile | ~5-20ms | Bun.write() is fast |
ensureDir | ~10ms | mkdir -p command |
readDir | ~5-15ms | ls -1 command |
sha256File | ~50-500ms | Depends on file size |
fastHash | <1ms | xxHash64 is very fast |
import { pathExistsSync, writeTextFileSync, rename } from "@sidequest/core/fs";
// Write to temp file, then atomically rename
const tempPath = `${targetPath}.tmp`;
writeTextFileSync(tempPath, newContent);
await rename(tempPath, targetPath); // POSIX guarantees atomicity
import { stat, readTextFileSync, writeTextFileSync } from "@sidequest/core/fs";
// Get pre-modification stats
const preStat = await stat(filePath);
// Read and modify
const content = readTextFileSync(filePath);
const modified = transform(content);
// Verify file unchanged before writing
const postStat = await stat(filePath);
if (postStat.mtimeMs !== preStat.mtimeMs) {
throw new Error("File was modified during read (TOCTOU attack detected)");
}
writeTextFileSync(filePath, modified);
import { sha256File, pathExistsSync } from "@sidequest/core/fs";
const hash = await sha256File(sourceFile);
const processedMarker = `.processed/${hash}`;
if (pathExistsSync(processedMarker)) {
console.log("Already processed - skipping");
return;
}
// Process file...
writeTextFileSync(processedMarker, new Date().toISOString());
All functions are exported from core/src/fs/index.ts and use:
Bun.file() - File existence, reading, size, timestampsBun.write() - Writing filesBun.spawn() / Bun.spawnSync() - Shell commands with array argsBun.CryptoHasher - SHA256 hashingBun.hash - Fast non-cryptographic hashing (xxHash64)Bun.deepEquals() - Deep equality checksBun.Glob - Recursive file scanning (used elsewhere, not exported from fs)Zero node:fs dependencies in production code.
core/src/fs/index.ts