kasl/commands/mod.rs
1//! Command-line interface commands for kasl application.
2//!
3//! Contains all CLI command implementations for task management, activity monitoring,
4//! reporting, and system configuration.
5//!
6//! ## Features
7//!
8//! - **Core Commands**: Task management, activity monitoring, reporting, export
9//! - **Utility Commands**: Configuration, summaries, pauses, adjustments, updates
10//! - **Advanced Commands**: Templates, tags, database migrations
11//!
12//! ## Usage
13//!
14//! ```bash
15//! kasl watch # Start activity monitoring
16//! kasl task --name "Review code" # Create a new task
17//! kasl report # Generate today's report
18//! kasl export tasks --format csv # Export tasks to CSV
19//! ```
20
21pub mod autostart;
22pub mod export;
23pub mod inbox;
24pub mod init;
25pub mod migrations;
26pub mod pauses;
27pub mod report;
28pub mod sum;
29pub mod tag;
30pub mod task;
31pub mod template;
32pub mod update;
33pub mod watch;
34
35use crate::{db::workdays::Workdays, libs::messages::types::Message, msg_info, msg_warning};
36use anyhow::Result;
37use chrono::Local;
38use clap::{Parser, Subcommand};
39
40/// Defines the main subcommands that the application can execute.
41///
42/// Each variant corresponds to a specific command with its own argument structure.
43/// Commands are organized by functionality and frequency of use.
44#[derive(Debug, Subcommand)]
45enum Commands {
46 /// Manage autostart configuration for system boot
47 ///
48 /// Controls whether kasl automatically starts monitoring when the system boots.
49 /// Supports both system-level and user-level autostart on Windows.
50 #[command(about = "Manage autostart on system boot")]
51 Autostart(autostart::AutostartArgs),
52
53 /// Set up application configuration interactively
54 ///
55 /// Guides the user through setting up API credentials, monitor settings,
56 /// and other configuration options required for kasl to function properly.
57 ///
58 /// `init` stays as a deprecated alias until 2.0. An alias rather than a
59 /// hidden variant: clap_complete emits hidden subcommands into the
60 /// completion scripts, so Tab would keep teaching the old spelling.
61 #[command(about = "Set up configuration", alias = "init")]
62 Setup(init::SetupArgs),
63
64 /// Comprehensive task management command
65 ///
66 /// Handles all task-related operations including creation, editing, deletion,
67 /// viewing, and integration with external services like GitLab and Jira.
68 #[command(about = "Create task")]
69 Task(task::TaskArgs),
70
71 /// Manually end the current workday
72 ///
73 /// Records the end timestamp for today's work session. Typically used
74 /// when the automatic monitoring needs to be manually finalized.
75 #[command(about = "Write end timestamp to database")]
76 End,
77
78 /// Display monthly working hours summary
79 ///
80 /// Shows a comprehensive overview of work hours, productivity metrics,
81 /// and daily breakdowns for the current month.
82 #[command(about = "Get summary")]
83 Sum(sum::SumArgs),
84
85 /// Update kasl itself to the latest release
86 ///
87 /// Checks GitHub releases for newer versions and automatically downloads
88 /// and installs updates if available.
89 ///
90 /// `update` stays as a deprecated alias until 2.0; it read as "update my
91 /// data", which is what every other command does.
92 #[command(name = "self-update", about = "Update kasl itself to the latest release", alias = "update")]
93 SelfUpdate,
94
95 /// Generate and optionally submit work reports
96 ///
97 /// Creates detailed daily reports with work intervals, tasks, and productivity
98 /// metrics. Can automatically submit reports to configured APIs.
99 #[command(about = "Prepare a report")]
100 Report(report::ReportArgs),
101
102 /// Export application data to external formats
103 ///
104 /// Supports exporting tasks, reports, and summaries to CSV, JSON, and Excel
105 /// formats for external analysis or backup purposes.
106 #[command(about = "Export data to various formats")]
107 Export(export::ExportArgs),
108
109 /// Manage reusable task templates
110 ///
111 /// Create, edit, and use templates for frequently created tasks to
112 /// streamline task creation workflow.
113 #[command(about = "Manage task templates")]
114 Template(template::TemplateArgs),
115
116 /// Organize tasks with custom tags
117 ///
118 /// Create and manage tags to categorize and filter tasks by project,
119 /// priority, or any custom criteria.
120 #[command(about = "Manage task tags")]
121 Tag(tag::TagArgs),
122
123 /// Background activity monitoring daemon
124 ///
125 /// Monitors user input activity to automatically detect work sessions,
126 /// breaks, and workday boundaries. Can run as a background service.
127 #[command(about = "Watch user activity in the background to record pauses")]
128 Watch(watch::WatchArgs),
129
130 /// View recorded pauses and record ones the monitor missed
131 ///
132 /// Lists detected pauses for a date, and lets the user add an absence the
133 /// activity monitor did not catch or remove one recorded by mistake.
134 #[command(about = "View pauses and record ones the monitor missed")]
135 Pauses(pauses::PausesArgs),
136
137 /// Jira inbox of assigned open issues
138 ///
139 /// Syncs assigned unresolved Jira issues into a local table, lists them
140 /// by priority, and supports pin / dismiss / open / import into tasks.
141 #[command(about = "Manage Jira inbox issues")]
142 Inbox(inbox::InboxArgs),
143
144 /// Print a shell completion script
145 ///
146 /// Emits the completion script for the chosen shell on stdout; source it
147 /// from the shell profile to get completion for kasl's commands and flags.
148 #[command(about = "Print a shell completion script (source it from your shell profile)")]
149 Completions {
150 /// Target shell
151 shell: clap_complete::Shell,
152 },
153
154 /// Database migration management utilities (debug builds only)
155 ///
156 /// Provides tools for database schema management, migration history,
157 /// and rollback operations. Available only in debug builds for safety.
158 #[cfg(debug_assertions)]
159 #[command(about = "Database migration management")]
160 Migrations(migrations::MigrationsArgs),
161}
162
163/// The main CLI structure that parses command-line arguments.
164///
165/// Uses `clap` to define the application's interface and delegates
166/// command execution to the appropriate subcommand module. The CLI
167/// requires at least one subcommand to be specified.
168///
169/// # Examples
170///
171/// ```bash
172/// # Display help
173/// kasl --help
174///
175/// # Run a specific command
176/// kasl task --name "New task"
177/// ```
178#[derive(Debug, Parser)]
179#[command(name = "kasl", author, version, about, long_about = None)]
180#[command(arg_required_else_help(true))]
181pub struct Cli {
182 #[command(subcommand)]
183 command: Commands,
184}
185
186impl Cli {
187 /// Parses command-line arguments and executes the corresponding command.
188 ///
189 /// This is the main entry point for the CLI logic. It handles command
190 /// routing and provides centralized error handling for all commands.
191 ///
192 /// # Returns
193 ///
194 /// Returns `Ok(())` on successful command execution, or an error if
195 /// the command fails or invalid arguments are provided.
196 ///
197 /// # Examples
198 ///
199 /// ```rust,no_run
200 /// use kasl::commands::Cli;
201 ///
202 /// #[tokio::main]
203 /// async fn main() -> anyhow::Result<()> {
204 /// Cli::menu().await
205 /// }
206 /// ```
207 pub async fn menu() -> Result<()> {
208 let cli = Self::parse();
209
210 match cli.command {
211 Commands::Autostart(args) => autostart::cmd(args),
212 Commands::Setup(args) => {
213 warn_if_deprecated_alias();
214 init::cmd(args)
215 }
216 Commands::Task(args) => task::cmd(args).await,
217 Commands::End => {
218 // Manually end the current workday
219 Workdays::new()?.insert_end(Local::now().date_naive())?;
220 msg_info!(Message::WorkdayEnded);
221 Ok(())
222 }
223 Commands::Sum(args) => sum::cmd(args).await,
224 Commands::Report(args) => report::cmd(args).await,
225 Commands::Export(args) => export::cmd(args).await,
226 Commands::Template(args) => template::cmd(args),
227 Commands::Tag(args) => tag::cmd(args).await,
228 Commands::SelfUpdate => {
229 warn_if_deprecated_alias();
230 update::cmd().await
231 }
232 Commands::Watch(args) => watch::cmd(args).await,
233 Commands::Pauses(args) => pauses::cmd(args).await,
234 Commands::Completions { shell } => {
235 use clap::CommandFactory;
236 clap_complete::generate(shell, &mut Self::command(), "kasl", &mut std::io::stdout());
237 Ok(())
238 }
239 Commands::Inbox(args) => inbox::cmd(args).await,
240
241 // Database migrations only available in debug builds
242 #[cfg(debug_assertions)]
243 Commands::Migrations(args) => migrations::cmd(args),
244 }
245 }
246}
247
248/// Old command names still accepted as aliases, with their replacements.
249///
250/// Removed in 2.0; until then the alias works and says so.
251const DEPRECATED_ALIASES: [(&str, &str); 2] = [("init", "setup"), ("update", "self-update")];
252
253/// Prints a rename notice when the command was invoked by its old name.
254///
255/// clap resolves an alias to the canonical variant without recording which
256/// spelling was typed, so the first non-flag argument is what tells them
257/// apart.
258fn warn_if_deprecated_alias() {
259 let Some(typed) = std::env::args().nth(1) else {
260 return;
261 };
262 if let Some((old, new)) = DEPRECATED_ALIASES.iter().find(|(old, _)| *old == typed) {
263 msg_warning!(Message::DeprecatedCommand(old, new));
264 }
265}