1use anyhow::{Context, Result};
4use clap::{Parser, Subcommand};
5use std::fs;
6use std::path::Path;
7
8const COMMIT_TWIDDLE_TEMPLATE: &str = include_str!("../templates/commit-twiddle.md");
10const PR_CREATE_TEMPLATE: &str = include_str!("../templates/pr-create.md");
11const PR_UPDATE_TEMPLATE: &str = include_str!("../templates/pr-update.md");
12
13#[derive(Parser)]
15pub struct CommandsCommand {
16 #[command(subcommand)]
18 pub command: CommandsSubcommands,
19}
20
21#[derive(Subcommand)]
23pub enum CommandsSubcommands {
24 Generate(GenerateCommand),
26}
27
28#[derive(Parser)]
30pub struct GenerateCommand {
31 #[command(subcommand)]
33 pub command: GenerateSubcommands,
34}
35
36#[derive(Subcommand)]
38pub enum GenerateSubcommands {
39 #[command(name = "commit-twiddle")]
41 CommitTwiddle,
42 #[command(name = "pr-create")]
44 PrCreate,
45 #[command(name = "pr-update")]
47 PrUpdate,
48 All,
50}
51
52impl CommandsCommand {
53 pub fn execute(self) -> Result<()> {
55 match self.command {
56 CommandsSubcommands::Generate(generate_cmd) => generate_cmd.execute(),
57 }
58 }
59}
60
61impl GenerateCommand {
62 pub fn execute(self) -> Result<()> {
64 match self.command {
65 GenerateSubcommands::CommitTwiddle => {
66 generate_commit_twiddle()?;
67 println!("✅ Generated .claude/commands/commit-twiddle.md");
68 }
69 GenerateSubcommands::PrCreate => {
70 generate_pr_create()?;
71 println!("✅ Generated .claude/commands/pr-create.md");
72 }
73 GenerateSubcommands::PrUpdate => {
74 generate_pr_update()?;
75 println!("✅ Generated .claude/commands/pr-update.md");
76 }
77 GenerateSubcommands::All => {
78 generate_commit_twiddle()?;
79 generate_pr_create()?;
80 generate_pr_update()?;
81 println!("✅ Generated all command templates:");
82 println!(" - .claude/commands/commit-twiddle.md");
83 println!(" - .claude/commands/pr-create.md");
84 println!(" - .claude/commands/pr-update.md");
85 }
86 }
87 Ok(())
88 }
89}
90
91fn generate_commit_twiddle() -> Result<()> {
93 ensure_claude_commands_dir()?;
94 fs::write(
95 ".claude/commands/commit-twiddle.md",
96 COMMIT_TWIDDLE_TEMPLATE,
97 )
98 .context("Failed to write .claude/commands/commit-twiddle.md")?;
99 Ok(())
100}
101
102fn generate_pr_create() -> Result<()> {
104 ensure_claude_commands_dir()?;
105 fs::write(".claude/commands/pr-create.md", PR_CREATE_TEMPLATE)
106 .context("Failed to write .claude/commands/pr-create.md")?;
107 Ok(())
108}
109
110fn generate_pr_update() -> Result<()> {
112 ensure_claude_commands_dir()?;
113 fs::write(".claude/commands/pr-update.md", PR_UPDATE_TEMPLATE)
114 .context("Failed to write .claude/commands/pr-update.md")?;
115 Ok(())
116}
117
118fn ensure_claude_commands_dir() -> Result<()> {
120 let commands_dir = Path::new(".claude/commands");
121 if !commands_dir.exists() {
122 fs::create_dir_all(commands_dir).context("Failed to create .claude/commands directory")?;
123 }
124 Ok(())
125}