1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Jonathan Shook
//! The `ct-await` command grammar (see [`crate::cli`]); the `ct-await` bin is a
//! thin parse-and-dispatch wrapper over this `Cli`.
use clap::Parser;
use crate::explain::Format;
use crate::pattern;
use crate::pulse::HeartbeatOpts;
#[derive(Parser, Debug)]
#[command(
name = "ct-await",
version,
about = "Poll a read-only probe until it succeeds, an abort pattern appears, or the bound expires.",
long_about = "ct-await runs a gated read-only probe every --every seconds until the condition \
is established — probe exit 0, or a required --ok-match appearing in its output — \
or until an --err-match appears (immediate ERROR) or the required --timeout \
expires (ERROR). Observe an external process's effects without owning its \
execution (also reachable as `ct await`). See `ct-await --explain` for \
agent-oriented documentation."
)]
pub struct Cli {
/// Question this wait answers; printed as a "== ... ==" banner.
#[arg(long)]
pub question: Option<String>,
/// Seconds between probe runs (fractional allowed).
#[arg(long, value_name = "SECS", default_value_t = 5.0)]
pub every: f64,
/// Hard bound on the whole wait (fractional allowed). Required: a wait is bounded by design.
#[arg(long, value_name = "SECS")]
pub timeout: f64,
/// SUCCESS when this pattern (substring->glob->regex promoted) appears in the probe's output. When supplied it is the REQUIRED proof: a clean exit without it means "not yet".
#[arg(long, value_name = "PATTERN")]
pub ok_match: Option<String>,
/// End the wait immediately with ERROR when this pattern appears in the probe's output (decisive over --ok-match, exactly as in ct-test).
#[arg(long, value_name = "PATTERN")]
pub err_match: Option<String>,
/// Pin how matcher patterns are interpreted (promotion off): literal, glob, or regex.
#[arg(long, value_enum)]
pub mode: Option<pattern::Mode>,
#[command(flatten)]
pub heartbeat: HeartbeatOpts,
/// Template written to stdout when the wait ends. Tokens: {RESULT} {ELAPSED} {TICKS} {REASON} {QUESTION} {CMD}.
#[arg(long, alias = "emit-stdout")]
pub emit: Option<String>,
/// Template written to stderr when the wait ends (same tokens as --emit).
#[arg(long)]
pub emit_stderr: Option<String>,
/// Suppress the banner and the default outcome line.
#[arg(long)]
pub quiet: bool,
/// Print agent usage docs (md or json) and exit.
#[arg(long, value_enum, num_args = 0..=1, default_missing_value = "md")]
pub explain: Option<Format>,
/// The probe (after `--`): an argv run directly each tick, never through a shell. Exit 0 ends the wait with SUCCESS; any other exit means "not yet".
#[arg(last = true, value_name = "PROBE...")]
pub probe: Vec<String>,
}