@effected/cli-kit 0.0.0-stage → 0.26.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.
Files changed (103) hide show
  1. package/Cancelled.js +43 -0
  2. package/CliAudience.js +177 -0
  3. package/CliColor.js +59 -0
  4. package/CliEnv.js +101 -0
  5. package/CliExit.js +64 -0
  6. package/CliFailure.js +287 -0
  7. package/CliFormat.js +124 -0
  8. package/CliInteractive.js +94 -0
  9. package/CliLinks.js +153 -0
  10. package/CliLog.js +367 -0
  11. package/CliLogger.js +91 -0
  12. package/CliMessage.js +79 -0
  13. package/CliPrompt.js +110 -0
  14. package/CliRuntime.js +254 -0
  15. package/CliTest.js +206 -0
  16. package/CliTheme.js +142 -0
  17. package/ConfigIssueRenderer.js +63 -0
  18. package/Doc.js +548 -0
  19. package/Fmt.js +335 -0
  20. package/GithubAnnotation.js +39 -0
  21. package/Glyphs.js +82 -0
  22. package/LICENSE +21 -0
  23. package/NotInteractive.js +41 -0
  24. package/README.md +215 -2
  25. package/Render.js +280 -0
  26. package/SchemaIssueRenderer.js +47 -0
  27. package/Status.js +165 -0
  28. package/TestTerminal.js +101 -0
  29. package/Token.js +68 -0
  30. package/index.d.ts +3951 -0
  31. package/index.js +27 -0
  32. package/internal/ExitRequested.js +21 -0
  33. package/internal/HelpRouting.js +35 -0
  34. package/internal/ansi.js +229 -0
  35. package/internal/autoFormat.js +33 -0
  36. package/internal/canPrompt.js +14 -0
  37. package/internal/counts.js +83 -0
  38. package/internal/diagnostics.js +31 -0
  39. package/internal/displayPath.js +46 -0
  40. package/internal/displayWidth.js +42 -0
  41. package/internal/failureTarget.js +195 -0
  42. package/internal/fallbackAnswer.js +17 -0
  43. package/internal/fileSink.js +61 -0
  44. package/internal/format.js +175 -0
  45. package/internal/inspect.js +40 -0
  46. package/internal/isExitCode.js +11 -0
  47. package/internal/layout.js +249 -0
  48. package/internal/linkScheme.js +29 -0
  49. package/internal/linkTarget.js +49 -0
  50. package/internal/logSafety.js +45 -0
  51. package/internal/renderAnsi.js +51 -0
  52. package/internal/renderDoc.js +322 -0
  53. package/internal/renderGithubLog.js +59 -0
  54. package/internal/renderMarkdown.js +367 -0
  55. package/internal/renderPlain.js +49 -0
  56. package/internal/scanAudience.js +105 -0
  57. package/internal/splitFrame.js +55 -0
  58. package/internal/terminalCapabilities.js +23 -0
  59. package/internal/wizardGate.js +17 -0
  60. package/package.json +90 -5
  61. package/testing.d.ts +246 -0
  62. package/testing.js +4 -0
  63. package/tsdoc-metadata.json +11 -0
  64. package/ui/CliUi.js +507 -0
  65. package/ui/CliUiDetached.js +36 -0
  66. package/ui/CliUiLive.js +436 -0
  67. package/ui/CliUiRouteStream.js +72 -0
  68. package/ui/Confirm.js +244 -0
  69. package/ui/DocView.js +76 -0
  70. package/ui/KeyHelp.js +61 -0
  71. package/ui/KeyTable.js +198 -0
  72. package/ui/MultiSelect.js +259 -0
  73. package/ui/Select.js +229 -0
  74. package/ui/Tabs.js +201 -0
  75. package/ui/TextInput.js +289 -0
  76. package/ui/Toggle.js +31 -0
  77. package/ui/UiKey.js +48 -0
  78. package/ui/UiProvider.js +62 -0
  79. package/ui/UiStreams.js +17 -0
  80. package/ui/UiTheme.js +147 -0
  81. package/ui/Viewport.js +203 -0
  82. package/ui/internal/ErrorBoundary.js +29 -0
  83. package/ui/internal/Holder.js +73 -0
  84. package/ui/internal/ScreenContext.js +51 -0
  85. package/ui/internal/UiProviders.js +38 -0
  86. package/ui/internal/ink.js +121 -0
  87. package/ui/internal/inkChalk.js +47 -0
  88. package/ui/internal/inkConsole.js +150 -0
  89. package/ui/internal/lazyView.js +73 -0
  90. package/ui/internal/lineRouter.js +70 -0
  91. package/ui/internal/lineText.js +18 -0
  92. package/ui/internal/mountPermit.js +15 -0
  93. package/ui/internal/processStreams.js +18 -0
  94. package/ui/internal/renderOptions.js +12 -0
  95. package/ui/testing/CliUiTest.js +792 -0
  96. package/ui/testing/fakeStreams.js +104 -0
  97. package/ui/testing/terminalModel.js +67 -0
  98. package/ui-testing-serializer.d.ts +12 -0
  99. package/ui-testing-serializer.js +32 -0
  100. package/ui-testing.d.ts +558 -0
  101. package/ui-testing.js +3 -0
  102. package/ui.d.ts +1990 -0
  103. package/ui.js +17 -0
