Files
oh-my-pi/packages/coding-agent/src/capability/fs.ts
T
can1357 e22d123009 refactor(fs): migrated remaining sync file operations to async
- Converted readdirSync, readFileSync, and statSync to async readdir, readFile, stat across skills and agent discovery.
- Made scanDirectoryForSkills async and refactored custom directory scanning to use Promise.all for concurrent processing.
- Updated agent discovery to use fs/promises for async file reading and refactored helper patterns.
- Added AgentParsingError exception class for better error handling during agent parsing.
- Added filesystem error type guards (isEnoent, isEacces, isPerm, etc.) to pi-utils for safe error checking.
- Added color manipulation utilities to pi-utils for accessibility features.
- Added color-blind mode setting to settings manager.
- Migrated plugins, settings, and config modules from sync to async file operations.
- Updated error handling to use new pi-utils type guards for type-safe checking.
2026-01-24 03:18:03 +01:00

90 lines
2.1 KiB
TypeScript

import * as fs from "node:fs";
import * as path from "node:path";
const contentCache = new Map<string, string | null>();
const dirCache = new Map<string, fs.Dirent[]>();
function resolvePath(filePath: string): string {
return path.resolve(filePath);
}
export async function readFile(filePath: string): Promise<string | null> {
const abs = resolvePath(filePath);
if (contentCache.has(abs)) {
return contentCache.get(abs) ?? null;
}
try {
const content = await Bun.file(abs).text();
contentCache.set(abs, content);
return content;
} catch {
contentCache.set(abs, null);
return null;
}
}
export async function readDirEntries(dirPath: string): Promise<fs.Dirent[]> {
const abs = resolvePath(dirPath);
if (dirCache.has(abs)) {
return dirCache.get(abs) ?? [];
}
try {
const entries = await fs.promises.readdir(abs, { withFileTypes: true });
dirCache.set(abs, entries);
return entries;
} catch {
dirCache.set(abs, []);
return [];
}
}
export async function readDir(dirPath: string): Promise<string[]> {
const entries = await readDirEntries(dirPath);
return entries.map((entry) => entry.name);
}
export async function walkUp(
startDir: string,
name: string,
opts: { file?: boolean; dir?: boolean } = {},
): Promise<string | null> {
const { file = true, dir = true } = opts;
let current = resolvePath(startDir);
while (true) {
const entries = await readDirEntries(current);
const entry = entries.find((e) => e.name === name);
if (entry) {
if (file && entry.isFile()) return path.join(current, name);
if (dir && entry.isDirectory()) return path.join(current, name);
}
const parent = path.dirname(current);
if (parent === current) return null;
current = parent;
}
}
export function cacheStats(): { content: number; dir: number } {
return {
content: contentCache.size,
dir: dirCache.size,
};
}
export function clearCache(): void {
contentCache.clear();
dirCache.clear();
}
export function invalidate(filePath: string): void {
const abs = resolvePath(filePath);
contentCache.delete(abs);
dirCache.delete(abs);
const parent = path.dirname(abs);
if (parent !== abs) {
dirCache.delete(parent);
}
}