/** * Cleanup and postmortem handler utilities. * * This module provides a system for registering and running cleanup callbacks * in response to process exit, signals, or fatal exceptions. It is intended to * allow reliably releasing resources or shutting down subprocesses, files, sockets, etc. */ import { type CrashFingerprint } from "./crash-fingerprint"; import type { CrashProvenance } from "./crash-journal"; import { redactCrashSecrets } from "./crash-redaction"; export declare enum Reason { PRE_EXIT = "pre_exit",// Pre-exit phase (not used by default) EXIT = "exit",// Normal process exit SIGINT = "sigint",// Ctrl-C or SIGINT SIGTERM = "sigterm",// SIGTERM SIGHUP = "sighup",// SIGHUP UNCAUGHT_EXCEPTION = "uncaught_exception",// Fatal exception UNHANDLED_REJECTION = "unhandled_rejection",// Unhandled promise rejection MANUAL = "manual" } /** Cap for the durable crash log; it is reset past this so a crash loop cannot fill the disk. */ export declare const CRASH_LOG_MAX_BYTES: number; /** * Per-record budget so a single oversized error body cannot bypass the file * cap: every persisted record is truncated to this many bytes (UTF-8 safe, * with a marker) before the append/reset decision. */ export declare const CRASH_RECORD_MAX_BYTES: number; export { redactCrashSecrets }; /** * Append a fatal-crash record to the dedicated, rotation-immune crash log * (`~/.gjc/agent/gjc-crash.log`). * * The daily logger file is gzip-archived at date rollover by every gjc process * independently; that shared-archive race can truncate a day's log to an empty * `.gz`, destroying the `logger.error` crash record written here. This * append-only file is never rotated, so a crash stays diagnosable regardless. * * Fully defensive: it never throws (a failing crash writer must not mask the * original fatal) and uses synchronous IO so the record lands before * `process.exit`. Returns the path written, or `undefined` on failure. */ export declare function recordFatalCrash(label: string, reason: unknown, options?: CrashRecordOptions): string | undefined; export interface HandledErrorRecordOptions { /** Override the log target; defaults to `getHandledErrorLogPath()`. */ readonly path?: string; readonly now?: Date; } /** * Record one handled (non-fatal) error, at most once per fingerprint while it * stays hot. * * A handled error is only useful when its stack establishes a stable identity. * The bounded process-local set prevents one retry loop from turning routine * failures into disk churn while preserving the fatal crash store's signal. * The set is LRU with a hard cap: at saturation the coldest fingerprint is * evicted so a long-lived process keeps recording newly seen failure classes * instead of going permanently blind past the cap. */ export declare function recordHandledError(label: string, error: unknown, options?: HandledErrorRecordOptions): string | undefined; /** Reset handled-error process dedupe so isolated tests can exercise repeats. */ export declare function resetHandledErrorDedupeForTest(): void; interface CrashRecordOptions { path?: string; now?: Date; provenance?: CrashProvenance; fingerprint?: CrashFingerprint; } /** * Register a process cleanup callback, to be run on shutdown, signal, or fatal error. * * Returns a Callback instance that can be used to cancel (unregister) or manually clean up. * If register is called after cleanup already began, invokes callback on a microtask. */ export declare function register(id: string, callback: (reason: Reason) => void | Promise): () => void; /** * Runs all cleanup callbacks without exiting. * Use this in workers or when you need to clean up but continue execution. */ export declare function cleanup(): Promise; /** * Runs all cleanup callbacks and exits. * * In main thread: waits for stdout and stderr drain, then calls process.exit(). * In workers: runs cleanup only (process.exit would kill entire process). */ export declare function quit(code?: number): Promise;