Skip to main content

objectiveai_cli/command/tools/install/
github.rs

1//! `tools install github` — fetch the manifest, check the whitelist,
2//! and install the tool under
3//! `~/.objectiveai/bin/tools/<owner>/<repository>/<version>/`. The
4//! bare-naked contract surfaces the untrusted decision as the typed
5//! `Error::NotWhitelisted { kind: "tool", .. }` variant.
6//!
7//! The SDK `Request` does not expose `upgrade`; this leaf always
8//! installs fresh and surfaces `Error::AlreadyInstalled` if a
9//! manifest already exists.
10
11use objectiveai_sdk::cli::command::tools::install::github::{Request, Response};
12
13use crate::context::Context;
14use crate::error::Error;
15
16pub async fn execute(ctx: &Context, request: Request) -> Result<Response, Error> {
17    let manifest = ctx
18        .filesystem
19        .fetch_tool_manifest(
20            &request.owner,
21            &request.repository,
22            request.commit_sha.as_deref(),
23            None,
24        )
25        .await?;
26
27    let effective_sha = request.commit_sha.as_deref().unwrap_or("HEAD");
28    let whitelist = crate::filesystem::install::default_whitelist();
29    let allowed = crate::filesystem::install::check_plugin_whitelist(
30        &request.owner,
31        &request.repository,
32        effective_sha,
33        &manifest.version,
34        &whitelist,
35    )
36    .map_err(Error::WhitelistRegex)?;
37
38    if !allowed && !request.allow_untrusted {
39        return Err(Error::NotWhitelisted {
40            kind: "tool",
41            owner: request.owner.clone(),
42            repository: request.repository.clone(),
43            commit_sha: effective_sha.to_string(),
44            version: manifest.version.clone(),
45        });
46    }
47
48    let installed = ctx
49        .filesystem
50        .install_tool_from_manifest(
51            &request.owner,
52            &request.repository,
53            &manifest,
54            None,
55            false,
56        )
57        .await?;
58    Ok(Response { installed })
59}
60
61pub mod request_schema {
62    use objectiveai_sdk::cli::command::tools::install::github as sdk;
63    use objectiveai_sdk::cli::command::tools::install::github::request_schema::{Request, Response};
64
65    use crate::context::Context;
66    use crate::error::Error;
67
68    pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
69        Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::Request)))
70    }
71}
72
73pub mod response_schema {
74    use objectiveai_sdk::cli::command::tools::install::github as sdk;
75    use objectiveai_sdk::cli::command::tools::install::github::response_schema::{Request, Response};
76
77    use crate::context::Context;
78    use crate::error::Error;
79
80    pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
81        Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::Response)))
82    }
83}