Logo ProcessKit API Reference

CliClient Type

A reusable handle to one command-line program with shared defaults applied to every invocation. The defaults live in a *template* `Command`, configured with the full `Command` builder via `WithDefaults` (timeout, working directory, environment, encoding, ok-codes, retry, logger, …) — no separate, partial setter API to learn. Build `Command`s for argument lists (`client.Command [ "status" ]`) or run them straight through the client's runner (`client.RunAsync [ "status" ]`).

Constructors

Constructor Description

CliClient(program)

Full Usage: CliClient(program)

Parameters:
    program : string

Returns: CliClient

A client for `program`, run through the default `JobRunner`.

program : string
Returns: CliClient

Instance members

Instance member Description

this.Command

Full Usage: this.Command

Parameters:
    args : string seq

Returns: Command

Build a configured `Command` for `args` (the template's shared defaults applied).

args : string seq
Returns: Command

this.EnsureAvailableAsync

Full Usage: this.EnsureAvailableAsync

Returns: Task<Result<string, ProcessError>>

Preflight-check that this client's program can be resolved to a real executable on this host, WITHOUT spawning it — the `doctor`/install-wizard use case ("is this tool installed?"), cheaper and side-effect-free next to probing availability by actually running the program (`ProbeAsync`). A thin wrapper over `Exec.which`/`Native.Common.resolveProgram` (the same PATH/PATHEXT-aware logic the spawn path itself falls back on for its own `NotFound` diagnostic), so this check and an actual run of the client's program never disagree on found-vs-not-found. **Resolution is always LOCAL — never delegated to `Runner`.** Availability is a fact about the host's `PATH`/filesystem, independent of which `IProcessRunner` a command is eventually run through, so a test double/mock injected via `WithRunner` (e.g. a `ScriptedRunner`) has no bearing on this result: it always probes the real host, even when `Runner` is a double. A caller unit-testing wrapper-app logic around this check should stub around `EnsureAvailableAsync` itself (branch on an injected flag, or skip calling it), rather than expect a mocked `Runner` to control it.

Returns: Task<Result<string, ProcessError>>

this.ExitCodeAsync

Full Usage: this.ExitCodeAsync

Parameters:
Returns: Task<Result<int, ProcessError>>

The exit code; a signal kill or timeout errors instead of inventing a sentinel.

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<int, ProcessError>>

this.FirstLineAsync

Full Usage: this.FirstLineAsync

Parameters:
Returns: Task<Result<string option, ProcessError>>

The first stdout line satisfying `predicate`, or `None` if stdout closes without a match.

args : string seq
predicate : Func<string, bool>
?cancellationToken : CancellationToken
Returns: Task<Result<string option, ProcessError>>

this.OutputBytesAsync

Full Usage: this.OutputBytesAsync

Parameters:
Returns: Task<Result<ProcessResult<byte[]>, ProcessError>>

Build the command for `args` and run it to completion, capturing stdout as raw bytes.

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<ProcessResult<byte[]>, ProcessError>>

this.OutputJsonAsync

Full Usage: this.OutputJsonAsync

Parameters:
Returns: Task<Result<'T, ProcessError>>
Type parameters: 'T

Build the command for `args`, require a zero/accepted exit, and deserialize the trimmed stdout as JSON into a `'T` via `System.Text.Json` (`options` omitted uses the BCL defaults); invalid JSON becomes `ProcessError.Parse`, just like `ParseAsync`. Give an explicit type argument — there is no parser argument to infer `'T` from. **Trimming / AOT:** deserializes via reflection-based `System.Text.Json` (`JsonSerializer.Deserialize(string, Type, JsonSerializerOptions)`), so it is not trim-/AOT-safe — pass `options` with a source-generated `JsonSerializerContext`/`JsonTypeInfo<'T>` resolver, or avoid this verb, in a trimmed/NativeAOT app.

args : string seq
?options : JsonSerializerOptions
?cancellationToken : CancellationToken
Returns: Task<Result<'T, ProcessError>>

this.OutputStringAsync

Full Usage: this.OutputStringAsync

Parameters:
Returns: Task<Result<ProcessResult<string>, ProcessError>>

Build the command for `args` and run it to completion (a non-zero exit is data).

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<ProcessResult<string>, ProcessError>>

this.ParseAsync

Full Usage: this.ParseAsync

Parameters:
Returns: Task<Result<'T, ProcessError>>
Type parameters: 'T

Require a zero/accepted exit and parse the trimmed stdout into a `'T`; a thrown parser error becomes `ProcessError.Parse`.

args : string seq
parser : Func<string, 'T>
?cancellationToken : CancellationToken
Returns: Task<Result<'T, ProcessError>>

this.ProbeAsync

Full Usage: this.ProbeAsync

Parameters:
Returns: Task<Result<bool, ProcessError>>

Read the exit code as a yes/no answer: 0 -> true, 1 -> false, anything else errors.

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<bool, ProcessError>>

this.RunAsync

Full Usage: this.RunAsync

Parameters:
Returns: Task<Result<string, ProcessError>>

Build the command for `args` and run it (requiring a zero/accepted exit), returning trimmed stdout.

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<string, ProcessError>>

this.RunUnitAsync

Full Usage: this.RunUnitAsync

Parameters:
Returns: Task<Result<unit, ProcessError>>

Build the command for `args` and run it (requiring a zero/accepted exit), discarding output.

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<unit, ProcessError>>

this.Runner

Full Usage: this.Runner

Returns: IProcessRunner

The runner every command is run through.

Returns: IProcessRunner

this.StartAsync

Full Usage: this.StartAsync

Parameters:
Returns: Task<Result<RunningProcess, ProcessError>>

Start the command for `args` and return a live `RunningProcess`.

args : string seq
?cancellationToken : CancellationToken
Returns: Task<Result<RunningProcess, ProcessError>>

this.TryParseAsync

Full Usage: this.TryParseAsync

Parameters:
Returns: Task<Result<'T, ProcessError>>
Type parameters: 'T

Like `ParseAsync`, but with the standard .NET try-parse shape: pass a BCL parser like `int.TryParse` with an explicit type argument (`TryParseAsync<int>(int.TryParse)` — needed because BCL `TryParse` is overloaded). A `false` return becomes `ProcessError.Parse`. (F# can use the `Result`-returning `Runner.tryParse`.)

args : string seq
parser : TryParser<'T>
?cancellationToken : CancellationToken
Returns: Task<Result<'T, ProcessError>>

this.WithDefaults

Full Usage: this.WithDefaults

Parameters:
Returns: CliClient

Configure the shared defaults by transforming the template `Command` with the full builder, e.g. `client.WithDefaults(fun c -> c.CurrentDir(repo).Timeout(ts).Env("K", "V"))`. Composable. Use the builder to set options; don't return a fresh `Command.create` (it would re-point the client at a different program and drop the accumulated defaults).

configure : Func<Command, Command>
Returns: CliClient

this.WithRunner

Full Usage: this.WithRunner

Parameters:
Returns: CliClient

Run every command this client builds through `runner` instead of the default `JobRunner` (e.g. a shared `ProcessGroup`).

runner : IProcessRunner
Returns: CliClient

Type something to start searching.