Skip to main content

objectiveai_sdk/cli/command/update/
mod.rs

1//! `update` — async handler stub.
2
3use crate::cli::command::CommandRequest;
4
5#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
6#[schemars(rename = "cli.command.update.Request")]
7pub struct Request {
8    pub path_type: Path,
9    #[serde(flatten)]
10    pub base: crate::cli::command::RequestBase,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
14#[schemars(rename = "cli.command.update.Path")]
15pub enum Path {
16    #[serde(rename = "update")]
17    Update,
18}
19impl CommandRequest for Request {
20    fn into_command(&self) -> Vec<String> {
21        let mut argv = vec!["update".to_string()];
22        self.base.push_flags(&mut argv);
23        argv
24    }
25
26    fn request_base(&self) -> &crate::cli::command::RequestBase {
27        &self.base
28    }
29
30    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
31        Some(&mut self.base)
32    }
33}
34
35/// Per-stage update event. Update is a streaming leaf — one
36/// `ResponseItem` per (asset, stage) pair as the update progresses
37/// through the four shipped binaries (cli, api, viewer, mcp).
38#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
39#[serde(tag = "type", rename_all = "snake_case")]
40#[schemars(rename = "cli.command.update.ResponseItem")]
41pub enum ResponseItem {
42    #[schemars(title = "Checking")]
43    Checking {
44        asset_name: String,
45        current_version: String,
46    },
47    #[schemars(title = "Found")]
48    Found {
49        current_version: String,
50        remote_version: String,
51        asset_name: String,
52        url: String,
53    },
54    #[schemars(title = "Installed")]
55    Installed {
56        current_version: String,
57        remote_version: String,
58    },
59    #[schemars(title = "Skipped")]
60    Skipped {
61        reason: ResponseSkipReason,
62    },
63    #[schemars(title = "UpToDate")]
64    UpToDate {
65        current_version: String,
66        remote_version: String,
67    },
68}
69
70/// All-at-once view of an update run. Used only for schema generation
71/// (`response-schema`); the leaf's `execute` returns
72/// `Stream<ResponseItem>` rather than building a `Response`.
73#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
74#[schemars(rename = "cli.command.update.Response")]
75pub struct Response {
76    pub items: Vec<ResponseItem>,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
80#[serde(rename_all = "snake_case")]
81#[schemars(rename = "cli.command.update.ResponseSkipReason")]
82pub enum ResponseSkipReason {
83    DevTree,
84    UnsupportedPlatform,
85    IncompleteRelease,
86}
87
88#[derive(clap::Args)]
89pub struct Args {
90    #[command(flatten)]
91    pub base: crate::cli::command::RequestBaseArgs,
92}
93
94#[derive(clap::Args)]
95#[command(args_conflicts_with_subcommands = true)]
96pub struct Command {
97    #[command(flatten)]
98    pub args: Args,
99    #[command(subcommand)]
100    pub schema: Option<Schema>,
101}
102
103#[derive(clap::Subcommand)]
104pub enum Schema {
105    /// Emit the JSON Schema for this leaf's `Request` type and exit.
106    RequestSchema(request_schema::Args),
107    /// Emit the JSON Schema for this leaf's `Response` type and exit.
108    ResponseSchema(response_schema::Args),
109}
110
111impl TryFrom<Args> for Request {
112    type Error = crate::cli::command::FromArgsError;
113    fn try_from(args: Args) -> Result<Self, Self::Error> {
114        Ok(Self { path_type: Path::Update, base: args.base.into() })
115    }
116}
117
118#[cfg(feature = "cli-executor")]
119pub async fn execute<E: crate::cli::command::CommandExecutor>(
120    executor: &E,
121    mut request: Request,
122
123        agent_arguments: Option<&crate::cli::command::AgentArguments>,
124    ) -> Result<E::Stream<ResponseItem>, E::Error> {
125    request.base.clear_transform();
126    executor.execute(request, agent_arguments).await
127}
128
129#[cfg(feature = "cli-executor")]
130pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
131    executor: &E,
132    mut request: Request,
133    transform: crate::cli::command::Transform,
134
135        agent_arguments: Option<&crate::cli::command::AgentArguments>,
136    ) -> Result<E::Stream<serde_json::Value>, E::Error> {
137    request.base.set_transform(transform);
138    executor.execute(request, agent_arguments).await
139}
140
141#[cfg(feature = "mcp")]
142impl crate::cli::command::CommandResponse for ResponseItem {
143    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
144        crate::cli::command::McpResponseItem::JSONL(serde_json::to_value(self).unwrap())
145    }
146}
147
148#[cfg(feature = "mcp")]
149impl crate::cli::command::CommandResponse for Response {
150    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
151        crate::cli::command::McpResponseItem::JSONL(serde_json::to_value(self).unwrap())
152    }
153}
154
155pub mod request_schema;
156
157pub mod response_schema;