← Files Codex Process JobsARCHIVED FILE
scripts/logs.mjs
6.41 KB · Sep 30, 2026 · 23:13 UTC
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
export const DEFAULT_MAX_LOG_BYTES = 16 * 1024 * 1024;
export const DEFAULT_READ_BYTES = 64 * 1024;
export const MAX_MODEL_LOG_BYTES = 1024 * 1024;
const TRUNCATION_MARKER = Buffer.from("[... earlier output truncated ...]\n", "utf8");
export function resolveMaxLogBytes(env = process.env) {
const parsed = Number.parseInt(env.CODEX_PROCESS_JOBS_MAX_LOG_BYTES ?? "", 10);
if (!Number.isFinite(parsed)) return DEFAULT_MAX_LOG_BYTES;
return Math.max(1_024, Math.min(parsed, 1024 * 1024 * 1024));
}
function compactAndAppend(fd, currentSize, chunk, limit) {
const payload = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
if (currentSize + payload.length <= limit) {
fs.writeSync(fd, payload);
return currentSize + payload.length;
}
const available = Math.max(0, limit - TRUNCATION_MARKER.length);
const payloadTail = payload.subarray(Math.max(0, payload.length - available));
const existingBudget = Math.max(0, available - payloadTail.length);
const existingBytes = Math.min(currentSize, existingBudget);
const existingTail = Buffer.alloc(existingBytes);
if (existingBytes > 0) {
fs.readSync(fd, existingTail, 0, existingBytes, Math.max(0, currentSize - existingBytes));
}
fs.ftruncateSync(fd, 0);
fs.writeSync(fd, TRUNCATION_MARKER);
if (existingTail.length > 0) fs.writeSync(fd, existingTail);
if (payloadTail.length > 0) fs.writeSync(fd, payloadTail);
return TRUNCATION_MARKER.length + existingTail.length + payloadTail.length;
}
export function createBoundedLogWriter(file, limit = DEFAULT_MAX_LOG_BYTES) {
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
const flags = fs.constants.O_RDWR
| fs.constants.O_CREAT
| fs.constants.O_APPEND
| (fs.constants.O_NOFOLLOW ?? 0);
const fd = fs.openSync(file, flags, 0o600);
let stat;
try {
stat = fs.fstatSync(fd);
if (!stat.isFile()) throw new Error(`Tracked log is not a regular file: ${file}`);
fs.fchmodSync(fd, 0o600);
} catch (error) {
fs.closeSync(fd);
throw error;
}
let size = stat.size;
if (size > limit) {
const tail = readTail(file, Math.max(0, limit - TRUNCATION_MARKER.length));
fs.ftruncateSync(fd, 0);
fs.writeSync(fd, TRUNCATION_MARKER);
fs.writeSync(fd, tail);
size = TRUNCATION_MARKER.length + tail.length;
}
return {
append(chunk) {
size = compactAndAppend(fd, size, chunk, limit);
},
close() {
fs.closeSync(fd);
},
get size() {
return size;
},
};
}
export function readTail(file, maxBytes = DEFAULT_READ_BYTES) {
try {
const fd = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
try {
const stat = fs.fstatSync(fd);
if (!stat.isFile()) throw new Error(`Tracked log is not a regular file: ${file}`);
const size = stat.size;
const length = Math.max(0, Math.min(size, maxBytes));
const buffer = Buffer.alloc(length);
if (length > 0) fs.readSync(fd, buffer, 0, length, size - length);
return buffer;
} finally {
fs.closeSync(fd);
}
} catch (error) {
if (error?.code === "ENOENT") return Buffer.alloc(0);
throw error;
}
}
export function readLog(file, { full = false, maxBytes = DEFAULT_READ_BYTES } = {}) {
if (!full) return readTail(file, maxBytes).toString("utf8");
try {
const fd = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
try {
const stat = fs.fstatSync(fd);
if (!stat.isFile()) throw new Error(`Tracked log is not a regular file: ${file}`);
const limit = Math.max(1, Math.min(maxBytes, MAX_MODEL_LOG_BYTES));
if (stat.size <= limit) {
const buffer = Buffer.alloc(stat.size);
if (stat.size > 0) fs.readSync(fd, buffer, 0, stat.size, 0);
return buffer.toString("utf8");
}
const length = Math.max(0, limit - TRUNCATION_MARKER.length);
const buffer = Buffer.alloc(length);
if (length > 0) fs.readSync(fd, buffer, 0, length, stat.size - length);
return Buffer.concat([TRUNCATION_MARKER, buffer]).toString("utf8");
} finally {
fs.closeSync(fd);
}
} catch (error) {
if (error?.code === "ENOENT") return "";
throw error;
}
}
function readGeneration(fd, size) {
// Hash a fixed-length prefix so the generation remains stable as an
// append-only file grows. Bounded logs cannot compact below 1 KiB, so a
// short file does not need a generation to distinguish normal appends.
if (size < 256) return null;
const prefix = Buffer.alloc(256);
fs.readSync(fd, prefix, 0, prefix.length, 0);
return crypto.createHash("sha256").update(prefix).digest("hex").slice(0, 16);
}
export function readLogSince(file, sinceByte, { maxBytes = DEFAULT_READ_BYTES, generation = null } = {}) {
const offset = Number(sinceByte);
if (!Number.isSafeInteger(offset) || offset < 0) {
throw new Error("Log cursor must be a non-negative safe integer.");
}
const limit = Math.max(1, Math.min(Number(maxBytes) || DEFAULT_READ_BYTES, MAX_MODEL_LOG_BYTES));
try {
const fd = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
try {
const stat = fs.fstatSync(fd);
if (!stat.isFile()) throw new Error(`Tracked log is not a regular file: ${file}`);
if (generation != null && !/^[a-f0-9]{16}$/.test(String(generation))) {
throw new Error("Log cursor generation must be 16 lowercase hexadecimal characters.");
}
const currentGeneration = readGeneration(fd, stat.size);
const compacted = offset > stat.size
|| (generation != null && currentGeneration !== generation);
const requestedStart = compacted ? 0 : offset;
const available = Math.max(0, stat.size - requestedStart);
const length = Math.min(available, limit);
const startOffset = available > limit ? stat.size - length : requestedStart;
const buffer = Buffer.alloc(length);
if (length > 0) fs.readSync(fd, buffer, 0, length, startOffset);
return {
text: buffer.toString("utf8"),
startOffset,
nextOffset: stat.size,
generation: currentGeneration,
compacted,
truncated: available > limit,
};
} finally {
fs.closeSync(fd);
}
} catch (error) {
if (error?.code === "ENOENT") {
return { text: "", startOffset: 0, nextOffset: 0, generation: null, compacted: offset > 0, truncated: false };
}
throw error;
}
}
SHA-256: 69bd6c4849d6e78919e82ecc8c6f0b1f5036e69b8c92ef700c7db14e1904afbe