Files
wehub-resource-sync adc62957a7
CI / Multi-repo Path Gate (AST-grep) (windows-latest) (push) Has been cancelled
CI / Version Consistency Check (push) Has been cancelled
CI / npm pack + install test (push) Has been cancelled
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Test (Windows path suite) (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / No Committed Build Artifacts (push) Has been cancelled
CI / Multi-repo Path Gate (AST-grep) (ubuntu-latest) (push) Has been cancelled
Upgrade Test / omc update + session-start hook (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:36:54 +08:00

96 lines
2.2 KiB
JavaScript

/**
* Atomic file writes for oh-my-claudecode hooks.
* Self-contained module with no external dependencies.
*
* Mirrors templates/hooks/lib/atomic-write.mjs for use by plugin hook scripts.
*/
import { openSync, writeSync, fsyncSync, closeSync, renameSync, unlinkSync, mkdirSync, existsSync } from 'fs';
import { dirname, basename, join } from 'path';
import { randomUUID } from 'crypto';
/**
* Ensure directory exists
*/
export function ensureDirSync(dir) {
if (existsSync(dir)) {
return;
}
try {
mkdirSync(dir, { recursive: true });
} catch (err) {
if (err.code === 'EEXIST') {
return;
}
throw err;
}
}
/**
* Write string content atomically to a file.
* Uses temp file + atomic rename pattern with fsync for durability.
*
* @param {string} filePath Target file path
* @param {string} content String content to write
*/
export function atomicWriteFileSync(filePath, content) {
const dir = dirname(filePath);
const base = basename(filePath);
const tempPath = join(dir, `.${base}.tmp.${randomUUID()}`);
let fd = null;
let success = false;
try {
// Ensure parent directory exists
ensureDirSync(dir);
// Open temp file with exclusive creation (O_CREAT | O_EXCL | O_WRONLY)
fd = openSync(tempPath, 'wx', 0o600);
// Write content
writeSync(fd, content, 0, 'utf-8');
// Sync file data to disk before rename
fsyncSync(fd);
// Close before rename
closeSync(fd);
fd = null;
// Atomic rename - replaces target file if it exists
renameSync(tempPath, filePath);
success = true;
// Best-effort directory fsync to ensure rename is durable
try {
const dirFd = openSync(dir, 'r');
try {
fsyncSync(dirFd);
} finally {
closeSync(dirFd);
}
} catch {
// Some platforms don't support directory fsync - that's okay
}
} finally {
// Close fd if still open
if (fd !== null) {
try {
closeSync(fd);
} catch {
// Ignore close errors
}
}
// Clean up temp file on error
if (!success) {
try {
unlinkSync(tempPath);
} catch {
// Ignore cleanup errors
}
}
}
}