hacksh 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,6 +23,7 @@ interactive input with `prompt`.
23
23
  - [Output formats](#output-formats)
24
24
  - [Programmatic API and errors](#programmatic-api-and-errors)
25
25
  - [Entry points](#entry-points)
26
+ - [Composable run functions](#composable-run-functions)
26
27
  - [Printers and events](#printers-and-events)
27
28
  - [Standalone parsing and help](#standalone-parsing-and-help)
28
29
  - [Errors](#errors)
@@ -129,6 +130,7 @@ const copy = defineCommand({
129
130
  }),
130
131
  run({ args }) {
131
132
  const [destination, ...files] = args.positionals; // [string, ...string[]]
133
+ return { destination, files };
132
134
  },
133
135
  });
134
136
  ```
@@ -346,6 +348,8 @@ context API to `node:child_process`, `spawnSync`, or a custom subprocess wrapper
346
348
  handler so execution uses the invocation’s environment, cancellation, and printer.
347
349
 
348
350
  ```ts
351
+ import { HackshExecError } from "hacksh";
352
+
349
353
  const check = defineCommand({
350
354
  name: "check-head",
351
355
  async run({ exec, logger }) {
@@ -359,7 +363,7 @@ const check = defineCommand({
359
363
  return;
360
364
  }
361
365
  // Missing executables, cancellation, and other failures must still fail the command.
362
- throw new Error("Could not inspect HEAD", { cause: head });
366
+ throw new HackshExecError("Could not inspect HEAD", head);
363
367
  }
364
368
  logger.info("HEAD is {commit}", { commit: head.stdout });
365
369
  },
@@ -482,8 +486,9 @@ holding the exact text, including the newline `println` adds, or
482
486
  pretty stdout, except that terminal control sequences are removed as in every JSON string. `json`
483
487
  values are normalized like log properties.
484
488
 
485
- hacksh never prints a `run` return value; it is returned to `runCommand` callers only. Output that
486
- was written before a failure stays written, and the error follows on stderr. Like logger calls,
489
+ hacksh never prints a `run` return value; it is returned to `runCommand` callers only.
490
+ `runMain` reports thrown `HackshError` instances on stderr and rethrows other exceptions.
491
+ Output that was written before a failure stays written. Like logger calls,
487
492
  `output` calls do not need to be awaited and are drained before execution finishes. Writing to
488
493
  `process.stdout` or `console.log` directly bypasses the printer, the output mode, and any `stdout`
489
494
  writer given to `runMain` or `runCommand`.
@@ -606,14 +611,15 @@ later aborts the context's `signal`.
606
611
 
607
612
  `runMain` listens for `SIGINT` and `SIGTERM` while it runs and removes those listeners before it
608
613
  returns or exits. The first signal aborts the invocation with an `AbortError` named after the
609
- signal; once `run` settles, output is drained and the process exits with 130 for `SIGINT` or 143 for
610
- `SIGTERM`, even if `run` threw. A second signal while `run` is still pending exits immediately with
611
- that signal's status.
614
+ signal. When `run` returns, throws a `HackshError`, or rejects with that exact signal reason,
615
+ output is drained and the process exits with 130 for `SIGINT` or 143 for `SIGTERM`. Unrelated
616
+ exceptions and output failures still reject instead of being converted to a signal exit.
617
+ A second signal while the invocation is pending exits immediately with that signal's status.
612
618
 
613
619
  Throw `HackshExitError(exitCode, message?)` to choose the exit status, an integer from 0 to 255.
614
- `runMain` prints a non-empty message as an ordinary error and prints nothing when the message is
615
- omitted; `onError` still receives the error. `runCommand` rethrows it, so library callers read
616
- `exitCode` from the caught error. Other failures exit with 1, or 130 for a cancelled prompt.
620
+ `runMain` prints a non-empty message as an ordinary CLI error and prints nothing when the message
621
+ is omitted; `onError` still receives the error. `runCommand` rethrows it unchanged.
622
+ Other `HackshError` instances exit with 1, or 130 for a cancelled prompt.
617
623
 
618
624
  ## Output formats
619
625
 
@@ -621,10 +627,9 @@ omitted; `onError` still receives the error. `runCommand` rethrows it, so librar
621
627
  Their `output` option accepts `"auto"` (the default), `"pretty"`, or `"json"`. A valid
622
628
  `HACKSH_OUTPUT` environment value takes precedence over that option. `auto` selects JSON only when
623
629
  `CI` has a non-empty value; redirecting or piping stdout alone retains pretty output. Invalid
624
- explicit option or environment values never execute the command. `runCommand` rejects with a
625
- `TypeError`. `runMain` gives that error to `onError` when configured; otherwise it emits the error
626
- through a supplied printer or as a dedicated JSON error line, drains output, and exits with status
627
- code `1`. Output values are case-sensitive.
630
+ explicit option or environment values never execute the command. Both entry points reject with a
631
+ `TypeError`; `runMain` does not call `onError`, print a fallback error event, or force an exit.
632
+ Output values are case-sensitive.
628
633
 
629
634
  ```ts
630
635
  await runMain(main, { output: "auto" });
@@ -687,13 +692,19 @@ the semantic events that the command emits.
687
692
 
688
693
  ### Entry points
689
694
 
690
- `defineCommand` preserves the handler's return type. `runCommand(command, argv, options)` handles
691
- help and version output without exiting, throws errors to its caller, and returns a promise of the
692
- awaited handler result, unioned with results from every possible routed descendant and `undefined`
693
- for help/version. Routing-only commands add no handler result. Async and void handlers retain their
694
- result types; `runMain` deliberately discards results.
695
-
696
- `runMain(command)` reads `process.argv`, prints validation or usage errors, and exits with status 1.
695
+ `defineCommand` preserves the handler's exact return type. Handlers are ordinary functions that
696
+ return values or `void`, synchronously or asynchronously. `runCommand(command, argv, options)`
697
+ returns a promise of the awaited result, unioned with results from every possible routed
698
+ descendant and `undefined` for help/version. Routing-only commands add no handler result.
699
+ Thrown exceptions, argument errors, and output failures reject the promise. `runCommand` never
700
+ exits or automatically prints a return value or error.
701
+
702
+ `runMain(command)` reads `process.argv`, discards return values, and only handles thrown
703
+ `HackshError` instances as normal CLI failures. Other exceptions reject without automatic error
704
+ display, `onError`, or process exit. Pending output is drained and signal listeners are removed
705
+ on both success and rejection. Output failures also reject, including while reporting a CLI
706
+ error; they are not hidden by a forced exit. See
707
+ [Cancellation and exit status](#cancellation-and-exit-status) for exit codes.
697
708
  Use `argv` to inject arguments. Omitting it uses `process.argv.slice(2)`; an empty array is an
698
709
  explicit empty invocation. `runMain` returns `Promise<void>`. A reusable entry point is an ordinary
699
710
  local function:
@@ -708,18 +719,73 @@ await mainEntry([]); // explicitly supplies no arguments
708
719
 
709
720
  Help and the usage appended to validation or routing errors use the invocation's printer.
710
721
  Usage events target stdout for help and stderr for errors. Pass `onError` to replace the entire
711
- default error display, including usage; output written by this application callback remains its
712
- own responsibility:
722
+ default display of a `HackshError`, including usage. It receives the original error instance;
723
+ output written by this application callback remains its own responsibility. If the callback
724
+ throws or rejects, `runMain` drains output, removes its listeners, and rejects without exiting:
713
725
 
714
726
  ```ts
715
727
  await runMain(main, {
716
728
  argv: ["--help"],
717
729
  async onError(error) {
718
- console.error(`gh-pr-commits: ${error instanceof Error ? error.message : String(error)}`);
730
+ console.error(`gh-pr-commits: ${error.message}`);
719
731
  },
720
732
  });
721
733
  ```
722
734
 
735
+ ### Composable run functions
736
+
737
+ Use ordinary functions and `await`; no handler factory or result envelope is required.
738
+ Throw a `HackshError` subclass for an expected CLI failure. Catch only the specific failures
739
+ the caller can recover from and rethrow everything else:
740
+
741
+ ```ts
742
+ import { z } from "zod";
743
+ import { defineCommand, HackshError, type CommandContext } from "hacksh";
744
+
745
+ class AppError extends HackshError {}
746
+
747
+ class NotFoundError extends AppError {
748
+ readonly id: string;
749
+
750
+ constructor(id: string) {
751
+ super(`User ${id} was not found`);
752
+ this.id = id;
753
+ }
754
+ }
755
+
756
+ const users = new Map([["alice", { id: "alice", displayName: "Alice" }]]);
757
+
758
+ function loadUser(id: string) {
759
+ const user = users.get(id);
760
+ if (!user) throw new NotFoundError(id);
761
+ return user;
762
+ }
763
+
764
+ const schema = z.object({ id: z.string() });
765
+
766
+ function run({ args }: CommandContext<typeof schema>) {
767
+ try {
768
+ return loadUser(args.id);
769
+ } catch (error) {
770
+ if (error instanceof NotFoundError) {
771
+ return { id: error.id, displayName: "Guest" };
772
+ }
773
+ throw error;
774
+ }
775
+ }
776
+
777
+ const command = defineCommand({ args: schema, run });
778
+ ```
779
+
780
+ The context's `args` is the validated, transformed schema output, not raw argv. Domain functions
781
+ such as `loadUser` need not depend on `CommandContext`. Omit the recovery branch when an expected
782
+ failure should reach `runMain` and be displayed there.
783
+
784
+ `HackshError(message?, options?)` supports the standard `ErrorOptions.cause` and uses the concrete
785
+ subclass name as `error.name`. Application subclasses can add their own fields. A plain `Error`,
786
+ `TypeError`, or non-error thrown value is not classified as an expected CLI failure. Do not
787
+ blanket-wrap unknown exceptions in `HackshError`: doing so would hide that distinction.
788
+
723
789
  ### Printers and events
724
790
 
725
791
  The root `hacksh` entry exposes command-definition and execution APIs. Import printer factories,
@@ -790,6 +856,8 @@ await showUsage(main, {
790
856
 
791
857
  ### Errors
792
858
 
859
+ - `HackshError` — base class for expected CLI failures. Extend it for application-specific errors;
860
+ all error classes below inherit from it.
793
861
  - `HackshUsageError` — routing and usage failures (such as an unknown subcommand).
794
862
  - `HackshValidationError` — argument and option validation failures, whose `issues` identify CLI
795
863
  names such as `--repo` or `<PR>` and rejected unknown tokens in `issues[].arg`.
@@ -79,7 +79,11 @@ interface HackshIssue {
79
79
  message: string;
80
80
  issue?: $ZodIssue;
81
81
  }
82
- declare class HackshUsageError extends Error {
82
+ /** An expected CLI failure that runMain reports; application errors can extend this class. */
83
+ declare class HackshError extends Error {
84
+ constructor(message?: string, options?: ErrorOptions);
85
+ }
86
+ declare class HackshUsageError extends HackshError {
83
87
  readonly command: AnyCommandDef;
84
88
  constructor(message: string, command: AnyCommandDef, options?: ErrorOptions);
85
89
  }
@@ -95,19 +99,19 @@ interface PromptErrorDetails {
95
99
  choices?: readonly string[];
96
100
  }
97
101
  /** An input request that could not be completed safely. */
98
- declare class HackshPromptError extends Error {
102
+ declare class HackshPromptError extends HackshError {
99
103
  readonly reason: HackshPromptErrorReason;
100
104
  readonly prompt: PromptErrorDetails;
101
105
  constructor(reason: HackshPromptErrorReason, prompt: PromptErrorDetails, message: string, options?: ErrorOptions);
102
106
  }
103
107
  /** An external command that did not succeed; `result` is not enumerable so error summaries omit child output. */
104
- declare class HackshExecError extends Error {
108
+ declare class HackshExecError extends HackshError {
105
109
  #private;
106
110
  constructor(message: string, result: ExecFailure, options?: ErrorOptions);
107
111
  get result(): ExecFailure;
108
112
  }
109
113
  /** A requested process exit status; `runMain` exits with it and reports only a non-empty message. */
110
- declare class HackshExitError extends Error {
114
+ declare class HackshExitError extends HackshError {
111
115
  readonly exitCode: number;
112
116
  constructor(exitCode: number, message?: string, options?: ErrorOptions);
113
117
  }
@@ -410,7 +414,7 @@ interface CommandDef<S extends ArgsSchema = EmptyArgs, R = unknown, Children ext
410
414
  run?(context: CommandContext<S>): R;
411
415
  }
412
416
  type AnyCommandDef = CommandDef<ArgsSchema>;
413
- declare function defineCommand<S extends ArgsSchema = EmptyArgs, R = never, Children extends Record<string, AnyCommandDef> = {}>(def: CommandDef<S, R, Children>): CommandDef<S, NoInfer<R>, NoInfer<Children>>;
417
+ declare function defineCommand<S extends ArgsSchema = EmptyArgs, R = never, Children extends Record<string, AnyCommandDef> = {}>(def: CommandDef<S, R, Children>): NoInfer<CommandDef<S, R, Children>>;
414
418
  //#endregion
415
- export { HackshErrorSummary as $, SelectPromptState as A, UsageArgumentSummary as B, PrintStream as C, PromptState as D, PromptPrintEvent as E, UsagePrintEvent as F, showUsage as G, UsageOptionSummary as H, VersionPrintEvent as I, LogLevel as J, summarizeUsage as K, createJsonPrinter as L, TerminalInput as M, TerminalOutput as N, PromptStatus as O, TextPromptState as P, HackshErrorKind as Q, resolveOutputMode as R, PrintEvent as S, PromptChoiceState as T, UsageSummary as U, UsageCommandSummary as V, renderUsage as W, LogRecord as X, LogProperties as Y, Logger as Z, OutputFormat as _, ExecSkipped as _t, ArgsSchema as a, HackshUsageError as at, OutputPrintEvent as b, SelectOption as c, PromptKind as ct, Output as d, ExecCommand as dt, HackshExecError as et, ConfirmPromptState as f, ExecFailure as ft, LogPrintEvent as g, ExecReturn as gt, JsonPrinterOptions as h, ExecResult as ht, defineCommand as i, HackshPromptErrorReason as it, StreamColors as j, ResolveOutputModeOptions as k, SelectOptions as l, ValidationIssueSummary as lt, ExecPrintEvent as m, ExecOptions as mt, CommandContext as n, HackshIssue as nt, ConfirmOptions as o, HackshValidationError as ot, ErrorPrintEvent as p, ExecFailureReason as pt, LogKind as q, CommandDef as r, HackshPromptError as rt, Prompter as s, PromptErrorDetails as st, AnyCommandDef as t, HackshExitError as tt, TextOptions as u, Exec as ut, OutputMode as v, ExecSuccess as vt, Printer as w, OutputWriter as x, OutputPreference as y, ShowUsageOptions as z };
416
- //# sourceMappingURL=command-B-Ok_6KW.d.ts.map
419
+ export { HackshErrorKind as $, SelectPromptState as A, UsageArgumentSummary as B, PrintStream as C, PromptState as D, PromptPrintEvent as E, UsagePrintEvent as F, showUsage as G, UsageOptionSummary as H, VersionPrintEvent as I, LogLevel as J, summarizeUsage as K, createJsonPrinter as L, TerminalInput as M, TerminalOutput as N, PromptStatus as O, TextPromptState as P, HackshError as Q, resolveOutputMode as R, PrintEvent as S, PromptChoiceState as T, UsageSummary as U, UsageCommandSummary as V, renderUsage as W, LogRecord as X, LogProperties as Y, Logger as Z, OutputFormat as _, ExecReturn as _t, ArgsSchema as a, HackshPromptErrorReason as at, OutputPrintEvent as b, SelectOption as c, PromptErrorDetails as ct, Output as d, Exec as dt, HackshErrorSummary as et, ConfirmPromptState as f, ExecCommand as ft, LogPrintEvent as g, ExecResult as gt, JsonPrinterOptions as h, ExecOptions as ht, defineCommand as i, HackshPromptError as it, StreamColors as j, ResolveOutputModeOptions as k, SelectOptions as l, PromptKind as lt, ExecPrintEvent as m, ExecFailureReason as mt, CommandContext as n, HackshExitError as nt, ConfirmOptions as o, HackshUsageError as ot, ErrorPrintEvent as p, ExecFailure as pt, LogKind as q, CommandDef as r, HackshIssue as rt, Prompter as s, HackshValidationError as st, AnyCommandDef as t, HackshExecError as tt, TextOptions as u, ValidationIssueSummary as ut, OutputMode as v, ExecSkipped as vt, Printer as w, OutputWriter as x, OutputPreference as y, ExecSuccess as yt, ShowUsageOptions as z };
420
+ //# sourceMappingURL=command-t16M3-AZ.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { G as showUsage, K as summarizeUsage, M as TerminalInput, N as TerminalOutput, W as renderUsage, Z as Logger, _t as ExecSkipped, a as ArgsSchema, at as HackshUsageError, c as SelectOption, ct as PromptKind, d as Output, dt as ExecCommand, et as HackshExecError, ft as ExecFailure, gt as ExecReturn, ht as ExecResult, i as defineCommand, it as HackshPromptErrorReason, l as SelectOptions, mt as ExecOptions, n as CommandContext, nt as HackshIssue, o as ConfirmOptions, ot as HackshValidationError, pt as ExecFailureReason, r as CommandDef, rt as HackshPromptError, s as Prompter, st as PromptErrorDetails, t as AnyCommandDef, tt as HackshExitError, u as TextOptions, ut as Exec, vt as ExecSuccess, w as Printer, y as OutputPreference, z as ShowUsageOptions } from "./command-B-Ok_6KW.js";
1
+ import { G as showUsage, K as summarizeUsage, M as TerminalInput, N as TerminalOutput, Q as HackshError, W as renderUsage, Z as Logger, _t as ExecReturn, a as ArgsSchema, at as HackshPromptErrorReason, c as SelectOption, ct as PromptErrorDetails, d as Output, dt as Exec, ft as ExecCommand, gt as ExecResult, ht as ExecOptions, i as defineCommand, it as HackshPromptError, l as SelectOptions, lt as PromptKind, mt as ExecFailureReason, n as CommandContext, nt as HackshExitError, o as ConfirmOptions, ot as HackshUsageError, pt as ExecFailure, r as CommandDef, rt as HackshIssue, s as Prompter, st as HackshValidationError, t as AnyCommandDef, tt as HackshExecError, u as TextOptions, vt as ExecSkipped, w as Printer, y as OutputPreference, yt as ExecSuccess, z as ShowUsageOptions } from "./command-t16M3-AZ.js";
2
2
  import { output } from "zod/v4/core";
3
3
  //#region src/parser.d.ts
4
4
  /**
@@ -33,11 +33,11 @@ type CommandResult<C> = HandlerResult<C> | (C extends {
33
33
  } ? Children extends Record<string, AnyCommandDef> ? string extends keyof Children ? unknown : CommandResult<Children[keyof Children]> : never : never);
34
34
  declare function runCommand<C extends AnyCommandDef>(root: C, argv: string[], options?: RunCommandOptions): Promise<CommandResult<C> | undefined>;
35
35
  interface RunMainOptions extends OutputOptions {
36
- onError?: (error: unknown) => void | Promise<void>;
36
+ onError?: (error: HackshError) => void | Promise<void>;
37
37
  argv?: string[];
38
38
  printer?: Printer;
39
39
  }
40
40
  declare function runMain<S extends ArgsSchema>(command: CommandDef<S>, options?: RunMainOptions): Promise<void>;
41
41
  //#endregion
42
- export { type CommandContext, type CommandDef, type ConfirmOptions, type Exec, type ExecCommand, type ExecFailure, type ExecFailureReason, type ExecOptions, type ExecResult, type ExecReturn, type ExecSkipped, type ExecSuccess, HackshExecError, HackshExitError, type HackshIssue, HackshPromptError, type HackshPromptErrorReason, HackshUsageError, HackshValidationError, type Logger, type Output, type OutputOptions, type PromptErrorDetails, type PromptKind, type Prompter, type RunCommandOptions, type RunMainOptions, type SelectOption, type SelectOptions, type ShowUsageOptions, type TextOptions, defineCommand, parseArgs, renderUsage, runCommand, runMain, showUsage, summarizeUsage };
42
+ export { type CommandContext, type CommandDef, type ConfirmOptions, type Exec, type ExecCommand, type ExecFailure, type ExecFailureReason, type ExecOptions, type ExecResult, type ExecReturn, type ExecSkipped, type ExecSuccess, HackshError, HackshExecError, HackshExitError, type HackshIssue, HackshPromptError, type HackshPromptErrorReason, HackshUsageError, HackshValidationError, type Logger, type Output, type OutputOptions, type PromptErrorDetails, type PromptKind, type Prompter, type RunCommandOptions, type RunMainOptions, type SelectOption, type SelectOptions, type ShowUsageOptions, type TextOptions, defineCommand, parseArgs, renderUsage, runCommand, runMain, showUsage, summarizeUsage };
43
43
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as createExec, c as HackshPromptError, d as summarizeError, f as summarizeErrors, i as resolveOutputMode, l as HackshUsageError, n as createJsonPrinter, o as HackshExecError, r as createPrintQueue, s as HackshExitError, t as createPrettyPrinter, u as HackshValidationError } from "./pretty-DJ2CE6TU.js";
1
+ import { a as createExec, c as HackshExitError, d as HackshValidationError, f as summarizeError, i as resolveOutputMode, l as HackshPromptError, n as createJsonPrinter, o as HackshError, p as summarizeErrors, r as createPrintQueue, s as HackshExecError, t as createPrettyPrinter, u as HackshUsageError } from "./pretty-Db7-kATM.js";
2
2
  import { globalRegistry, safeParseAsync } from "zod/v4/core";
3
3
  import { parseArgs as parseArgs$1 } from "node:util";
4
4
  import { readFile, realpath } from "node:fs/promises";
@@ -1178,13 +1178,6 @@ async function runCommand(root, argv, options = {}) {
1178
1178
  await output.drain();
1179
1179
  }
1180
1180
  }
1181
- async function drainAndExit(output, code = 1) {
1182
- try {
1183
- await output.drain();
1184
- } finally {
1185
- process.exit(code);
1186
- }
1187
- }
1188
1181
  function commandErrorExitCode(error) {
1189
1182
  if (error instanceof HackshExitError) return error.exitCode;
1190
1183
  return error instanceof HackshPromptError && error.reason === "cancelled" ? 130 : 1;
@@ -1213,21 +1206,6 @@ function listenForExitSignals() {
1213
1206
  }
1214
1207
  };
1215
1208
  }
1216
- async function reportOutputSetupError(error, options) {
1217
- if (options.onError) {
1218
- await options.onError(error);
1219
- return drainAndExit(createPrintQueue(options.printer ?? { print: () => void 0 }));
1220
- }
1221
- const output = createPrintQueue(options.printer ?? createJsonPrinter({
1222
- stdout: options.stdout ?? process.stdout,
1223
- stderr: options.stderr ?? process.stderr
1224
- }));
1225
- await output.printer.print({
1226
- type: "error",
1227
- error: summarizeError(error)
1228
- });
1229
- return drainAndExit(output);
1230
- }
1231
1209
  async function reportCommandError(error, output) {
1232
1210
  if (error instanceof HackshExitError && error.message === "") return;
1233
1211
  await output.printer.print({
@@ -1240,37 +1218,33 @@ async function reportCommandError(error, output) {
1240
1218
  });
1241
1219
  }
1242
1220
  async function runMain(command, options = {}) {
1243
- let output;
1244
- try {
1245
- output = prepareOutput(options, options.env ?? process.env);
1246
- } catch (error) {
1247
- return reportOutputSetupError(error, options);
1248
- }
1221
+ const output = prepareOutput(options, options.env ?? process.env);
1249
1222
  const signals = listenForExitSignals();
1250
- const exit = (code) => {
1251
- signals.release();
1252
- return drainAndExit(output, signals.exitCode() ?? code);
1253
- };
1223
+ let exitCode;
1254
1224
  try {
1255
- await executeCommand(command, options.argv ?? process.argv.slice(2), output, options.env, signals.signal, () => findPackageVersion(process.argv[1]));
1256
- } catch (error) {
1257
- if (options.onError) {
1258
- await options.onError(error);
1259
- return exit(commandErrorExitCode(error));
1225
+ try {
1226
+ await executeCommand(command, options.argv ?? process.argv.slice(2), output, options.env, signals.signal, () => findPackageVersion(process.argv[1]));
1227
+ } catch (error) {
1228
+ const signalExitCode = signals.exitCode();
1229
+ if (signalExitCode !== void 0 && error === signals.signal.reason) exitCode = signalExitCode;
1230
+ else {
1231
+ if (!(error instanceof HackshError)) throw error;
1232
+ if (options.onError) await options.onError(error);
1233
+ else await reportCommandError(error, output);
1234
+ exitCode = commandErrorExitCode(error);
1235
+ }
1260
1236
  }
1237
+ } finally {
1261
1238
  try {
1262
- await reportCommandError(error, output);
1239
+ await output.drain();
1263
1240
  } finally {
1264
- await exit(commandErrorExitCode(error));
1241
+ signals.release();
1265
1242
  }
1266
- } finally {
1267
- signals.release();
1268
1243
  }
1269
- const signalExitCode = signals.exitCode();
1270
- if (signalExitCode !== void 0) return drainAndExit(output, signalExitCode);
1271
- await output.drain();
1244
+ const code = signals.exitCode() ?? exitCode;
1245
+ if (code !== void 0) process.exit(code);
1272
1246
  }
1273
1247
  //#endregion
1274
- export { HackshExecError, HackshExitError, HackshPromptError, HackshUsageError, HackshValidationError, defineCommand, parseArgs, renderUsage, runCommand, runMain, showUsage, summarizeUsage };
1248
+ export { HackshError, HackshExecError, HackshExitError, HackshPromptError, HackshUsageError, HackshValidationError, defineCommand, parseArgs, renderUsage, runCommand, runMain, showUsage, summarizeUsage };
1275
1249
 
1276
1250
  //# sourceMappingURL=index.js.map