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