Skip to content

Commit 994a15b

Browse files
committed
feat: add --watch flag for real-time auto-refresh
Adds a global --watch <SECONDS> flag that re-runs any command at a configurable interval with screen clearing, enabling live monitoring of prices, orderbooks, positions, and other data.
1 parent 3ba646b commit 994a15b

File tree

4 files changed

+77
-1
lines changed

4 files changed

+77
-1
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ path = "src/main.rs"
1717
polymarket-client-sdk = { version = "0.4", features = ["gamma", "data", "bridge", "clob", "ctf"] }
1818
alloy = { version = "1.6.3", default-features = false, features = ["providers", "sol-types", "contract", "reqwest", "reqwest-rustls-tls", "signer-local", "signers"] }
1919
clap = { version = "4", features = ["derive"] }
20-
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
20+
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal"] }
2121
serde_json = "1"
2222
serde = { version = "1", features = ["derive"] }
2323
tabled = "0.17"

src/main.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ pub(crate) struct Cli {
1919
#[arg(short, long, global = true, default_value = "table")]
2020
pub(crate) output: OutputFormat,
2121

22+
/// Auto-refresh every N seconds (table output only)
23+
#[arg(short, long, global = true)]
24+
pub(crate) watch: Option<u64>,
25+
2226
/// Private key (overrides env var and config file)
2327
#[arg(long, global = true)]
2428
private_key: Option<String>,
@@ -71,6 +75,18 @@ async fn main() -> ExitCode {
7175
let cli = Cli::parse();
7276
let output = cli.output;
7377

78+
if let Some(interval) = cli.watch {
79+
if matches!(output, OutputFormat::Json) {
80+
eprintln!("Error: --watch is not supported with JSON output");
81+
return ExitCode::FAILURE;
82+
}
83+
if interval == 0 {
84+
eprintln!("Error: --watch interval must be at least 1 second");
85+
return ExitCode::FAILURE;
86+
}
87+
return watch_loop(interval).await;
88+
}
89+
7490
if let Err(e) = run(cli).await {
7591
match output {
7692
OutputFormat::Json => {
@@ -86,6 +102,28 @@ async fn main() -> ExitCode {
86102
ExitCode::SUCCESS
87103
}
88104

105+
async fn watch_loop(interval_secs: u64) -> ExitCode {
106+
let interval = std::time::Duration::from_secs(interval_secs);
107+
loop {
108+
print!("\x1b[2J\x1b[H");
109+
let now = chrono::Local::now().format("%H:%M:%S");
110+
println!("Every {interval_secs}s \u{2014} {now} (Ctrl+C to stop)\n");
111+
112+
let cli = Cli::parse();
113+
if let Err(e) = run(cli).await {
114+
eprintln!("Error: {e}");
115+
}
116+
117+
tokio::select! {
118+
_ = tokio::time::sleep(interval) => {}
119+
_ = tokio::signal::ctrl_c() => {
120+
println!();
121+
return ExitCode::SUCCESS;
122+
}
123+
}
124+
}
125+
}
126+
89127
#[allow(clippy::too_many_lines)]
90128
pub(crate) async fn run(cli: Cli) -> anyhow::Result<()> {
91129
match cli.command {

tests/cli_integration.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,30 @@ fn wallet_address_succeeds_or_fails_gracefully() {
486486
// Either succeeds or fails with an error message — not a panic
487487
assert!(output.status.success() || !output.stderr.is_empty());
488488
}
489+
490+
#[test]
491+
fn watch_flag_appears_in_help() {
492+
polymarket()
493+
.arg("--help")
494+
.assert()
495+
.success()
496+
.stdout(predicate::str::contains("--watch"));
497+
}
498+
499+
#[test]
500+
fn watch_with_json_output_rejected() {
501+
polymarket()
502+
.args(["--watch", "5", "-o", "json", "wallet", "show"])
503+
.assert()
504+
.failure()
505+
.stderr(predicate::str::contains("--watch is not supported with JSON"));
506+
}
507+
508+
#[test]
509+
fn watch_zero_interval_rejected() {
510+
polymarket()
511+
.args(["--watch", "0", "wallet", "show"])
512+
.assert()
513+
.failure()
514+
.stderr(predicate::str::contains("at least 1 second"));
515+
}

0 commit comments

Comments
 (0)