hacksh 0.6.0 → 0.7.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
@@ -357,6 +357,42 @@ set to `undefined`. Concurrent invocations with different `env` options do not s
357
357
  `HackshExecError` messages include the command and the reason but never the child's output; read
358
358
  `error.result` for the full failure, which error summaries and JSON error events omit.
359
359
 
360
+ Before starting a child, `exec` prints an `exec` event through the invocation's printer, on stderr
361
+ in both formats. Pretty output shows `$` followed by the command line and, when set, its `cwd`. The
362
+ JSON event has `phase: "start"`, `command` (`file`, `args`, and `cwd` when set), `stdio`, and
363
+ `interactive`; it never includes `env` or `input`. Pass `display: false` to hide one call. Pass
364
+ `redact` with secret values to replace every occurrence in the file, arguments, and cwd with `***`
365
+ in the event, the result's `command`, the `HackshExecError` message, and a `spawn` failure's
366
+ `error`. The child still receives the real values, and its captured output is returned unchanged.
367
+
368
+ ```ts
369
+ await exec("git", ["worktree", "add", path, branch], { cwd: repository });
370
+ await exec("gh", ["auth", "login", "--with-token"], { input: token, display: false });
371
+ await exec("curl", ["-H", `Authorization: Bearer ${token}`, url], { redact: [token] });
372
+ ```
373
+
374
+ Child output is captured by default and never written to the terminal by hacksh. Set `stdin`,
375
+ `stdout`, or `stderr` to `"inherit"` to hand that stream of the parent process to the child; an
376
+ inherited stream bypasses the printer and any `stdout`/`stderr` writers given to `runMain` or
377
+ `runCommand`, and its result field is `""`. `input` cannot be combined with `stdin: "inherit"`.
378
+ Set `interactive: true` when the child talks to the user through the terminal, including tools
379
+ that open `/dev/tty` themselves; hacksh cannot detect that, and it does not create a PTY.
380
+
381
+ ```ts
382
+ // Select a row: the table goes to stdin, the selection comes back on stdout.
383
+ const { stdout: picked } = await exec("fzf", [], { input: table, interactive: true });
384
+ // Hand the whole terminal to a long-running command.
385
+ await exec("gh", ["run", "watch", id], { stdin: "inherit", stdout: "inherit", stderr: "inherit" });
386
+ ```
387
+
388
+ These calls fail before starting the child, without an `exec` event, and follow `reject` like any
389
+ other failure: `json-output` when a stream is inherited in JSON mode, `non-interactive` when
390
+ `interactive: true` is used outside an interactive mode (the same rule as prompts), and
391
+ `overlapping` when a call that uses the terminal (interactive or inheriting a stream) starts while
392
+ a prompt or another such call is active. A prompt started during such a call fails with
393
+ `HackshPromptError` reason `overlapping`. Captured calls can run alongside prompts. Signals such
394
+ as Ctrl-C reach the whole foreground process group; hacksh does not forward them or manage jobs.
395
+
360
396
  On Deno, `exec` needs `--allow-run` and unscoped `--allow-env`, because Deno's `node:child_process`
361
397
  reads the whole environment to start a process.
362
398
 
