Skip to main content

systemprompt_cli/commands/core/services/
mod.rs

1//! `services` command group: authoring, packaging and operating services
2//! bundles.
3//!
4//! The group spans the two sides of a bundle's life. An editing repository
5//! runs [`validate`], [`bundle`], [`keygen`] and [`publish`] in CI: they touch
6//! only the filesystem and the registry, never a profile or a database.
7//! An instance runs [`refresh`] and [`inspect`] against its own profile.
8//!
9//! [`refresh`] is the one command whose exit code carries meaning, because it
10//! is written for a supervisor script rather than a reader:
11//!
12//! | Code | Meaning |
13//! |------|---------|
14//! | 0 | every source resolved to the composition already active |
15//! | 3 | at least one source changed; the new composition is now current |
16//! | 1 | a source could not be resolved |
17//!
18//! Copyright (c) systemprompt.io — Business Source License 1.1.
19//! See <https://systemprompt.io> for licensing details.
20
21pub mod bundle;
22pub mod inspect;
23pub mod keygen;
24pub mod publish;
25pub mod reconcile;
26pub mod refresh;
27pub mod signing;
28pub mod staging;
29pub mod validate;
30pub mod versions;
31
32use anyhow::Result;
33use clap::Subcommand;
34
35use crate::context::CommandContext;
36use crate::shared::render_result;
37
38#[derive(Debug, Subcommand)]
39pub enum ServicesCommands {
40    #[command(
41        about = "Check a services tree loads, optionally against a base and a previous \
42                       bundle"
43    )]
44    Validate(validate::ValidateArgs),
45
46    #[command(about = "Pack a services tree into a signed bundle archive")]
47    Bundle(bundle::BundleArgs),
48
49    #[command(about = "Generate an ed25519 bundle signing key")]
50    Keygen(keygen::KeygenArgs),
51
52    #[command(about = "Publish a bundle archive to an OCI registry")]
53    Publish(publish::PublishArgs),
54
55    #[command(
56        about = "Re-resolve the profile's bundle sources (exit 3 when the composition \
57                       changed)"
58    )]
59    Refresh(refresh::RefreshArgs),
60
61    #[command(about = "Print bundle provenance for an archive or the active composition")]
62    Inspect(inspect::InspectArgs),
63}
64
65pub async fn execute(command: ServicesCommands, ctx: &CommandContext) -> Result<()> {
66    match command {
67        ServicesCommands::Validate(args) => {
68            let (output, ok) = validate::execute(&args)?;
69            render_result(&output, &ctx.cli);
70            if !ok {
71                anyhow::bail!("Services validation failed");
72            }
73            Ok(())
74        },
75        ServicesCommands::Bundle(args) => {
76            render_result(&bundle::execute(&args)?, &ctx.cli);
77            Ok(())
78        },
79        ServicesCommands::Keygen(args) => {
80            render_result(&keygen::execute(&args)?, &ctx.cli);
81            Ok(())
82        },
83        ServicesCommands::Publish(args) => {
84            render_result(&publish::execute(&args).await?, &ctx.cli);
85            Ok(())
86        },
87        ServicesCommands::Refresh(args) => Box::pin(refresh::execute(&args, ctx)).await,
88        ServicesCommands::Inspect(args) => {
89            render_result(&inspect::execute(&args)?, &ctx.cli);
90            Ok(())
91        },
92    }
93}