Skip to main content

objectiveai_cli/command/plugins/install/
github.rs

1//! `plugins install github` — fetch the manifest, check the
2//! whitelist, and install the plugin under
3//! `~/.objectiveai/plugins/<owner>/<repository>/<version>/`. The
4//! bare-naked contract surfaces the untrusted decision as the typed
5//! `Error::NotWhitelisted { kind: "plugin", .. }` 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::plugins::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_plugin_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: "plugin",
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 source = crate::filesystem::install::raw_manifest_url(
49        &request.owner,
50        &request.repository,
51        request.commit_sha.as_deref(),
52    );
53    let installed = ctx
54        .filesystem
55        .install_plugin_from_manifest(
56            &request.owner,
57            &request.repository,
58            &manifest,
59            &source,
60            None,
61            false,
62        )
63        .await?;
64    Ok(Response { installed })
65}
66
67pub mod request_schema {
68    use objectiveai_sdk::cli::command::plugins::install::github as sdk;
69    use objectiveai_sdk::cli::command::plugins::install::github::request_schema::{Request, Response};
70
71    use crate::context::Context;
72    use crate::error::Error;
73
74    pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
75        Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::Request)))
76    }
77}
78
79pub mod response_schema {
80    use objectiveai_sdk::cli::command::plugins::install::github as sdk;
81    use objectiveai_sdk::cli::command::plugins::install::github::response_schema::{Request, Response};
82
83    use crate::context::Context;
84    use crate::error::Error;
85
86    pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
87        Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::Response)))
88    }
89}