@@ -390,7 +426,8 @@ capabilities. A stream without those readable operations fails with an `input-er
390
426
  is attempted.
391
427
 
392
428
  JSON output contains exactly one `PrintEvent` object per line. Help and version events and
393
- trace/debug/info logs go to stdout; errors and warning/error/fatal logs go to stderr. Usage attached
429
+ trace/debug/info logs go to stdout; errors, warning/error/fatal logs, and `exec` events go to
430
+ stderr. Usage attached
394
431
  to an error retains its `stderr` stream. Every log level is emitted by default. JSON strings have
395
432
  terminal control sequences removed, and the printer never serializes executable command or Zod
396
433
  schema objects.
package/dist/index.d.ts CHANGED
@@ -1,50 +1,4 @@
1
1
  import { $ZodIssue, $ZodObject, output } from "zod/v4/core";
2
- //#region src/exec.d.ts
3
- type Environment = Readonly<Record<string, string | undefined>>;
4
- interface ExecOptions {
5
- cwd?: string;
6
- env?: Environment;
7
- input?: string;
8
- reject?: boolean;
9
- timeout?: number;
10
- signal?: AbortSignal;
11
- maxBuffer?: number;
12
- forceKillAfterDelay?: number;
13
- }
14
- interface ExecCommand {
15
- file: string;
16
- args: readonly string[];
17
- cwd: string | undefined;
18
- }
19
- interface ExecSuccess {
20
- status: "succeeded";
21
- command: ExecCommand;
22
- stdout: string;
23
- stderr: string;
24
- exitCode: 0;
25
- }
26
- type ExecFailure = {
27
- status: "failed";
28
- command: ExecCommand;
29
- stdout: string;
30
- stderr: string;
31
- } & ({
32
- reason: "exit-code";
33
- exitCode: number;
34
- } | {
35
- reason: "signal";
36
- signal: string;
37
- } | {
38
- reason: "spawn";
39
- error: Error;
40
- } | {
41
- reason: "timeout" | "aborted" | "output-limit";
42
- });
43
- type ExecFailureReason = ExecFailure["reason"];
44
- type ExecResult = ExecSuccess | ExecFailure;
45
- type ExecReturn<O extends ExecOptions> = "reject" extends keyof O ? false extends O["reject"] ? ExecResult : ExecSuccess : ExecSuccess;
46
- type Exec = <const O extends ExecOptions = {}>(file: string, args?: readonly string[], options?: O & { [K in Exclude<keyof O, keyof ExecOptions>]: never; }) => Promise<ExecReturn<O>>;
47
- //#endregion
48
2
  //#region src/errors.d.ts
49
3
  interface HackshIssue {
50
4
  arg: string;
@@ -97,6 +51,60 @@ interface HackshErrorSummary {
97
51
  value?: unknown;
98
52
  }
99
53
  //#endregion
54
+ //#region src/prompts.d.ts
55
+ interface SelectOption<T extends string> {
56
+ value: T;
57
+ label?: string;
58
+ hint?: string;
59
+ }
60
+ interface SelectOptions<T extends string> {
61
+ message: string;
62
+ options: readonly SelectOption<T>[];
63
+ initialValue?: T;
64
+ }
65
+ interface ConfirmOptions {
66
+ message: string;
67
+ initialValue?: boolean;
68
+ }
69
+ interface TextOptions {
70
+ message: string;
71
+ placeholder?: string;
72
+ validate?(value: string): string | undefined;
73
+ }
74
+ interface Prompter {
75
+ select<const T extends string>(options: SelectOptions<T>): Promise<T>;
76
+ confirm(options: ConfirmOptions): Promise<boolean>;
77
+ text(options: TextOptions): Promise<string>;
78
+ }
79
+ //#endregion
80
+ //#region src/logger.d.ts
81
+ type LogLevel = "trace" | "debug" | "info" | "warning" | "error" | "fatal";
82
+ type LogKind = "message" | "step" | "success";
83
+ type LogProperties = Record<string, unknown>;
84
+ /** A structured message emitted by a command's logger. */
85
+ interface LogRecord {
86
+ level: LogLevel;
87
+ kind: LogKind;
88
+ category: readonly string[];
89
+ message: string;
90
+ rawMessage: string;
91
+ properties: LogProperties;
92
+ timestamp: number;
93
+ }
94
+ interface Logger extends Prompter {
95
+ readonly category: readonly string[];
96
+ trace(message: string, properties?: LogProperties): void;
97
+ debug(message: string, properties?: LogProperties): void;
98
+ info(message: string, properties?: LogProperties): void;
99
+ warn(message: string, properties?: LogProperties): void;
100
+ error(message: string | Error, properties?: LogProperties): void;
101
+ fatal(message: string | Error, properties?: LogProperties): void;
102
+ step(message: string, properties?: LogProperties): void;
103
+ success(message: string, properties?: LogProperties): void;
104
+ with(properties: LogProperties): Logger;
105
+ getChild(category: string): Logger;
106
+ }
107
+ //#endregion
100
108
  //#region src/output.d.ts
101
109
  interface OutputOptions {
102
110
  output?: OutputPreference;
@@ -227,8 +235,21 @@ interface PromptPrintEvent {
227
235
  type: "prompt";
228
236
  prompt: PromptState;
229
237
  }
238
+ interface ExecPrintEvent {
239
+ type: "exec";
240
+ phase: "start";
241
+ command: Omit<ExecCommand, "cwd"> & {
242
+ cwd?: string;
243
+ };
244
+ stdio: {
245
+ stdin: "ignore" | "input" | "inherit";
246
+ stdout: "pipe" | "inherit";
247
+ stderr: "pipe" | "inherit";
248
+ };
249
+ interactive: boolean;
250
+ }
230
251
  /** A semantic, command- and schema-free output value emitted by hacksh. */
231
- type PrintEvent = UsagePrintEvent | VersionPrintEvent | ErrorPrintEvent | LogPrintEvent | PromptPrintEvent;
252
+ type PrintEvent = UsagePrintEvent | VersionPrintEvent | ErrorPrintEvent | LogPrintEvent | PromptPrintEvent | ExecPrintEvent;
232
253
  /** Receives every output event produced by one command invocation. */
233
254
  interface Printer {
234
255
  print(event: PrintEvent): void | Promise<void>;
@@ -265,59 +286,63 @@ declare function createStreamPrinter(options: StreamPrinterOptions): Printer;
265
286
  /** Create a one-semantic-event-per-line JSON printer. */
266
287
  declare function createJsonPrinter(options?: JsonPrinterOptions): Printer;
267
288
  //#endregion
268
- //#region src/prompts.d.ts
269
- interface SelectOption<T extends string> {
270
- value: T;
271
- label?: string;
272
- hint?: string;
273
- }
274
- interface SelectOptions<T extends string> {
275
- message: string;
276
- options: readonly SelectOption<T>[];
277
- initialValue?: T;
278
- }
279
- interface ConfirmOptions {
280
- message: string;
281
- initialValue?: boolean;
282
- }
283
- interface TextOptions {
284
- message: string;
285
- placeholder?: string;
286
- validate?(value: string): string | undefined;
287
- }
288
- interface Prompter {
289
- select<const T extends string>(options: SelectOptions<T>): Promise<T>;
290
- confirm(options: ConfirmOptions): Promise<boolean>;
291
- text(options: TextOptions): Promise<string>;
289
+ //#region src/exec.d.ts
290
+ type Environment = Readonly<Record<string, string | undefined>>;
291
+ interface ExecOptions {
292
+ cwd?: string;
293
+ env?: Environment;
294
+ input?: string;
295
+ reject?: boolean;
296
+ timeout?: number;
297
+ signal?: AbortSignal;
298
+ maxBuffer?: number;
299
+ forceKillAfterDelay?: number;
300
+ stdin?: "pipe" | "inherit";
301
+ stdout?: "pipe" | "inherit";
302
+ stderr?: "pipe" | "inherit";
303
+ interactive?: boolean;
304
+ display?: boolean;
305
+ redact?: readonly string[];
292
306
  }
293
- //#endregion
294
- //#region src/logger.d.ts
295
- type LogLevel = "trace" | "debug" | "info" | "warning" | "error" | "fatal";
296
- type LogKind = "message" | "step" | "success";
297
- type LogProperties = Record<string, unknown>;
298
- /** A structured message emitted by a command's logger. */
299
- interface LogRecord {
300
- level: LogLevel;
301
- kind: LogKind;
302
- category: readonly string[];
303
- message: string;
304
- rawMessage: string;
305
- properties: LogProperties;
306
- timestamp: number;
307
+ interface ExecCommand {
308
+ file: string;
309
+ args: readonly string[];
310
+ cwd: string | undefined;
307
311
  }
308
- interface Logger extends Prompter {
309
- readonly category: readonly string[];
310
- trace(message: string, properties?: LogProperties): void;
311
- debug(message: string, properties?: LogProperties): void;
312
- info(message: string, properties?: LogProperties): void;
313
- warn(message: string, properties?: LogProperties): void;
314
- error(message: string | Error, properties?: LogProperties): void;
315
- fatal(message: string | Error, properties?: LogProperties): void;
316
- step(message: string, properties?: LogProperties): void;
317
- success(message: string, properties?: LogProperties): void;
318
- with(properties: LogProperties): Logger;
319
- getChild(category: string): Logger;
312
+ interface ExecSuccess {
313
+ status: "succeeded";
314
+ command: ExecCommand;
315
+ stdout: string;
316
+ stderr: string;
317
+ exitCode: 0;
320
318
  }
319
+ type ExecFailure = {
320
+ status: "failed";
321
+ command: ExecCommand;
322
+ stdout: string;
323
+ stderr: string;
324
+ } & ({
325
+ reason: "exit-code";
326
+ exitCode: number;
327
+ } | {
328
+ reason: "signal";
329
+ signal: string;
330
+ } | {
331
+ reason: "spawn";
332
+ error: Error;
333
+ } | {
334
+ reason: "timeout" | "aborted" | "output-limit";
335
+ } | {
336
+ reason: "json-output" | "non-interactive" | "overlapping";
337
+ });
338
+ type ExecFailureReason = ExecFailure["reason"];
339
+ type ExecResult = ExecSuccess | ExecFailure;
340
+ type ExecReturn<O extends ExecOptions> = "reject" extends keyof O ? false extends O["reject"] ? ExecResult : ExecSuccess : ExecSuccess;
341
+ type RejectInheritedInput<O> = O extends {
342
+ input: string;
343
+ stdin: "inherit";
344
+ } ? never : unknown;
345
+ type Exec = <const O extends ExecOptions = {}>(file: string, args?: readonly string[], options?: O & { [K in Exclude<keyof O, keyof ExecOptions>]: never; } & RejectInheritedInput<O>) => Promise<ExecReturn<O>>;
321
346
  //#endregion
322
347
  //#region src/schema.d.ts
323
348
  type ArgsSchema = $ZodObject;
@@ -390,5 +415,5 @@ interface RunMainOptions extends OutputOptions {
390
415
  declare function runMain<S extends ArgsSchema>(command: CommandDef<S>, options?: RunMainOptions): Promise<void>;
391
416
  declare function createMain<S extends ArgsSchema>(command: CommandDef<S>, options?: RunMainOptions): (argv?: string[]) => Promise<void>;
392
417
  //#endregion
393
- export { type ArgOptions, type ArgOptionsMap, type CommandContext, type CommandDef, type ConfirmOptions, type ConfirmPromptState, type ErrorPrintEvent, type Exec, type ExecCommand, type ExecFailure, type ExecFailureReason, type ExecOptions, type ExecResult, type ExecReturn, type ExecSuccess, type HackshErrorKind, type HackshErrorSummary, HackshExecError, type HackshIssue, HackshPromptError, type HackshPromptErrorReason, HackshUsageError, HackshValidationError, type JsonPrinterOptions, type LogKind, type LogLevel, type LogPrintEvent, type LogProperties, type LogRecord, type Logger, type OutputFormat, type OutputMode, type OutputOptions, type OutputPreference, type OutputWriter, type PrettyPrinterOptions, type PrintEvent, type PrintStream, type Printer, type PromptChoiceState, type PromptErrorDetails, type PromptKind, type PromptPrintEvent, type PromptState, type PromptStatus, type Prompter, type ResolveOutputModeOptions, type RunCommandOptions, type RunMainOptions, type SelectOption, type SelectOptions, type SelectPromptState, type ShowUsageCallback, type ShowUsageOptions, type StreamPrinterOptions, type TerminalInput, type TerminalOutput, type TextOptions, type TextPromptState, type UsageArgumentSummary, type UsageCommandSummary, type UsageOptionSummary, type UsageOutput, type UsagePrintEvent, type UsageSummary, type UsageWriter, type ValidationIssueSummary, type VersionPrintEvent, consolePrinter, createJsonPrinter, createMain, createPrettyPrinter, createStreamPrinter, defineCommand, parseArgs, renderUsage, resolveOutputMode, runCommand, runMain, showUsage, summarizeUsage };
418
+ export { type ArgOptions, type ArgOptionsMap, type CommandContext, type CommandDef, type ConfirmOptions, type ConfirmPromptState, type ErrorPrintEvent, type Exec, type ExecCommand, type ExecFailure, type ExecFailureReason, type ExecOptions, type ExecPrintEvent, type ExecResult, type ExecReturn, type ExecSuccess, type HackshErrorKind, type HackshErrorSummary, HackshExecError, type HackshIssue, HackshPromptError, type HackshPromptErrorReason, HackshUsageError, HackshValidationError, type JsonPrinterOptions, type LogKind, type LogLevel, type LogPrintEvent, type LogProperties, type LogRecord, type Logger, type OutputFormat, type OutputMode, type OutputOptions, type OutputPreference, type OutputWriter, type PrettyPrinterOptions, type PrintEvent, type PrintStream, type Printer, type PromptChoiceState, type PromptErrorDetails, type PromptKind, type PromptPrintEvent, type PromptState, type PromptStatus, type Prompter, type ResolveOutputModeOptions, type RunCommandOptions, type RunMainOptions, type SelectOption, type SelectOptions, type SelectPromptState, type ShowUsageCallback, type ShowUsageOptions, type StreamPrinterOptions, type TerminalInput, type TerminalOutput, type TextOptions, type TextPromptState, type UsageArgumentSummary, type UsageCommandSummary, type UsageOptionSummary, type UsageOutput, type UsagePrintEvent, type UsageSummary, type UsageWriter, type ValidationIssueSummary, type VersionPrintEvent, consolePrinter, createJsonPrinter, createMain, createPrettyPrinter, createStreamPrinter, defineCommand, parseArgs, renderUsage, resolveOutputMode, runCommand, runMain, showUsage, summarizeUsage };
394
419
  //# sourceMappingURL=index.d.ts.map