/** * The process entry point for an Effect CLI: render a failure the way a user * expects, map an exit to an exit code, and run the program. * * This is the one module in the library that runs an effect. A process entry * point is an external contract (Node hands you a synchronous `main`, and the * exit code is the only thing the shell sees), so `Effect.runFork` lives here * and nowhere else. * * ```ts * const AppLayer = Layer.mergeAll(Logger.layerConfig(), Sqlite.layerConfig()); * * runMain(main.pipe(Effect.provide(AppLayer)), { * debug: process.env.MYTOOL_DEBUG !== undefined, * flush: Logger.flush.pipe(Effect.provide(AppLayer)), * }); * ``` */ import { Cause, Effect, Exit } from "effect"; /** * What a CLI program resolves to: an explicit exit code, or nothing when the * command simply succeeded. */ export type MainResult = number | void; /** Options for {@link renderFailure}. */ export interface RenderFailureOptions { /** Append the stack to a tagged failure too. Defects always keep their stack. */ readonly debug?: boolean; } /** * What the user sees when the program fails. * * A tagged failure is an expected error whose `message` already reads * `operation: cause` down the chain, so print that. A defect is an untyped * throw whose stack is the only clue it carries, so print the stack. * Interruption renders as `interrupted`. */ export declare function renderFailure(cause: Cause.Cause, options?: RenderFailureOptions): string; /** * The exit code for a finished program: a number result is the code itself, * a void result is 0, interruption is 130 (the shell's convention for * SIGINT), and any other failure is 1. Pure, so the mapping can be tested * without a process. */ export declare function exitCodeFor(exit: Exit.Exit): number; /** Options for {@link runMain}. `EF` is the flush effect's error type, if any. */ export interface RunMainOptions { /** Add stacks to tagged failures. Usually driven by a `*_DEBUG` env var. */ readonly debug?: boolean; /** * Run on every path, success or failure, before exiting. Typically * `Logger.flush` provided with the same layer as the program, so queued log * writes land before the process goes away. Its own failures are swallowed: * flushing never changes the exit code. */ readonly flush?: Effect.Effect; /** Where a failure is printed. Defaults to `process.stderr`. */ readonly stderr?: (text: string) => void; /** How the process ends. Defaults to `process.exit`; inject in tests. */ readonly exit?: (code: number) => void; /** Install SIGINT/SIGTERM handlers that interrupt the program. Defaults to `true`. */ readonly signals?: boolean; } /** * Runs `program` as the process entry point. * * The program is provided in full by the caller: `runMain` requires * `Effect`, so every layer is already applied * and `flush` (which usually needs the same layers) is passed separately * rather than inferred. * * SIGINT and SIGTERM interrupt the running fiber, which lets finalizers run * and exits 130. A typed failure or a defect prints through `renderFailure` * and exits 1. */ export declare function runMain(program: Effect.Effect, options?: RunMainOptions): void;