claude_wrapper/command/mod.rs
1pub mod agents;
2pub mod auth;
3pub mod auto_mode;
4pub mod doctor;
5pub mod install;
6pub mod marketplace;
7pub mod mcp;
8pub mod plugin;
9pub mod project;
10pub mod query;
11pub mod raw;
12pub(crate) mod spawn_args;
13pub mod ultrareview;
14pub mod update;
15pub mod version;
16
17#[cfg(feature = "async")]
18use std::future::Future;
19
20#[cfg(any(feature = "async", feature = "sync"))]
21use crate::Claude;
22#[cfg(any(feature = "async", feature = "sync"))]
23use crate::error::Result;
24
25/// Trait implemented by all claude CLI command builders.
26///
27/// Each command defines its own `Output` type and builds its argument
28/// list via `args()`. Execution is dispatched through the shared `Claude`
29/// client which provides binary path, environment, and timeout config.
30///
31/// The async `execute` method is only present when the `async` feature
32/// is enabled. In sync-only builds, callers reach the blocking path
33/// via [`ClaudeCommandSyncExt::execute_sync`].
34pub trait ClaudeCommand: Send + Sync {
35 /// The typed result of executing this command.
36 type Output: Send;
37
38 /// Build the CLI argument list for this command.
39 fn args(&self) -> Vec<String>;
40
41 /// Execute the command using the given claude client.
42 ///
43 /// Dropping the returned future mid-flight kills the spawned CLI
44 /// process and, on Unix, its whole process group (SIGKILL): a
45 /// caller that races `execute` against cancellation (e.g.
46 /// `tokio::select!`) does not leave an abandoned run executing in
47 /// the background, and subprocesses the CLI spawned for tool use
48 /// die with it.
49 #[cfg(feature = "async")]
50 fn execute(&self, claude: &Claude) -> impl Future<Output = Result<Self::Output>> + Send;
51}
52
53/// Blocking `execute_sync` for any command that returns `CommandOutput`.
54///
55/// Most command builders (all except the json-decoding convenience
56/// methods) produce `CommandOutput` — this extension trait gives them
57/// a one-line blocking entry point that routes through
58/// [`crate::exec::run_claude_sync`].
59///
60/// ```no_run
61/// # #[cfg(feature = "sync")]
62/// # {
63/// use claude_wrapper::{Claude, ClaudeCommandSyncExt, VersionCommand};
64///
65/// # fn example() -> claude_wrapper::Result<()> {
66/// let claude = Claude::builder().build()?;
67/// let out = VersionCommand::new().execute_sync(&claude)?;
68/// println!("{}", out.stdout);
69/// # Ok(())
70/// # }
71/// # }
72/// ```
73///
74/// Commands with custom execute paths (e.g. [`crate::QueryCommand`],
75/// which honours `retry_policy`) override this via an inherent method
76/// of the same name — inherent-method resolution wins, so callers
77/// don't need to disambiguate.
78#[cfg(feature = "sync")]
79pub trait ClaudeCommandSyncExt {
80 /// Blocking analog of [`ClaudeCommand::execute`] for commands
81 /// producing `CommandOutput`.
82 fn execute_sync(&self, claude: &Claude) -> Result<crate::exec::CommandOutput>;
83}
84
85#[cfg(feature = "sync")]
86impl<T> ClaudeCommandSyncExt for T
87where
88 T: ClaudeCommand<Output = crate::exec::CommandOutput>,
89{
90 fn execute_sync(&self, claude: &Claude) -> Result<crate::exec::CommandOutput> {
91 crate::exec::run_claude_sync(claude, self.args())
92 }
93}