Skip to main content

claude_wrapper/command/
install.rs

1//! `claude install` -- install a Claude Code native build.
2
3#[cfg(feature = "async")]
4use crate::Claude;
5use crate::command::ClaudeCommand;
6#[cfg(feature = "async")]
7use crate::error::Result;
8#[cfg(feature = "async")]
9use crate::exec;
10use crate::exec::CommandOutput;
11
12/// Run `claude install [target] [--force]`.
13///
14/// Installs a Claude Code native build. `target` accepts `"stable"`,
15/// `"latest"`, or a specific version; omit it to use the CLI's default.
16///
17/// # Example
18///
19/// ```no_run
20/// # #[cfg(feature = "async")] {
21/// use claude_wrapper::{Claude, ClaudeCommand, InstallCommand};
22///
23/// # async fn example() -> claude_wrapper::Result<()> {
24/// let claude = Claude::builder().build()?;
25/// let out = InstallCommand::new()
26///     .target("stable")
27///     .force()
28///     .execute(&claude)
29///     .await?;
30/// println!("{}", out.stdout);
31/// # Ok(()) }
32/// # }
33/// ```
34#[derive(Debug, Clone, Default)]
35pub struct InstallCommand {
36    target: Option<String>,
37    force: bool,
38}
39
40impl InstallCommand {
41    /// Create a new [`InstallCommand`].
42    #[must_use]
43    pub fn new() -> Self {
44        Self::default()
45    }
46
47    /// Target to install: `"stable"`, `"latest"`, or a specific version.
48    #[must_use]
49    pub fn target(mut self, target: impl Into<String>) -> Self {
50        self.target = Some(target.into());
51        self
52    }
53
54    /// Force installation even if already installed.
55    #[must_use]
56    pub fn force(mut self) -> Self {
57        self.force = true;
58        self
59    }
60}
61
62impl ClaudeCommand for InstallCommand {
63    type Output = CommandOutput;
64
65    fn args(&self) -> Vec<String> {
66        let mut args = vec!["install".to_string()];
67        if self.force {
68            args.push("--force".to_string());
69        }
70        if let Some(ref target) = self.target {
71            args.push(target.clone());
72        }
73        args
74    }
75
76    #[cfg(feature = "async")]
77    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
78        exec::run_claude(claude, self.args()).await
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn install_command_defaults() {
88        assert_eq!(ClaudeCommand::args(&InstallCommand::new()), vec!["install"]);
89    }
90
91    #[test]
92    fn install_command_with_target_and_force() {
93        let cmd = InstallCommand::new().target("latest").force();
94        assert_eq!(
95            ClaudeCommand::args(&cmd),
96            vec!["install", "--force", "latest"]
97        );
98    }
99}