Skip to main content

systemprompt_cli/commands/core/content/
mod.rs

1//! `core content` command group: manage and inspect published content.
2//!
3//! Dispatches the [`ContentCommands`] subcommands — list/show/search,
4//! edit/delete, ingest verification and status, plus the `link`, `analytics`,
5//! and `files` sub-groups. On a `--database-url` invocation only the read-only
6//! commands are served; the mutating commands require a full profile context.
7
8pub mod analytics;
9pub mod delete;
10pub mod delete_source;
11mod edit;
12mod edit_apply;
13pub mod files;
14pub mod link;
15pub mod list;
16pub mod popular;
17pub mod search;
18pub mod show;
19pub mod status;
20pub mod types;
21pub mod verify;
22
23use crate::context::CommandContext;
24use crate::shared::render_result;
25use anyhow::{Context, Result, bail};
26use clap::Subcommand;
27
28#[derive(Debug, Subcommand)]
29pub enum ContentCommands {
30    #[command(about = "List content with pagination")]
31    List(list::ListArgs),
32
33    #[command(about = "Show content details")]
34    Show(show::ShowArgs),
35
36    #[command(about = "Search content")]
37    Search(search::SearchArgs),
38
39    #[command(about = "Edit content fields")]
40    Edit(edit::EditArgs),
41
42    #[command(about = "Delete content by ID")]
43    Delete(delete::DeleteArgs),
44
45    #[command(name = "delete-source", about = "Delete all content from a source")]
46    DeleteSource(delete_source::DeleteSourceArgs),
47
48    #[command(about = "Get popular content")]
49    Popular(popular::PopularArgs),
50
51    #[command(about = "Verify content is published and accessible")]
52    Verify(verify::VerifyArgs),
53
54    #[command(about = "Show content health status for a source")]
55    Status(status::StatusArgs),
56
57    #[command(subcommand, about = "Link generation and management")]
58    Link(link::LinkCommands),
59
60    #[command(subcommand, about = "Content analytics")]
61    Analytics(analytics::AnalyticsCommands),
62
63    #[command(subcommand, about = "Content-file operations (link, unlink, featured)")]
64    Files(files::ContentFilesCommands),
65}
66
67fn ensure_full_profile(command: &ContentCommands, ctx: &CommandContext) -> Result<()> {
68    if ctx.is_database_scoped()
69        && matches!(
70            command,
71            ContentCommands::Edit(_)
72                | ContentCommands::Delete(_)
73                | ContentCommands::DeleteSource(_)
74                | ContentCommands::Verify(_)
75                | ContentCommands::Link(_)
76                | ContentCommands::Files(_)
77        )
78    {
79        bail!("This content command requires full profile context");
80    }
81    Ok(())
82}
83
84pub async fn execute(command: ContentCommands, ctx: &CommandContext) -> Result<()> {
85    ensure_full_profile(&command, ctx)?;
86
87    match command {
88        ContentCommands::List(args) => {
89            let result = list::execute(args, ctx)
90                .await
91                .context("Failed to list content")?;
92            render_result(&result, &ctx.cli);
93        },
94        ContentCommands::Show(args) => {
95            let result = show::execute(args, ctx)
96                .await
97                .context("Failed to show content")?;
98            render_result(&result, &ctx.cli);
99        },
100        ContentCommands::Search(args) => {
101            let result = search::execute(args, ctx)
102                .await
103                .context("Failed to search content")?;
104            render_result(&result, &ctx.cli);
105        },
106        ContentCommands::Edit(args) => {
107            let result = edit::execute(args, &ctx.cli)
108                .await
109                .context("Failed to edit content")?;
110            render_result(&result, &ctx.cli);
111        },
112        ContentCommands::Delete(args) => {
113            let result = delete::execute(args, ctx)
114                .await
115                .context("Failed to delete content")?;
116            render_result(&result, &ctx.cli);
117        },
118        ContentCommands::DeleteSource(args) => {
119            let result = delete_source::execute(args, &ctx.cli)
120                .await
121                .context("Failed to delete source content")?;
122            render_result(&result, &ctx.cli);
123        },
124        ContentCommands::Popular(args) => {
125            let result = popular::execute(args, ctx)
126                .await
127                .context("Failed to get popular content")?;
128            render_result(&result, &ctx.cli);
129        },
130        ContentCommands::Verify(args) => {
131            let result = verify::execute(args, ctx)
132                .await
133                .context("Failed to verify content")?;
134            render_result(&result, &ctx.cli);
135        },
136        ContentCommands::Status(args) => {
137            let result = status::execute(args, ctx)
138                .await
139                .context("Failed to get content status")?;
140            render_result(&result, &ctx.cli);
141        },
142        ContentCommands::Link(cmd) => {
143            link::execute(cmd, ctx).await?;
144        },
145        ContentCommands::Analytics(cmd) => {
146            analytics::execute(cmd, ctx).await?;
147        },
148        ContentCommands::Files(cmd) => {
149            files::execute(cmd, &ctx.cli).await?;
150        },
151    }
152    Ok(())
153}