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