systemprompt_cli/commands/core/content/
delete.rs1use super::types::DeleteOutput;
2use crate::cli_settings::CliConfig;
3use crate::interactive::require_confirmation;
4use crate::shared::CommandResult;
5use anyhow::{anyhow, Result};
6use clap::Args;
7use systemprompt_content::ContentRepository;
8use systemprompt_identifiers::{ContentId, SourceId};
9use systemprompt_logging::CliService;
10use systemprompt_runtime::AppContext;
11
12#[derive(Debug, Args)]
13pub struct DeleteArgs {
14 #[arg(help = "Content ID or slug")]
15 pub identifier: String,
16
17 #[arg(long, help = "Source ID (required when using slug)")]
18 pub source: Option<String>,
19
20 #[arg(short = 'y', long, help = "Skip confirmation")]
21 pub yes: bool,
22
23 #[arg(long, help = "Preview deletion without executing")]
24 pub dry_run: bool,
25}
26
27pub async fn execute(args: DeleteArgs, config: &CliConfig) -> Result<CommandResult<DeleteOutput>> {
28 let ctx = AppContext::new().await?;
29 let repo = ContentRepository::new(ctx.db_pool())?;
30
31 let content = if args.identifier.starts_with("content_")
32 || args.identifier.contains('-') && args.identifier.len() > 30
33 {
34 let id = ContentId::new(args.identifier.clone());
35 repo.get_by_id(&id)
36 .await?
37 .ok_or_else(|| anyhow!("Content not found: {}", args.identifier))?
38 } else {
39 let source_id = args
40 .source
41 .as_ref()
42 .ok_or_else(|| anyhow!("Source ID required when using slug (use --source)"))?;
43 let source = SourceId::new(source_id.clone());
44 repo.get_by_source_and_slug(&source, &args.identifier)
45 .await?
46 .ok_or_else(|| {
47 anyhow!(
48 "Content not found: {} in source {}",
49 args.identifier,
50 source_id
51 )
52 })?
53 };
54
55 if args.dry_run {
56 let output = DeleteOutput {
57 deleted: false,
58 content_id: content.id.clone(),
59 message: Some(format!(
60 "[DRY-RUN] Would delete content '{}' ({})",
61 content.title, content.id
62 )),
63 };
64 return Ok(CommandResult::card(output).with_title("Content Delete (Dry Run)"));
65 }
66
67 if config.is_interactive() && !args.yes {
68 CliService::warning(&format!(
69 "This will permanently delete content: {}",
70 args.identifier
71 ));
72 }
73
74 require_confirmation("Are you sure you want to continue?", args.yes, config)?;
75
76 repo.delete(&content.id).await?;
77
78 let output = DeleteOutput {
79 deleted: true,
80 content_id: content.id.clone(),
81 message: None,
82 };
83
84 Ok(CommandResult::card(output).with_title("Content Deleted"))
85}