/** * Process-level shutdown handlers. * * OpenCode does not reliably await plugin `dispose()` before Node exits, and * host-level SIGTERM/SIGINT propagate to our `aft` children through the process * group. Without explicit cleanup, children see SIGTERM, their `exit` handler * fires, and (before the sibling fix in bridge.ts) they would auto-restart into * orphaned processes. Even with that fixed, we still want orderly shutdown so * pending requests get rejected and the bridges terminate before Node is gone. * * Each plugin instance (and there can be several per Node process when OpenCode * loads the plugin from multiple contexts) registers its cleanup callback here. * We install the OS-level signal handlers exactly once per Node process via a * `globalThis` guard — otherwise each plugin reload would stack another SIGTERM * listener and fire duplicate shutdowns. */ type Cleanup = (reason: string) => Promise | void; export interface ShutdownCleanupRegistration { /** Run only this registration's cleanup and remove it from the process-exit registry. */ dispose(reason: string): Promise; /** Remove the cleanup without running it. */ unregister(): void; } export declare function runCleanups(reason: string): Promise; /** Conventional exit codes for fatal signals (128 + signal number). */ export declare const SIGNAL_EXIT_CODES: { readonly SIGINT: 130; readonly SIGTERM: 143; readonly SIGHUP: 129; }; /** * Decide whether AFT's handler must terminate the process after cleanup. * * Registering ANY listener for SIGINT/SIGTERM/SIGHUP disables Node/Bun's * default terminate-on-signal behavior. If AFT's listener is the only one, * the default was suppressed solely by us, so we must exit or the host hangs * forever (OpenCode serve + Desktop /event SSE hung on Ctrl-C until SIGKILL). * If the host or another plugin also listens, terminating is THEIR call — * forcing an exit here would race a host's graceful shutdown. */ export declare function shouldForceExit(otherListenerCount: number): boolean; /** * Register one plugin instance's cleanup for process-exit drains. The returned * registration also owns instance disposal, so removing, running, and * de-duplicating that cleanup cannot drift apart at factory call sites. */ export declare function registerShutdownCleanup(fn: Cleanup): ShutdownCleanupRegistration; /** Read the registered callback invocation count without exposing it in production state. */ export declare function __shutdownCleanupInvocationCountForTests(cleanup: unknown): number; export {}; //# sourceMappingURL=shutdown-hooks.d.ts.map