package/index.d.ts ADDED
@@ -0,0 +1,3951 @@
1
+ import { Array as Array$1, Cause, Context, Duration, Effect, FileSystem, Layer, LogLevel, Logger, MutableRef, Option, Path, Runtime, Schema, Stdio, Terminal } from "effect";
2
+ import { Audience, AudienceKind, ColorLevel, CurrentRuntimeEnv, RuntimeEnv, TerminalEnv } from "@effected/env";
3
+ import { CliError, CliOutput, Command, Flag, Param, Prompt } from "effect/cli";
4
+ import { Distribution } from "@effected/kit";
5
+ import { ConfigValidationError } from "@effected/config-file";
6
+ declare const Cancelled_base: Schema.Class<Cancelled, Schema.TaggedStruct<"Cancelled", {
7
+ readonly reason: Schema.Literals<readonly ["escape", "interrupt"]>;
8
+ }>, import("effect/Cause").YieldableError>;
9
+ /**
10
+ * A person backed out of an interactive prompt: they pressed escape, or the
11
+ * prompt was interrupted.
12
+ *
13
+ * @remarks
14
+ * Exits `130`, the conventional status for a run ended by the user, through
15
+ * core's own `Runtime.errorExitCode` marker, so `CliRuntime.reportFailures`
16
+ * keeps it. Its default rendering is one line, `cancelled; nothing written`,
17
+ * because nothing has been written by the time a prompt is cancelled and a
18
+ * stack trace would only alarm. A consumer `render` still overrides the line, and can hand off to it: the line is
19
+ * the error's `message`, so `error.message` and `String(error)` carry it.
20
+ *
21
+ * @public
22
+ */
23
+ export declare class Cancelled extends Cancelled_base {
24
+ /**
25
+ * The one line, `cancelled; nothing written`.
26
+ *
27
+ * @remarks
28
+ * A prototype getter, not a field, so it is not part of the encoded form, equality or a JSON dump. Assigning to
29
+ * it is ignored: a library that rewrites `error.message` (to prefix a context, say) must not make this error throw,
30
+ * which a getter-only property does in strict mode. The line is fixed.
31
+ */
32
+ get message(): string;
33
+ set message(_value: string);
34
+ /**
35
+ * The process exit code: `130`.
36
+ *
37
+ * @remarks
38
+ * A prototype getter rather than an own field, so a JSON or logger dump of the error does not carry the
39
+ * runtime marker.
40
+ */
41
+ get [Runtime.errorExitCode](): number;
42
+ }
43
+ /**
44
+ * The four parsed audience flags a root command carries once {@link CliAudience.flags} is shared onto it.
45
+ *
46
+ * @public
47
+ */
48
+ interface AudienceFlagInput {
49
+ /** Every `--audience <kind>` occurrence. */
50
+ readonly audience: ReadonlyArray<AudienceKind>;
51
+ /** Every `--human` occurrence. */
52
+ readonly human: ReadonlyArray<boolean>;
53
+ /** Every `--agent` occurrence. */
54
+ readonly agent: ReadonlyArray<boolean>;
55
+ /** Every `--ci` occurrence. */
56
+ readonly ci: ReadonlyArray<boolean>;
57
+ }
58
+ /**
59
+ * Options for {@link CliAudience.flags}.
60
+ *
61
+ * @public
62
+ */
63
+ interface CliAudienceFlagsOptions {
64
+ /**
65
+ * Hide all four flags from every help screen. They still parse and resolve; describe them in the root
66
+ * command's description instead.
67
+ */
68
+ readonly hidden?: boolean | undefined;
69
+ }
70
+ /**
71
+ * Resolves to nothing for a command that carries the four audience flags, and to an unsatisfiable marker otherwise,
72
+ * so `CliAudience.run` on a root that forgot `Command.withSharedFlags(CliAudience.flags())` does not compile. (A
73
+ * plain `Input extends AudienceFlagInput` constraint does not do this: `Command` is contravariant in its input, so
74
+ * a command with no flags still type-checks against it.)
75
+ *
76
+ * @public
77
+ */
78
+ type RequiresAudienceFlags<Input> = [Input] extends [AudienceFlagInput] ? unknown : {
79
+ readonly "missing shared flags": "pipe the root through Command.withSharedFlags(CliAudience.flags())";
80
+ };
81
+ /**
82
+ * The audience flags of a CLI: `--audience <human|agent|ci>` and the shorthands `--human`, `--agent`, `--ci`,
83
+ * resolved into `@effected/env`'s `Audience`.
84
+ *
85
+ * @remarks
86
+ * The one wiring: share the flags on the root command and hand the root to {@link CliAudience.run} (or
87
+ * {@link CliAudience.runWith}), which resolves the flags from argv before core parses and applies
88
+ * {@link CliAudience.provide} itself:
89
+ *
90
+ * ```ts
91
+ * const root = Command.make("tool").pipe(
92
+ * Command.withSharedFlags(CliAudience.flags()),
93
+ * Command.withSubcommands([verify]),
94
+ * )
95
+ * NodeRuntime.runMain(
96
+ * CliRuntime.main(CliAudience.run(root, { version }), { platform: NodeServices.layer, env: {} }),
97
+ * )
98
+ * ```
99
+ *
100
+ * Core lists a shared flag in the help of every subcommand, not only at the root: that is upstream (Effect-TS/effect
101
+ * issue 8642), and `flags({ hidden: true })` is the way to keep them out of help altogether.
102
+ *
103
+ * A root that forgot `Command.withSharedFlags(CliAudience.flags())` does not compile. Giving more than one
104
+ * occurrence across the four flags is a usage error even when they agree; a boolean set to false (`--no-agent`,
105
+ * `--agent=false`) counts as not given. A bad `--audience` value is core's own parse error. Both exit `64` under
106
+ * `CliRuntime.main`. A conflicting audience together with `--help` exits `0` and prints help, because core handles
107
+ * its action flags before the resolver runs.
108
+ *
109
+ * A flag decides `CliInteractive` from the audience it names and the terminal facts: `--human` is interactive when
110
+ * `TerminalEnv` says there is a terminal on stdin and on stdout, even where the environment detected an agent, so a
111
+ * person running the tool inside an agent can ask for the human experience; in a pipe it still cannot prompt. A
112
+ * non-human flag (`--agent`, `--ci`, `--audience agent|ci`) turns it off and drops `--wizard`, and switches
113
+ * diagnostics to NDJSON, for the whole run including the parse step where a fallback prompt fires. Without
114
+ * `TerminalEnv` in the environment a flag only narrows. `--wizard` follows the decision: a run a flag makes
115
+ * interactive gets it back where the environment's gate had dropped it, and only there: a consumer's own `builtIns`
116
+ * without it stay without it.
117
+ * {@link CliAudience.provide} on its own, the path for a bare `Command.run`, acts only on the subcommand handler,
118
+ * because core parses the root flags into a local context before any of it is visible.
119
+ *
120
+ * @public
121
+ */
122
+ export declare class CliAudience {
123
+ private constructor();
124
+ /**
125
+ * The four flags, for `Command.withSharedFlags` on the root command.
126
+ *
127
+ * @remarks
128
+ * Each is repeatable, so every occurrence is counted; a boolean given as `false` (`--agent=false`,
129
+ * `--no-agent`) is not an occurrence. Core lists shared flags in every command's help; pass
130
+ * `hidden` to remove them from all of them.
131
+ */
132
+ static readonly flags: (options?: CliAudienceFlagsOptions) => {
133
+ readonly audience: Flag.Flag<ReadonlyArray<AudienceKind>>;
134
+ readonly human: Flag.Flag<ReadonlyArray<boolean>>;
135
+ readonly agent: Flag.Flag<ReadonlyArray<boolean>>;
136
+ readonly ci: Flag.Flag<ReadonlyArray<boolean>>;
137
+ };
138
+ /**
139
+ * Resolve the flags before every subcommand handler and re-provide `Audience`.
140
+ *
141
+ * @remarks
142
+ * `CliAudience.run` and `runWith` apply this themselves, so a program run through them never needs it. Use it
143
+ * directly only with a bare `Command.run`, which leaves a fallback prompt blind to the flags (see the class
144
+ * remarks).
145
+ *
146
+ * A failure report is written outside the run, where the flag is not in force, so only `runWith` and `run` carry
147
+ * the flag's audience to it; with this on its own the report follows the environment's audience.
148
+ *
149
+ * Pipe it onto the composite root, after `withSubcommands`, since a parent's handler does not run when a
150
+ * subcommand is selected. With exactly one flag the audience is `{ kind, source: "flag" }`; with none the
151
+ * ambient `Audience` is read and provided back unchanged, so `Audience` stays in the requirement a handler
152
+ * reading it already has, and is added to a program whose handlers do not read it.
153
+ */
154
+ static readonly provide: <const Name extends string, Input extends AudienceFlagInput, ContextInput, E, R>(command: Command.Command<Name, Input, ContextInput, E, R>) => Command.Command<Name, Input, ContextInput, E | CliError.UserError, Exclude<R, Audience> | Audience>;
155
+ /**
156
+ * Run a command the way `Command.runWith` does, with the audience flag resolved BEFORE core parses.
157
+ *
158
+ * @remarks
159
+ * It scans `argv` for the four audience flags first, then runs core around a provided `Audience` (when exactly
160
+ * one is given: `{ kind, source: "flag" }`) and a `CliInteractive` decided from it: `--human` is interactive when
161
+ * `TerminalEnv` reports a terminal on stdin and stdout and `TERM` is not `dumb` (it can turn prompting on under a detected agent), a
162
+ * non-human flag or a conflict makes it false. A fallback prompt fires while core parses, earlier than
163
+ * anything `CliAudience.provide` can reach, so `--agent init` on a terminal would otherwise still prompt. No
164
+ * flag leaves the ambient values untouched. A conflict still gets core's own usage error, exit `64`, from
165
+ * `CliAudience.provide`'s resolver.
166
+ *
167
+ * @param command - the composite root, with the flags shared and `CliAudience.provide` piped on
168
+ * @param config - the same `version` and `renderErrors` as core's
169
+ */
170
+ static readonly runWith: <const Name extends string, Input, E, R, ContextInput>(command: Command.Command<Name, Input, ContextInput, E, R> & RequiresAudienceFlags<Input>, config: {
171
+ readonly version: string;
172
+ readonly renderErrors?: boolean | undefined;
173
+ }) => ((input: ReadonlyArray<string>) => Effect.Effect<void, Exclude<E | CliError.UserError, Terminal.QuitError> | CliError.CliError, Exclude<R, Audience> | Audience | Command.Environment>);
174
+ /**
175
+ * `Command.run` with the audience flag resolved before parsing: reads `Stdio.args` and calls
176
+ * {@link CliAudience.runWith}.
177
+ *
178
+ * @param command - the composite root
179
+ * @param config - the same `version` and `renderErrors` as core's
180
+ */
181
+ static readonly run: <const Name extends string, Input, E, R, ContextInput>(command: Command.Command<Name, Input, ContextInput, E, R> & RequiresAudienceFlags<Input>, config: {
182
+ readonly version: string;
183
+ readonly renderErrors?: boolean | undefined;
184
+ }) => Effect.Effect<void, Exclude<E | CliError.UserError, Terminal.QuitError> | CliError.CliError, Exclude<R, Audience> | Audience | Command.Environment>;
185
+ }
186
+ /**
187
+ * Whether a CLI's output should carry ANSI colour, decided once and shared by
188
+ * everything that renders — help text, error output, and any rendered result.
189
+ *
190
+ * @remarks
191
+ * The decision is `@effected/env`'s `TerminalEnv.colorLevel("stdout")`, which
192
+ * follows Node's `getColorDepth` precedence: `FORCE_COLOR` first (`0` or an
193
+ * unrecognised value forces colour off; an empty value, `1` or `true` force basic colour, `2` 256 colours and
194
+ * `3` truecolor, even without a terminal), then a non-empty `NO_COLOR` or `NODE_DISABLE_COLORS` and
195
+ * `TERM=dumb`, then the TTY gate. `FORCE_COLOR` therefore beats `NO_COLOR`.
196
+ * The environment
197
+ * is read through the ambient `ConfigProvider`, never `process`, so a test
198
+ * swaps it with `Effect.provideService(ConfigProvider.ConfigProvider, ...)`;
199
+ * an ambient `TerminalEnv`, such as `TerminalEnv.layerTest`, answers instead
200
+ * when one is provided.
201
+ *
202
+ * @public
203
+ */
204
+ export declare class CliColor {
205
+ private constructor();
206
+ /**
207
+ * The decision, for passing to a pure renderer as a plain boolean.
208
+ *
209
+ * @public
210
+ */
211
+ static readonly enabled: Effect.Effect<boolean, never, Stdio.Stdio>;
212
+ /**
213
+ * Core's default `CliOutput.Formatter`, coloured by the same decision as
214
+ * {@link CliColor.enabled}, so help text, parse errors and rendered
215
+ * output never disagree on whether colour is on.
216
+ *
217
+ * @remarks
218
+ * `overrides` replaces individual methods of the default formatter — for
219
+ * example `formatVersion`, to append a "via `<carrier>`" line without
220
+ * losing the other defaults. Each call mints a fresh layer; bind the
221
+ * result to a `const` or the decision is re-read every time it is
222
+ * provided.
223
+ *
224
+ * The `never` in its output does not mean it installs nothing.
225
+ * `CliOutput.Formatter` is a `Context.Reference`, whose key type is
226
+ * `never`, so this layer sets the formatter reference rather than
227
+ * providing a service. Every command it is provided to renders with the
228
+ * formatter it sets, and without it they fall back to core's default
229
+ * formatter.
230
+ *
231
+ * @public
232
+ */
233
+ static readonly formatterLayer: (overrides?: Partial<CliOutput.Formatter>) => Layer.Layer<never, never, Stdio.Stdio>;
234
+ }
235
+ /**
236
+ * The symbols a theme draws with.
237
+ *
238
+ * @public
239
+ */
240
+ interface GlyphSet {
241
+ /** Which set this is. */
242
+ readonly kind: "unicode" | "ascii";
243
+ /** The truncation marker. */
244
+ readonly ellipsis: string;
245
+ /** The frames of a spinner, in order. */
246
+ readonly spinner: ReadonlyArray<string>;
247
+ /** A list bullet. */
248
+ readonly bullet: string;
249
+ /** A directional arrow. */
250
+ readonly arrow: string;
251
+ /** The separator between the segments of a breadcrumb or path: one for people, one for agents. */
252
+ readonly pathSeparator: {
253
+ readonly human: string;
254
+ readonly agent: string;
255
+ };
256
+ /** How long a spinner frame is shown, in milliseconds. */
257
+ readonly spinnerIntervalMs: number;
258
+ /**
259
+ * The segments a tree is drawn with: `branch` before a child that has later siblings, `last` before the final
260
+ * child, and `pipe` and `blank` as the indent under each. All four are one width so branches align.
261
+ */
262
+ readonly tree: {
263
+ readonly branch: string;
264
+ readonly last: string;
265
+ readonly pipe: string;
266
+ readonly blank: string;
267
+ };
268
+ }
269
+ /**
270
+ * Options for {@link Glyphs.select}.
271
+ *
272
+ * @public
273
+ */
274
+ interface GlyphSelectOptions {
275
+ /**
276
+ * `true` is ASCII, `false` is Unicode, and `auto` (the default) is ASCII only when `term` is `dumb`.
277
+ */
278
+ readonly ascii?: boolean | "auto" | undefined;
279
+ /**
280
+ * The `TERM` value, which only `auto` reads. It is passed in rather than read: this selection is pure, so a
281
+ * caller with no Effect context (an Ink component) uses it, and `process` is never consulted. Unset is not
282
+ * `dumb`.
283
+ */
284
+ readonly term?: string | undefined;
285
+ }
286
+ /**
287
+ * The two glyph sets: Unicode, and a plain-ASCII fallback for terminals that cannot draw it.
288
+ *
289
+ * @remarks
290
+ * The sets are shared, so they and their nested values are frozen.
291
+ *
292
+ * @public
293
+ */
294
+ export declare class Glyphs {
295
+ private constructor();
296
+ /** Unicode symbols. */
297
+ static readonly unicode: GlyphSet;
298
+ /**
299
+ * Pick a glyph set without a service: the one `CliTheme` uses, as a pure function.
300
+ *
301
+ * @remarks
302
+ * `CliTheme.layer` reads `TERM` through `Config` and calls this, so the two agree. `StreamEnv` carries no
303
+ * `TERM`, and nothing else in it decides ASCII, so the caller passes `term` when it wants `auto` to mean
304
+ * something.
305
+ *
306
+ * @param options - whether to force ASCII or Unicode, and the `TERM` value `auto` reads
307
+ */
308
+ static readonly select: (options?: GlyphSelectOptions) => GlyphSet;
309
+ /** ASCII-only symbols. */
310
+ static readonly ascii: GlyphSet;
311
+ }
312
+ /**
313
+ * A named terminal colour: the eight ANSI colours and their bright variants.
314
+ *
315
+ * @remarks
316
+ * The bright variants are spelled as chalk and Ink spell them (`redBright`, `blackBright`), so a style maps to
317
+ * either without a rename table. `gray` is chalk's alias for `blackBright`.
318
+ *
319
+ * @public
320
+ */
321
+ type NamedColor = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright" | "gray";
322
+ /**
323
+ * A terminal style: an optional foreground colour and text attributes.
324
+ *
325
+ * @remarks
326
+ * A style is data; it carries no escape sequences. `CliTheme.paint` renders it for the terminal's colour
327
+ * level, and at level `none` rendering is the identity. A hex foreground that is not `#rgb` or `#rrggbb`, and
328
+ * a name that is not a {@link NamedColor}, is ignored when rendered rather than failing.
329
+ *
330
+ * @public
331
+ */
332
+ interface Style {
333
+ /** The foreground: a named colour or a `#rrggbb` hex. */
334
+ readonly fg?: NamedColor | `#${string}`;
335
+ /** Bold. */
336
+ readonly bold?: boolean;
337
+ /** Dim, or faint. */
338
+ readonly dim?: boolean;
339
+ /** Italic. */
340
+ readonly italic?: boolean;
341
+ /** Underline. */
342
+ readonly underline?: boolean;
343
+ }
344
+ /**
345
+ * The semantic tokens a theme resolves to a {@link Style}.
346
+ *
347
+ * @public
348
+ */
349
+ type TokenName = "success" | "failure" | "warning" | "info" | "error" | "muted" | "accent" | "emphasis";
350
+ /**
351
+ * Constructors for {@link Style} values, and the pure resolution of a token to one.
352
+ *
353
+ * @public
354
+ */
355
+ export declare class Token {
356
+ private constructor();
357
+ /**
358
+ * The default {@link Style} of every token, frozen.
359
+ *
360
+ * @remarks
361
+ * Data, not a service: it is what `CliTheme` starts from, and a renderer with no Effect context (an Ink
362
+ * component) reads it directly.
363
+ */
364
+ static readonly defaults: Readonly<Record<TokenName, Style>>;
365
+ /**
366
+ * The style a token or style resolves to, as a pure function: no service, no terminal.
367
+ *
368
+ * @remarks
369
+ * An explicit style resolves to itself. A token name resolves to its override when `overrides` has one, else
370
+ * its default; a name that is not a token (including an `Object.prototype` member) resolves to the empty
371
+ * style. This is the same resolution `CliTheme.paint` applies, which is what `StreamTheme.style` reports.
372
+ *
373
+ * @param token - a token name or an explicit style
374
+ * @param overrides - styles that replace the default of a token, as `CliThemeOptions.tokens` does
375
+ */
376
+ static readonly resolve: (token: TokenName | Style, overrides?: Partial<Record<TokenName, Style>>) => Style;
377
+ /**
378
+ * A foreground from a hex colour.
379
+ *
380
+ * @param hex - `#rrggbb` (or `#rgb`)
381
+ */
382
+ static readonly hex: (hex: `#${string}`) => Style;
383
+ /**
384
+ * A foreground from a named colour.
385
+ *
386
+ * @param color - the colour
387
+ */
388
+ static readonly named: (color: NamedColor) => Style;
389
+ /**
390
+ * A style, as written. Exists so a style reads as a token at a call site.
391
+ *
392
+ * @param style - the style
393
+ */
394
+ static readonly style: (style: Style) => Style;
395
+ }
396
+ /**
397
+ * How one status looks: a Unicode glyph, an ASCII fallback, a token and a rank.
398
+ *
399
+ * @public
400
+ */
401
+ interface StatusDef {
402
+ /** The Unicode glyph. */
403
+ readonly glyph: string;
404
+ /** The ASCII fallback, used when the theme's glyphs are ASCII. */
405
+ readonly ascii: string;
406
+ /** The semantic token, or an explicit style, the glyph is painted with. */
407
+ readonly token: TokenName | Style;
408
+ /** Severity for {@link Status.worst}: the highest rank wins. */
409
+ readonly rank: number;
410
+ }
411
+ /**
412
+ * The names of the core vocabulary.
413
+ *
414
+ * @public
415
+ */
416
+ type CoreStatusName = "success" | "failure" | "warning" | "info" | "skip" | "pending";
417
+ /**
418
+ * An open vocabulary of statuses.
419
+ *
420
+ * @remarks
421
+ * Start from `Status.core` and add your own with `extend`. The names are a type parameter,
422
+ * so `def` and `worst` reject a name the vocabulary does not have at compile time.
423
+ *
424
+ * @example
425
+ * ```ts
426
+ * import { Status } from "@effected/cli-kit"
427
+ *
428
+ * const vocab = Status.extend({
429
+ * timeout: { glyph: "⏱", ascii: "[time]", token: "warning", rank: 85 },
430
+ * })
431
+ * const worst = vocab.worst(["success", "timeout"])
432
+ * // => "timeout"
433
+ * ```
434
+ *
435
+ * @public
436
+ */
437
+ export declare class Status<Names extends string> {
438
+ private readonly defs;
439
+ private constructor();
440
+ /** The core vocabulary: success, skip, pending, info, warning and failure, by rank 10, 20, 30, 40, 60, 90. */
441
+ static readonly core: Status<CoreStatusName>;
442
+ /**
443
+ * The core vocabulary plus `extra`; an entry that reuses a core name replaces it.
444
+ *
445
+ * @param extra - the statuses to add, by name
446
+ */
447
+ static readonly extend: <const Extra extends Record<string, StatusDef>>(extra: Extra) => Status<CoreStatusName | (keyof Extra & string)>;
448
+ /**
449
+ * This vocabulary plus `extra`; an entry that reuses a name replaces it.
450
+ *
451
+ * @remarks
452
+ * An entry may replace a core name. Replacing `warning` with a lower rank moves the threshold at which
453
+ * `CliMessage.status` defaults to stderr for this vocabulary, since that threshold is `warning`'s rank in the
454
+ * vocabulary it is given.
455
+ *
456
+ * @param extra - the statuses to add, by name
457
+ */
458
+ extend<const Extra extends Record<string, StatusDef>>(extra: Extra): Status<Names | (keyof Extra & string)>;
459
+ /**
460
+ * The definition of a status.
461
+ *
462
+ * @remarks
463
+ * A name the vocabulary does not have is a defect: it throws an `Error` naming it and the names that exist. The
464
+ * types already reject one, so it is reachable only through a cast.
465
+ *
466
+ * @param name - a name in this vocabulary
467
+ */
468
+ def(name: Names): StatusDef;
469
+ /**
470
+ * The full definition of a status as an immutable snapshot, for a caller that stores it.
471
+ *
472
+ * @remarks
473
+ * `def` answers the vocabulary's own entry. `resolve` answers a frozen copy, so a document node that holds
474
+ * the definition stays plain data and editing it cannot change the vocabulary. The copy is shallow: a
475
+ * `token` given as a `Style` keeps its own identity. Throws on an unknown name, as {@link Status.def} does;
476
+ * storing an empty definition in a document instead would fail far from the cause.
477
+ *
478
+ * @param name - a name in this vocabulary
479
+ */
480
+ resolve(name: Names): StatusDef;
481
+ /**
482
+ * A status's glyph from a glyph set: `def.ascii` for an ASCII set, `def.glyph` otherwise. Unpainted, for a caller
483
+ * that draws it itself (an Ink tree, a reporter).
484
+ *
485
+ * @remarks
486
+ * Throws on an unknown name, as {@link Status.def} does. The glyph is sanitised, as text in a document is: escape
487
+ * sequences and control characters in a vocabulary's glyph are removed, so a glyph built from data cannot paint the
488
+ * terminal, plant a hyperlink or move the cursor. Every kit path that draws a status glyph takes it from here.
489
+ *
490
+ * @param name - a name in this vocabulary
491
+ * @param glyphs - the glyph set, such as `Glyphs.unicode`, `Glyphs.ascii` or a theme's
492
+ */
493
+ glyph(name: Names, glyphs: GlyphSet): string;
494
+ /**
495
+ * The status with the highest rank; a tie goes to the one that comes first in `names`.
496
+ *
497
+ * @remarks
498
+ * `rank` is SEVERITY, not an aggregation policy: the higher rank wins, so in `Status.core` a `skip` outranks a
499
+ * `success`. A consumer whose aggregate differs (a test run where passes dominate skips, say) folds its own
500
+ * rule over the names instead of reading this.
501
+ *
502
+ * Takes at least one name, so the answer is always a name. For an array that may be empty, use
503
+ * {@link Status.worstOption}. They are two methods because a literal and an array variable are the same
504
+ * array at runtime, so one method could not return a name for one and an `Option` for the other.
505
+ *
506
+ * @param names - the statuses to compare
507
+ */
508
+ worst(names: Array$1.NonEmptyReadonlyArray<Names>): Names;
509
+ /**
510
+ * The status with the highest rank of an array that may be empty: `None` when it is, otherwise `Some` of
511
+ * the worst, a tie going to the one that comes first in `names`. Rank is severity, not an aggregation policy; see
512
+ * {@link Status.worst}.
513
+ *
514
+ * @param names - the statuses to compare
515
+ */
516
+ worstOption(names: ReadonlyArray<Names>): Option.Option<Names>;
517
+ }
518
+ /**
519
+ * The shape of the {@link CliTheme} service: a colour level, a glyph set and the functions that use them.
520
+ *
521
+ * @remarks
522
+ * The whole shape is one immutable value with no mockable behaviour, so `Layer.succeed` (via
523
+ * {@link CliTheme.layerTest}) is the complete double.
524
+ *
525
+ * @public
526
+ */
527
+ interface CliThemeShape extends StreamTheme {
528
+ /**
529
+ * The theme of one output stream, painting with THAT stream's colour level.
530
+ *
531
+ * @remarks
532
+ * The members above are the `stdout` ones. Anything written to stderr must be painted through
533
+ * `forStream("stderr")`: redirecting one stream (`tool 2>err.log`, `tool | jq`) changes that stream's colour
534
+ * and not the other's.
535
+ */
536
+ readonly forStream: (stream: "stdout" | "stderr") => StreamTheme;
537
+ }
538
+ /**
539
+ * A theme bound to one stream's colour level.
540
+ *
541
+ * @public
542
+ */
543
+ interface StreamTheme {
544
+ /** Render `text` in a token or an explicit style; the identity when colour is `none`. */
545
+ readonly paint: (token: TokenName | Style, text: string) => string;
546
+ /**
547
+ * The resolved {@link Style} of a token or style: the one `paint` renders, whatever the colour level.
548
+ *
549
+ * @remarks
550
+ * Pure data, for a renderer that is not ANSI (an Ink component maps it to its own props). It applies this
551
+ * theme's token overrides, so it is `Token.resolve` with them.
552
+ */
553
+ readonly style: (token: TokenName | Style) => Style;
554
+ /** The raw opening SGR sequence of a token or style; `""` when colour is `none`. */
555
+ readonly sgr: (token: TokenName | Style) => string;
556
+ /** The glyph set in use. */
557
+ readonly glyphs: GlyphSet;
558
+ /** The colour level of the stream. */
559
+ readonly color: ColorLevel;
560
+ /**
561
+ * Render a status from a vocabulary: its glyph, sanitised (see `Status.glyph`) and painted with its token, then
562
+ * `text` when given, as it is: sanitising `text` is the caller's, as `CliMessage` and `CliLog.status` do.
563
+ */
564
+ readonly status: <N extends string>(vocab: Status<N>, name: N, text?: string) => string;
565
+ }
566
+ /**
567
+ * Options for {@link CliTheme.layer}.
568
+ *
569
+ * @public
570
+ */
571
+ interface CliThemeOptions {
572
+ /** Styles that replace the default of a token. */
573
+ readonly tokens?: Partial<Record<TokenName, Style>> | undefined;
574
+ /** The glyph set. `auto`, the default, is ASCII only when `TERM=dumb`. */
575
+ readonly glyphs?: "unicode" | "ascii" | "auto" | undefined;
576
+ }
577
+ /**
578
+ * Options for {@link CliTheme.layerTest}.
579
+ *
580
+ * @public
581
+ */
582
+ interface CliThemeTestOptions {
583
+ /** The stdout colour level; `none` by default. */
584
+ readonly color?: ColorLevel | undefined;
585
+ /** The stderr colour level; the same as `color` by default. */
586
+ readonly stderrColor?: ColorLevel | undefined;
587
+ /** The glyph set; Unicode by default. */
588
+ readonly glyphs?: "unicode" | "ascii" | undefined;
589
+ }
590
+ declare const CliTheme_base: Context.ServiceClass<CliTheme, "@effected/cli-kit/CliTheme", CliThemeShape>;
591
+ /**
592
+ * The presentation of a CLI: colour tokens, glyphs and statuses, decided once from the terminal.
593
+ *
594
+ * @remarks
595
+ * A `Context.Service`, not a `Reference`. A colour level is a fact about the terminal, not a preference with a
596
+ * safe default, so there is nothing sensible for an unprovided theme to read; requiring it puts `CliTheme` in
597
+ * `R` and a program that forgot to wire it fails to compile rather than printing plain text to a colour
598
+ * terminal. {@link CliTheme.layer} reads `TerminalEnv`.
599
+ *
600
+ * @public
601
+ */
602
+ export declare class CliTheme extends CliTheme_base {
603
+ /**
604
+ * The theme for the terminal `TerminalEnv` describes.
605
+ *
606
+ * @remarks
607
+ * Bind the layer to a constant and provide it once. With `glyphs: "auto"` the glyph set is ASCII only when
608
+ * `TERM=dumb`, read through `Config`.
609
+ *
610
+ * @param options - token overrides and the glyph set
611
+ */
612
+ static readonly layer: (options?: CliThemeOptions) => Layer.Layer<CliTheme, never, TerminalEnv>;
613
+ /**
614
+ * The theme an audience sees of `theme`: for an agent, the same theme at colour `none` (`paint` the identity, `sgr`
615
+ * empty, `status` unpainted), whatever the terminal could do, because an agent never gets an escape of any kind; for
616
+ * anyone else, or when the audience is not known, `theme` itself.
617
+ *
618
+ * @remarks
619
+ * The one rule the kit applies wherever it paints for an audience: `Render.context` takes its colour and `paint`
620
+ * from it, `CliMessage` and `CliLog.status` paint their glyphs through it, and `./ui` gives it to the trees it
621
+ * mounts, so `useTheme`, `Styled` and the widgets' colour-`none` text markers all agree. A program that paints its
622
+ * own lines applies the same rule with it rather than re-implementing it:
623
+ *
624
+ * ```ts
625
+ * const line = Effect.gen(function* () {
626
+ * const theme = CliTheme.forAudience((yield* CliTheme).forStream("stdout"), (yield* Audience).kind)
627
+ * return theme.status(Status.core, "success", Fmt.sanitize(name))
628
+ * })
629
+ * ```
630
+ *
631
+ * Pure: it reads nothing, so the audience is the caller's to pass, `undefined` when it is not known.
632
+ *
633
+ * @param theme - a stream's theme, such as `CliTheme.forStream("stdout")`
634
+ * @param audience - who the output is for, or `undefined` when that is not known
635
+ */
636
+ static readonly forAudience: (theme: StreamTheme, audience: AudienceKind | undefined) => StreamTheme;
637
+ /**
638
+ * A fixed theme that needs nothing; `none` colour and Unicode glyphs unless told otherwise.
639
+ *
640
+ * @param options - the colour level and glyph set
641
+ */
642
+ static readonly layerTest: (options?: CliThemeTestOptions) => Layer.Layer<CliTheme>;
643
+ /**
644
+ * Sets core's `Prompt.Theme` from the tokens, so built-in prompts match the rest of the output.
645
+ *
646
+ * @remarks
647
+ * The colour fields are raw SGR openers and are empty strings when colour is `none`, and `colors` is the theme's
648
+ * own decision (`false` at `none`), so core's prompts and its command wizard write no colour or style escape, not
649
+ * even a reset, and core never re-reads the host for `NO_COLOR` or a TTY. Cursor and redraw controls are still
650
+ * written, whatever the theme says. Under ASCII glyphs the prompt symbols fall back to ASCII too.
651
+ */
652
+ static readonly promptTheme: Layer.Layer<never, never, CliTheme>;
653
+ }
654
+ /**
655
+ * A status as a document stores it: its name and its resolved definition.
656
+ *
657
+ * @remarks
658
+ * The definition is stored, not the vocabulary, so a node stays plain data.
659
+ *
660
+ * @public
661
+ */
662
+ interface StatusRef {
663
+ /** The name in the vocabulary it was resolved from. */
664
+ readonly name: string;
665
+ /** The resolved definition. */
666
+ readonly def: StatusDef;
667
+ }
668
+ /**
669
+ * Where a link points: a URL, or a file with an optional position.
670
+ *
671
+ * @public
672
+ */
673
+ type LinkTarget = {
674
+ readonly url: string;
675
+ } | {
676
+ readonly file: string;
677
+ readonly line?: number;
678
+ readonly col?: number;
679
+ };
680
+ /**
681
+ * Content that flows inside a line.
682
+ *
683
+ * @remarks
684
+ * - `Text`: a run of text, optionally painted with a token or style.
685
+ * - `Code`: code in a monospace span.
686
+ * - `Link`: a labelled link to a URL or a file position.
687
+ * - `StatusMark`: a status glyph, carrying its resolved definition.
688
+ * - `Path`: a path or breadcrumb, joined with the audience's path separator.
689
+ * - `Strong` and `Emphasis`: content in bold or italic; markdown `**` and `_`.
690
+ * - `File`: a path shown through the context's `displayPath`, never linked.
691
+ *
692
+ * @public
693
+ */
694
+ type Inline = {
695
+ readonly _tag: "Text";
696
+ readonly value: string;
697
+ readonly token?: TokenName | Style;
698
+ } | {
699
+ readonly _tag: "Code";
700
+ readonly value: string;
701
+ } | {
702
+ readonly _tag: "Link";
703
+ readonly target: LinkTarget;
704
+ readonly label: ReadonlyArray<Inline>;
705
+ /**
706
+ * Whether plain text (and `ansi` with links off, and markdown with no URL) follows the label with the target in
707
+ * parentheses. Unset, it does so only when the label does not already show the target's display form.
708
+ */
709
+ readonly suffix?: boolean;
710
+ } | {
711
+ readonly _tag: "StatusMark";
712
+ readonly name: string;
713
+ readonly def: StatusDef;
714
+ } | {
715
+ readonly _tag: "Path";
716
+ readonly segments: ReadonlyArray<string>;
717
+ } | {
718
+ readonly _tag: "Strong";
719
+ readonly content: ReadonlyArray<Inline>;
720
+ } | {
721
+ readonly _tag: "Emphasis";
722
+ readonly content: ReadonlyArray<Inline>;
723
+ } | {
724
+ readonly _tag: "File";
725
+ readonly path: string;
726
+ };
727
+ /**
728
+ * A node of a {@link TreeNode} tree: a label and its children.
729
+ *
730
+ * @public
731
+ */
732
+ interface TreeNode {
733
+ /** What the node says. */
734
+ readonly label: ReadonlyArray<Inline>;
735
+ /** Its children, in order. */
736
+ readonly children: ReadonlyArray<TreeNode>;
737
+ }
738
+ /**
739
+ * One column of a table.
740
+ *
741
+ * @public
742
+ */
743
+ interface Column {
744
+ /** The header cell. */
745
+ readonly header: ReadonlyArray<Inline>;
746
+ /** How the column's cells align; left when unset. */
747
+ readonly align?: "left" | "right" | "center";
748
+ }
749
+ /**
750
+ * One counter of a `Counts` block.
751
+ *
752
+ * @public
753
+ */
754
+ interface Counter {
755
+ /** A stable identifier, for a caller's total rule. */
756
+ readonly key: string;
757
+ /**
758
+ * What the counter is called when shown: one label, or a singular and a plural form, `one` for a count of exactly 1
759
+ * and `other` for any other, 0 included. The count is the counter's own `n`, except in a share headline
760
+ * (`1/3 repos`), which reads by the total. A `CountsTable` heads its column with `other`, since the column holds
761
+ * every row's count.
762
+ */
763
+ readonly label: string | {
764
+ readonly one: string;
765
+ readonly other: string;
766
+ };
767
+ /** The count. */
768
+ readonly n: number;
769
+ /** The status the count is painted with. */
770
+ readonly status: StatusRef;
771
+ /** Show the counter when `n` is zero; by default a zero counter is hidden. */
772
+ readonly showZero?: boolean;
773
+ }
774
+ /**
775
+ * A block of a document.
776
+ *
777
+ * @remarks
778
+ * - `Paragraph`: one logical line; a paragraph of paragraphs is a `Section`.
779
+ * - `List` and `Table`: with an optional `cap` on the rows shown, and an `overflow` that says what the hidden rows
780
+ * amount to, given how many there are.
781
+ * - `Tree`: nested labels.
782
+ * - `Collapsible`: a titled body a renderer may fold.
783
+ * - `Callout`: a body with a kind.
784
+ * - `CodeBlock`: preformatted text, with an optional language.
785
+ * - `Diff`: expected against received text, with an optional cap on the lines shown.
786
+ * - `Section`: children under an optional title.
787
+ * - `Counts`: labelled counters in one of three layouts. `total` replaces the default sum of every counter, and
788
+ * `durationMs` is how long it took. `share: false` drops the headline's share of the total, and `paint` limits what
789
+ * is painted.
790
+ * - `Verbatim`: lines kept exactly, each indented, never wrapped.
791
+ * - `CountsTable`: a table of `Counts` rows, a column per counter key, a `duration` column when some row has one, and
792
+ * an optional summed total row.
793
+ * - `Lines`: one line per entry; markdown keeps them apart with hard breaks.
794
+ * - `Line`: one line, which `truncate` cuts to the width instead of wrapping, and `wrap: false` keeps whole.
795
+ * - `DiffText`: a unified diff, as given; `truncate` cuts each line to the width.
796
+ * - A `List` may be `compact`, with no blank lines between an item's children (a blank line of an item's own content
797
+ * keeps the item's indent in plain and `ansi`), and a `Table` may be `style: "pipe"`.
798
+ * - `Annotation`: a GitHub Actions annotation, which only `Render.githubLog` writes.
799
+ *
800
+ * Nodes are plain data and nothing decodes them, so a function field such as `overflow` or `total` is fine.
801
+ *
802
+ * @public
803
+ */
804
+ type Block = {
805
+ readonly _tag: "Heading";
806
+ readonly level: 1 | 2 | 3 | 4;
807
+ readonly content: ReadonlyArray<Inline>;
808
+ } | {
809
+ readonly _tag: "Paragraph";
810
+ readonly content: ReadonlyArray<Inline>;
811
+ } | {
812
+ readonly _tag: "List";
813
+ readonly items: ReadonlyArray<Block>;
814
+ readonly cap?: number;
815
+ readonly overflow?: (hidden: number) => ReadonlyArray<Inline>;
816
+ readonly compact?: boolean;
817
+ } | {
818
+ readonly _tag: "Table";
819
+ readonly columns: ReadonlyArray<Column>;
820
+ readonly rows: ReadonlyArray<ReadonlyArray<ReadonlyArray<Inline>>>;
821
+ readonly cap?: number;
822
+ readonly overflow?: (hidden: number) => ReadonlyArray<Inline>;
823
+ readonly style?: "pipe";
824
+ } | {
825
+ readonly _tag: "Tree";
826
+ readonly root: TreeNode;
827
+ } | {
828
+ readonly _tag: "Collapsible";
829
+ readonly title: ReadonlyArray<Inline>;
830
+ readonly body: ReadonlyArray<Block>;
831
+ readonly open?: boolean;
832
+ } | {
833
+ readonly _tag: "Callout";
834
+ readonly kind: "note" | "tip" | "important" | "warning" | "caution";
835
+ readonly body: ReadonlyArray<Block>;
836
+ } | {
837
+ readonly _tag: "CodeBlock";
838
+ readonly lang?: string;
839
+ readonly text: string;
840
+ } | {
841
+ readonly _tag: "Diff";
842
+ readonly expected: string;
843
+ readonly received: string;
844
+ readonly cap?: number;
845
+ } | {
846
+ readonly _tag: "Section";
847
+ readonly title?: ReadonlyArray<Inline>;
848
+ readonly children: ReadonlyArray<Block>;
849
+ } | {
850
+ readonly _tag: "Counts";
851
+ readonly label?: ReadonlyArray<Inline>;
852
+ readonly counters: ReadonlyArray<Counter>;
853
+ readonly total?: (counters: ReadonlyArray<Counter>) => number;
854
+ readonly qualifier?: ReadonlyArray<Inline>;
855
+ readonly durationMs?: number;
856
+ readonly layout: "inline" | "columns" | "row";
857
+ readonly share?: boolean;
858
+ readonly paint?: "all" | "glyph" | "none";
859
+ readonly suffix?: ReadonlyArray<Inline>;
860
+ } | {
861
+ readonly _tag: "CountsTable";
862
+ readonly rows: ReadonlyArray<CountsRow>;
863
+ readonly totalRow?: boolean | ReadonlyArray<Inline>;
864
+ readonly labelHeader?: ReadonlyArray<Inline>;
865
+ readonly durationHeader?: ReadonlyArray<Inline>;
866
+ } | {
867
+ readonly _tag: "Lines";
868
+ readonly lines: ReadonlyArray<ReadonlyArray<Inline>>;
869
+ readonly truncate?: boolean;
870
+ readonly wrap?: boolean;
871
+ } | {
872
+ readonly _tag: "Line";
873
+ readonly content: ReadonlyArray<Inline>;
874
+ readonly truncate?: boolean;
875
+ readonly wrap?: boolean;
876
+ } | {
877
+ readonly _tag: "DiffText";
878
+ readonly text: string;
879
+ readonly cap?: number;
880
+ readonly truncate?: boolean;
881
+ } | {
882
+ readonly _tag: "Verbatim";
883
+ readonly text: string;
884
+ readonly indent?: number;
885
+ } | ({
886
+ readonly _tag: "Annotation";
887
+ readonly message: string;
888
+ } & AnnotationOptions);
889
+ /**
890
+ * Where and how a GitHub Actions annotation is shown: its level, and an optional position and title.
891
+ *
892
+ * @public
893
+ */
894
+ interface AnnotationOptions {
895
+ /** `error`, `warning` or `notice`. */
896
+ readonly level: "error" | "warning" | "notice";
897
+ /** The file it points at, as the runner should show it (relative to the workspace). */
898
+ readonly file?: string;
899
+ /** The line it starts on. */
900
+ readonly line?: number;
901
+ /** The column it starts at. */
902
+ readonly col?: number;
903
+ /** The line it ends on. */
904
+ readonly endLine?: number;
905
+ /** The column it ends at. */
906
+ readonly endColumn?: number;
907
+ /** Its title. */
908
+ readonly title?: string;
909
+ }
910
+ /**
911
+ * One row of a `CountsTable`: its label, its counters and how long it took.
912
+ *
913
+ * @public
914
+ */
915
+ interface CountsRow {
916
+ /** What the row is, such as a project name. */
917
+ readonly label: ReadonlyArray<Inline>;
918
+ /** Its counters; their keys pick the column each lands in. */
919
+ readonly counters: ReadonlyArray<Counter>;
920
+ /** How long it took, in milliseconds, shown with `Fmt.duration` in the duration column. */
921
+ readonly durationMs?: number;
922
+ }
923
+ /**
924
+ * The options of {@link Doc.countsTable}.
925
+ *
926
+ * @public
927
+ */
928
+ interface CountsTableOptions {
929
+ /** A last row summing each column: labelled with a plain `Total` when `true`, or with the content given (`Doc.strong("Total")` for a bold one). */
930
+ readonly totalRow?: boolean | InlineInput;
931
+ /** The header of the label column, such as `Project`; empty when unset. */
932
+ readonly labelHeader?: InlineInput;
933
+ /** The header of the duration column, shown only when some row has a `durationMs`; `duration` when unset. */
934
+ readonly durationHeader?: InlineInput;
935
+ }
936
+ /**
937
+ * Options for {@link Doc.list}.
938
+ *
939
+ * @public
940
+ */
941
+ interface ListOptions extends OverflowOptions {
942
+ /** No blank lines between the children of an item, such as a section's title and body. */
943
+ readonly compact?: boolean;
944
+ }
945
+ /**
946
+ * Options for {@link Doc.table}.
947
+ *
948
+ * @public
949
+ */
950
+ interface TableOptions extends OverflowOptions {
951
+ /**
952
+ * `pipe` gives plain and `ansi` istanbul's shape: rules above and below the header and at the end, cells joined
953
+ * with ` | `. Markdown's table is a pipe table either way. Unset, the columns are space-aligned.
954
+ */
955
+ readonly style?: "pipe";
956
+ }
957
+ /**
958
+ * Options for `Doc.link`.
959
+ *
960
+ * @public
961
+ */
962
+ interface LinkOptions {
963
+ /**
964
+ * Whether the target follows the label in parentheses where a link cannot be followed: plain text, `ansi` with
965
+ * links off, markdown with no URL. `true` always, `false` never; unset, only when the label does not already show
966
+ * the target's display form (`displayPath(file)`, then `:line` and `:col` when present).
967
+ */
968
+ readonly suffix?: boolean;
969
+ }
970
+ /**
971
+ * A whole document: its blocks, in order.
972
+ *
973
+ * @public
974
+ */
975
+ type Document = ReadonlyArray<Block>;
976
+ /**
977
+ * What a constructor accepts for content: a string, one `Inline`, or an array of either.
978
+ *
979
+ * @remarks
980
+ * A string becomes a `Text` node with no token.
981
+ *
982
+ * @public
983
+ */
984
+ type InlineInput = string | Inline | ReadonlyArray<string | Inline>;
985
+ /**
986
+ * A tree node as a constructor accepts it: the label may be a string and `children` may be left out.
987
+ *
988
+ * @public
989
+ */
990
+ interface TreeInput {
991
+ /** What the node says. */
992
+ readonly label: InlineInput;
993
+ /** Its children; none when omitted. */
994
+ readonly children?: ReadonlyArray<TreeInput>;
995
+ }
996
+ /**
997
+ * The inline node with a given `_tag`, so a constructor can return its precise type.
998
+ *
999
+ * @public
1000
+ */
1001
+ type InlineOf<Tag extends Inline["_tag"]> = Extract<Inline, {
1002
+ readonly _tag: Tag;
1003
+ }>;
1004
+ /**
1005
+ * The block node with a given `_tag`, so a constructor can return its precise type.
1006
+ *
1007
+ * @public
1008
+ */
1009
+ type BlockOf<Tag extends Block["_tag"]> = Extract<Block, {
1010
+ readonly _tag: Tag;
1011
+ }>;
1012
+ /**
1013
+ * The cap and overflow options of a list or table.
1014
+ *
1015
+ * @public
1016
+ */
1017
+ interface OverflowOptions {
1018
+ /** The most rows to show; the renderer hides the rest. */
1019
+ readonly cap?: number;
1020
+ /** Says what the hidden rows amount to, given how many there are; it is a function and is never serialised. */
1021
+ readonly overflow?: (hidden: number) => InlineInput;
1022
+ }
1023
+ /**
1024
+ * The options of {@link Doc.counts}.
1025
+ *
1026
+ * @public
1027
+ */
1028
+ interface CountsOptions {
1029
+ /** A leading label. */
1030
+ readonly label?: InlineInput;
1031
+ /** The counters, in the order they are shown. */
1032
+ readonly counters: ReadonlyArray<Counter>;
1033
+ /** Replaces the default total, the sum of `n` over every counter, for example to fold timed-out runs in. */
1034
+ readonly total?: (counters: ReadonlyArray<Counter>) => number;
1035
+ /** Text after the counters, such as `(1 flaky)`. */
1036
+ readonly qualifier?: InlineInput;
1037
+ /** How long it took, in milliseconds. */
1038
+ readonly durationMs?: number;
1039
+ /** How the counters are laid out. */
1040
+ readonly layout: "inline" | "columns" | "row";
1041
+ /** Whether the first counter shows its share of the total, `n/total`; `true` by default. `false` shows `n label`. */
1042
+ readonly share?: boolean;
1043
+ /**
1044
+ * What is painted: `all` (the default) paints the counters, the label, the qualifier and the duration; `glyph`
1045
+ * paints only a status glyph, if one is shown; `none` paints nothing.
1046
+ */
1047
+ readonly paint?: "all" | "glyph" | "none";
1048
+ /** Text after the duration, such as `across 3 files`. */
1049
+ readonly suffix?: InlineInput;
1050
+ }
1051
+ /**
1052
+ * Options for {@link Doc.print}.
1053
+ *
1054
+ * @public
1055
+ */
1056
+ interface DocPrintOptions {
1057
+ /** The stream to write to; `stdout` by default. */
1058
+ readonly stream?: "stdout" | "stderr" | undefined;
1059
+ /**
1060
+ * The renderer. `auto`, the default, is chosen from the audience: `plain` for an agent, `githubLog` for a CI
1061
+ * that `CurrentRuntimeEnv` says is GitHub Actions and `plain` for any other, and `ansi` for a human.
1062
+ */
1063
+ readonly format?: "auto" | "plain" | "ansi" | "markdown" | "githubLog" | undefined;
1064
+ /** Turns an absolute path into its display form, for example relative to the workspace; see `Render.context`. */
1065
+ readonly displayPath?: ((absolute: string) => string) | undefined;
1066
+ /** The display columns to lay out at, replacing the audience's default; see `Render.context`. */
1067
+ readonly width?: number | undefined;
1068
+ }
1069
+ /**
1070
+ * Constructors for the document IR, and two helpers a renderer shares.
1071
+ *
1072
+ * @remarks
1073
+ * Every constructor returns a frozen node and copies the arrays it is given, so editing an input afterwards
1074
+ * cannot change a document. An optional field that is not given is absent from the node, not `undefined`.
1075
+ * Content arguments accept a string, an `Inline` or an array of either.
1076
+ *
1077
+ * A node is plain data: nothing decodes or encodes one, so a function field such as `overflow` or `total` is fine
1078
+ * and a document is not meant to be serialised.
1079
+ *
1080
+ * Freezing covers what a `Doc` constructor builds. A literal you write by hand is not frozen, and a `Style` object
1081
+ * given as a token is shared by reference (the freeze of a status definition is shallow for the same reason).
1082
+ *
1083
+ * @example
1084
+ * ```ts
1085
+ * import { Doc, Status } from "@effected/cli-kit"
1086
+ *
1087
+ * const report = [
1088
+ * Doc.heading(2, "Results"),
1089
+ * Doc.paragraph(Doc.status(Status.core, "success"), " ", "3 checks passed"),
1090
+ * Doc.table([{ header: "Check" }, { header: "Time", align: "right" }], [["lint", "1.2s"]]),
1091
+ * ]
1092
+ * // Written for whoever is reading: `yield* Doc.print(report)`
1093
+ * ```
1094
+ *
1095
+ * @public
1096
+ */
1097
+ export declare class Doc {
1098
+ private constructor();
1099
+ /**
1100
+ * A run of text.
1101
+ *
1102
+ * @param value - the text
1103
+ * @param token - a semantic token or a style to paint it with
1104
+ */
1105
+ static text(value: string, token?: TokenName | Style): InlineOf<"Text">;
1106
+ /**
1107
+ * Code in a monospace span.
1108
+ *
1109
+ * @param value - the code
1110
+ */
1111
+ static code(value: string): InlineOf<"Code">;
1112
+ /**
1113
+ * A link to a URL or a file position.
1114
+ *
1115
+ * @param target - `{ url }` or `{ file, line?, col? }`
1116
+ * @param label - what the link says; when omitted, the bare URL or file path, which leaves out `line` and `col`
1117
+ * @param options - `suffix`, whether the target follows the label where the link cannot be followed
1118
+ */
1119
+ static link(target: LinkTarget, label?: InlineInput, options?: LinkOptions): InlineOf<"Link">;
1120
+ /**
1121
+ * A link when there is a target, and its label alone when there is none: a string label as a `Text`, any other
1122
+ * inline as itself.
1123
+ *
1124
+ * @param target - `{ url }`, `{ file, line?, col? }`, or `undefined` for no link
1125
+ * @param label - what the link says
1126
+ * @param options - `suffix`, whether the target follows the label where the link cannot be followed
1127
+ */
1128
+ static link(target: LinkTarget | undefined, label: string | Inline, options?: LinkOptions): Inline;
1129
+ /**
1130
+ * A status glyph, holding the resolved definition.
1131
+ *
1132
+ * @remarks
1133
+ * A name the vocabulary does not have is a compile error.
1134
+ *
1135
+ * @param vocab - the vocabulary the name belongs to
1136
+ * @param name - a status name in it
1137
+ */
1138
+ static status<N extends string>(vocab: Status<N>, name: NoInfer<N>): InlineOf<"StatusMark">;
1139
+ /**
1140
+ * Content in bold: markdown `**…**`, bold in `ansi`, and the content as is in plain and `githubLog`.
1141
+ *
1142
+ * @param content - any number of strings, inlines or arrays of them, in order
1143
+ */
1144
+ static strong(...content: Array<InlineInput>): InlineOf<"Strong">;
1145
+ /**
1146
+ * Content in italic: markdown `*…*` (which GFM reads inside a word too), italic in `ansi`, and the content as is in
1147
+ * plain and `githubLog`.
1148
+ *
1149
+ * @param content - any number of strings, inlines or arrays of them, in order
1150
+ */
1151
+ static em(...content: Array<InlineInput>): InlineOf<"Emphasis">;
1152
+ /**
1153
+ * A file path, shown through the context's `displayPath` and never linked.
1154
+ *
1155
+ * @param path - the path, usually absolute
1156
+ */
1157
+ static file(path: string): InlineOf<"File">;
1158
+ /**
1159
+ * A path or breadcrumb; a renderer joins the segments with the audience's separator.
1160
+ *
1161
+ * @param segments - the segments, in order
1162
+ */
1163
+ static path(...segments: Array<string>): InlineOf<"Path">;
1164
+ /**
1165
+ * A heading.
1166
+ *
1167
+ * @param level - 1 to 4
1168
+ * @param content - the heading text
1169
+ */
1170
+ static heading(level: 1 | 2 | 3 | 4, content: InlineInput): BlockOf<"Heading">;
1171
+ /**
1172
+ * One logical line of content.
1173
+ *
1174
+ * @param content - any number of strings, inlines or arrays of them, in order
1175
+ */
1176
+ static paragraph(...content: Array<InlineInput>): BlockOf<"Paragraph">;
1177
+ /**
1178
+ * A list of blocks.
1179
+ *
1180
+ * @param items - the items
1181
+ * @param options - `cap`, `overflow`, and `compact` for no blank lines inside an item
1182
+ */
1183
+ static list(items: ReadonlyArray<Block>, options?: ListOptions): BlockOf<"List">;
1184
+ /**
1185
+ * A table.
1186
+ *
1187
+ * @param columns - the columns: a header and an optional alignment each
1188
+ * @param rows - the rows; each cell takes a string, an inline or an array of either
1189
+ * @param options - `cap`, `overflow`, and `style: "pipe"` for istanbul's shape in plain and `ansi`
1190
+ */
1191
+ static table(columns: ReadonlyArray<{
1192
+ readonly header: InlineInput;
1193
+ readonly align?: "left" | "right" | "center";
1194
+ }>, rows: ReadonlyArray<ReadonlyArray<InlineInput>>, options?: TableOptions): BlockOf<"Table">;
1195
+ /**
1196
+ * A tree of labels.
1197
+ *
1198
+ * @param root - the root; a node's `children` may be left out
1199
+ */
1200
+ static tree(root: TreeInput): BlockOf<"Tree">;
1201
+ /**
1202
+ * A titled body a renderer may fold.
1203
+ *
1204
+ * @param title - the title
1205
+ * @param body - the body
1206
+ * @param options - `open` asks for it to start unfolded
1207
+ */
1208
+ static collapsible(title: InlineInput, body: ReadonlyArray<Block>, options?: {
1209
+ readonly open?: boolean;
1210
+ }): BlockOf<"Collapsible">;
1211
+ /**
1212
+ * A callout.
1213
+ *
1214
+ * @param kind - `note`, `tip`, `important`, `warning` or `caution`
1215
+ * @param body - the body
1216
+ */
1217
+ static callout(kind: "note" | "tip" | "important" | "warning" | "caution", body: ReadonlyArray<Block>): BlockOf<"Callout">;
1218
+ /**
1219
+ * Preformatted text.
1220
+ *
1221
+ * @param text - the text
1222
+ * @param lang - its language, for a renderer that fences it
1223
+ */
1224
+ static codeBlock(text: string, lang?: string): BlockOf<"CodeBlock">;
1225
+ /**
1226
+ * Expected against received text.
1227
+ *
1228
+ * @param expected - the expected text
1229
+ * @param received - the received text
1230
+ * @param options - `cap` limits the lines shown
1231
+ */
1232
+ static diff(expected: string, received: string, options?: {
1233
+ readonly cap?: number;
1234
+ }): BlockOf<"Diff">;
1235
+ /**
1236
+ * Children under an optional title.
1237
+ *
1238
+ * @remarks
1239
+ * The children are separated by blank lines (unless the document is compact); a title sits directly above the first.
1240
+ * `Doc.section(undefined, blocks)` is the way to space a document's top-level blocks, which are otherwise joined with
1241
+ * no blank line.
1242
+ *
1243
+ * @param title - the title, or `undefined` for none
1244
+ * @param children - the blocks
1245
+ */
1246
+ static section(title: InlineInput | undefined, children: ReadonlyArray<Block>): BlockOf<"Section">;
1247
+ /**
1248
+ * One counter of a `Counts` block, with its status definition resolved.
1249
+ *
1250
+ * @remarks
1251
+ * A name the vocabulary does not have is a compile error.
1252
+ *
1253
+ * The label is one string, or `{ one, other }` to pluralise by count: `one` when the count is exactly 1 and `other`
1254
+ * for every other count, 0 included. A count standing alone reads by its own `n` (`1 change`, `2 changes`); a
1255
+ * headline shown as a share of the total reads by that total, the noun it counts (`1/1 repo`, `1/3 repos`,
1256
+ * `2/3 repos`).
1257
+ *
1258
+ * @param vocab - the vocabulary the status belongs to
1259
+ * @param name - a status name in it
1260
+ * @param options - the counter's `key`, its `label` (one string, or `{ one, other }`), its count `n`, and `showZero`
1261
+ * to keep it when `n` is zero
1262
+ */
1263
+ static counter<N extends string>(vocab: Status<N>, name: NoInfer<N>, options: {
1264
+ readonly key: string;
1265
+ readonly label: string | {
1266
+ readonly one: string;
1267
+ readonly other: string;
1268
+ };
1269
+ readonly n: number;
1270
+ readonly showZero?: boolean;
1271
+ }): Counter;
1272
+ /**
1273
+ * Counters in one of three layouts.
1274
+ *
1275
+ * @param options - the counters, the layout and the optional label, total rule, qualifier and duration
1276
+ */
1277
+ static counts(options: CountsOptions): BlockOf<"Counts">;
1278
+ /**
1279
+ * Counters as a table: a row per entry, a column per counter key (in the order the keys first appear, headed by
1280
+ * the counter's label), and an optional total row summing each column.
1281
+ *
1282
+ * @remarks
1283
+ * A row without a counter for some key leaves that cell empty, and it counts as zero in the total. A counter whose
1284
+ * `n` is zero shows `0`, as a `Doc.table` cell would: a counter's `showZero` has no effect in a table, only in a
1285
+ * `Counts` block, so there is no need to set it. `totalRow`
1286
+ * labels the total row with a plain `Total` when `true`, or with the content given: for a bold one, pass
1287
+ * `totalRow: Doc.strong("Total")`. A column is headed by its counter's `label`; a counter's status paints its cells
1288
+ * in `ansi` and is ignored in markdown, so a plain numbers table may pass any status. `labelHeader` heads the label column, which
1289
+ * is otherwise empty. When some row has a `durationMs`, a last column shows it with `Fmt.duration`, headed
1290
+ * `durationHeader` (`duration` by default); a row without one has an empty cell there and counts as zero in the
1291
+ * total row's summed duration.
1292
+ *
1293
+ * @param rows - each row's label, counters and optional duration
1294
+ * @param options - `totalRow`, to add the summed row; the label and duration column headers
1295
+ */
1296
+ static countsTable(rows: ReadonlyArray<{
1297
+ readonly label: InlineInput;
1298
+ readonly counters: ReadonlyArray<Counter>;
1299
+ readonly durationMs?: number;
1300
+ }>, options?: CountsTableOptions): BlockOf<"CountsTable">;
1301
+ /**
1302
+ * Lines, one per entry, in every renderer: markdown joins them with hard breaks so they never collapse into one.
1303
+ *
1304
+ * @remarks
1305
+ * `truncate` and `wrap: false` hold for every entry as they do for {@link Doc.line}: each entry is cut to the width,
1306
+ * or kept whole on one line, rather than wrapped. Markdown keeps every entry whole either way.
1307
+ *
1308
+ * @param lines - the entries; each takes a string, an inline or an array of either
1309
+ * @param options - `truncate`, to cut each entry to the width; `wrap: false`, to keep each whole
1310
+ */
1311
+ static lines(lines: ReadonlyArray<InlineInput>, options?: {
1312
+ readonly truncate?: boolean;
1313
+ readonly wrap?: boolean;
1314
+ }): BlockOf<"Lines">;
1315
+ /**
1316
+ * One line of content; with `truncate`, it is cut to the width with the glyph set's ellipsis instead of wrapping,
1317
+ * and with `wrap: false` it is kept whole on one line whatever the width.
1318
+ *
1319
+ * @remarks
1320
+ * By default a line longer than the width wraps. `wrap: false` keeps it atomic in every audience and renderer, still
1321
+ * carrying its status glyphs, theme tokens and links, which {@link Doc.verbatim} (a plain string) cannot: the tool for
1322
+ * a finding such as `✗ path:line:col rule message` that a reader greps or reads line by line, while the prose around
1323
+ * it still wraps. A line break inside it is still a space. With both `truncate` and `wrap: false`, `truncate` wins:
1324
+ * the line is cut to the width.
1325
+ *
1326
+ * @param content - the line
1327
+ * @param options - `truncate`, to cut it to the width; `wrap: false`, to keep it whole
1328
+ */
1329
+ static line(content: InlineInput, options?: {
1330
+ readonly truncate?: boolean;
1331
+ readonly wrap?: boolean;
1332
+ }): BlockOf<"Line">;
1333
+ /**
1334
+ * A unified diff as given, such as a test runner's: sanitized, its `+` and `-` lines painted `success` and
1335
+ * `failure` in `ansi`, and a `diff` fence in markdown.
1336
+ *
1337
+ * @remarks
1338
+ * With `truncate`, plain and `ansi` cut each line to the width with the glyph set's ellipsis instead of wrapping
1339
+ * it; an agent's or a CI's width is unbounded, so nothing is cut for them unless the context gives a finite width.
1340
+ * Markdown keeps every line whole. Inside a compact list item a blank line of the diff keeps the item's indent.
1341
+ *
1342
+ * A trailing line break ends the last line, as in a unified diff file, and adds no blank line after it: `"a\n"` is
1343
+ * one line. To end on a blank line, end the text with two line breaks.
1344
+ *
1345
+ * @param unified - the diff
1346
+ * @param options - `cap`, the most lines shown; `truncate`, to cut each line to the width
1347
+ */
1348
+ static diffText(unified: string, options?: {
1349
+ readonly cap?: number;
1350
+ readonly truncate?: boolean;
1351
+ }): BlockOf<"DiffText">;
1352
+ /**
1353
+ * Lines kept exactly: each indented by `indent` spaces, sanitized, and never wrapped.
1354
+ *
1355
+ * @remarks
1356
+ * Plain, `ansi` and `githubLog` write the lines as they are; markdown fences them, so the indentation survives.
1357
+ *
1358
+ * It is the tool for a single line that must never wrap nor be cut, whatever the width: {@link Doc.line} wraps at
1359
+ * the width, or cuts with `truncate`, and `verbatim` does neither.
1360
+ *
1361
+ * @param text - the lines
1362
+ * @param options - `indent`, the spaces in front of every line; none by default
1363
+ */
1364
+ static verbatim(text: string, options?: {
1365
+ readonly indent?: number;
1366
+ }): BlockOf<"Verbatim">;
1367
+ /**
1368
+ * A GitHub Actions annotation: `Render.githubLog` writes it as one workflow command (`::error file=…::message`),
1369
+ * and every other renderer writes nothing.
1370
+ *
1371
+ * @remarks
1372
+ * It is the kit's own command, so `githubLog` does not neutralize the command itself; its message and properties are
1373
+ * escaped, so no text in them can end the command or start another, and a `##[` in its message, title or file gets
1374
+ * a braille pattern blank (U+2800) before the `[`, as in plain text. It is a command where a line starts: at the top level, as a
1375
+ * top-level section's child, or as a direct child of a group's body. Nested deeper, it is dropped.
1376
+ *
1377
+ * @param options - the level, and the optional file, position and title
1378
+ * @param message - what it says
1379
+ */
1380
+ static annotation(options: AnnotationOptions, message: string): BlockOf<"Annotation">;
1381
+ /**
1382
+ * The total of a `Counts` block: the caller's rule when it has one, otherwise the sum of `n` over every counter.
1383
+ *
1384
+ * @remarks
1385
+ * The rule sees every counter, including the ones a renderer hides, so hiding never changes the total.
1386
+ *
1387
+ * @param block - the `Counts` block
1388
+ */
1389
+ static total(block: BlockOf<"Counts">): number;
1390
+ /**
1391
+ * The counters a renderer shows: every one except a zero counter that does not ask for `showZero`.
1392
+ *
1393
+ * @param block - the `Counts` block
1394
+ */
1395
+ static visibleCounters(block: BlockOf<"Counts">): ReadonlyArray<Counter>;
1396
+ /**
1397
+ * Render a document for whoever is running the program and write it to a stream.
1398
+ *
1399
+ * @remarks
1400
+ * The context is {@link Render.context} for the stream, so the width, the colour, the links and the audience
1401
+ * come from the services the program already has, and the text is written with `Console.log` or
1402
+ * `Console.error`: a test captures it by swapping the `Console`. With `format: "auto"` the renderer follows
1403
+ * the audience, and the width is unbounded for an agent, a CI, and a human whose stream is not a terminal.
1404
+ *
1405
+ * An agent is never written an escape of any kind, even with an explicit `format: "ansi"`: its context is
1406
+ * colourless and its links are off. A document that renders to nothing prints nothing.
1407
+ *
1408
+ * The whole document is written as one `Console.log` (or `Console.error`) call, with its line breaks embedded, so a
1409
+ * captured `Console` holds one entry per document, not one per line. Top-level blocks are joined with no blank
1410
+ * line between them; wrap them in `Doc.section(undefined, [...])` to space them.
1411
+ *
1412
+ * `CurrentRuntimeEnv` is read if the environment has one and is not required: a `ci` audience prints
1413
+ * GitHub's log format only when it says GitHub Actions, and plain text otherwise, including when it is
1414
+ * absent. An explicit `format` is honoured whatever the audience.
1415
+ *
1416
+ * The context is built here, at print time, so it carries the fiber's count of open Actions log groups
1417
+ * (`RenderContext.groupDepth`): printed inside an `ActionLogger.group` from `@effected/github-actions`, a
1418
+ * document's top-level collapsible renders as plain text rather than as a second `::group::`, which would end
1419
+ * the open one at the runner.
1420
+ *
1421
+ * @param doc - the document
1422
+ * @param options - the stream and the format
1423
+ */
1424
+ static readonly print: (doc: Document, options?: DocPrintOptions) => Effect.Effect<void, never, CliTheme | TerminalEnv | Audience | CliLinks>;
1425
+ }
1426
+ /**
1427
+ * Whether file links open in an editor.
1428
+ *
1429
+ * @remarks
1430
+ * `vscode` writes `vscode://file/<path>:<line>:<col>`, `file` writes `file://<path>`, `off` writes no file link, and
1431
+ * `auto` picks `vscode` when it finds a signal of VS Code and `file` otherwise.
1432
+ *
1433
+ * @public
1434
+ */
1435
+ type EditorLinks = "auto" | "vscode" | "file" | "off";
1436
+ /**
1437
+ * The shape of the {@link CliLinks} service: the mode decided, and the URL a link target becomes.
1438
+ *
1439
+ * @public
1440
+ */
1441
+ interface CliLinksShape {
1442
+ /** The mode `auto` resolved to, or the one that was asked for. */
1443
+ readonly mode: "vscode" | "file" | "off";
1444
+ /**
1445
+ * The URL a target opens, or `None` when it has none.
1446
+ *
1447
+ * @remarks
1448
+ * A `{ url }` target is its URL, whatever the mode. A `{ file }` target is `vscode://file/<path>:<line>:<col>` or
1449
+ * `file://<path>`, with the path URL-encoded; `off` gives it none, and so does a relative path when the layer
1450
+ * has no working directory to resolve it against. A column needs a line.
1451
+ */
1452
+ readonly target: (target: LinkTarget) => Option.Option<string>;
1453
+ }
1454
+ /**
1455
+ * Options for {@link CliLinks.layer}.
1456
+ *
1457
+ * @public
1458
+ */
1459
+ interface CliLinksOptions {
1460
+ /** The setting, `auto` by default. An environment variable the consumer names beats it. */
1461
+ readonly editorLinks?: EditorLinks | undefined;
1462
+ /** The environment variable that overrides the setting, read through `Config`. Not read unless named. */
1463
+ readonly envVar?: string | undefined;
1464
+ /** The working directory; `PWD` through `Config`, then `Path.resolve(".")`, when omitted. */
1465
+ readonly cwd?: string | undefined;
1466
+ }
1467
+ /**
1468
+ * The options of {@link CliLinks.linker}.
1469
+ *
1470
+ * @public
1471
+ */
1472
+ interface CliLinksLinkerOptions {
1473
+ /** The service that turns a target into a URL. */
1474
+ readonly links: CliLinksShape;
1475
+ /** Whether the stream's terminal renders OSC 8 hyperlinks. */
1476
+ readonly hyperlinks: boolean;
1477
+ /** Who the output is for. */
1478
+ readonly audience: AudienceKind;
1479
+ }
1480
+ declare const CliLinks_base: Context.ServiceClass<CliLinks, "@effected/cli-kit/CliLinks", CliLinksShape>;
1481
+ /**
1482
+ * Editor-aware links for file targets: where a link to a file opens.
1483
+ *
1484
+ * @remarks
1485
+ * The mode is decided once, when the layer is built. `auto` is `vscode` when `CurrentRuntimeEnv.terminal` is
1486
+ * `vscode` (`TERM_PROGRAM=vscode`) or a `.vscode/` directory sits at the project root, and `file` otherwise. The
1487
+ * root is the nearest directory, from the working directory up, that holds `.git` or `pnpm-workspace.yaml`; the
1488
+ * climb is bounded, at most 64 directories above the working directory, and stops where `Path.dirname` reaches the
1489
+ * filesystem root. With no root, the working directory itself is checked.
1490
+ *
1491
+ * Whether a link is written at all is a separate question, answered by {@link CliLinks.linker}.
1492
+ *
1493
+ * @public
1494
+ */
1495
+ export declare class CliLinks extends CliLinks_base {
1496
+ /**
1497
+ * The links for the working directory, reading the filesystem for a `.vscode/` directory.
1498
+ *
1499
+ * @remarks
1500
+ * A layer-returning function mints a fresh layer per call: call it once and bind the result to a constant.
1501
+ *
1502
+ * @param options - the setting, the environment variable that overrides it, and the working directory
1503
+ */
1504
+ static readonly layer: (options?: CliLinksOptions) => Layer.Layer<CliLinks, never, FileSystem.FileSystem | Path.Path | CurrentRuntimeEnv>;
1505
+ /**
1506
+ * Links fixed to a mode, with no filesystem: a relative path has no link, since there is no working directory.
1507
+ *
1508
+ * @param mode - `vscode`, `file` or `off`
1509
+ */
1510
+ static readonly layerTest: (mode: "vscode" | "file" | "off") => Layer.Layer<CliLinks>;
1511
+ /**
1512
+ * The function that writes a link: a target and a label in, the label out, wrapped in OSC 8 when it should be.
1513
+ *
1514
+ * @remarks
1515
+ * It writes the hyperlink `ESC ] 8 ; ; URL ESC \ label ESC ] 8 ; ; ESC \` only when the stream's terminal can
1516
+ * render it (`hyperlinks`) and the audience is not an agent, which never gets an escape of any kind; in every other
1517
+ * case, and whenever the target has no URL, it returns the label unchanged. The URL has its control characters
1518
+ * removed again here, so a hostile target cannot end the sequence early or start another, and a URL whose scheme is
1519
+ * not one a link may have (`javascript:`, `data:`, and the like; the same list markdown uses) is the label alone. It is pure and cheap,
1520
+ * which {@link RenderContext}'s `link` requires.
1521
+ *
1522
+ * @param options - the links, whether hyperlinks are available, and the audience
1523
+ */
1524
+ static readonly linker: (options: CliLinksLinkerOptions) => (target: LinkTarget, label: string) => string;
1525
+ }
1526
+ /**
1527
+ * How a log record is turned into a line.
1528
+ *
1529
+ * @public
1530
+ */
1531
+ interface CliLoggerOptions {
1532
+ /**
1533
+ * Render one message. Defaults to joining an array with spaces and
1534
+ * `String`-ing anything else.
1535
+ *
1536
+ * @remarks
1537
+ * An array arrives because `Effect.log("synced", 3, "repos")` is variadic.
1538
+ *
1539
+ * The text is sanitised, because it is whatever the program logged: with the default render, the line has its
1540
+ * escape sequences and control characters removed (a line break stays one, a tab becomes a space); with yours, you
1541
+ * receive the string parts already sanitised and own what you add, a colour included. Under GitHub Actions, where
1542
+ * `CurrentRuntimeEnv` says so, a line the runner would read as a workflow command is neutralized either way.
1543
+ *
1544
+ * The logger reads `CurrentRuntimeEnv` from the logging fiber's context, so a line logged outside its scope
1545
+ * (`CliLogger.layer()` provided alone, with no `CurrentRuntimeEnv`, or the warnings logged while `CliRuntime.main`
1546
+ * builds its environment) is sanitised but not neutralized. Provide the environment around the program, as `main`
1547
+ * does, for the neutralizing to apply.
1548
+ */
1549
+ readonly render?: ((message: unknown) => string) | undefined;
1550
+ /**
1551
+ * The level at and above which output goes to stderr. Defaults to `"All"`,
1552
+ * so every log level is a diagnostic and stdout carries only what the
1553
+ * program writes with `Console.log`.
1554
+ *
1555
+ * @remarks
1556
+ * Pass `"Error"` to send only errors to stderr, for a tool whose output *is*
1557
+ * its log lines rather than a separate document written with
1558
+ * `Console.log`.
1559
+ */
1560
+ readonly stderrFrom?: LogLevel.LogLevel | undefined;
1561
+ }
1562
+ /**
1563
+ * A `Logger` that renders CLI output rather than service logs: no timestamp, level or fiber id, with every level
1564
+ * going to stderr by default so stdout carries only what the program writes.
1565
+ *
1566
+ * @remarks
1567
+ * Effect's default logger emits `[00:33:56.619] INFO (#2): message`. That is
1568
+ * the right shape for a long-running service being scraped and the wrong one
1569
+ * for a tool a person is watching: the timestamp, level and fiber id are noise
1570
+ * in front of output a human is reading, and they make a formatted block — a
1571
+ * permissions table, a summary — unreadable.
1572
+ *
1573
+ * **A program that never installs a CLI logger looks correct in review and
1574
+ * ships timestamps to its users**, so install this one at the program's
1575
+ * boundary.
1576
+ *
1577
+ * It writes through the `Console` reference read off the logging fiber,
1578
+ * synchronously, as core's own default logger does: `Logger.make` takes a
1579
+ * synchronous callback, and a `Stdio` sink write is an `Effect` a logger cannot
1580
+ * `yield*`. `Console.Console` is a `Context.Reference`, so it never appears in
1581
+ * `R`, and a test swaps the reference rather than stubbing a global.
1582
+ *
1583
+ * @example
1584
+ * ```ts
1585
+ * import { CliLogger } from "@effected/cli-kit"
1586
+ * import { Console, Effect } from "effect"
1587
+ *
1588
+ * const program = Effect.gen(function* () {
1589
+ * yield* Effect.log("synced 3 repos") // stderr, no timestamp — a diagnostic
1590
+ * yield* Console.log("3 repos synced") // stdout — the program's actual output
1591
+ * yield* Effect.logError("one failed") // stderr
1592
+ * })
1593
+ *
1594
+ * program.pipe(Effect.provide(CliLogger.layer()))
1595
+ * ```
1596
+ *
1597
+ * `stderrFrom` defaults to `"All"`: a CLI's stdout is its product, so every
1598
+ * log level is a diagnostic unless a consumer narrows the threshold. Write
1599
+ * program output with `Console.log`, never `Effect.log`. Pass
1600
+ * `stderrFrom: "Error"` for a tool whose output *is* its log lines.
1601
+ *
1602
+ * @public
1603
+ */
1604
+ export declare class CliLogger {
1605
+ private constructor();
1606
+ /**
1607
+ * The logger itself, for composing into an existing `Logger.layer` set.
1608
+ *
1609
+ * @remarks
1610
+ * Prefer {@link CliLogger.layer}. Reach for this only when you are building
1611
+ * the logger set yourself and want this one among several.
1612
+ */
1613
+ static readonly make: (options?: CliLoggerOptions) => Logger.Logger<unknown, void>;
1614
+ /**
1615
+ * Replace the default logger with this one.
1616
+ *
1617
+ * @remarks
1618
+ * `Logger.layer` **replaces** rather than merges, so nothing is emitted twice.
1619
+ *
1620
+ * Merge this into the layer you provide to the whole program rather than
1621
+ * providing it beneath: merged, it also covers lines emitted during layer
1622
+ * construction, which is exactly where a startup failure prints.
1623
+ */
1624
+ static readonly layer: (options?: CliLoggerOptions) => Layer.Layer<never>;
1625
+ }
1626
+ /**
1627
+ * Options for `CliLog.status`.
1628
+ *
1629
+ * @public
1630
+ */
1631
+ interface CliLogStatusOptions {
1632
+ /**
1633
+ * The level the line is logged at. By default it follows the status's rank in its vocabulary: `Error` at or above
1634
+ * `failure`'s rank, `Warn` at or above `warning`'s, and `Info` below that.
1635
+ */
1636
+ readonly level?: LogLevel.Severity | undefined;
1637
+ /**
1638
+ * What the line starts with, before the glyph, so an indented report line keeps its place in a block: a number of
1639
+ * spaces (floored, at most 64; zero, a negative or a non-finite number is none), or a string. A string is sanitised as text is (escapes and controls removed, a tab a space) and its line
1640
+ * breaks dropped, so the indent can never carry an escape onto the trusted line. None by default.
1641
+ */
1642
+ readonly indent?: number | string | undefined;
1643
+ }
1644
+ /**
1645
+ * Options for `CliLog.layer`.
1646
+ *
1647
+ * @public
1648
+ */
1649
+ interface CliLogOptions {
1650
+ /**
1651
+ * The diagnostics level, for a host that has already decided it.
1652
+ *
1653
+ * @remarks
1654
+ * Beats `envVar`, which is then not read at all (so a bad value there neither warns nor overrides this), and
1655
+ * loses to core's `--log-level` flag like every diagnostics level: the sink follows the flag while it is set.
1656
+ */
1657
+ readonly level?: LogLevel.LogLevel | undefined;
1658
+ /**
1659
+ * The environment variable that sets the diagnostics level, for example `MYTOOL_LOG_LEVEL`. Read through
1660
+ * `Config`, never `process`. Unset or empty means `None`. Ignored when `level` is given.
1661
+ */
1662
+ readonly envVar?: string | undefined;
1663
+ /**
1664
+ * Whether to install the plain `CliLogger` for ordinary lines. `true` by default.
1665
+ *
1666
+ * @remarks
1667
+ * `false` is the diagnostics-only mode for a library host (an MCP server, a test reporter): the layer installs
1668
+ * only the diagnostics sink, the file sink if any, and `extraLoggers`. With no level set as well, stderr gets
1669
+ * no output. An invalid level in `envVar` still prints its one warning line, through a private `CliLogger`,
1670
+ * since that is a configuration error the host should see.
1671
+ *
1672
+ * Only `CliLog`'s own records are silenced. Under `CliRuntime.main`, what the platform logs while it builds follows
1673
+ * the build-time format: in NDJSON (`json`, or `auto` for an agent or a CI) it goes through this layer, so `false`
1674
+ * silences it there as at runtime; otherwise it goes through a plain `CliLogger`, routed by `logger.stderrFrom` as the
1675
+ * host set it. The audience-override warning is a
1676
+ * configuration error and is never silenced: it is written exactly once, as NDJSON when the build-time format is
1677
+ * NDJSON and as a plain line otherwise, whatever this option says, to stderr alone (never stdout, whatever
1678
+ * `logger.stderrFrom` says) and never to `extraLoggers` or the file sink. The failure report and the `CliMessage` lines
1679
+ * always go through a plain `CliLogger`.
1680
+ */
1681
+ readonly plainLogger?: boolean | undefined;
1682
+ /**
1683
+ * `json` is NDJSON, `pretty` a human line, `auto` (the default) decides by the audience alone: NDJSON for an agent
1684
+ * or a CI, the pretty `CliLogger` line for a human, at build time and at runtime alike.
1685
+ *
1686
+ * @remarks
1687
+ * Stderr's terminal state is never consulted, so a human piping stderr to a file gets plain lines, never a mix of
1688
+ * plain and NDJSON; colour still follows `stderr.color`, so those lines carry no escapes when stderr is not a colour
1689
+ * terminal. Pass `format: "json"` for machine-readable logs whoever runs the program.
1690
+ *
1691
+ * Under `CliRuntime.main` with `env.log`, what the platform logs while it builds is written before the platform
1692
+ * provides the terminal or the arguments, so `auto` decides those lines from what needs no platform: an audience
1693
+ * flag in {@link CliLogOptions.argv}, else the audience override variable (`env.audienceEnvVar`), else agent and
1694
+ * CI detection from the environment. An agent or a CI gets NDJSON, as its runtime lines are; anything else gets
1695
+ * a plain line, the same choice the runtime lines make. `json` is NDJSON and `pretty` plain throughout.
1696
+ */
1697
+ readonly format?: "auto" | "json" | "pretty" | undefined;
1698
+ /**
1699
+ * The program's arguments, for the format of what the platform logs while it builds under `CliRuntime.main` with
1700
+ * `format: "auto"`: an audience flag (`--agent`, `--ci`, `--human`, `--audience <kind>`) in them decides those
1701
+ * lines as it decides the run's. Only `CliRuntime.main` reads this.
1702
+ *
1703
+ * @remarks
1704
+ * The arguments core parses come from the platform's `Stdio`, which does not exist until the platform is built, and
1705
+ * this package never reads `process`. A Node host passes `process.argv.slice(2)`; without it the build-time lines
1706
+ * follow the environment alone, so `--agent` with no agent detected gets plain lines until the platform is built.
1707
+ */
1708
+ readonly argv?: ReadonlyArray<string> | undefined;
1709
+ /** Options for the `CliLogger` this layer builds for ordinary log lines; see {@link CliLoggerOptions}. */
1710
+ readonly logger?: CliLoggerOptions | undefined;
1711
+ /**
1712
+ * Loggers to keep beside the `CliLogger` and the sink, for example a telemetry logger: the layer owns the
1713
+ * whole set, so anything not listed here is dropped.
1714
+ *
1715
+ * @remarks
1716
+ * Each is floored at the `MinimumLogLevel` it had, like the `CliLogger`, so lowering the level for the
1717
+ * diagnostics sink never makes it see records it would not have seen otherwise.
1718
+ */
1719
+ readonly extraLoggers?: ReadonlyArray<Logger.Logger<unknown, unknown>> | undefined;
1720
+ /**
1721
+ * Whether a line the GitHub Actions runner would read as a workflow command is neutralized. `auto`, the default,
1722
+ * follows the `CurrentRuntimeEnv` of the fiber that logs, and where that fiber has none, `runtimeEnv`, else the one
1723
+ * the layer was built with: a host that builds this layer over its environment covers records logged outside it
1724
+ * too. `true` always neutralizes, `false` never does.
1725
+ */
1726
+ readonly neutralize?: boolean | "auto" | undefined;
1727
+ /**
1728
+ * The runtime environment `neutralize: "auto"` falls back to for a record whose fiber has no `CurrentRuntimeEnv`.
1729
+ *
1730
+ * @remarks
1731
+ * Given, it is used in place of the `CurrentRuntimeEnv` the layer captured when it was built, and beats it; the
1732
+ * logging fiber's own `CurrentRuntimeEnv` still comes first. The capture is invisible in the layer's type (it is read
1733
+ * if present, never required), so a host that builds this layer outside its environment either passes the snapshot
1734
+ * here, for example `RuntimeEnv.fromRecord(process.env)`, or provides `CurrentRuntimeEnv` around the layer.
1735
+ *
1736
+ * Neutralization under `"auto"` reads the logging fiber's `CurrentRuntimeEnv`, then this option, then the
1737
+ * `CurrentRuntimeEnv` captured when the layer was built. With none of the three, a record is not neutralized: set
1738
+ * this option, provide `CurrentRuntimeEnv` around the layer, or pass `neutralize: true`. Every `CliLog.layer`
1739
+ * overload points here.
1740
+ */
1741
+ readonly runtimeEnv?: RuntimeEnv | undefined;
1742
+ }
1743
+ /**
1744
+ * Where the file sink writes: a literal path, or the environment variable that holds it.
1745
+ *
1746
+ * @public
1747
+ */
1748
+ type CliLogFile = {
1749
+ readonly envVar: string;
1750
+ } | {
1751
+ readonly path: string;
1752
+ };
1753
+ /**
1754
+ * {@link CliLogOptions} with a file sink, which is what makes the layer require `FileSystem` and `Path`.
1755
+ *
1756
+ * @public
1757
+ */
1758
+ interface CliLogFileOptions extends CliLogOptions {
1759
+ /**
1760
+ * Also write every record the sink accepts to a file as NDJSON, asynchronously.
1761
+ *
1762
+ * @remarks
1763
+ * The line is identical to the stderr NDJSON line for the same log call and is filtered by the same
1764
+ * {@link CliLog.Level}. Lines are queued and appended by a fiber scoped to the layer, so logging never waits
1765
+ * on the disk, and the parent directory is created. The first write error prints exactly one stderr line,
1766
+ * `diagnostics log file <path> failed: <message>; further file logging disabled`, and the program keeps
1767
+ * running with its normal exit code: from then on lines, including any still queued, are discarded silently.
1768
+ * Closing the layer's scope flushes the lines queued before it, unless the sink had already disabled itself.
1769
+ * `{ envVar }` names the variable that holds the path; unset or empty, no file is written.
1770
+ *
1771
+ * `undefined` writes no file but keeps the requirements of a file sink (`FileSystem` and `Path`) in `R`, so a
1772
+ * host whose sink is optional has one stable layer type either way.
1773
+ *
1774
+ * Under `CliRuntime.main` with `env.log`, what the platform logs while it builds, before it provides
1775
+ * `FileSystem`, reaches stderr but not the file; the file starts with the program's own records.
1776
+ */
1777
+ readonly file: CliLogFile | undefined;
1778
+ }
1779
+ /**
1780
+ * Diagnostics kept apart from a program's output: a level, a format and a place to write.
1781
+ *
1782
+ * @remarks
1783
+ * Two kinds of line must never be silenced by a diagnostics default: the failure report
1784
+ * `CliRuntime.reportFailures` writes through `CliLogger`, and the `CliMessage` lines. This package therefore
1785
+ * never makes the diagnostics level a global switch. The diagnostics logger filters on its **own** threshold,
1786
+ * {@link CliLog.Level}, and writes to stderr only.
1787
+ *
1788
+ * `CliLog.layer` **owns the whole logger set**. It builds a `CliLogger` for ordinary log lines and the
1789
+ * diagnostics sink itself and replaces whatever was installed, without reading it, so there is no order to get
1790
+ * wrong. Use it instead of `CliLogger.layer`, not with it: `CliLogger.layer` alone is the no-diagnostics path,
1791
+ * and a `CliLogger.layer` layered on top would replace this layer's set.
1792
+ *
1793
+ * Effect drops a record below `MinimumLogLevel` before any logger runs, so to let a debug record reach the
1794
+ * diagnostics logger `MinimumLogLevel` has to be lowered. `CliLog.layer` does that only when the
1795
+ * diagnostics level is below the ambient minimum, and in the same step floors the `CliLogger` it built at the
1796
+ * minimum it had, so it never prints a record the diagnostics level alone let through. A failure report is
1797
+ * written outside the scope core's `--log-level` flag sets, so `--log-level none` does not silence it either.
1798
+ *
1799
+ * `format: "auto"`, the default, decides by the audience alone, at build time and at runtime alike: NDJSON for an
1800
+ * agent or a CI, the pretty line for a human, whatever stderr's terminal state. A human piping stderr therefore gets
1801
+ * plain lines (without escapes unless stderr is a colour terminal); pass `format: "json"` for machine-readable logs.
1802
+ *
1803
+ * The text a program logs is sanitised before anything is painted in the pretty line (the message, the component and an
1804
+ * error's cause lose their escape sequences and control characters), and under GitHub Actions, where
1805
+ * `CurrentRuntimeEnv` in the logging fiber's context says so, a line the runner would read as a workflow command is
1806
+ * neutralized. An NDJSON record is not safe merely because `JSON.stringify` escapes control characters: the runner's
1807
+ * legacy parser reads `##[` anywhere in a line, so under Actions it is written as the JSON escape `#\u0023[`, which
1808
+ * decodes to the identical text. The file sink's lines are not read by the runner and are written as they are.
1809
+ *
1810
+ * `CurrentRuntimeEnv` is read from the logging fiber's context, and where that has none, from the `runtimeEnv` option,
1811
+ * else from the layer's own build context (captured if present, never required), so a host that builds the layer over
1812
+ * its environment, or names it with `runtimeEnv`, neutralizes every record. A record with none of the three (a program
1813
+ * with no `CurrentRuntimeEnv` anywhere) is sanitised but not neutralized, unless the `neutralize` option says otherwise.
1814
+ *
1815
+ * Core's `--log-level` flag sets `MinimumLogLevel` inside the command. While it is set to something other than
1816
+ * the value this layer installed, the diagnostics logger follows the flag instead of its own level: it writes
1817
+ * every record that reaches it. The `CliLogger` prints the same record too, so a record at or above the ambient
1818
+ * minimum is written twice, once plain and once to the diagnostics sink. Stderr is therefore not pure NDJSON while
1819
+ * diagnostics are on: a parser reads the lines that start with `{`.
1820
+ *
1821
+ * One edge: a `--log-level` value that EQUALS the level this layer installed cannot be told from no flag, so the
1822
+ * sink keeps filtering on its own level rather than following the flag. The plain `CliLogger` prints those records
1823
+ * regardless.
1824
+ *
1825
+ * @example
1826
+ * ```ts
1827
+ * import { CliRuntime } from "@effected/cli-kit"
1828
+ * import { NodeRuntime, NodeServices } from "@effect/platform-node"
1829
+ *
1830
+ * // `env.log` makes `main` install `CliLog.layer`: set MYTOOL_LOG_LEVEL=debug to get diagnostics on stderr.
1831
+ * NodeRuntime.runMain(
1832
+ * CliRuntime.main(program, {
1833
+ * platform: NodeServices.layer,
1834
+ * env: { audienceEnvVar: "MYTOOL_AUDIENCE", log: { envVar: "MYTOOL_LOG_LEVEL" } },
1835
+ * }),
1836
+ * )
1837
+ * ```
1838
+ *
1839
+ * @public
1840
+ */
1841
+ export declare class CliLog {
1842
+ private constructor();
1843
+ /**
1844
+ * The diagnostics threshold. Defaults to `None`, silent.
1845
+ *
1846
+ * @remarks
1847
+ * `CliLog.layer` sets it from the environment variable. A scope may raise it to narrow the output; it
1848
+ * cannot lower it below the level the layer installed, because Effect has already dropped those records.
1849
+ */
1850
+ static readonly Level: Context.Reference<LogLevel.LogLevel>;
1851
+ /**
1852
+ * Read a log level the way `CliLog.layer` reads its environment variable: `Option.some` of the level, or
1853
+ * `Option.none()` when the text is not one.
1854
+ *
1855
+ * @remarks
1856
+ * Case-insensitive, and not trimmed. The spellings are `all`, `trace`, `debug`, `info`, `warn` (or `warning`),
1857
+ * `error`, `fatal` and `none`. For a host that reads a level from its own flag or config and wants the same answer
1858
+ * the layer would give.
1859
+ *
1860
+ * @example
1861
+ * ```ts
1862
+ * CliLog.parseLevel("WARNING") // Option.some("Warn")
1863
+ * CliLog.parseLevel("loud") // Option.none()
1864
+ * ```
1865
+ *
1866
+ * @param text - the level's spelling
1867
+ */
1868
+ static parseLevel(text: string): Option.Option<LogLevel.LogLevel>;
1869
+ /**
1870
+ * The whole logger set of a program: a `CliLogger` for ordinary lines plus the diagnostics sink.
1871
+ *
1872
+ * @remarks
1873
+ * Replaces the installed loggers without reading them. Provide it on the program you pass to
1874
+ * `CliRuntime.main`, or use `main`'s `env.log` option; never wrap it around `main`, whose own logger would
1875
+ * replace this one. Bind it to a constant.
1876
+ *
1877
+ * The requirements follow the format. `format: "json"` reads neither the audience nor the terminal, so it
1878
+ * requires neither; `"pretty"` requires `TerminalEnv` alone, for the stderr colour; `"auto"` and an omitted
1879
+ * format require both. A long-lived host that never builds a platform `Terminal` can provide
1880
+ * `TerminalEnv.layerStdio()` for the pretty case.
1881
+ *
1882
+ * A platform or program that installs its own `Logger.layer([...])` replaces this set: do not. The diagnostics
1883
+ * then go silent with no error.
1884
+ *
1885
+ * The NDJSON line is core's `Logger.formatJson`, unchanged so it stays interoperable with Effect tooling: the
1886
+ * `message` field is a string for one log argument and an array for several.
1887
+ *
1888
+ * Level parsing is case-insensitive and accepts `warn`, `warning`, `error`, `info`, `debug`, `trace`,
1889
+ * `fatal`, `all` and `none`. An invalid value warns once, through the `CliLogger`, and leaves diagnostics
1890
+ * off.
1891
+ *
1892
+ * With a `file` option ({@link CliLogFileOptions}) the layer also writes an async NDJSON file, and only then
1893
+ * does it require `FileSystem` and `Path`, and it leaves them in `R` unprovided: the platform supplies them, or
1894
+ * a test supplies a memory filesystem, so a host never provides Node inside its own layer.
1895
+ *
1896
+ * Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
1897
+ *
1898
+ * @param options - the level, the env var, the format, the `CliLogger` options and the optional file sink
1899
+ */
1900
+ static layer(options: CliLogOptions & {
1901
+ readonly format: "json";
1902
+ readonly file?: undefined;
1903
+ }): Layer.Layer<never, never, never>;
1904
+ /**
1905
+ * The logger set with NDJSON diagnostics and a file sink; see the first overload.
1906
+ *
1907
+ * @remarks
1908
+ * Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
1909
+ *
1910
+ * @param options - the level, the env var, the `CliLogger` options and the file sink
1911
+ */
1912
+ static layer(options: CliLogFileOptions & {
1913
+ readonly format: "json";
1914
+ }): Layer.Layer<never, never, FileSystem.FileSystem | Path.Path>;
1915
+ /**
1916
+ * The logger set with pretty diagnostics; see the first overload.
1917
+ *
1918
+ * @remarks
1919
+ * Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
1920
+ *
1921
+ * @param options - the level, the env var and the `CliLogger` options
1922
+ */
1923
+ static layer(options: CliLogOptions & {
1924
+ readonly format: "pretty";
1925
+ readonly file?: undefined;
1926
+ }): Layer.Layer<never, never, TerminalEnv>;
1927
+ /**
1928
+ * The logger set with pretty diagnostics and a file sink; see the first overload.
1929
+ *
1930
+ * @remarks
1931
+ * Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
1932
+ *
1933
+ * @param options - the level, the env var, the `CliLogger` options and the file sink
1934
+ */
1935
+ static layer(options: CliLogFileOptions & {
1936
+ readonly format: "pretty";
1937
+ }): Layer.Layer<never, never, TerminalEnv | FileSystem.FileSystem | Path.Path>;
1938
+ /**
1939
+ * The logger set with the format decided by the audience; see the first overload.
1940
+ *
1941
+ * @remarks
1942
+ * Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
1943
+ *
1944
+ * @param options - the level, the env var, the format and the `CliLogger` options
1945
+ */
1946
+ static layer(options?: CliLogOptions & {
1947
+ readonly file?: undefined;
1948
+ }): Layer.Layer<never, never, Audience | TerminalEnv>;
1949
+ /**
1950
+ * The logger set with the format decided by the audience, and a file sink; see the first overload.
1951
+ *
1952
+ * @remarks
1953
+ * Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
1954
+ *
1955
+ * @param options - the level, the env var, the format, the `CliLogger` options and the file sink
1956
+ */
1957
+ static layer(options: CliLogFileOptions): Layer.Layer<never, never, Audience | TerminalEnv | FileSystem.FileSystem | Path.Path>;
1958
+ /**
1959
+ * Log a status line: its glyph painted through the theme, then `text`, at a level that follows the status.
1960
+ *
1961
+ * @remarks
1962
+ * The line goes through the logger, so it is a diagnostic like any `Effect.log*` call: filtered by the level in
1963
+ * force (`--log-level`, `CliLog.Level`), routed by `CliLogger`'s `stderrFrom` (stderr by default) and neutralized
1964
+ * under GitHub Actions. What differs is the glyph: the logger sanitises every line a program logs, which strips a
1965
+ * colour a program painted itself, so a glyph on the log channel was always drawn bare. Here the kit paints it and
1966
+ * marks the line as its own, so the plain `CliLogger` line keeps the colour, while `text` is still sanitised:
1967
+ * escape sequences and control characters in it are removed, as in every line the kit writes.
1968
+ *
1969
+ * The glyph is painted with stderr's theme (where diagnostics go) through {@link CliTheme.forAudience}, so an agent
1970
+ * gets it unpainted, and an `Audience` is read only when provided, so it stays out of the requirements. ASCII glyphs
1971
+ * give the status's ASCII form. A diagnostics record carries the line as its message as any record does: the `CliLog`
1972
+ * sink's pretty line sanitises it (the glyph is drawn bare there), and NDJSON keeps it, JSON-escaped.
1973
+ *
1974
+ * The level defaults to the status's rank in `vocab`: `Error` at or above `failure`'s, `Warn` at or above
1975
+ * `warning`'s, `Info` below, so a custom status follows its own rank. Pass `level` to choose it, and `indent` (a
1976
+ * number of spaces, or a string, sanitised) to start the line inside an indented block: ` ✗ error x: red`.
1977
+ *
1978
+ * @example
1979
+ * ```ts
1980
+ * import { CliLog, Status } from "@effected/cli-kit"
1981
+ *
1982
+ * // ✗ in the failure colour, then the message: on stderr, filtered by the log level.
1983
+ * const reportError = (resource: string, message: string) =>
1984
+ * CliLog.status(Status.core, "failure", `${resource}: ${message}`)
1985
+ * ```
1986
+ *
1987
+ * @param vocab - the vocabulary the status belongs to
1988
+ * @param name - the status
1989
+ * @param text - the text after the glyph, sanitised
1990
+ * @param options - the level to log at, and the indent before the glyph
1991
+ */
1992
+ static readonly status: <N extends string>(vocab: Status<N>, name: N, text: string, options?: CliLogStatusOptions) => Effect.Effect<void, never, CliTheme>;
1993
+ /**
1994
+ * Mark the log records an effect emits as coming from `name`.
1995
+ *
1996
+ * @remarks
1997
+ * Shown as `[name]` in pretty output and as `annotations.component` in NDJSON.
1998
+ *
1999
+ * @param name - the component
2000
+ */
2001
+ static readonly component: (name: string) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
2002
+ }
2003
+ /**
2004
+ * Options for {@link CliEnv.layer} and for `CliRuntime.main`'s `env` option.
2005
+ *
2006
+ * @public
2007
+ */
2008
+ interface CliEnvOptions {
2009
+ /** The environment variable that overrides the audience, read through `Config`; see `Audience.layer`. */
2010
+ readonly audienceEnvVar?: string | undefined;
2011
+ /**
2012
+ * Overrides the stderr terminal check; omitted, core's `Stdio.stderrIsTerminal` answers.
2013
+ *
2014
+ * @remarks
2015
+ * The platform `Stdio` reads the host (`process.stderr.isTTY` on Node), so a program whose stdout is a terminal
2016
+ * but whose stderr is redirected to a file writes its failure report and warnings there unpainted, with nothing
2017
+ * passed here. A `Stdio` built with `Stdio.make` without the field answers `false`; pass this only for a host
2018
+ * whose `Stdio` cannot say.
2019
+ */
2020
+ readonly stderrIsTerminal?: Effect.Effect<boolean> | undefined;
2021
+ /** Options for the theme; see {@link CliThemeOptions}. */
2022
+ readonly theme?: CliThemeOptions | undefined;
2023
+ /**
2024
+ * Diagnostics options. Only `CliRuntime.main` reads this: when given, `main` uses `CliLog.layer` with these
2025
+ * options as the program's logger, instead of the default `CliLogger.layer()`. The platform is built under
2026
+ * that logger, so a line it logs while building goes to stderr.
2027
+ *
2028
+ * @remarks
2029
+ * It may carry the `file` option, which also writes an async NDJSON file. The platform must then provide
2030
+ * `FileSystem` and `Path`, and `main`'s type says so when it does not.
2031
+ *
2032
+ * A platform or program that installs its own `Logger.layer([...])` replaces this logger set, and the
2033
+ * diagnostics go silent with no error: do not install one. See `CliLog.layer`. Only `CliLog`'s own records can be
2034
+ * silenced (`plainLogger: false`): what the platform logs while it builds goes through the full `CliLog` when its
2035
+ * build-time format is NDJSON (`json`, or `auto` for an agent or a CI; see `CliLogOptions.format`) and through a plain
2036
+ * `CliLogger` otherwise, routed by `logger.stderrFrom` as the host set it. The audience-override warning is never silenced: it is written exactly once, in NDJSON when
2037
+ * the build-time format is NDJSON and as a plain line otherwise, to stderr alone (never stdout, whatever
2038
+ * `logger.stderrFrom` says) and never to the host's `extraLoggers` or log file. The failure report and the `CliMessage` lines always
2039
+ * go through a plain `CliLogger`.
2040
+ */
2041
+ readonly log?: CliLogOptions | CliLogFileOptions | undefined;
2042
+ /**
2043
+ * Methods of core's `CliOutput.Formatter` to replace in the one `CliRuntime.main` installs, for example
2044
+ * `formatVersion` to name the carrier a bin runs through. Only `CliRuntime.main` reads this.
2045
+ *
2046
+ * @remarks
2047
+ * `main` installs a coloured default formatter inside the platform, which shadows any formatter the platform
2048
+ * sets; this is the way to keep a method of your own. Methods you omit keep the coloured defaults.
2049
+ */
2050
+ readonly formatter?: Partial<CliOutput.Formatter> | undefined;
2051
+ /**
2052
+ * How an absolute path is shown: a function, or `{ relativeTo: root }` to show a path under `root` relative to it.
2053
+ * The identity by default.
2054
+ *
2055
+ * @remarks
2056
+ * It is every path the kit shows for this run: `Render.context` takes it as its default, so `Doc.print`, a
2057
+ * `Doc.path` or file link, and a live view's `final` document follow it, and so do the stack frames of the default
2058
+ * failure report. An explicit `displayPath` passed to `Doc.print` or `Render.context` still wins.
2059
+ *
2060
+ * `{ relativeTo: root }` takes an absolute `root`. A path under it is shown relative to it; `root` itself, and a path
2061
+ * outside it, are shown absolute, since a `../..` chain says less than the absolute path. It uses the `Path` service
2062
+ * when the platform provides one (as `CliRuntime.main`'s does), and otherwise a plain prefix test on `/` and `\`.
2063
+ */
2064
+ readonly displayPath?: ((absolute: string) => string) | {
2065
+ readonly relativeTo: string;
2066
+ } | undefined;
2067
+ /**
2068
+ * Which frames of a defect's stack the default failure report shows: `app`, the default, leaves out every
2069
+ * `node_modules` frame (Effect's and any other dependency's) and the runtime's own (every `node:` frame and every
2070
+ * frame with no file), and prints how many it left out after the frames it shows, as
2071
+ * `(+N internal frames hidden)`, or `no user frames (N internal frames hidden)` when none is left; `all` shows
2072
+ * every frame. Applies to the report `main` writes, `FailureDetails.defaultLines` and `FailureDetails.lines`. Only
2073
+ * `CliRuntime.main` reads this.
2074
+ */
2075
+ readonly stackFrames?: "app" | "all" | undefined;
2076
+ /**
2077
+ * Which spans the default failure report's `in: outer › inner` trail names: `app`, the default, leaves out the spans
2078
+ * the kit's own packages and Effect define (judged by the file of each span's definition site under `node_modules`),
2079
+ * `all` shows every span, and `off` drops the trail. Applies to the report `main` writes,
2080
+ * `FailureDetails.defaultLines` and `FailureDetails.lines`. Only `CliRuntime.main` reads this.
2081
+ */
2082
+ readonly spans?: "app" | "all" | "off" | undefined;
2083
+ /**
2084
+ * The environment variable that sets `spans` at run time (`app`, `all` or `off`, case-insensitive), read through
2085
+ * `Config`, as `log.envVar` sets the log level: so a user filing a bug can run `TOOL_SPANS=all tool …` without a
2086
+ * rebuild. `spans` beats it (the variable is then not read at all); unset or empty is the default; a value that is
2087
+ * not a setting is ignored with one warning. Not read unless named. Only `CliRuntime.main` reads this.
2088
+ */
2089
+ readonly spansEnvVar?: string | undefined;
2090
+ /**
2091
+ * A module of the running program itself, as a `file:` URL or an absolute path: pass the bin's `import.meta.url`.
2092
+ * `spans: "app"` keeps the spans of the package that holds it, even when it is installed under
2093
+ * `node_modules/@effected/` (a kit companion's bin); see `CliFailureOptions.appModule`. Only `CliRuntime.main`
2094
+ * reads this.
2095
+ */
2096
+ readonly appModule?: string | undefined;
2097
+ /** Whether file links open in an editor; `auto` by default. See {@link CliLinks}. */
2098
+ readonly editorLinks?: EditorLinks | undefined;
2099
+ /** The environment variable that overrides `editorLinks`, read through `Config`. Not read unless named. */
2100
+ readonly editorLinksEnvVar?: string | undefined;
2101
+ }
2102
+ /**
2103
+ * The services {@link CliEnv.layer} provides.
2104
+ *
2105
+ * @public
2106
+ */
2107
+ type CliEnvServices = CurrentRuntimeEnv | TerminalEnv | Audience | CliTheme | CliLinks | Terminal.Terminal;
2108
+ /**
2109
+ * Options for {@link CliEnv.layerTest}: the answers a test fixes. Every field has a quiet default.
2110
+ *
2111
+ * @public
2112
+ */
2113
+ interface CliEnvTestOptions {
2114
+ /** Whether standard input, output and error are all terminals; `false` by default, as for a pipe. */
2115
+ readonly tty?: boolean | undefined;
2116
+ /**
2117
+ * The `TERM` the layer's own builds read: `dumb` makes a terminal not interactive and, with the theme's glyphs at
2118
+ * `auto`, draws ASCII. Unset by default, whatever the host's `TERM` is.
2119
+ */
2120
+ readonly term?: string | undefined;
2121
+ /** The audience; `human` by default. */
2122
+ readonly audience?: AudienceKind | undefined;
2123
+ /** The width of the terminal, in columns; none by default, so a width falls back to the reader's (80). */
2124
+ readonly columns?: number | undefined;
2125
+ /** The colour level of both stdout and stderr; `none` by default. Fixed as given: `term` does not change it. */
2126
+ readonly color?: ColorLevel | undefined;
2127
+ /** Options for the theme, as {@link CliEnvOptions.theme}; its glyphs are `auto` by default, so `term` decides. */
2128
+ readonly theme?: CliThemeOptions | undefined;
2129
+ }
2130
+ /**
2131
+ * The services {@link CliEnv.layerTest} provides.
2132
+ *
2133
+ * @public
2134
+ */
2135
+ type CliEnvTestServices = TerminalEnv | Audience | CliTheme;
2136
+ /**
2137
+ * The environment services a CLI reads, built once and in the right order.
2138
+ *
2139
+ * @remarks
2140
+ * Builds `CurrentRuntimeEnv`, `TerminalEnv`, `Audience`, `CliTheme` and `CliLinks`, and sets `CliInteractive` from them, then
2141
+ * installs the two gates for the program: `CliPrompt.gateTerminal`, which replaces `Terminal` with a quiet one when
2142
+ * the run is not interactive so no prompt runner ever attaches to stdin, and `CliPrompt.gateWizard`, which drops
2143
+ * `--wizard` then. `TerminalEnv` is built from the real terminal first. The layer therefore also outputs
2144
+ * `Terminal`, the gated one, and consumers never compose the gates themselves. A
2145
+ * `Context.Reference`'s key type is `never`, so the layer's output type does not list `CliInteractive`: it sets
2146
+ * the reference rather than providing a service. Every read of the environment goes through `Config` and
2147
+ * degrades to "unset" when it fails, so building the layer does not fail on a bad provider; it fails only when
2148
+ * `Stdio` or `Terminal` do.
2149
+ *
2150
+ * `CliLinks` reads `FileSystem` and `Path` from the surrounding context if it has them, and does not require them: a
2151
+ * `.vscode/` directory is looked for, and a relative path resolved, only when the platform is provided OUTSIDE this
2152
+ * layer, as `CliRuntime.main` does. Without them `auto` is `vscode` on the terminal signal alone.
2153
+ *
2154
+ * Not interactive, the gated `Terminal`'s `readLine` fails as a quit, its input is already ended and its `display`
2155
+ * writes nothing. A program that reads piped data must read `Stdio.stdin`, and one that writes output must use
2156
+ * `Console` or `Stdio`, never `Terminal`. It also installs `CliTheme.promptTheme`, so core's prompts follow the
2157
+ * theme.
2158
+ *
2159
+ * It sets core's `TerminalCapabilities` from `TerminalEnv` (through `TerminalEnv.capabilities` in `@effected/env`), so
2160
+ * the colour of core's own help, version and error output follows the kit's colour rule, and `canAnimate` is stdout
2161
+ * being a terminal that is not `dumb`. `canPrompt` alone is held at `true` whatever the terminal is: core skips a
2162
+ * fallback prompt entirely when it is `false`, which would lose `CliPrompt.fallback`'s and `CliUi.fallback`'s
2163
+ * `otherwise` in every piped run, and `CliInteractive` with `CliPrompt.gateTerminal` already owns that decision (the
2164
+ * gate quits any other prompt at once when the run is not interactive). A `TerminalCapabilities` with
2165
+ * `canPrompt: false` provided inside the program bypasses the kit's fallbacks: the parameter then fails as missing even
2166
+ * when an `otherwise` is given.
2167
+ *
2168
+ * @public
2169
+ */
2170
+ export declare class CliEnv {
2171
+ private constructor();
2172
+ /**
2173
+ * The environment services for the terminal `Stdio` and `Terminal` describe.
2174
+ *
2175
+ * @remarks
2176
+ * A layer-returning function mints a fresh layer per call: call it once and bind the result to a constant.
2177
+ *
2178
+ * @param options - the audience env var, the stderr check and the theme options
2179
+ */
2180
+ static readonly layer: (options?: CliEnvOptions) => Layer.Layer<CliEnvServices, never, Stdio.Stdio | Terminal.Terminal>;
2181
+ /**
2182
+ * The environment services a test fixes, needing nothing and reading nothing of the host's: `TerminalEnv` and
2183
+ * `Audience` from the answers given, `CliTheme` built from them as {@link CliEnv.layer} builds it, and
2184
+ * `CliInteractive` set from them by the same rule (a human, every stream a terminal, and a `TERM` that is not
2185
+ * `dumb`), and core's `TerminalCapabilities` from them as `CliEnv.layer` sets it, `canPrompt` held at `true`.
2186
+ *
2187
+ * @remarks
2188
+ * `term` is handed to the theme and interactivity builds alone, through a `ConfigProvider` of their own: the
2189
+ * program under the layer keeps its own provider, and a host's `TERM` (a test runner in a dumb terminal) never
2190
+ * decides. A screen or a live view also needs `UiStreams` from `@effected/cli-kit/ui`, which `CliUiTest` provides; this
2191
+ * layer provides no `Terminal` and installs neither of `CliEnv.layer`'s prompt gates.
2192
+ *
2193
+ * A layer-returning function mints a fresh layer per call: call it once and bind the result to a constant.
2194
+ *
2195
+ * @param options - whether the streams are terminals, the `TERM`, the audience, the width, the colour and the theme
2196
+ */
2197
+ static readonly layerTest: (options?: CliEnvTestOptions) => Layer.Layer<CliEnvTestServices>;
2198
+ }
2199
+ /**
2200
+ * The shape behind {@link CliExit}.
2201
+ *
2202
+ * @public
2203
+ */
2204
+ interface CliExitShape {
2205
+ /** The highest exit code recorded during the run; `0` until one is set. */
2206
+ readonly code: MutableRef.MutableRef<number>;
2207
+ }
2208
+ declare const CliExit_base: Context.ServiceClass<CliExit, "@effected/cli-kit/CliExit", CliExitShape>;
2209
+ /**
2210
+ * The exit code a successful run wants, for commands whose findings are a
2211
+ * result rather than a failure (a linter that found problems, say).
2212
+ *
2213
+ * @remarks
2214
+ * Findings are not a failure — a JSON `tapError` must not fire, and the
2215
+ * handler must return normally — yet the process must exit non-zero. Writing
2216
+ * `process.exitCode` works only because Node's `runMain` skips
2217
+ * `process.exit(0)` on success; `process.exit(n)` in a handler skips every
2218
+ * finalizer. `CliRuntime.main` reads this cell after the program
2219
+ * succeeds and turns a non-zero code into a marked failure the runtime's
2220
+ * teardown honours, on any runtime, with finalizers intact.
2221
+ *
2222
+ * A `Service`, not a `Reference`: forgetting `CliRuntime.main` is a type error,
2223
+ * never a silently ignored global.
2224
+ *
2225
+ * @public
2226
+ */
2227
+ export declare class CliExit extends CliExit_base {
2228
+ /**
2229
+ * A fresh cell at `0`; `CliRuntime.main` provides it, and tests provide it
2230
+ * directly.
2231
+ *
2232
+ * @remarks
2233
+ * Every provide mints a new cell. Layers memoize by reference across
2234
+ * `Effect.provide` calls, so without `Layer.fresh` a second provide of this
2235
+ * layer anywhere in the program — a nested `CliRuntime.main`, a test
2236
+ * helper — would silently share the first run's cell and inherit its code.
2237
+ *
2238
+ * A program run under `CliRuntime.main` must NOT provide `CliExit.layer`
2239
+ * itself: `main` already provides one, and a second provide mints a second,
2240
+ * unrelated cell that `main` never reads back, so `CliExit.set` calls made
2241
+ * against it are silently discarded and the run exits `0`.
2242
+ */
2243
+ static readonly layer: Layer.Layer<CliExit>;
2244
+ /**
2245
+ * Record an exit code; the highest code set during the run wins.
2246
+ *
2247
+ * @remarks
2248
+ * Highest-wins, not last-wins, so a later "clean" step cannot quietly
2249
+ * downgrade an earlier finding's code.
2250
+ *
2251
+ * The code must be an integer in `0..255` — the range a POSIX exit status
2252
+ * can carry. Anything else dies as a defect naming the value: `256` would
2253
+ * wrap to exit `0` and silently pass a run with findings, and a fraction
2254
+ * such as `1.5` makes `process.exit` throw `ERR_OUT_OF_RANGE` after the
2255
+ * program has finished.
2256
+ *
2257
+ * The code only applies to a run that **succeeds**. A program failure beats
2258
+ * findings: when the program fails, `CliRuntime.main` never reads this
2259
+ * cell, and the failure's own exit code (or the `exitCode` fallback) wins.
2260
+ */
2261
+ static readonly set: (code: number) => Effect.Effect<void, never, CliExit>;
2262
+ }
2263
+ /**
2264
+ * The protocol an error class implements to say how a failure is shown: a method under this key that returns the
2265
+ * document.
2266
+ *
2267
+ * @remarks
2268
+ * `CliFailure.toDoc` calls it for a typed failure that has one, so an application error draws itself (a heading, a
2269
+ * table of what went wrong) and the default report uses it with no registration. A `Symbol.for` key, so two copies
2270
+ * of this package agree on it.
2271
+ *
2272
+ * @public
2273
+ */
2274
+ export declare const CliDoc: unique symbol;
2275
+ /**
2276
+ * An error that draws itself: see {@link CliDoc}.
2277
+ *
2278
+ * @public
2279
+ */
2280
+ interface CliDocSource {
2281
+ readonly [CliDoc]: () => Document;
2282
+ }
2283
+ /**
2284
+ * Options for {@link CliFailure.toDoc}.
2285
+ *
2286
+ * @public
2287
+ */
2288
+ interface CliFailureOptions {
2289
+ /**
2290
+ * A document per error `_tag`, for errors that do not implement {@link CliDoc}. A tag with no entry is shown by
2291
+ * the default rules.
2292
+ */
2293
+ readonly render?: Readonly<Record<string, (error: unknown) => Document>> | undefined;
2294
+ /** Turns an absolute path into its display form, for the stack frames; the identity by default. */
2295
+ readonly displayPath?: ((absolute: string) => string) | undefined;
2296
+ /**
2297
+ * Which frames of a defect's stack are shown. `app`, the default, shows the program's own: every `node_modules`
2298
+ * frame (Effect's and any other dependency's), `node:internal` and the runtime's generator frames are left out and
2299
+ * counted. When that leaves no frame, as for a program run from its install under `node_modules` (a global
2300
+ * install, `npx`, a pnpm store), only the runtime's and Effect's are left out, so its own frames still show. `all`
2301
+ * shows every frame, unfiltered.
2302
+ */
2303
+ readonly stackFrames?: "app" | "all" | undefined;
2304
+ /**
2305
+ * Which spans the `in: outer › inner` trail after a failure names. `app`, the default, leaves out the spans the kit
2306
+ * and Effect define themselves: a span whose definition site (an `Effect.fn`'s, or where the span was opened) is a
2307
+ * file under `node_modules/@effected/` or `node_modules/effect/`. A config that fails to decode under
2308
+ * `@effected/config-file` then reports no `ConfigFile.loadFrom` trail, while the program's own spans stay. `all`
2309
+ * shows every span, and `off` drops the trail. Under either, an `Effect.fn` call and its definition are one entry,
2310
+ * `name`, never `name (definition) › name`.
2311
+ *
2312
+ * @remarks
2313
+ * The rule reads file paths, never span names, and it fails open: when it cannot tell, it shows the span. A span
2314
+ * with no captured stack is kept. A kit package linked into a workspace (`link:`, `workspace:`) runs from its own
2315
+ * checkout rather than from `node_modules`, so its spans show as the program's. A bundled program is one file, so
2316
+ * `app` shows what `all` does, unless the bundle is itself installed under `node_modules/@effected/`. A program that
2317
+ * is installed under `node_modules/@effected/` (a kit companion's bin) names itself with `appModule`, or its own
2318
+ * spans are left out with the kit's.
2319
+ */
2320
+ readonly spans?: "app" | "all" | "off" | undefined;
2321
+ /**
2322
+ * A module of the running program itself, as a `file:` URL or an absolute path: its bin's `import.meta.url`. With
2323
+ * `spans: "app"`, a span defined in the installed package that holds this module is the program's, kept even under
2324
+ * `node_modules/@effected/`, while the packages it depends on (beside it, or nested in its own `node_modules`) are
2325
+ * still left out. The package is the path through the last `node_modules/<name>` (or `node_modules/@scope/name`)
2326
+ * in it, read from the path alone with no file system. A module not under `node_modules` changes nothing: the rule
2327
+ * already keeps its spans. Unset by default.
2328
+ */
2329
+ readonly appModule?: string | undefined;
2330
+ }
2331
+ /**
2332
+ * A failure as a document: what the default report prints, and a building block for a custom one.
2333
+ *
2334
+ * @remarks
2335
+ * One run of blocks per `Cause` reason. A typed failure is, in order of preference: the document of an error that
2336
+ * implements {@link CliDoc}; the document `options.render` holds for its `_tag`; for `Cancelled` and
2337
+ * `NotInteractive`, their one fixed line; a `Tree` of the rejected values, for a schema error or issue; else a failure
2338
+ * status line with its message. A defect is its message followed by a collapsible `stack` of the program's own frames,
2339
+ * each a file link (so a terminal can open it in an editor) shown through `displayPath`, with the runtime's frames (every
2340
+ * `node:` frame and every frame with no file) and every `node_modules` frame (Effect's and any other dependency's)
2341
+ * left out unless `stackFrames` is `all`. A frame is classified by its file alone, never by its function name, so a
2342
+ * program's own thunk that V8 names by Effect's method alias is still shown. When that would
2343
+ * leave no frame at all, as for a program run from its own install under `node_modules`, only the runtime's and
2344
+ * Effect's are left out. Then an
2345
+ * `Error.cause` chain as a tree. When cleaning leaves no frame the stack says
2346
+ * `no user frames (N internal frames hidden)`, never an empty block; when frames survive and some were left out, the
2347
+ * count follows them as `(+N internal frames hidden)`. A reason that ran under spans is followed by
2348
+ * `in: outer › inner`: by default only the program's own spans, the kit's and Effect's left out (`spans`). Interrupts are not rendered beside a real failure, and a cause with only interrupts is the
2349
+ * one line `interrupted`.
2350
+ *
2351
+ * All text goes through the document, so a control character in a message or a stack frame never reaches the terminal.
2352
+ * Building it never throws: an error whose `_tag`, `message`, `stack`, `cause` or `issue` getter throws is drawn without
2353
+ * that part (an unreadable `stack` as `no stack`, an unreadable `cause` ending the chain there). Render it with `Render.context` and `Render.plain`, `ansi`, `markdown` or `githubLog`, or `Doc.print` it.
2354
+ *
2355
+ * @public
2356
+ */
2357
+ export declare class CliFailure {
2358
+ private constructor();
2359
+ /**
2360
+ * Build the document of a cause.
2361
+ *
2362
+ * @param cause - the failure
2363
+ * @param options - per-tag documents and a path display function
2364
+ */
2365
+ static readonly toDoc: (cause: Cause.Cause<unknown>, options?: CliFailureOptions) => Document;
2366
+ }
2367
+ /**
2368
+ * An output format a `--format` flag can offer: `auto` (the renderer the audience gets, as `Doc.print` picks it),
2369
+ * one of the `Doc` renderers by name, or `json`, the command's data rather than its document.
2370
+ *
2371
+ * @public
2372
+ */
2373
+ type CliFormatName = "auto" | "plain" | "ansi" | "markdown" | "githubLog" | "json";
2374
+ /**
2375
+ * Options for {@link CliFormat.flag}.
2376
+ *
2377
+ * @typeParam F - the built-in formats offered under their own names
2378
+ * @typeParam A - the caller's alias names, each standing for a built-in format
2379
+ * @typeParam C - the caller's own formats, which the caller renders itself
2380
+ *
2381
+ * @public
2382
+ */
2383
+ interface CliFormatFlagOptions<F extends CliFormatName, A extends Readonly<Record<string, CliFormatName>> = Record<never, CliFormatName>, C extends string = never> {
2384
+ /**
2385
+ * The format when the flag is not given, spelled as on the command line (an alias by its own name): `auto` when it
2386
+ * is offered, otherwise the first one.
2387
+ */
2388
+ readonly default?: F | Extract<keyof A, string> | C | undefined;
2389
+ /** The flag's name; `format` by default. */
2390
+ readonly name?: string | undefined;
2391
+ /** The flag's description in help; one naming the offered formats by default. */
2392
+ readonly description?: string | undefined;
2393
+ /**
2394
+ * Names of the caller's own that stand for a built-in format: `{ human: "auto" }` offers `--format human`, whose
2395
+ * value is `auto`. The target need not be offered under its own name, so `["json"]` with `{ human: "auto" }` offers
2396
+ * exactly `json` and `human`. An alias may not reuse a built-in format's name or any other offered name.
2397
+ */
2398
+ readonly aliases?: A | undefined;
2399
+ /**
2400
+ * Formats the caller renders itself, such as `mermaid` or `dot`: offered under their own names and yielded as
2401
+ * themselves. {@link CliFormat.print} takes none of them; branch on a custom value before printing. A custom name
2402
+ * may not reuse a built-in format's name or any other offered name.
2403
+ */
2404
+ readonly custom?: ReadonlyArray<C> | undefined;
2405
+ }
2406
+ /**
2407
+ * What {@link CliFormat.print} prints: the command's document and, for `json`, its data.
2408
+ *
2409
+ * @public
2410
+ */
2411
+ interface CliFormatOutput {
2412
+ /** The document, built only when a document format is chosen. */
2413
+ readonly doc: () => Document;
2414
+ /** The data `json` prints, built only when `json` is chosen. A `json` format with no `json` here is a defect. */
2415
+ readonly json?: (() => unknown) | undefined;
2416
+ }
2417
+ /**
2418
+ * Options for {@link CliFormat.print}.
2419
+ *
2420
+ * @public
2421
+ */
2422
+ interface CliFormatPrintOptions {
2423
+ /** The stream to write to; stdout by default. */
2424
+ readonly stream?: "stdout" | "stderr" | undefined;
2425
+ /** The JSON indent, in spaces; `2` by default, `0` for one line. */
2426
+ readonly indent?: number | undefined;
2427
+ }
2428
+ /**
2429
+ * A `--format` flag and the one print that honours it, so a command builds its report once as a `Doc` and its data
2430
+ * once as a value, and never writes per-format output by hand.
2431
+ *
2432
+ * @remarks
2433
+ * The flag is core's `Flag.ChoiceWithValue` with the kit's names, default and description; the print hands every
2434
+ * document format to `Doc.print` and writes `json` itself.
2435
+ *
2436
+ * ```ts
2437
+ * const format = CliFormat.flag(["auto", "markdown", "json"])
2438
+ * const doctor = Command.make("doctor", { format }, ({ format }) =>
2439
+ * CliFormat.print(format, { doc: () => report(results), json: () => results }),
2440
+ * )
2441
+ * ```
2442
+ *
2443
+ * @public
2444
+ */
2445
+ export declare class CliFormat {
2446
+ private constructor();
2447
+ /**
2448
+ * A `--format` flag offering `formats`, and the caller's own `aliases` and `custom` formats.
2449
+ *
2450
+ * @remarks
2451
+ * Its default is `options.default`, else `auto` when it is offered, else the first format. Any other value is a
2452
+ * usage error from core's parser, naming the accepted ones. The value is the built-in format a name stands for
2453
+ * (`human` under `{ human: "auto" }` is `auto`), or a custom name as itself, so the value of a flag with no custom
2454
+ * formats goes straight to {@link CliFormat.print}.
2455
+ *
2456
+ * Two offered names that clash (an alias or custom name reusing a built-in name, or any name offered twice) and a
2457
+ * default that is not offered are programming mistakes: the call throws. A CLI that still accepts a `--json` of its
2458
+ * own declares and resolves that flag itself; {@link CliFormat.printJson} prints the JSON the same way.
2459
+ *
2460
+ * ```ts
2461
+ * // okfit's contract: --format human|json, and a graph command that also draws mermaid and dot
2462
+ * const format = CliFormat.flag(["json"], { aliases: { human: "auto" }, default: "human" })
2463
+ * const graph = CliFormat.flag(["json"], { custom: ["mermaid", "dot"], default: "mermaid" })
2464
+ * ```
2465
+ *
2466
+ * @param formats - the built-in formats the command offers under their own names, at least one
2467
+ * @param options - the default, the flag's name and description, aliases and custom formats
2468
+ */
2469
+ static readonly flag: <const F extends CliFormatName, const A extends Readonly<Record<string, CliFormatName>> = Record<never, CliFormatName>, const C extends string = never>(formats: readonly [F, ...ReadonlyArray<F>], options?: CliFormatFlagOptions<F, A, C>) => Flag.Flag<F | A[keyof A] | C>;
2470
+ /**
2471
+ * Print a command's output in `format`.
2472
+ *
2473
+ * @remarks
2474
+ * `json` writes `output.json()` exactly as {@link CliFormat.printJson} writes a value, which it delegates to. Every
2475
+ * other format prints `output.doc()` with `Doc.print`, which renders it as `auto` or the named renderer would.
2476
+ *
2477
+ * @param format - the chosen format, usually the value of {@link CliFormat.flag}
2478
+ * @param output - the document and the data
2479
+ * @param options - the stream and the JSON indent
2480
+ */
2481
+ static readonly print: (format: CliFormatName, output: CliFormatOutput, options?: CliFormatPrintOptions) => Effect.Effect<void, never, CliTheme | TerminalEnv | Audience | CliLinks>;
2482
+ /**
2483
+ * Print `value` as JSON, the way {@link CliFormat.print} prints the `json` format, for a CLI that keeps a JSON flag
2484
+ * of its own.
2485
+ *
2486
+ * @remarks
2487
+ * One `Console.log` (or `Console.error` for stderr), indented by `indent`: one document, never one line per item.
2488
+ * Under GitHub Actions a `##[` inside it is written as the JSON escape `#\u0023[`, which decodes to the same
2489
+ * text, so the runner cannot read it as a command. A value JSON cannot hold (a cycle, a bigint, `undefined`) is a
2490
+ * defect. It needs no theme, terminal or audience: whether this is GitHub Actions is read from `CurrentRuntimeEnv`
2491
+ * when the environment has it, and is "no" otherwise.
2492
+ *
2493
+ * ```ts
2494
+ * const status = Command.make("status", { json: Flag.Boolean("json").pipe(Flag.withDefault(false)) }, ({ json }) =>
2495
+ * json ? CliFormat.printJson(results) : Doc.print(report(results)),
2496
+ * )
2497
+ * ```
2498
+ *
2499
+ * @param value - the data to print
2500
+ * @param options - the stream and the JSON indent
2501
+ */
2502
+ static readonly printJson: (value: unknown, options?: CliFormatPrintOptions) => Effect.Effect<void>;
2503
+ }
2504
+ declare const CliInteractive_base: Context.Reference<boolean>;
2505
+ /**
2506
+ * Whether this run may prompt a person: a human audience, with a terminal on
2507
+ * both standard input and standard output, and a `TERM` that is not `dumb`.
2508
+ *
2509
+ * @remarks
2510
+ * A `Context.Reference`, not a `Context.Service`, for three reasons. It is one
2511
+ * boolean with a safe default, which is what a reference is for. A scoped
2512
+ * override, {@link CliInteractive.unless}, is a plain
2513
+ * `Effect.provideService`, so a command can switch prompting off for one
2514
+ * subtree without a layer. And forgetting to provide it is not a type error
2515
+ * but a harmless answer, since it reads `false` when no layer is provided: a
2516
+ * program that never wired it refuses to prompt rather than hanging on a
2517
+ * terminal that is not there. Read it with `yield* CliInteractive`.
2518
+ *
2519
+ * Because a reference's key type is `never`, {@link CliInteractive.layer} and
2520
+ * {@link CliInteractive.layerTest} are typed `Layer<never>`: they set the
2521
+ * reference rather than provide a service.
2522
+ *
2523
+ * Both layers also hold core's `TerminalCapabilities.canPrompt` at `true`,
2524
+ * keeping its `canColor` and `canAnimate` as they find them. Core skips a
2525
+ * `Flag.withFallbackPrompt` or `Argument.withFallbackPrompt` fallback entirely
2526
+ * when `canPrompt` is `false`, and decides that from the process's own
2527
+ * terminal, so a kit fallback (`CliPrompt.fallback`, `CliUi.fallback`) would
2528
+ * never be called in a piped run and its `otherwise` would be lost. With the
2529
+ * gate held open, this reference makes the prompt decision instead: the kit's
2530
+ * fallbacks answer without a person when it is `false`, and
2531
+ * `CliPrompt.gateTerminal` quits any other prompt at once. A
2532
+ * `TerminalCapabilities` with `canPrompt: false` provided inside the program,
2533
+ * under these layers, bypasses the kit's fallbacks again: the parameter fails
2534
+ * as missing even when an `otherwise` is given.
2535
+ *
2536
+ * @public
2537
+ */
2538
+ export declare class CliInteractive extends CliInteractive_base {
2539
+ /**
2540
+ * Decide from the audience and the terminal: `true` only for a human audience with a terminal on both
2541
+ * standard input and standard output, and a `TERM` that is not `dumb`.
2542
+ *
2543
+ * @remarks
2544
+ * A dumb terminal is a terminal, but it cannot move the cursor or take synchronized output, which a prompt or a
2545
+ * screen redrawing in place needs: it gets what a pipe gets. `TERM` is read through the ambient `ConfigProvider`,
2546
+ * as `@effected/env` reads the environment, so it adds no requirement; a test fixes it with
2547
+ * `Effect.provideService(ConfigProvider.ConfigProvider, ConfigProvider.fromUnknown({ TERM: "dumb" }))`.
2548
+ *
2549
+ * It also holds core's `TerminalCapabilities.canPrompt` at `true`; see {@link CliInteractive}.
2550
+ *
2551
+ * Bind the layer to a constant and provide it once; `Audience` and `TerminalEnv` come from `@effected/env`.
2552
+ */
2553
+ static readonly layer: Layer.Layer<never, never, Audience | TerminalEnv>;
2554
+ /**
2555
+ * A fixed answer that needs nothing. It holds core's `canPrompt` open too, as {@link CliInteractive.layer} does.
2556
+ *
2557
+ * @param value - whether the run is interactive
2558
+ */
2559
+ static readonly layerTest: (value: boolean) => Layer.Layer<never>;
2560
+ /**
2561
+ * Run `self` with interactivity switched off when `condition` holds.
2562
+ *
2563
+ * @remarks
2564
+ * It only narrows: `unless(false)` leaves the current value alone and never turns interactivity on, so a
2565
+ * non-interactive scope stays non-interactive. The outer value is restored when `self` ends, whether it
2566
+ * succeeds, fails or is interrupted.
2567
+ *
2568
+ * A flag that resolves the audience (`--human`, under `CliAudience.runWith` or `provide`) recomputes interactivity
2569
+ * from the terminal facts, so it can override an outer `unless` or a `layerTest(false)`: those narrow the
2570
+ * environment's answer, and the flag is a later, explicit one.
2571
+ *
2572
+ * @param condition - `true` to switch prompting off for `self`
2573
+ */
2574
+ static readonly unless: (condition: boolean) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
2575
+ }
2576
+ /**
2577
+ * Options for {@link CliMessage.status}.
2578
+ *
2579
+ * @public
2580
+ */
2581
+ interface CliMessageOptions {
2582
+ /**
2583
+ * Where the line goes. Defaults to stderr for a status whose rank is at or above `warning`'s in its
2584
+ * vocabulary, stdout otherwise.
2585
+ */
2586
+ readonly stream?: "stdout" | "stderr" | undefined;
2587
+ }
2588
+ /**
2589
+ * One-line status messages: a glyph and some text, themed for a person and plain for an agent.
2590
+ *
2591
+ * @remarks
2592
+ * Each line goes through `Console`, `log` for stdout and `error` for stderr, never through the logger, so no
2593
+ * log level can silence it. Only the glyph is painted; the text stays plain. An `agent` audience gets the glyph
2594
+ * and the text and never colour, even when the theme has colour. `success` and `info` go to stdout, `warning`
2595
+ * and `failure` to stderr.
2596
+ *
2597
+ * The text is whatever the caller supplies, so it is sanitised: escape sequences and control characters are removed
2598
+ * (a line break is kept as one, a tab becomes a space), as in a document. Under GitHub Actions, where
2599
+ * `CurrentRuntimeEnv` says so, a line the runner would read as a workflow command is neutralized as well. The glyph
2600
+ * comes from the vocabulary, sanitised too (`Status.glyph`), so a glyph built from data cannot inject an escape either.
2601
+ *
2602
+ * @public
2603
+ */
2604
+ export declare class CliMessage {
2605
+ private constructor();
2606
+ /**
2607
+ * Print a status line from a vocabulary.
2608
+ *
2609
+ * @remarks
2610
+ * The stream defaults to stderr when the status ranks at or above `warning` in `vocab`, and stdout
2611
+ * otherwise, so a custom status follows its own rank: a `timeout` ranked 85 goes to stderr.
2612
+ *
2613
+ * @param vocab - the vocabulary the status belongs to
2614
+ * @param name - the status
2615
+ * @param text - the text after the glyph
2616
+ * @param options - the stream override
2617
+ */
2618
+ static readonly status: <N extends string>(vocab: Status<N>, name: N, text: string, options?: CliMessageOptions) => Effect.Effect<void, never, CliTheme | Audience>;
2619
+ /**
2620
+ * A success line, on stdout.
2621
+ *
2622
+ * @param text - the text after the glyph
2623
+ */
2624
+ static readonly success: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
2625
+ /**
2626
+ * An informational line, on stdout.
2627
+ *
2628
+ * @param text - the text after the glyph
2629
+ */
2630
+ static readonly info: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
2631
+ /**
2632
+ * A warning line, on stderr.
2633
+ *
2634
+ * @param text - the text after the glyph
2635
+ */
2636
+ static readonly warning: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
2637
+ /**
2638
+ * A failure line, on stderr.
2639
+ *
2640
+ * @param text - the text after the glyph
2641
+ */
2642
+ static readonly failure: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
2643
+ }
2644
+ /**
2645
+ * Which missing parameter a fallback stands in for, so a non-interactive run can fail with core's own error.
2646
+ *
2647
+ * @public
2648
+ */
2649
+ type CliPromptTarget = {
2650
+ readonly flag: string;
2651
+ } | {
2652
+ readonly argument: string;
2653
+ };
2654
+ /**
2655
+ * Options for {@link CliPrompt.fallback}.
2656
+ *
2657
+ * @public
2658
+ */
2659
+ type CliPromptFallbackOptions<A> = CliPromptTarget & {
2660
+ /** The value to use when the run is not interactive. Without it a non-interactive run fails as missing. */
2661
+ readonly otherwise?: A;
2662
+ };
2663
+ /**
2664
+ * Prompts that know whether there is a person to ask.
2665
+ *
2666
+ * @public
2667
+ */
2668
+ export declare class CliPrompt {
2669
+ private constructor();
2670
+ /**
2671
+ * A fallback for `Flag.withFallbackPrompt` or `Argument.withFallbackPrompt` that only prompts when the run is
2672
+ * interactive.
2673
+ *
2674
+ * @remarks
2675
+ * Interactive (`CliInteractive`): the prompt runs and its answer is used. Not interactive: `otherwise` is used
2676
+ * when given, and the terminal is never read; without it the parameter fails as missing, exactly as it would
2677
+ * with no fallback, so core renders its own message and `CliRuntime.main` exits `64`. Name the parameter with
2678
+ * `flag` (the name without dashes, as given to `Flag.String`) or `argument` so that error can be built.
2679
+ *
2680
+ * Why the prompt runs inside this function rather than being handed back to core: core's
2681
+ * `withFallbackPrompt` turns a quit, such as Ctrl-C, into the original missing-parameter error, which would
2682
+ * exit `64` as if the flag had been forgotten. Here a quit is `Cancelled` with reason `interrupt`, exit `130`.
2683
+ * It is raised as a defect because core's parse step turns every typed failure into a usage error. Core then
2684
+ * runs the already-answered `Prompt.succeed` it is handed. Because it travels as a defect, a handler's
2685
+ * `Effect.catchTag("Cancelled", ...)` cannot see it, and only `CliRuntime.main` (or
2686
+ * `CliRuntime.reportFailures`) renders it as one line with exit `130`; under a bare `runMain` it prints a
2687
+ * stack.
2688
+ *
2689
+ * Core runs `Prompt.run` on the answered prompt it is handed, and an answered prompt never reads the terminal's
2690
+ * input (core acquires it only when a prompt needs a key), so piped stdin is left untouched without any gate.
2691
+ * `CliPrompt.gateTerminal`, which `CliEnv.layer` installs, covers the prompts this function does not wrap.
2692
+ *
2693
+ * Core calls a fallback only when its `TerminalCapabilities.canPrompt` is `true`, and its own default decides that
2694
+ * from the process's terminal, so in a piped run it would fail the parameter as missing without calling this
2695
+ * function and `otherwise` would be lost. `CliInteractive.layer` and `CliInteractive.layerTest` (and so
2696
+ * `CliEnv.layer`) hold `canPrompt` at `true` for that reason: the decision is `CliInteractive`'s, made here. A
2697
+ * `TerminalCapabilities` with `canPrompt: false` provided inside the program bypasses this fallback again, and a
2698
+ * program that sets `CliInteractive` with neither layer keeps core's own gate.
2699
+ *
2700
+ * @param prompt - the prompt to show
2701
+ * @param options - the parameter it stands in for, and the non-interactive default
2702
+ */
2703
+ static readonly fallback: <A>(prompt: Prompt.Prompt<A>, options: CliPromptFallbackOptions<A>) => Param.FallbackPrompt<A>;
2704
+ /**
2705
+ * Gates core's `Terminal` on `CliInteractive`, so a run that is not interactive never touches the real one.
2706
+ *
2707
+ * @remarks
2708
+ * A prompt that needs a key reads the terminal's input, and the real Node terminal then attaches a readline to
2709
+ * stdin, which drops piped input and puts a TTY stdin into raw mode. Core's `withFallbackPrompt`, a `Prompt.run`
2710
+ * in a handler and the command wizard all do so whether or not anyone is there to answer. Not interactive, this
2711
+ * terminal's input is an already-ended queue, its `readLine` fails as quit and its `display` writes nothing, so
2712
+ * any such prompt is quit at once and the real terminal is never read. Its `columns`, `rows` and `size` always come
2713
+ * from the real one, so layout keeps working. Interactive, every call passes through to the real terminal.
2714
+ *
2715
+ * The decision is made on every call, not when the layer is built, so a scope that narrows `CliInteractive`
2716
+ * later, such as an audience flag under `CliAudience.runWith`, gates it too.
2717
+ *
2718
+ * It requires the real `Terminal`. `CliEnv.layer` installs it, after `TerminalEnv` is built from the real
2719
+ * terminal, so consumers do not compose it.
2720
+ */
2721
+ static readonly gateTerminal: Layer.Layer<Terminal.Terminal, never, Terminal.Terminal>;
2722
+ /**
2723
+ * Drops core's `--wizard` built-in flag when the run is not interactive.
2724
+ *
2725
+ * @remarks
2726
+ * The wizard prompts, so offering it without a terminal only leads to a dead end. With the flag gone, core
2727
+ * treats `--wizard` as an unknown flag, a usage error that exits `64`, and lists it nowhere in `--help`.
2728
+ * The layer reads `CliInteractive` and the ambient `CliConfig` when it is built, so provide those first, for
2729
+ * example `CliPrompt.gateWizard.pipe(Layer.provide(CliInteractive.layer))`. It filters the ambient `CliConfig`,
2730
+ * so a consumer's own `builtIns` survive, and returns it untouched when interactive. An audience flag read
2731
+ * later is covered by `CliAudience.runWith`, which drops the wizard too. When this layer removes the flag it records
2732
+ * that it did, so `runWith` puts it back only when a flag turns interactivity on where this took it away: a
2733
+ * consumer who never had `Wizard` in their `builtIns` keeps it out.
2734
+ */
2735
+ static readonly gateWizard: Layer.Layer<never>;
2736
+ }
2737
+ /**
2738
+ * What `render` is told about a failure beyond the squashed error.
2739
+ *
2740
+ * @public
2741
+ */
2742
+ interface FailureDetails {
2743
+ /** The whole cause the program failed with, before squashing. */
2744
+ readonly cause: Cause.Cause<unknown>;
2745
+ /**
2746
+ * `true` when the cause carries no typed failure, so `error` is a defect:
2747
+ * a `die`, a thrown exception, a bug. `false` when `error` is a typed
2748
+ * failure from the error channel.
2749
+ */
2750
+ readonly isDefect: boolean;
2751
+ /**
2752
+ * `true` when the squashed `error` is the kit's {@link Cancelled}: the person quit a prompt or screen (Esc, Ctrl-C).
2753
+ * It is not a bug and there is nothing to report, whichever channel it arrived through.
2754
+ *
2755
+ * @remarks
2756
+ * A cancel from `CliPrompt.fallback` is a defect (`isDefect` is `true`) and one from `CliUi.run` is a typed failure
2757
+ * (`isDefect` is `false`), so a `render` that gives a defect the "please report this" treatment must test this flag
2758
+ * first, or Esc prints an issue-report request. `isDefect` keeps its plain meaning, the absence of a typed failure,
2759
+ * and the exit code is unchanged (`130` for the `interrupt` reason). `defaultLines` and `lines()` already draw it as
2760
+ * its one fixed line.
2761
+ */
2762
+ readonly isCancelled: boolean;
2763
+ /**
2764
+ * `true` when the squashed `error` is the kit's {@link NotInteractive}: the program asked for a prompt or a screen in
2765
+ * a run that cannot show one (a pipe, an agent, a CI). It is a usage problem, not a bug, whichever channel it
2766
+ * arrived through; `isDefect` is as for {@link FailureDetails.isCancelled}.
2767
+ */
2768
+ readonly isNotInteractive: boolean;
2769
+ /**
2770
+ * The report the kit writes for this failure when there is no `render`: for this run, in this audience, with its
2771
+ * colour, links and `displayPath`. A `render` that hands a failure back returns these lines unchanged, and the
2772
+ * output is then exactly the default report. It equals `lines()`; to drop the leading status and keep the run's
2773
+ * settings, use {@link FailureDetails.lines} with `status: false`.
2774
+ */
2775
+ readonly defaultLines: ReadonlyArray<string>;
2776
+ /**
2777
+ * The report the kit would write for this failure, rendered for this run: its audience, colour, links and
2778
+ * `displayPath`.
2779
+ *
2780
+ * @remarks
2781
+ * `lines()` is {@link FailureDetails.defaultLines}. With `status: false` the leading status glyph, or the `[FAIL]`
2782
+ * tag in plain text, is left off, so a render that puts its own prefix in front (the program's name, say) reads
2783
+ * cleanly and still gets the run's colour and paths. `CliRuntime.defaultRender` with `status: false` drops the
2784
+ * status too, but it has no run to read and renders plain with absolute paths.
2785
+ *
2786
+ * ```ts
2787
+ * const render = (_error: unknown, details: FailureDetails) =>
2788
+ * details.lines({ status: false }).map((line, i) => (i === 0 ? `prog: ${line}` : line))
2789
+ * ```
2790
+ *
2791
+ * `spans` chooses the `in:` trail for these lines alone, as `CliFailureOptions.spans` does (`app`, `all` or
2792
+ * `off`); without it the run's own setting (`env.spans`, `app` by default) applies.
2793
+ *
2794
+ * @param options - `status: false` leaves off the leading status; `spans` chooses the span trail
2795
+ */
2796
+ readonly lines: (options?: {
2797
+ readonly status?: boolean | undefined;
2798
+ readonly spans?: "app" | "all" | "off" | undefined;
2799
+ }) => ReadonlyArray<string>;
2800
+ /**
2801
+ * The exit code this failure exits with: the error's own `Runtime.errorExitCode` when it carries one, else its
2802
+ * entry in `exitCodes` (a typed failure only), else `exitCode`, else `1`.
2803
+ *
2804
+ * @remarks
2805
+ * The code is decided before `render` is called, so a render can print it. A hook that parses a fixed stderr shape
2806
+ * builds it here, reading the tag off `error` itself:
2807
+ *
2808
+ * ```ts
2809
+ * const render = (error: unknown, details: FailureDetails) => {
2810
+ * const tag = Predicate.hasProperty(error, "_tag") && Predicate.isString(error._tag) ? error._tag : "Defect";
2811
+ * return `${details.exitCode} ${tag}: ${Fmt.sanitize(Fmt.describe(error))}`;
2812
+ * };
2813
+ * ```
2814
+ */
2815
+ readonly exitCode: number;
2816
+ }
2817
+ /**
2818
+ * How a failure is turned into output and an exit code.
2819
+ *
2820
+ * @public
2821
+ */
2822
+ interface ReportFailuresOptions {
2823
+ /**
2824
+ * Render the failure. Defaults to the failure's document, `CliFailure.toDoc(cause)`, rendered for the
2825
+ * audience: a failure status line, a tree for a schema failure, a defect's message with its cleaned stack, and
2826
+ * the one fixed line each for `Cancelled` and `NotInteractive`. Under `CliRuntime.main` with `env` it is painted for
2827
+ * a person and plain for an agent or a CI; elsewhere it is plain. It is still written through the logger.
2828
+ *
2829
+ * @remarks
2830
+ * Return several lines to print several: a config error's own message
2831
+ * followed by the rendered issue lines, say.
2832
+ *
2833
+ * `error` is the squashed cause: the first typed failure when there is
2834
+ * one, otherwise the first defect. `details` says which it is, so a typed
2835
+ * failure can render as one line and a defect as a full report, without
2836
+ * guessing from the error's shape. A renderer that takes only `error`
2837
+ * still fits.
2838
+ *
2839
+ * What it returns is text the kit did not build, so the report applies the output policy to it: under GitHub
2840
+ * Actions a line the runner would read as a workflow command is neutralized (with no environment services at all,
2841
+ * always), and for an agent or a CI audience escape sequences are removed (GitHub Actions detects as `ci`). For a person the escapes you return are kept,
2842
+ * since the kit cannot tell your own colour from an injected sequence: a `render` must sanitise the data it
2843
+ * interpolates (an error message, a file name) itself.
2844
+ */
2845
+ readonly render?: ((error: unknown, details: FailureDetails) => string | ReadonlyArray<string>) | undefined;
2846
+ /**
2847
+ * The exit code to use when the error does not carry one.
2848
+ *
2849
+ * @remarks
2850
+ * An error carrying `Runtime.errorExitCode` keeps its own; this is only the
2851
+ * fallback, and it defaults to `1`. Pass an integer in `0..255`, the range a
2852
+ * POSIX exit status can carry — `256` wraps to `0` and passes a failed run.
2853
+ */
2854
+ readonly exitCode?: number | undefined;
2855
+ /**
2856
+ * Exit codes by tag: a typed failure whose `_tag` is a key here exits with that code.
2857
+ *
2858
+ * @remarks
2859
+ * Checked after the error's own `Runtime.errorExitCode` (an error that chose its code keeps it) and before
2860
+ * `exitCode`, which stays the fallback for every other failure, defects included. Only a typed failure is looked
2861
+ * up: a defect that happens to carry a `_tag` exits with `exitCode`. A usage error (`usageExitCode`), a cancel
2862
+ * (`130`) and a non-interactive prompt (`64`) carry their own codes and are not looked up either.
2863
+ *
2864
+ * Each code must be an integer in `1..255`: `0` would pass a failed run, and `256` wraps to `0`. Anything else
2865
+ * throws a `RangeError` when the options are passed, since it is a wiring mistake, not a runtime condition.
2866
+ *
2867
+ * ```ts
2868
+ * CliRuntime.main(program, { platform, exitCodes: { DataStoreError: 3, SidecarTimeoutError: 2 }, exitCode: 5 })
2869
+ * ```
2870
+ */
2871
+ readonly exitCodes?: Readonly<Record<string, number>> | undefined;
2872
+ /**
2873
+ * The exit code for a usage error: a `ShowHelp` carrying parse errors, or a
2874
+ * `CliError.UserError` `Command.runWith` already printed.
2875
+ *
2876
+ * @remarks
2877
+ * Defaults to `64` (BSD `EX_USAGE`); pass an integer in `0..255`. A
2878
+ * `ShowHelp` with no errors — a bare root invocation, or `--help` — always
2879
+ * exits `0`. A `UserError` that carries its own `Runtime.errorExitCode` —
2880
+ * one marked with `CliRuntime.reported(error, 3)` — keeps that code instead.
2881
+ *
2882
+ * Keep `Command.runWith`'s default `renderErrors`: with `renderErrors: false`
2883
+ * runWith prints no parse errors and `reportFailures` never renders a
2884
+ * `ShowHelp`, so a parse error would exit with this code having printed
2885
+ * nothing on stderr.
2886
+ */
2887
+ readonly usageExitCode?: number | undefined;
2888
+ }
2889
+ /**
2890
+ * Options for `CliRuntime.main`.
2891
+ *
2892
+ * @public
2893
+ */
2894
+ interface MainOptions<RP, EP> extends ReportFailuresOptions {
2895
+ /**
2896
+ * The platform layer, usually `NodeServices.layer` or an app platform built
2897
+ * on it. Passed in so this package never imports a platform.
2898
+ */
2899
+ readonly platform: Layer.Layer<RP, EP>;
2900
+ /**
2901
+ * The logger, provided outermost. Defaults to `CliLogger.layer()`, or to `CliLog.layer(env.log)` when
2902
+ * `env.log` is given. An explicit `logger` wins over both.
2903
+ */
2904
+ readonly logger?: Layer.Layer<never> | undefined;
2905
+ /**
2906
+ * Provide the environment services, built by {@link CliEnv.layer}, inside failure reporting, where the platform
2907
+ * sits, together with `CliColor.formatterLayer` so help text follows the same colour decision.
2908
+ *
2909
+ * @remarks
2910
+ * The program may then require `CurrentRuntimeEnv`, `TerminalEnv`, `Audience` and `CliTheme` and read
2911
+ * `CliInteractive`. Without it `CliInteractive` keeps its non-interactive default, so forgetting this wiring
2912
+ * gives a CLI that never prompts. With `env.log`, `main` uses `CliLog.layer` as the logger set, and `env.log`
2913
+ * may carry the `file` option when the platform provides `FileSystem` and `Path`. A failure building the env
2914
+ * layer renders as one line and exits through `exitCode`.
2915
+ *
2916
+ * Not interactive, the `Terminal` the program sees is gated: its `readLine` fails as a quit, its input is
2917
+ * already ended and its `display` writes nothing. A program that reads piped data must read `Stdio.stdin`, and
2918
+ * one that writes output must use `Console` or `Stdio`, never `Terminal`.
2919
+ *
2920
+ * Stderr's colour follows its own terminal check, read from core's `Stdio`, so with stderr redirected and stdout
2921
+ * a terminal the failure report goes into the file unpainted. `env.stderrIsTerminal` replaces that check for a
2922
+ * host whose `Stdio` cannot say; a bin on the platform `Stdio` passes nothing.
2923
+ */
2924
+ readonly env?: CliEnvOptions | undefined;
2925
+ /**
2926
+ * Where the help document goes when it is printed with a usage error:
2927
+ * `"stdout"` (the default, core's behaviour) or `"stderr"`, beside the
2928
+ * errors.
2929
+ *
2930
+ * @remarks
2931
+ * `"stderr"` keeps stdout clean for a caller that parses it, such as a
2932
+ * hook piping JSON into `jq`: an unknown flag, a bad value or an unknown
2933
+ * subcommand then writes nothing to stdout. An explicit `--help` and a
2934
+ * bare invocation of a command group still print help on stdout: neither
2935
+ * is an error.
2936
+ *
2937
+ * `main` routes through core's `CliOutput.Presenter`, so the help and
2938
+ * errors are rendered by whichever `CliOutput` Formatter is in effect
2939
+ * where `Command.runWith` runs, one provided inside `program` included,
2940
+ * and written to whichever `Console` is in effect there. To change the
2941
+ * Formatter `main` installs, pass `env.formatter` (for example
2942
+ * `formatVersion`); a Formatter the platform provides is shadowed by
2943
+ * `main`'s, so pass it through `env.formatter` as well.
2944
+ *
2945
+ * Two cases keep help on stdout even under `"stderr"`. A `CliOutput`
2946
+ * Presenter provided inside `program` replaces the routing. And with
2947
+ * `Command.runWith`'s `renderErrors: false` core presents the help as
2948
+ * plain help, with no errors, so it is not a usage error's.
2949
+ */
2950
+ readonly helpOnUsageError?: "stdout" | "stderr" | undefined;
2951
+ /**
2952
+ * The carrier package the bin was installed through, when a carrier launched it: `null` (or `undefined`) for a
2953
+ * direct install.
2954
+ *
2955
+ * @remarks
2956
+ * Given (even as `null`), `main` provides `@effected/kit`'s `CurrentDistribution` around the program, as
2957
+ * `Option.some` of the carrier or `Option.none()`, so a program and the engine it calls read the same value. With a
2958
+ * carrier, `--version` ends with its `via <name> <version>` suffix (`distributionSuffix`), appended to whatever
2959
+ * `formatVersion` is in effect, the coloured default or `env.formatter`'s: do not also append it in
2960
+ * `env.formatter`.
2961
+ *
2962
+ * Core's default `formatVersion` prints `<name> v<version>`. A program moving off a hand-rolled `--version` that
2963
+ * printed another shape (no `v`, say) keeps it by passing that shape as `env.formatter`'s `formatVersion`; the
2964
+ * suffix is appended to it either way.
2965
+ *
2966
+ * ```ts
2967
+ * CliRuntime.main(CliAudience.run(root, { version }), { platform, env, distribution: options.distribution ?? null })
2968
+ * ```
2969
+ */
2970
+ readonly distribution?: Distribution | null | undefined;
2971
+ }
2972
+ /**
2973
+ * Report a CLI program's failures through the program's own logger.
2974
+ *
2975
+ * @remarks
2976
+ * ## What it prevents
2977
+ *
2978
+ * A platform `runMain` reports an unhandled failure using Effect's **default**
2979
+ * logger. That logger sits **outside** the layers the program was provided —
2980
+ * `makeRunMain` composes its reporting `tapCause` around the already-provided
2981
+ * effect — so a program that carefully installs {@link CliLogger} still prints
2982
+ * its failures in the structured format that logger exists to replace, and
2983
+ * prints them on **stdout**, the one stream errors must not use.
2984
+ *
2985
+ * Nothing about the call site suggests this. The program looks correct, the
2986
+ * logger is installed, every success path is right, and only a failure reveals
2987
+ * it.
2988
+ *
2989
+ * ## Why a combinator, and not a `runMain`
2990
+ *
2991
+ * The fix has to happen **inside** the effect, before any `runMain` sees it. So
2992
+ * this is a combinator you apply to your program, and you still call your own
2993
+ * platform's runner. Wrapping `runMain` itself would drag a platform choice into a library that
2994
+ * has no business making one, and would make this package unusable from Bun or
2995
+ * Deno for no gain.
2996
+ *
2997
+ * ## What it does with the failure
2998
+ *
2999
+ * Renders it through the ambient logger, then **re-fails with a marked error**
3000
+ * so the runtime still sees a failure — the exit code is the runtime's to set,
3001
+ * and swallowing the failure would make a broken run exit `0`.
3002
+ *
3003
+ * The marks are core's own, and they are what make this work without a platform
3004
+ * import:
3005
+ *
3006
+ * - `Runtime.errorExitCode` — `defaultTeardown` takes the squashed error's
3007
+ * value as the process exit code. An error that already carries one **keeps
3008
+ * it**: that was a deliberate choice by whatever raised it, and flattening
3009
+ * every failure to a single code would discard it.
3010
+ * - `Runtime.errorReported` — set to `false`, which suppresses the runtime's own
3011
+ * duplicate report. **The polarity is inverted relative to the name**: the
3012
+ * marker means "should this be reported", so the intuitive
3013
+ * `errorReported: true` — "I have reported it, stay quiet" — produces exactly
3014
+ * the double report it was meant to prevent.
3015
+ *
3016
+ * An **interrupt is left alone**: it is not a failure to report, and the
3017
+ * default teardown already maps an interrupt-only cause to `130`.
3018
+ *
3019
+ * A `CliError.ShowHelp` is never rendered: `Command.runWith` already printed
3020
+ * the help text (and any parse errors) before re-failing with it, so
3021
+ * rendering it again would print nothing but a stray "Help requested" line.
3022
+ * A `ShowHelp` carrying errors is remapped to `usageExitCode` (default `64`,
3023
+ * BSD `EX_USAGE`); a bare `--help` or root invocation — `errors` empty —
3024
+ * keeps exit `0`. A `CliError.UserError` whose `Runtime.errorReported` mark
3025
+ * is `false` is likewise skipped: that is how `Command.runWith` leaves one it
3026
+ * already rendered through its `CliOutput` formatter. It exits with its own
3027
+ * `Runtime.errorExitCode` when it carries one, otherwise `usageExitCode`;
3028
+ * under runWith's `renderErrors: false` the mark stays set, and it renders
3029
+ * here like any other failure. A handler failure carrying a
3030
+ * `CliError.userMessage` is skipped the same way, since `Command.runWith`
3031
+ * renders it and sets the mark to `false`; it keeps the exit code a
3032
+ * handler failure gets (`exitCodes` by tag, then `exitCode`). Every other
3033
+ * error renders even when it already carries the reported mark — a gate
3034
+ * failure marked with `CliRuntime.reported` still prints its line. The
3035
+ * private `ExitRequested` sentinel `CliRuntime.main`
3036
+ * raises is likewise never rendered; it only carries the exit code a
3037
+ * successful program recorded through `CliExit`.
3038
+ *
3039
+ * @example
3040
+ * ```ts
3041
+ * import { CliRuntime } from "@effected/cli-kit"
3042
+ * import { NodeRuntime } from "@effect/platform-node"
3043
+ * import { Effect } from "effect"
3044
+ *
3045
+ * NodeRuntime.runMain(program.pipe(CliRuntime.reportFailures(), Effect.provide(MainLive)))
3046
+ * ```
3047
+ *
3048
+ * @public
3049
+ */
3050
+ export declare class CliRuntime {
3051
+ private constructor();
3052
+ /**
3053
+ * What `reportFailures` and `main` render a failure as when no `render` option is given, for a consumer's own
3054
+ * `render` to hand a failure back to.
3055
+ *
3056
+ * @remarks
3057
+ * The plain lines of `CliFailure.toDoc(details.cause)`: a failure status line, a `Tree` for a schema failure, a
3058
+ * defect's message with its cleaned `stack`, and the one fixed line each for `Cancelled` and `NotInteractive`.
3059
+ * It has no terminal to ask, so it is the plain rendering for an agent, with absolute paths; the report `main` writes
3060
+ * with no `render` option is the same document in the renderer the audience gets (painted for a person), and that
3061
+ * report is `details.defaultLines`: return those to hand a failure back with the run's colour, links and path
3062
+ * display. With `status: false` the leading status (the glyph, or `[FAIL]` in plain text) is left off, so a prefix
3063
+ * such as the program's name reads cleanly; for that AND the run's settings, use `details.lines({ status: false })`.
3064
+ * A custom `render` that only cares about its own errors delegates the rest:
3065
+ *
3066
+ * ```ts
3067
+ * const render = (error: unknown, details: FailureDetails) =>
3068
+ * error instanceof MyError ? myLines(error) : CliRuntime.defaultRender(error, details)
3069
+ * ```
3070
+ *
3071
+ * @param error - the squashed failure
3072
+ * @param details - what `render` is told about the failure; accepted so a delegating `render` passes both
3073
+ * arguments through unchanged (only `cause` and `isDefect` are read)
3074
+ * @param options - `status: false` leaves off the leading status glyph or `[FAIL]` tag
3075
+ */
3076
+ static readonly defaultRender: (error: unknown, details: Pick<FailureDetails, "cause" | "isDefect">, options?: {
3077
+ readonly status?: boolean | undefined;
3078
+ }) => string | ReadonlyArray<string>;
3079
+ /**
3080
+ * Catch a program's failure, render it through the ambient logger, and re-fail with the exit code and the
3081
+ * no-double-report mark.
3082
+ *
3083
+ * @param options - how to render the failure and which exit codes to use
3084
+ */
3085
+ static readonly reportFailures: (options?: ReportFailuresOptions) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, Error, R>;
3086
+ /**
3087
+ * Assemble a CLI program in the one order that reports every failure well.
3088
+ *
3089
+ * @remarks
3090
+ * - `CliExit` is provided fresh, and a non-zero code after success becomes a
3091
+ * marked failure the teardown honours.
3092
+ * - The platform layer is provided **inside** failure reporting, so a
3093
+ * layer-build failure (`HOME` unset, say) renders as one line with the
3094
+ * fallback code rather than escaping to the runtime's stack trace.
3095
+ * - The logger is provided **outermost**, so it is present whichever branch
3096
+ * fails.
3097
+ * - With the `env` option, `CliEnv.layer` and `CliColor.formatterLayer` are
3098
+ * provided beside the platform, inside failure reporting, so the program can
3099
+ * read the audience, terminal, theme and `CliInteractive`.
3100
+ *
3101
+ * You still call your platform's runner.
3102
+ *
3103
+ * @example
3104
+ * ```ts
3105
+ * import { CliRuntime } from "@effected/cli-kit"
3106
+ * import { NodeRuntime, NodeServices } from "@effect/platform-node"
3107
+ * import { Command } from "effect/cli"
3108
+ *
3109
+ * NodeRuntime.runMain(
3110
+ * CliRuntime.main(Command.run(root, { version: "1.0.0" }), { platform: NodeServices.layer, exitCode: 3 }),
3111
+ * )
3112
+ * ```
3113
+ *
3114
+ * @param program - the CLI program, usually `Command.run(root, { version })`
3115
+ * @param options - the platform layer, and optionally the logger, environment services, exit codes and rendering
3116
+ */
3117
+ static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
3118
+ readonly env?: undefined;
3119
+ }): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit>, RP>>;
3120
+ static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
3121
+ readonly env: CliEnvOptions & {
3122
+ readonly log: CliLogFileOptions;
3123
+ };
3124
+ }): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit | CliEnvServices>, RP> | Exclude<Stdio.Stdio | Terminal.Terminal | FileSystem.FileSystem | Path.Path, RP>>;
3125
+ static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
3126
+ readonly env: CliEnvOptions & {
3127
+ readonly log?: CliLogOptions & {
3128
+ readonly file?: undefined;
3129
+ };
3130
+ };
3131
+ }): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit | CliEnvServices>, RP> | Exclude<Stdio.Stdio | Terminal.Terminal, RP>>;
3132
+ static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
3133
+ readonly env: CliEnvOptions;
3134
+ }): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit | CliEnvServices>, RP> | Exclude<Stdio.Stdio | Terminal.Terminal | FileSystem.FileSystem | Path.Path, RP>>;
3135
+ /**
3136
+ * Mark an error as already reported, carrying an exit code.
3137
+ *
3138
+ * @remarks
3139
+ * Exported because a program that reports a failure itself — a validation
3140
+ * command that prints its own diagnostics, say — needs the same two marks
3141
+ * and should not have to rediscover the inverted polarity.
3142
+ *
3143
+ * Under `CliRuntime.main` or {@link CliRuntime.reportFailures}, do NOT
3144
+ * print the failure yourself before failing with it: `reportFailures`
3145
+ * renders every error except a `ShowHelp`, a `CliError.UserError` whose
3146
+ * reported mark is `false`, and any error carrying a string
3147
+ * `[CliError.userMessage]` whose reported mark is `false`, so it would
3148
+ * print twice. Fail with the marked
3149
+ * error and put any multi-line rendering in the `render` option instead. The
3150
+ * mark matters for a program run WITHOUT `reportFailures`, where it keeps the
3151
+ * runtime from reporting a failure the program already printed.
3152
+ *
3153
+ * A `CliError.UserError` marked with `reported` is treated as already
3154
+ * printed and is not rendered — use a different error type if the program
3155
+ * has not printed it. `reportFailures` cannot tell a `UserError` that
3156
+ * `Command.runWith` printed from one marked here: both carry the same `false`
3157
+ * mark. It does keep the code you pass: `reported(userError, 3)` exits `3`,
3158
+ * not `usageExitCode`.
3159
+ *
3160
+ * The same holds for an error carrying a string `[CliError.userMessage]`:
3161
+ * `Command.runWith` prints such a handler failure and leaves the same
3162
+ * `false` mark, so one marked here is treated as already printed and is not
3163
+ * rendered. Mark an error without the annotation, or leave it unmarked, if
3164
+ * the program has not printed it. It keeps the code you pass.
3165
+ *
3166
+ * The marks are added in place, so a typed error comes back as its own
3167
+ * type: the `E` overload returns the very instance it was given, and a
3168
+ * program failing with it keeps `catchTags` narrowing downstream without a
3169
+ * cast. Any other value takes the `unknown` fallback and is wrapped in a
3170
+ * plain `Error`.
3171
+ *
3172
+ * The `E extends Error` constraint is structural, not nominal — TypeScript
3173
+ * cannot express "is really an `Error`", so the guarantee holds only when
3174
+ * the argument passes `instanceof Error` at runtime. A value that merely
3175
+ * satisfies `Error`'s shape (an object `implements Error`, or an error
3176
+ * revived from JSON) still takes the wrapping branch and comes back as a
3177
+ * fresh, stripped `Error` typed as `E`.
3178
+ */
3179
+ static reported<E extends Error>(error: E, exitCode?: number): E;
3180
+ static reported(error: unknown, exitCode?: number): Error;
3181
+ }
3182
+ /**
3183
+ * Turns a `@effected/config-file` `ConfigValidationError` into one line per rejected value.
3184
+ *
3185
+ * @remarks
3186
+ * `ConfigValidationError` carries the structured `issue` tree rather than a
3187
+ * string, so a caller holds a tree it has to turn into sentences. This is that
3188
+ * step, the same treatment {@link SchemaIssueRenderer} gives a bare issue.
3189
+ *
3190
+ * `ConfigValidationError.message` names the file but not the value, and the
3191
+ * value is the diagnostic: printing only the message tells a user their config
3192
+ * is invalid without saying which value is wrong or how it is shaped.
3193
+ *
3194
+ * `@effected/config-file` is an optional peer, and this module only
3195
+ * `import type`s it, so the import is erased at build time. A consumer without
3196
+ * the package installed can import this module without the resolver being asked
3197
+ * for it.
3198
+ *
3199
+ * @example
3200
+ * ```ts
3201
+ * import { ConfigIssueRenderer } from "@effected/cli-kit"
3202
+ * import { Effect } from "effect"
3203
+ *
3204
+ * const load = configFile.load.pipe(
3205
+ * Effect.catchTag("ConfigValidationError", (error) =>
3206
+ * Effect.gen(function* () {
3207
+ * yield* Effect.logError(String(error))
3208
+ * for (const line of ConfigIssueRenderer.render(error)) yield* Effect.logError(` ${line}`)
3209
+ * }),
3210
+ * ),
3211
+ * )
3212
+ * ```
3213
+ *
3214
+ * @public
3215
+ */
3216
+ export declare class ConfigIssueRenderer {
3217
+ private constructor();
3218
+ /**
3219
+ * One line per rejected value.
3220
+ *
3221
+ * @remarks
3222
+ * Takes the **error**, not its `issue`, because that is what a `catchTag`
3223
+ * hands you and because `issue` is typed `Schema.Defect`, which every call
3224
+ * site would otherwise have to reach into. Inside
3225
+ * `Effect.catchTag("ConfigValidationError", …)` the error is already this
3226
+ * type.
3227
+ *
3228
+ * An unknown key the schema has a near match for at the same path ends in a
3229
+ * hint, `unknown key at theme.colour (did you mean "color"?)`, drawn from the
3230
+ * keys the struct declares there (every branch's, under a union) with
3231
+ * {@link Fmt.suggest}'s threshold. A key with no near match is drawn exactly
3232
+ * as {@link SchemaIssueRenderer} draws it.
3233
+ *
3234
+ * It cannot throw on a malformed value: the issue tree is validated by
3235
+ * a guard before it is read, so a renderer on an error path never becomes the
3236
+ * reason a program dies.
3237
+ */
3238
+ static readonly render: (error: ConfigValidationError) => ReadonlyArray<string>;
3239
+ }
3240
+ /**
3241
+ * Options for {@link Fmt.truncate}.
3242
+ *
3243
+ * @public
3244
+ */
3245
+ interface TruncateOptions {
3246
+ /** Marks the cut; `…` by default. Counted by display width. */
3247
+ readonly ellipsis?: string | undefined;
3248
+ }
3249
+ /**
3250
+ * Options for {@link Fmt.percent}.
3251
+ *
3252
+ * @public
3253
+ */
3254
+ interface PercentOptions {
3255
+ /** Decimal places to round to; `1` by default. A trailing zero decimal is dropped. */
3256
+ readonly digits?: number | undefined;
3257
+ /**
3258
+ * What the input is scaled to: `1` (the default) is a ratio from 0 to 1, `100` is already a percentage from 0
3259
+ * to 100, as istanbul's coverage numbers are.
3260
+ */
3261
+ readonly scale?: 1 | 100 | undefined;
3262
+ }
3263
+ /**
3264
+ * Options for {@link Fmt.pad}.
3265
+ *
3266
+ * @public
3267
+ */
3268
+ interface PadOptions {
3269
+ /**
3270
+ * Where the text sits in the padded field: `left` (the default) fills on the right, `right` fills on the left, and
3271
+ * `center` splits the fill, the odd column going on the right.
3272
+ */
3273
+ readonly align?: "left" | "right" | "center" | undefined;
3274
+ /** The fill, one column wide; a space by default. Anything that is not exactly one column wide is a space. */
3275
+ readonly fill?: string | undefined;
3276
+ }
3277
+ /**
3278
+ * Options for {@link Fmt.suggest}.
3279
+ *
3280
+ * @public
3281
+ */
3282
+ interface SuggestOptions {
3283
+ /** The most edits a suggestion may be away from the input; `2` by default, as `effect/cli` uses. */
3284
+ readonly maxDistance?: number | undefined;
3285
+ }
3286
+ /**
3287
+ * Small, pure formatting primitives for terminal output.
3288
+ *
3289
+ * @public
3290
+ */
3291
+ export declare class Fmt {
3292
+ private constructor();
3293
+ /**
3294
+ * Text made safe to lay out and print, exactly as the renderers make it: complete ANSI and OSC sequences removed,
3295
+ * every other control character removed (a stray ESC, BEL, BS, DEL, the C1 range) except line feed and carriage
3296
+ * return, and a tab turned into a space.
3297
+ *
3298
+ * @remarks
3299
+ * For a `render` or any other text a program builds by hand from data it does not control: an error message, a
3300
+ * file name, a value from the environment. Line breaks are kept, so split on them if the text must be one line.
3301
+ *
3302
+ * @param text - the text
3303
+ */
3304
+ static readonly sanitize: (text: string) => string;
3305
+ /**
3306
+ * The display width of `text` in terminal columns: wide East Asian characters and emoji count two,
3307
+ * combining marks and ANSI escapes count none.
3308
+ *
3309
+ * @param text - the text to measure
3310
+ */
3311
+ static readonly width: (text: string) => number;
3312
+ /**
3313
+ * Cut `text` to at most `width` columns, ending in `ellipsis` when it was cut.
3314
+ *
3315
+ * @remarks
3316
+ * Grapheme-safe: a grapheme, such as a wide character or an emoji ZWJ family, is kept whole or dropped
3317
+ * whole, so the result is never wider than `width`. Text that already fits is returned unchanged, colour
3318
+ * escapes included. Text that must be cut is cut as plain text: its ANSI escapes are dropped rather than cut
3319
+ * in half. When the ellipsis cannot fit, it is omitted and the text is cut to `width`; a `width` of 0 or
3320
+ * less gives `""`.
3321
+ *
3322
+ * @param text - the text to truncate
3323
+ * @param width - the most columns the result may take
3324
+ * @param options - the ellipsis
3325
+ */
3326
+ static readonly truncate: (text: string, width: number, options?: TruncateOptions) => string;
3327
+ /**
3328
+ * A duration as short human text: `250ms`, `1.2s`, `2s`, `1m 3s`, `2m`, `1h 2m`, `2h`.
3329
+ *
3330
+ * @remarks
3331
+ * Under a second it is whole milliseconds; under a minute, seconds to one decimal with a trailing `.0`
3332
+ * dropped; under an hour, minutes and whole seconds, with the seconds dropped when zero; from an hour, hours and
3333
+ * whole minutes, the seconds dropped. A value that rounds up to the next unit (`999.6` to a second, `59999` to a
3334
+ * minute, `3599999` to an hour) is written in that unit, so `1000ms`, `60s` and `60m` never appear. There is no
3335
+ * days unit. The format is bespoke: core's `Duration.format` renders differently.
3336
+ *
3337
+ * The input is anything `Duration.Input` admits. A plain number is milliseconds and is used as given, never
3338
+ * converted through a `Duration`, which rounds a fractional millisecond to whole nanoseconds and would move a value
3339
+ * such as `999.4999999` across the rounding boundary. A `bigint` is nanoseconds, as in core. A negative, infinite
3340
+ * or invalid input (a string `Duration.Input` cannot parse) is `0ms`: a formatter in a render path never throws.
3341
+ *
3342
+ * @param input - the duration; a number is milliseconds
3343
+ */
3344
+ static readonly duration: (input: Duration.Input) => string;
3345
+ /**
3346
+ * A ratio from 0 to 1 as a percentage, or a number already from 0 to 100 with `scale: 100`: `83.3%`, `50%`,
3347
+ * `100%`.
3348
+ *
3349
+ * @remarks
3350
+ * Rounded to `digits` decimal places (one by default) with trailing zeros dropped, so whole values print
3351
+ * without a decimal. A value that rounds to zero prints `0%`, never `-0%`. The input is not validated.
3352
+ *
3353
+ * @param n - the ratio, 0 to 1 (0 to 100 with `scale: 100`)
3354
+ * @param options - the decimal places and the scale
3355
+ */
3356
+ static readonly percent: (n: number, options?: PercentOptions) => string;
3357
+ /**
3358
+ * A count with its noun: `1 test`, `2 tests`, `0 tests`.
3359
+ *
3360
+ * @param n - the count
3361
+ * @param singular - the noun for exactly one
3362
+ * @param plural - the noun otherwise; `singular` with an `s` appended by default
3363
+ */
3364
+ static readonly plural: (n: number, singular: string, plural?: string) => string;
3365
+ /**
3366
+ * Pad `text` to `width` terminal columns, measured as {@link Fmt.width} measures: a wide character counts two and
3367
+ * an escape sequence none, so coloured text pads to the same column as plain text.
3368
+ *
3369
+ * @remarks
3370
+ * Text already `width` columns or wider is returned unchanged: compose with {@link Fmt.truncate} to cut it. A
3371
+ * `width` that is not a finite number pads nothing. Never throws.
3372
+ *
3373
+ * @param text - the text to pad
3374
+ * @param width - the columns the result should take
3375
+ * @param options - the alignment and the fill
3376
+ */
3377
+ static readonly pad: (text: string, width: number, options?: PadOptions) => string;
3378
+ /**
3379
+ * `text` without its escape sequences: CSI (colour, cursor moves, erases), OSC (titles, OSC 8 hyperlinks) ending in
3380
+ * BEL or ST, the DCS, SOS, PM and APC strings, and every other escape, the nF sequences (`ESC ( B`) and the
3381
+ * two-byte ones (`ESC 7`, `ESC 8`, `ESC =`, `ESC c`).
3382
+ *
3383
+ * @remarks
3384
+ * The same strip {@link Fmt.width} and {@link Fmt.sanitize} start from. Only complete sequences go: a lone ESC, or
3385
+ * any other control character, is kept, and so is an ESC in front of a lowercase letter other than `c`, which a
3386
+ * stray ESC before a word would otherwise cost the word its first letter. An unterminated CSI or OSC keeps its `[`
3387
+ * or `]`. Use {@link Fmt.sanitize} for text that will be laid out and printed.
3388
+ *
3389
+ * @param text - the text
3390
+ */
3391
+ static readonly stripAnsi: (text: string) => string;
3392
+ /**
3393
+ * Whether `text` is nothing but escape sequences, as {@link Fmt.stripAnsi} reads them: a cursor hide or show, a
3394
+ * clear-screen, an erase-scrollback. Empty text is not escape-only, and neither is a bare control character
3395
+ * (`\r`, BEL), which is not an escape sequence.
3396
+ *
3397
+ * @param text - the text
3398
+ */
3399
+ static readonly isEscapeOnly: (text: string) => boolean;
3400
+ /**
3401
+ * Integers as compact ranges: `[1, 2, 3, 5, 10, 11]` is `"1-3,5,10-11"`, a run of consecutive numbers written
3402
+ * `start-end` and the rest one by one, joined with commas.
3403
+ *
3404
+ * @remarks
3405
+ * The input is sorted and its duplicates dropped first, so order does not matter. Anything that is not a finite
3406
+ * integer is left out, and no input is `""`. Never throws.
3407
+ *
3408
+ * @param numbers - the integers, such as line numbers
3409
+ */
3410
+ static readonly ranges: (numbers: Iterable<number>) => string;
3411
+ /**
3412
+ * Any value as text, without ever throwing.
3413
+ *
3414
+ * @remarks
3415
+ * A string is itself; a number, boolean, bigint or symbol is `String(value)`; `undefined` and `null` are
3416
+ * `"undefined"` and `"null"`. A value with a string `message` (an `Error`, one from another realm, a plain
3417
+ * `{ message }`) is that message. Anything else is its JSON, or `String(value)` when it has none (a cycle, a
3418
+ * function), or `"[unprintable value]"` when that throws too. A getter that throws is a value with no message.
3419
+ *
3420
+ * The text is not sanitised: pass it through {@link Fmt.sanitize} before printing data you do not control. For
3421
+ * the messages along an error's `cause` chain, use {@link Fmt.causeMessage}; for the two combined, use
3422
+ * {@link Fmt.errorText}.
3423
+ *
3424
+ * It is `@effected/kit`'s `ErrorText.describe`, the same function, so a front end that cannot depend on this
3425
+ * package (an MCP server) describes a value with the same words.
3426
+ *
3427
+ * @param value - the value
3428
+ */
3429
+ static readonly describe: (value: unknown) => string;
3430
+ /**
3431
+ * Every distinct non-empty message along a value's `cause` chain, nearest first and joined with `: `, or
3432
+ * `undefined` when nothing along it has one.
3433
+ *
3434
+ * @remarks
3435
+ * The kit's one guarded cause-message read, the one its own errors render a preserved cause with. A node's message
3436
+ * is a thrown string or a non-empty string `message` property, read without `instanceof Error`, so an error from
3437
+ * another realm or a plain `{ message }` object counts. A deeper message the joined text already contains is not
3438
+ * repeated, and one that contains the joined text replaces it, so a `SqlError` wrapping SQLite's own text reads
3439
+ * `Failed to execute statement: SQLITE_BUSY: database is locked`. It is the whole chain, not the innermost
3440
+ * message alone. The walk stops after eight nodes, so a cyclic chain terminates.
3441
+ *
3442
+ * Never throws: a `message` getter that throws leaves that node without text, and a `cause` getter that throws ends
3443
+ * the walk with the text found so far, `undefined` when there is none, so a caller's own fallback
3444
+ * (`?? Fmt.describe(value)`, which {@link Fmt.errorText} spells once) applies.
3445
+ *
3446
+ * It is `@effected/kit`'s `ErrorText.causeMessage`, the same function.
3447
+ *
3448
+ * @param value - the error, or whatever was thrown
3449
+ */
3450
+ static readonly causeMessage: (value: unknown) => string | undefined;
3451
+ /**
3452
+ * The text of an unknown failure: {@link Fmt.causeMessage} when the chain carries a message, otherwise
3453
+ * {@link Fmt.describe}.
3454
+ *
3455
+ * @remarks
3456
+ * Exactly `Fmt.causeMessage(value) ?? Fmt.describe(value)`, the fallback an I/O site turning a caught value into
3457
+ * text would otherwise spell out by hand at every call. An error whose message is empty and whose chain carries none
3458
+ * is `""`, as `describe` reads it. Never throws, and not sanitised: pass it through {@link Fmt.sanitize} before
3459
+ * printing data you do not control. It is `@effected/kit`'s `ErrorText.of`, the same function.
3460
+ *
3461
+ * @param value - the error, or whatever was thrown
3462
+ */
3463
+ static readonly errorText: (value: unknown) => string;
3464
+ /**
3465
+ * The candidates nearest to `input`, for a "did you mean" hint: those at the smallest edit distance found, up to
3466
+ * `maxDistance` edits (two by default), in the order given, each once. No candidate that close is `[]`.
3467
+ *
3468
+ * @remarks
3469
+ * The distance is Levenshtein's (one insertion, deletion or substitution per edit), over UTF-16 code units and
3470
+ * case-sensitive, with the same two-edit threshold and the same ties-all-kept rule `effect/cli` uses for an unknown
3471
+ * subcommand or flag, so a program's own suggestions agree with the parser's. A candidate equal to `input` is at
3472
+ * distance zero and is the only one returned.
3473
+ *
3474
+ * The cost is linear in the candidates' total length: a candidate whose length differs from `input`'s by more than
3475
+ * `maxDistance` is skipped unmeasured, and only the band of the edit matrix within `maxDistance` of its diagonal is
3476
+ * measured, so a long typed value cannot make it quadratic. A `maxDistance` that is not a non-negative integer is a programming mistake and
3477
+ * throws a `RangeError`.
3478
+ *
3479
+ * ```ts
3480
+ * Fmt.suggest("stauts", ["status", "stack", "build"]) // => ["status"]
3481
+ * ```
3482
+ *
3483
+ * @param input - what was typed: an unknown key, a profile name, a phase name
3484
+ * @param candidates - the names it could have meant
3485
+ * @param options - the most edits a suggestion may be away
3486
+ */
3487
+ static readonly suggest: (input: string, candidates: Iterable<string>, options?: SuggestOptions) => ReadonlyArray<string>;
3488
+ }
3489
+ /**
3490
+ * The severity of a GitHub annotation.
3491
+ *
3492
+ * @public
3493
+ */
3494
+ type AnnotationLevel = "error" | "warning" | "notice";
3495
+ /**
3496
+ * What an annotation says about where it points and what it is called.
3497
+ *
3498
+ * @public
3499
+ */
3500
+ interface GithubAnnotationProperties {
3501
+ /** `error`, `warning` or `notice`. */
3502
+ readonly level: AnnotationLevel;
3503
+ /** The repository-relative path of the annotated file. */
3504
+ readonly file?: string;
3505
+ /** The first annotated line, 1-based. */
3506
+ readonly line?: number;
3507
+ /** The first annotated column, 1-based. */
3508
+ readonly col?: number;
3509
+ /** The last annotated line. */
3510
+ readonly endLine?: number;
3511
+ /** The last annotated column. */
3512
+ readonly endColumn?: number;
3513
+ /** A short title shown above the annotation. */
3514
+ readonly title?: string;
3515
+ }
3516
+ /**
3517
+ * GitHub Actions annotations, as workflow commands.
3518
+ *
3519
+ * @public
3520
+ */
3521
+ export declare class GithubAnnotation {
3522
+ private constructor();
3523
+ /**
3524
+ * Format an annotation as a workflow command: `::error title=T,file=F,line=1,endLine=2,col=3,endColumn=4::message`.
3525
+ *
3526
+ * @remarks
3527
+ * The message escapes `%`, CR and LF; a property value escapes those and `:` and `,`, per GitHub's
3528
+ * [workflow-command documentation](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions).
3529
+ * The percent sign is escaped first, so an escape that was just written is never escaped again. An unescaped line
3530
+ * break in a message would let the text after it be read as a new command, which is why the escaping is not optional.
3531
+ *
3532
+ * A property that is not given is left out, and the properties are written in the order `title`, `file`, `line`,
3533
+ * `endLine`, `col`, `endColumn`, the same as `@effected/github-commands`' `WorkflowCommand`, which this renders
3534
+ * through.
3535
+ *
3536
+ * @param annotation - the level and the optional file, position and title
3537
+ * @param message - the annotation's text
3538
+ */
3539
+ static readonly format: (annotation: GithubAnnotationProperties, message: string) => string;
3540
+ }
3541
+ declare const NotInteractive_base: Schema.Class<NotInteractive, Schema.TaggedStruct<"NotInteractive", {}>, import("effect/Cause").YieldableError>;
3542
+ /**
3543
+ * A command needed to prompt, but there is no terminal to prompt on.
3544
+ *
3545
+ * @remarks
3546
+ * Exits `64` (BSD `EX_USAGE`) through core's `Runtime.errorExitCode` marker:
3547
+ * the caller invoked the command the wrong way, so the fix is to run it in a
3548
+ * terminal or pass the flag that supplies the answer. Its default rendering is
3549
+ * one line, `not interactive: run in a terminal or pass the flag`, which is the error's `message`, so a consumer
3550
+ * `render` can print `error.message` and keep it.
3551
+ *
3552
+ * @public
3553
+ */
3554
+ export declare class NotInteractive extends NotInteractive_base {
3555
+ /**
3556
+ * The one line, `not interactive: run in a terminal or pass the flag`.
3557
+ *
3558
+ * @remarks
3559
+ * A prototype getter, not a field, so it is not part of the encoded form, equality or a JSON dump. Assigning to
3560
+ * it is ignored: a library that rewrites `error.message` must not make this error throw, which a getter-only
3561
+ * property does in strict mode. The line is fixed.
3562
+ */
3563
+ get message(): string;
3564
+ set message(_value: string);
3565
+ /**
3566
+ * The process exit code: `64`.
3567
+ *
3568
+ * @remarks
3569
+ * A prototype getter rather than an own field, so a JSON or logger dump of the error does not carry the
3570
+ * runtime marker. It is the error's own code, so `CliRuntime`'s `usageExitCode` option does not change it.
3571
+ */
3572
+ get [Runtime.errorExitCode](): number;
3573
+ }
3574
+ /**
3575
+ * Everything a renderer needs to know about where its output is going.
3576
+ *
3577
+ * @remarks
3578
+ * A renderer is a pure function of a document and one of these, so two contexts give two renderings of the
3579
+ * same document. `paint` and `link` are plain functions: a context for a stream with no colour passes the
3580
+ * identity, and one whose hyperlinks are off passes a `link` that returns its label unchanged.
3581
+ *
3582
+ * @public
3583
+ */
3584
+ interface RenderContext {
3585
+ /**
3586
+ * The display columns available.
3587
+ *
3588
+ * @remarks
3589
+ * `Infinity` is no limit. A renderer clamps what it is given: zero or a negative width is 1, and `NaN` is 80.
3590
+ * `Render.context` gives a human writing to a terminal `TerminalEnv.width()`, which is the terminal's columns as
3591
+ * stdout reports them, even for a context built for `"stderr"` (core's `Terminal` has one width), and gives no limit
3592
+ * when the stream is not a terminal; pass `width` to override it.
3593
+ */
3594
+ readonly width: number;
3595
+ /** Who the output is for. */
3596
+ readonly audience: AudienceKind;
3597
+ /** The colour level of the stream being written. */
3598
+ readonly color: ColorLevel;
3599
+ /** Paints text in a token or a style; the identity at colour `none`. */
3600
+ readonly paint: (token: TokenName | Style, text: string) => string;
3601
+ /** The glyph set: status glyphs, separators, the ellipsis. */
3602
+ readonly glyphs: GlyphSet;
3603
+ /**
3604
+ * Wraps a label as a link to a target; returns the label unchanged when links are off.
3605
+ *
3606
+ * @remarks
3607
+ * It must be pure and cheap: a renderer may call it more than once for one link. `Render.ansi` calls it once with
3608
+ * the plain label to learn whether links are on (an unchanged label means off, and the target is then written
3609
+ * after the label), and again when it paints, with the painted label. So it must decide on whether links are
3610
+ * allowed, not on the label's content, and it must not count or record its calls.
3611
+ */
3612
+ readonly link: (target: LinkTarget, label: string) => string;
3613
+ /** Turns an absolute path into its display form; the identity by default. */
3614
+ readonly displayPath: (absolute: string) => string;
3615
+ /**
3616
+ * Whether the output will be read by the GitHub Actions runner, which has two command parsers: a line is a command
3617
+ * if, after .NET whitespace, it starts with `::`, or if `##[` occurs ANYWHERE in it (a bare `##` is not one). When
3618
+ * `true`, `plain`, `ansi` and `markdown` put a braille pattern blank (U+2800, one blank cell) in front of such a
3619
+ * `::` line and before the `[` of each `##[`, so a document's text, an error message, say, can never inject a command. Unset or `false`
3620
+ * leaves their text alone. `Render.githubLog` ignores it and always neutralizes: its output is for the runner by
3621
+ * definition.
3622
+ *
3623
+ * @remarks
3624
+ * The trigger is the runner, not the audience: a person or an agent whose output lands in an Actions log is read
3625
+ * by it just the same. `Render.context` sets it when `CurrentRuntimeEnv` says GitHub Actions.
3626
+ */
3627
+ readonly neutralizeWorkflowCommands?: boolean | undefined;
3628
+ /**
3629
+ * A base URL for file links in markdown, such as `https://github.com/<owner>/<repo>/blob/<sha>/`. When set,
3630
+ * `Render.markdown` links a `{ file }` target to the base followed by its display path (`displayPath`, URL-encoded,
3631
+ * without a leading `/`) and `#L<line>` when it has a line, in place of a `file://` URL a step summary's reader
3632
+ * cannot open. The other renderers do not read it.
3633
+ */
3634
+ readonly linkBase?: string | undefined;
3635
+ /**
3636
+ * How many GitHub Actions log groups are open around the output. Unset or `0`, none is: `Render.githubLog` then
3637
+ * writes a top-level collapsible as a `::group::`. Above `0` it writes the collapsible as plain does, its title on
3638
+ * a line and its body indented, because the runner does not nest groups and a second `::group::` would end the open
3639
+ * one. The other renderers do not read it.
3640
+ *
3641
+ * @remarks
3642
+ * `Render.context` reads it from the fiber-local keyed by `WorkflowCommand.groupDepthKey`
3643
+ * (`@effected/github-commands`), the count `ActionLogger.group` in `@effected/github-actions` provides around a
3644
+ * group's body, so a context built inside a group knows it. It is read when the context is built, not when a
3645
+ * document is rendered: a context built outside a group and used inside one still says none is open, so build it
3646
+ * where the document is printed, as `Doc.print` does.
3647
+ */
3648
+ readonly groupDepth?: number | undefined;
3649
+ }
3650
+ /**
3651
+ * Options for {@link Render.contextOf}.
3652
+ *
3653
+ * @public
3654
+ */
3655
+ interface RenderContextOfOptions {
3656
+ /** Who the output is for. An `agent` gets no escape of any kind, whatever the other options say. */
3657
+ readonly audience: AudienceKind;
3658
+ /** The colour level; `none` by default, which paints nothing. */
3659
+ readonly color?: ColorLevel | undefined;
3660
+ /** The glyph set; Unicode by default. */
3661
+ readonly glyphs?: GlyphSet | undefined;
3662
+ /** The display columns; unbounded (`Infinity`) by default. */
3663
+ readonly width?: number | undefined;
3664
+ /** Turns an absolute path into its display form; the identity by default. */
3665
+ readonly displayPath?: ((absolute: string) => string) | undefined;
3666
+ /**
3667
+ * Hyperlinks: `off` (the default) leaves every label unlinked; a `CliLinksShape`, such as a `CliLinks` service's
3668
+ * value, makes OSC 8 hyperlinks through {@link CliLinks.linker}, for any audience but an agent.
3669
+ */
3670
+ readonly links?: "off" | CliLinksShape | undefined;
3671
+ /**
3672
+ * See {@link RenderContext.neutralizeWorkflowCommands}. `true` by default for a `ci` audience, whose output the
3673
+ * Actions runner may read (it is harmless elsewhere), and unset for the others; an explicit `false` always wins.
3674
+ */
3675
+ readonly neutralizeWorkflowCommands?: boolean | undefined;
3676
+ /** See {@link RenderContext.linkBase}; unset by default. */
3677
+ readonly linkBase?: string | undefined;
3678
+ /** See {@link RenderContext.groupDepth}; unset (no group open) by default. */
3679
+ readonly groupDepth?: number | undefined;
3680
+ }
3681
+ /**
3682
+ * Options for {@link Render.context}.
3683
+ *
3684
+ * @public
3685
+ */
3686
+ interface RenderContextOptions {
3687
+ /**
3688
+ * The display columns to lay out at. By default a human writing to a terminal gets `TerminalEnv.width()`, the
3689
+ * terminal's columns as stdout reports them even when the stream is `"stderr"`; a human whose stream is not a
3690
+ * terminal (a pipe, a file), an agent and a CI get no limit at all.
3691
+ */
3692
+ readonly width?: number | undefined;
3693
+ /** Turns an absolute path into its display form, for example relative to the working directory; the identity by default. */
3694
+ readonly displayPath?: ((absolute: string) => string) | undefined;
3695
+ }
3696
+ /**
3697
+ * Pure renderers of a document: `(doc, context) => string`.
3698
+ *
3699
+ * @remarks
3700
+ * A renderer has no environment and no effects, so the same document and context always give the same string.
3701
+ * {@link Render.plain} is for agents; the rest of the set follows.
3702
+ *
3703
+ * @example
3704
+ * ```ts
3705
+ * import { Doc, Render } from "@effected/cli-kit"
3706
+ *
3707
+ * const doc = [Doc.heading(2, "Results"), Doc.paragraph("3 checks passed")]
3708
+ * const ctx = Render.contextOf({ audience: "agent" })
3709
+ *
3710
+ * Render.plain(doc, ctx)
3711
+ * // => "Results\n3 checks passed"
3712
+ * ```
3713
+ *
3714
+ * @public
3715
+ */
3716
+ export declare class Render {
3717
+ private constructor();
3718
+ /**
3719
+ * The {@link RenderContext} for a stream, from the services a CLI already has.
3720
+ *
3721
+ * @remarks
3722
+ * Everything is read once, here, so the renderers stay pure:
3723
+ *
3724
+ * - `audience` is the `Audience` in force, so an audience flag is honoured;
3725
+ * - `color`, `paint` and `glyphs` are the `CliTheme`'s for THAT stream, so redirecting stdout does not quiet
3726
+ * stderr; except that an agent's `color` is `none` and its `paint` the identity, so no renderer, `ansi` included,
3727
+ * writes an escape for an agent whatever the terminal could do;
3728
+ * - `link` is `CliLinks.linker` over that stream's hyperlink support and the audience, so an agent never
3729
+ * gets an escape and a terminal without OSC 8 gets the label;
3730
+ * - `neutralizeWorkflowCommands` is set when `CurrentRuntimeEnv` says GitHub Actions (read if present, not
3731
+ * required), for every audience, since the runner reads whatever is written there;
3732
+ * - `width` is the option, else `TerminalEnv.width()` for a human whose stream is a terminal, and **unbounded**
3733
+ * (`Infinity`) for a human whose stream is not one (`tool | grep`, `tool > out.txt`), an agent or a CI, so nothing
3734
+ * a reader needs is truncated or wrapped for a terminal that is not there: a pipe has no width to honour;
3735
+ * - `groupDepth` is the fiber's count of open Actions log groups (the fiber-local keyed by
3736
+ * `WorkflowCommand.groupDepthKey`, which `ActionLogger.group` provides), set when it is above `0`, so a
3737
+ * document printed inside a group opens no second one; see {@link RenderContext.groupDepth}.
3738
+ * - `displayPath` is the option, else the run's own path display (`CliEnvOptions.displayPath`, which
3739
+ * `CliEnv.layer` sets), else the identity.
3740
+ *
3741
+ * @param stream - the stream the output is for
3742
+ * @param options - an explicit width and a path display function
3743
+ */
3744
+ static readonly context: (stream: "stdout" | "stderr", options?: RenderContextOptions) => Effect.Effect<RenderContext, never, CliTheme | TerminalEnv | Audience | CliLinks>;
3745
+ /**
3746
+ * A {@link RenderContext} from plain options, for a caller outside Effect, such as a test reporter or an Ink tree.
3747
+ *
3748
+ * @remarks
3749
+ * Pure: nothing is read from the environment. The defaults are colour `none`, the identity paint, no links,
3750
+ * Unicode glyphs, unbounded width and the identity `displayPath`, so a context built from an audience alone renders
3751
+ * with no escape of any kind. A colour level paints with the default token styles. An `agent` is colourless and
3752
+ * unlinked whatever `color` and `links` say, as in {@link Render.context}.
3753
+ *
3754
+ * @param options - the audience, and the colour, glyphs, width, path display, links, neutralizing, link base and
3755
+ * open group depth
3756
+ */
3757
+ static readonly contextOf: (options: RenderContextOfOptions) => RenderContext;
3758
+ /**
3759
+ * Render a document as plain text for an agent.
3760
+ *
3761
+ * @remarks
3762
+ * There are no escape sequences of any kind, whatever the context's colour or hyperlinks allow: `paint` and
3763
+ * `link` are never called, and a control character in a document's text is removed. The audience is treated as
3764
+ * `agent`, so a path joins with ` > `.
3765
+ *
3766
+ * - A heading is its text alone, code is in backticks, and a link is its label followed by the target in
3767
+ * parentheses, as `path:line:col` through `displayPath` for a file, unless the label already is the target.
3768
+ * - A paragraph wraps to the width and is never truncated; a word longer than the width, such as a URL, stays
3769
+ * whole on its own line.
3770
+ * - A list uses `- ` items, and past its cap the overflow row. A table is aligned text columns with a rule under
3771
+ * the header; a short row is padded with empty cells, a cell holding line breaks shows its first line and an
3772
+ * ellipsis, and cells are truncated only when the table is wider than the context, widest column first. A tree uses the glyph set's tree segments.
3773
+ * - A collapsible is its title and the indented body, a callout its upper-case kind and the body, a code block
3774
+ * four-space indented, and a diff `- expected` lines then `+ received` lines, the cap limiting each side.
3775
+ * - Counts take their total and their visible counters from {@link Doc.total} and {@link Doc.visibleCounters}.
3776
+ * Inline gives `3/5 passed, 1 failed (1.2s)`: the first counter is the headline and shows its share of the
3777
+ * total, unless `share` is `false`. Columns gives aligned label and number pairs, and row one line of cells.
3778
+ * - A link with `suffix: false` never has its target after the label, and one with `suffix: true` always does.
3779
+ * - Verbatim text is its lines exactly, each indented by `indent` spaces, never wrapped; an annotation is nothing.
3780
+ * - Strong and emphasised content is its text; a file is its display path, unlinked. `Lines` are one line per entry,
3781
+ * a `Line` with `truncate` is cut to the width with the ellipsis, and diff text is its lines as given, the cap
3782
+ * followed by `… N more lines`. A counts table is a table with a column per counter key and the total row last,
3783
+ * and a counts `suffix` follows the duration.
3784
+ * - A compact list has no blank lines inside an item. A `style: "pipe"` table is istanbul's shape: a rule of dashes
3785
+ * meeting at `|` above and below the header and at the end, and cells joined with ` | `.
3786
+ * - Top-level blocks are consecutive lines; a section separates its title and children with blank lines.
3787
+ *
3788
+ * @param doc - the document
3789
+ * @param ctx - where the output is going
3790
+ */
3791
+ static readonly plain: (doc: Document, ctx: RenderContext) => string;
3792
+ /**
3793
+ * Render a document for a person: the same layout as {@link Render.plain}, painted and linked.
3794
+ *
3795
+ * @remarks
3796
+ * The context's `paint` and `link` do the styling, so a context at colour `none` with links off gives exactly
3797
+ * what `plain` gives, apart from two things: code has no backticks (it is painted `accent` instead), and a path
3798
+ * joins with the audience's separator (`›` for a person) rather than ` > `. Tokens:
3799
+ *
3800
+ * - headings, section and collapsible titles, and table headers are `emphasis`; the rule under a header, tree
3801
+ * lines and overflow rows are `muted`;
3802
+ * - a status glyph takes its definition's token, and a diff's `-` lines are `failure` and `+` lines `success`;
3803
+ * - a callout's label takes its kind's token (`note` info, `tip` success, `important` accent, `warning` warning,
3804
+ * `caution` error), and a counter the token of its status, with the qualifier, the duration and the suffix `muted`.
3805
+ * A `Counts` with `paint: "none"` paints none of it, and with `paint: "glyph"` only a status glyph.
3806
+ * - strong content is bold and emphasised content italic, over any token it has; in diff text a `+` line is
3807
+ * `success` and a `-` line `failure`; a counts table's counts take their status's token.
3808
+ *
3809
+ * A link goes through `ctx.link`, which makes an OSC 8 hyperlink only when the policy allows it. When it does
3810
+ * not (it returns the label unchanged), the target follows the label in parentheses, muted, as in plain text.
3811
+ *
3812
+ * Text is cut and wrapped before it is painted, so a colour or a hyperlink is never cut in half, and a table
3813
+ * cut to the width keeps the colour of what remains. Tables are plain aligned columns, never box drawing:
3814
+ * box drawing costs two columns of every row for nothing a rule and the padding do not already say, and it
3815
+ * cannot be matched to plain text.
3816
+ *
3817
+ * @param doc - the document
3818
+ * @param ctx - where the output is going
3819
+ */
3820
+ static readonly ansi: (doc: Document, ctx: RenderContext) => string;
3821
+ /**
3822
+ * Render a document as GitHub-flavoured markdown, for a step summary or a file.
3823
+ *
3824
+ * @remarks
3825
+ * There is no ANSI and no OSC 8 (`paint` and `link` are never called), and the width does not apply: a reader
3826
+ * wraps. Everything a document carries as text is escaped so that it cannot become markdown: the characters
3827
+ * that mean something, `|` everywhere so text can never form a table, the marker at the start of a line (a
3828
+ * heading, bullet, setext underline or ordered item) and the start of an autolink (a URL scheme or `www.`). An
3829
+ * email address is not escaped: a reader may make a `mailto:` link of it, which is harmless. A leading indent is
3830
+ * dropped, since markdown would read it as code.
3831
+ *
3832
+ * Under GitHub Actions (`neutralizeWorkflowCommands`) the same neutralizing applies, since markdown can be printed
3833
+ * to the log. Markdown escapes `[` in text, so `##[` cannot appear outside code and the headings are untouched
3834
+ * (a bare `##` is not a command); code spans and blocks, which are not escaped, get the blank marker, which can
3835
+ * also land inside code or table text where it would otherwise have formed a command.
3836
+ *
3837
+ * GitHub also turns `@user`, `@org/team`, `#123` and commit SHAs in rendered markdown into mentions and references.
3838
+ * Nothing here escapes them: in a step summary they do not notify, but markdown posted as a comment could ping
3839
+ * whoever the text names.
3840
+ *
3841
+ * - A heading is `#` repeated by its level. A section's title is a heading of level 2 for a section at the top,
3842
+ * one deeper for each section nested inside it, to level 6.
3843
+ * - A table is a GFM pipe table: `|` is `\|` in a cell and a line break in a cell is `<br>`. A short row is
3844
+ * padded and a long one widens the table. With no header, the header row is empty.
3845
+ * - A collapsible is `<details><summary>title</summary>`, a blank line, the body as markdown, a blank line and
3846
+ * `</details>`. The title is HTML, so it is HTML-escaped and plain.
3847
+ * - A callout is a quoted `[!KIND]` followed by its body. A code block is a fence longer than any backtick run it
3848
+ * holds, and a diff a `diff` fence of `-` and `+` lines.
3849
+ * - A link is `[label](url)` when it has a URL a reader can follow: an `http`, `https`, `mailto`, `file` or
3850
+ * `vscode` URL, or a relative one. A file link has one when its path is absolute (`file://`). Otherwise, such as
3851
+ * for a `javascript:` URL or a relative file path, it is the label followed by the target in inline code, as
3852
+ * `path:line:col` for a file.
3853
+ * - A list is bullets, a tree a nested bullet list under its root label, and overflow rows paragraphs after what
3854
+ * they cap. Counts inline is a paragraph, columns a list of `label: n` and row a one-row table of the counter
3855
+ * labels over their numbers, every header named (the duration as `duration`), with the label above the table and
3856
+ * the qualifier and suffix below it.
3857
+ * - Verbatim text is a fenced code block, so its indentation survives; an annotation is nothing.
3858
+ * - Strong content is `**…**` and emphasised `*…*`, which GFM reads inside a word too, with the spaces at a run's
3859
+ * edges kept outside the markers. `Lines` are one paragraph with a hard break between entries, an empty entry
3860
+ * between two others an empty line (one at either end is dropped); a `Line` is one
3861
+ * paragraph; diff text a `diff` fence; a counts table a pipe table; a file is its display path as text.
3862
+ * - With `linkBase`, a file link goes to the base and the display path, plus `#L<line>`, in place of `file://`. A
3863
+ * display path that is absolute or climbs out with `..` is not under the base, so its link has no URL form.
3864
+ * - A compact list item joins its parts with no blank line, putting a hard break where two paragraphs would merge.
3865
+ * A row of counts names its duration column `duration`.
3866
+ *
3867
+ * @param doc - the document
3868
+ * @param ctx - where the output is going; its glyph set, audience and `displayPath` are used
3869
+ */
3870
+ static readonly markdown: (doc: Document, ctx: RenderContext) => string;
3871
+ /**
3872
+ * Render a document for a GitHub Actions log.
3873
+ *
3874
+ * @remarks
3875
+ * Everything is what {@link Render.plain} renders, except an annotation, which is one workflow command
3876
+ * (`::error file=…,line=…::message`), and a collapsible that starts a line, which is a group: `::group::title`, its
3877
+ * body, `::endgroup::`. An annotation is a command at the top level, as a top-level section's child, and as a direct
3878
+ * child of a group's body; anywhere deeper (inside a list, a callout, or a section within a group) it is nothing,
3879
+ * as in plain. Its message and properties are escaped, so no text can end
3880
+ * the command or start another, and the kit's own command is never neutralized, though a `##[` in its message,
3881
+ * title or file is. That is a top-level collapsible, or one that is a direct child of a
3882
+ * top-level section. GitHub does not nest groups, so a collapsible inside a group, or inside a list or callout
3883
+ * (where it would not start a line), keeps plain's rendering: its title on a line and its body indented.
3884
+ *
3885
+ * A group already open around the output counts the same way. When the context's `groupDepth` is above `0`
3886
+ * ({@link RenderContext.groupDepth}, which `Render.context` reads from the fiber-local `ActionLogger.group` in
3887
+ * `@effected/github-actions` provides, by the key `WorkflowCommand.groupDepthKey`), a top-level collapsible keeps
3888
+ * plain's rendering too, so a document printed inside an `ActionLogger.group` does not open a second group, which
3889
+ * would end the first at the runner. The depth is the context's, read when the context was built. What no depth
3890
+ * can fix is two fibers writing groups at once: the runner has one log stream, so concurrent sibling groups, this
3891
+ * renderer's or `ActionLogger`'s, interleave in it. Render and print a document from the fiber that owns the
3892
+ * stream, not from a fiber racing another group.
3893
+ *
3894
+ * The runner has two command parsers, and a line is a command if either accepts it: after its leading whitespace it
3895
+ * starts with `::`, or `##[` occurs ANYWHERE in it (a bare `##` is not one). A document's text must not be able to
3896
+ * do that (`::add-mask::`, `::error::`, `##[error]`), so such a `::` line gets a braille pattern blank (U+2800) in
3897
+ * front, which the runner neither trims nor skips, and every `##[` gets one before the `[`. The text is
3898
+ * otherwise unchanged. A
3899
+ * group's title is a command's data, so its `%`, CR and LF are escaped and a `##[` in it is neutralized. Lines are split at CR, LF and CRLF before
3900
+ * that check, as the runner splits them. There is no ANSI and `paint` and `link` are never called, and the audience
3901
+ * is treated as `agent`, as `plain` does.
3902
+ *
3903
+ * @param doc - the document
3904
+ * @param ctx - where the output is going; the width, glyph set and `displayPath` are used as plain uses them
3905
+ */
3906
+ static readonly githubLog: (doc: Document, ctx: RenderContext) => string;
3907
+ }
3908
+ /**
3909
+ * Turns a `SchemaIssue` tree into lines a user can act on.
3910
+ *
3911
+ * @remarks
3912
+ * A decode failure arrives as a structured tree; a person needs
3913
+ * `unknown key at groups.g.cleanup.rulesetz`. The formatters core ships for
3914
+ * this live on `SchemaIssue` rather than on `SchemaError` or `Schema`, and
3915
+ * `SchemaError.message` does not use them, so printing the error alone does not
3916
+ * give these lines.
3917
+ *
3918
+ * The lines and `CliFailure`'s tree are two views of the same rejected values (`internal/format`), so a schema
3919
+ * failure in the default report and these lines never disagree.
3920
+ *
3921
+ * @example
3922
+ * ```ts
3923
+ * import { SchemaIssueRenderer } from "@effected/cli-kit"
3924
+ * import { Effect, Schema } from "effect"
3925
+ *
3926
+ * const result = Schema.decodeUnknownEffect(MySchema)(input, {
3927
+ * onExcessProperty: "error",
3928
+ * errors: "all",
3929
+ * })
3930
+ *
3931
+ * const reported = result.pipe(
3932
+ * Effect.catchTag("SchemaError", (error) =>
3933
+ * Effect.forEach(SchemaIssueRenderer.render(error.issue), (line) => Effect.logError(` ${line}`)),
3934
+ * ),
3935
+ * )
3936
+ * ```
3937
+ *
3938
+ * @public
3939
+ */
3940
+ export declare class SchemaIssueRenderer {
3941
+ private constructor();
3942
+ /**
3943
+ * One line per rejected value, deepest path last.
3944
+ *
3945
+ * @param issue - a `SchemaIssue` tree, or any value
3946
+ * @returns the lines, or empty when `issue` is not an issue tree
3947
+ */
3948
+ static readonly render: (issue: unknown) => ReadonlyArray<string>;
3949
+ }
3950
+ export type { AnnotationLevel, AnnotationOptions, AudienceFlagInput, Block, BlockOf, CliAudienceFlagsOptions, CliDocSource, CliEnvOptions, CliEnvServices, CliEnvTestOptions, CliEnvTestServices, CliExitShape, CliFailureOptions, CliFormatFlagOptions, CliFormatName, CliFormatOutput, CliFormatPrintOptions, CliLinksLinkerOptions, CliLinksOptions, CliLinksShape, CliLogFile, CliLogFileOptions, CliLogOptions, CliLogStatusOptions, CliLoggerOptions, CliMessageOptions, CliPromptFallbackOptions, CliPromptTarget, CliThemeOptions, CliThemeShape, CliThemeTestOptions, Column, CoreStatusName, Counter, CountsOptions, CountsRow, CountsTableOptions, DocPrintOptions, Document, EditorLinks, FailureDetails, GithubAnnotationProperties, GlyphSelectOptions, GlyphSet, Inline, InlineInput, InlineOf, LinkOptions, LinkTarget, ListOptions, MainOptions, NamedColor, OverflowOptions, PadOptions, PercentOptions, RenderContext, RenderContextOfOptions, RenderContextOptions, ReportFailuresOptions, RequiresAudienceFlags, StatusDef, StatusRef, StreamTheme, Style, SuggestOptions, TableOptions, TokenName, TreeInput, TreeNode, TruncateOptions };
3951
+ //# sourceMappingURL=index.d.ts.map