From fd4795e28655c7866ce34d5ccded7c5c7c5b197c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Mar 2026 23:18:02 +0000 Subject: [PATCH 1/3] feat: add loading spinner animation during API requests Show a braille dot spinner on stderr while connecting to DeepWiki and waiting for API responses, providing visual feedback similar to yarn/pnpm. Uses indicatif with automatic non-TTY detection and Drop-based cleanup. https://claude.ai/code/session_0189yH7UdpfPaidQN67f1QuT --- .typos.toml | 1 + Cargo.lock | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 13 +++++++++++ src/spinner.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 src/spinner.rs diff --git a/.typos.toml b/.typos.toml index 96261e3..6a7224c 100644 --- a/.typos.toml +++ b/.typos.toml @@ -9,3 +9,4 @@ serde = "serde" reqwest = "reqwest" clippy = "clippy" streamable = "streamable" +indicatif = "indicatif" diff --git a/Cargo.lock b/Cargo.lock index f45ad04..802a1b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,6 +280,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -337,6 +350,7 @@ dependencies = [ "anyhow", "assert_cmd", "clap", + "indicatif", "predicates", "rmcp", "serde", @@ -373,6 +387,12 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "errno" version = "0.3.14" @@ -765,6 +785,19 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -900,6 +933,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.21.3" @@ -965,6 +1004,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + [[package]] name = "potential_utf" version = "0.1.4" @@ -1808,6 +1853,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "untrusted" version = "0.9.0" @@ -2068,6 +2119,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" diff --git a/Cargo.toml b/Cargo.toml index c062bf8..08d4c2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0" clap = { version = "4", features = ["derive"] } +indicatif = "0.17" rmcp = { version = "0.17", features = ["transport-streamable-http-client-reqwest", "client", "reqwest"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/main.rs b/src/main.rs index 6f53570..b30e007 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,13 @@ mod cli; mod client; mod output; +mod spinner; use anyhow::Result; use clap::Parser; use cli::{Cli, Command}; use client::DeepWikiClient; +use spinner::Spinner; #[tokio::main] async fn main() { @@ -27,13 +29,16 @@ async fn run() -> Result<()> { return Ok(()); } + let spinner = Spinner::start("Connecting to DeepWiki..."); let client = DeepWikiClient::connect().await?; + spinner.set_message(&command_spinner_message(&cli.command)); let text = match &cli.command { Command::Ask { repo, question } => client.ask_question(repo, question).await?, Command::Structure { repo } => client.read_wiki_structure(repo).await?, Command::Read { repo } => client.read_wiki_contents(repo).await?, }; + spinner.finish(); println!("{}", output::format_for_claude(&text, repo, query_type)); client.cancel().await?; @@ -41,6 +46,14 @@ async fn run() -> Result<()> { Ok(()) } +fn command_spinner_message(command: &Command) -> String { + match command { + Command::Ask { repo, .. } => format!("Asking DeepWiki about {}...", repo), + Command::Structure { repo } => format!("Fetching wiki structure for {}...", repo), + Command::Read { repo } => format!("Reading wiki contents for {}...", repo), + } +} + fn repo_and_query_type(command: &Command) -> (&str, &str) { match command { Command::Ask { repo, .. } => (repo, "ask"), diff --git a/src/spinner.rs b/src/spinner.rs new file mode 100644 index 0000000..bd4a006 --- /dev/null +++ b/src/spinner.rs @@ -0,0 +1,56 @@ +use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; +use std::time::Duration; + +const TICK_INTERVAL: Duration = Duration::from_millis(80); + +pub struct Spinner { + bar: ProgressBar, +} + +impl Spinner { + pub fn start(message: &str) -> Self { + let bar = ProgressBar::new_spinner(); + bar.set_draw_target(ProgressDrawTarget::stderr()); + bar.set_style( + ProgressStyle::default_spinner() + .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]) + .template("{spinner} {msg}") + .expect("template should be valid"), + ); + bar.set_message(message.to_string()); + bar.enable_steady_tick(TICK_INTERVAL); + Self { bar } + } + + pub fn set_message(&self, message: &str) { + self.bar.set_message(message.to_string()); + } + + pub fn finish(self) { + self.bar.finish_and_clear(); + } +} + +impl Drop for Spinner { + fn drop(&mut self) { + self.bar.finish_and_clear(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn spinner_starts_and_finishes_without_panic() { + let spinner = Spinner::start("test message"); + spinner.set_message("updated message"); + spinner.finish(); + } + + #[test] + fn spinner_drop_cleans_up() { + let spinner = Spinner::start("test message"); + drop(spinner); + } +} From ee4fccb1de6f49098cd9f87c9f21b71bd7af197c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Mar 2026 23:21:36 +0000 Subject: [PATCH 2/3] chore: bump version to 0.2.0 https://claude.ai/code/session_0189yH7UdpfPaidQN67f1QuT --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 802a1b5..a38fcc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,7 +345,7 @@ dependencies = [ [[package]] name = "deepwiki-cli" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 08d4c2f..fd2f7e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deepwiki-cli" -version = "0.1.1" +version = "0.2.0" edition = "2021" description = "CLI for DeepWiki — query GitHub repo wikis without MCP overhead" license = "MIT" From 34f830a9594d2475d75bdcc56ee2c862cf598248 Mon Sep 17 00:00:00 2001 From: minsoo-web Date: Tue, 3 Mar 2026 08:35:18 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/spinner.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spinner.rs b/src/spinner.rs index bd4a006..21e3f61 100644 --- a/src/spinner.rs +++ b/src/spinner.rs @@ -33,7 +33,9 @@ impl Spinner { impl Drop for Spinner { fn drop(&mut self) { - self.bar.finish_and_clear(); + if !self.bar.is_finished() { + self.bar.finish_and_clear(); + } } }