waka-cli 0.2.1

Command-line client for the WakaTime API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
//! Command-line argument definitions.

use clap::{Parser, Subcommand};
use std::path::PathBuf;

/// Command-line client for the WakaTime API.
#[derive(Debug, Parser)]
#[command(name = "waka-cli", version, about, propagate_version = true)]
pub struct Cli {
    /// WakaTime API key; see <https://wakatime.com/api-key>
    #[arg(long, env = "WAKATIME_API_KEY", global = true, hide_env_values = true)]
    pub api_key: Option<String>,

    /// OAuth 2.0 access token, used as Bearer auth
    #[arg(
        long,
        env = "WAKATIME_BEARER_TOKEN",
        global = true,
        hide_env_values = true,
        conflicts_with = "api_key"
    )]
    pub bearer_token: Option<String>,

    /// The user to query; defaults to "current"
    #[arg(long, env = "WAKATIME_USER", global = true)]
    pub user: Option<String>,

    /// Override the API base URL, e.g. for a mock server
    #[arg(long, env = "WAKATIME_BASE_URL", global = true)]
    pub base_url: Option<String>,

    /// Request timeout in seconds
    #[arg(long, env = "WAKATIME_TIMEOUT", global = true)]
    pub timeout: Option<u64>,

    /// Print the raw API response as JSON to stdout
    #[arg(long, global = true)]
    pub json: bool,

    #[command(subcommand)]
    pub command: Command,
}

/// The available subcommands.
#[derive(Debug, Subcommand)]
pub enum Command {
    /// Show the user's profile
    User,

    /// Total time logged since the account was created
    AllTime {
        /// Only show stats for this project
        #[arg(long)]
        project: Option<String>,
    },

    /// Coding activity stats for a time range
    Stats {
        /// Time range: last_7_days, last_30_days, last_6_months, last_year, all_time or a year like 2024
        range: String,
        /// Keystroke timeout preference in minutes
        #[arg(long)]
        keystroke_timeout: Option<u32>,
        /// Only count heartbeats triggered by writes
        #[arg(long)]
        writes_only: bool,
        /// Show more detailed stats limited to this project
        #[arg(long)]
        project: Option<String>,
    },

    /// Aggregate stats of all WakaTime users for a time range
    StatsAggregated {
        /// Time range, e.g. last_7_days
        range: String,
    },

    /// Daily coding activity summaries for a date range
    Summaries {
        /// Start date, e.g. 2026-01-01
        start: String,
        /// End date, e.g. 2026-01-08
        end: String,
        /// Only show summaries for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
        /// Keystroke timeout preference in minutes
        #[arg(long)]
        keystroke_timeout: Option<u32>,
        /// Only count heartbeats triggered by writes
        #[arg(long)]
        writes_only: bool,
        /// Timezone for the given dates
        #[arg(long)]
        timezone: Option<String>,
        /// Alternative way to supply start and end dates, e.g. "Last 7 Days"
        #[arg(long)]
        range: Option<String>,
    },

    /// Coding activity for a single day as an array of durations
    Durations {
        /// The date, e.g. 2026-06-01
        date: String,
        /// Only show durations for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
        /// Keystroke timeout preference in minutes
        #[arg(long)]
        keystroke_timeout: Option<u32>,
        /// Only count heartbeats triggered by writes
        #[arg(long)]
        writes_only: bool,
        /// Timezone for the given date
        #[arg(long)]
        timezone: Option<String>,
        /// Primary key to slice durations by; defaults to entity
        #[arg(long)]
        slice_by: Option<String>,
    },

    /// An insight about the user's coding activity
    Insights {
        /// Insight type: weekdays, days, best_day, daily_average, projects, languages, editors,
        /// categories, machines or operating_systems
        insight_type: String,
        /// Time range, e.g. last_7_days
        range: String,
        /// Keystroke timeout preference in minutes
        #[arg(long)]
        keystroke_timeout: Option<u32>,
        /// Only count heartbeats triggered by writes
        #[arg(long)]
        writes_only: bool,
        /// Filter to a day of the week, either 0-6 or a weekday name
        #[arg(long)]
        weekday: Option<String>,
    },

    /// List the user's projects
    Projects {
        /// Filter project names by a search term
        #[arg(long)]
        query: Option<String>,
        /// Page number
        #[arg(long, conflicts_with = "all")]
        page: Option<u32>,
        /// Fetch all pages
        #[arg(long)]
        all: bool,
    },

    /// List commits of a project, including the time spent on them
    Commits {
        /// The project name
        project: String,
        /// Filter commits by author
        #[arg(long)]
        author: Option<String>,
        /// Filter commits to a branch
        #[arg(long)]
        branch: Option<String>,
        /// Page number
        #[arg(long, conflicts_with = "all")]
        page: Option<u32>,
        /// Fetch all pages
        #[arg(long)]
        all: bool,
    },

    /// Show a single commit of a project, including the time spent on it
    Commit {
        /// The project name
        project: String,
        /// The commit hash
        hash: String,
        /// Filter the commit to a branch
        #[arg(long)]
        branch: Option<String>,
    },

    /// List the user's goals
    Goals,

    /// Show a single goal
    Goal {
        /// The goal id
        id: String,
    },

    /// The public leaderboard of users ranked by coding activity
    Leaders {
        /// Filter leaders by language
        #[arg(long)]
        language: Option<String>,
        /// Filter leaders by the hireable badge
        #[arg(long)]
        hireable: bool,
        /// Filter leaders by a two-character country code
        #[arg(long)]
        country_code: Option<String>,
        /// Page number
        #[arg(long)]
        page: Option<u32>,
    },

    /// List the user's private leaderboards
    Leaderboards,

    /// The leaders of a private leaderboard
    Leaderboard {
        /// The leaderboard id
        board: String,
        /// Filter leaders by language
        #[arg(long)]
        language: Option<String>,
        /// Filter leaders by a two-character country code
        #[arg(long)]
        country_code: Option<String>,
        /// Page number
        #[arg(long)]
        page: Option<u32>,
    },

    /// List the machines the user has logged coding activity from
    MachineNames,

    /// List the plugin user agents the user has logged coding activity from
    UserAgents,

    /// List the editors with WakaTime plugins
    Editors {
        /// Include editors with unreleased plugins
        #[arg(long)]
        unreleased: bool,
    },

    /// List the programming languages known to WakaTime
    ProgramLanguages,

    /// WakaTime service metadata, e.g. server IP addresses
    Meta,

    /// Today's coding activity, as used by editor status bars
    StatusBar,

    /// Inspect, send or delete heartbeats
    Heartbeats {
        #[command(subcommand)]
        command: HeartbeatsCommand,
    },

    /// Inspect, log or delete external durations
    ExternalDurations {
        #[command(subcommand)]
        command: ExternalDurationsCommand,
    },

    /// Inspect or request data dump exports
    DataDumps {
        #[command(subcommand)]
        command: DataDumpsCommand,
    },

    /// Inspect or modify custom rules
    CustomRules {
        #[command(subcommand)]
        command: CustomRulesCommand,
    },

    /// Organizations and their dashboards
    Org {
        #[command(subcommand)]
        command: OrgCommand,
    },

    /// Generate shell completions and print them to stdout
    Completions {
        /// The shell to generate completions for
        #[arg(value_enum)]
        shell: clap_complete::Shell,
    },
}

/// Subcommands for heartbeats.
#[derive(Debug, Subcommand)]
pub enum HeartbeatsCommand {
    /// List the heartbeats of a single day
    List {
        /// The date, e.g. 2026-06-01
        date: String,
    },
    /// Send a single heartbeat representing coding activity
    Send {
        /// The entity the heartbeat is logging time against, e.g. a file path or domain
        #[arg(long)]
        entity: String,
        /// Type of entity: file, app, url or domain
        #[arg(long = "type", value_name = "TYPE")]
        entity_type: String,
        /// UNIX epoch timestamp; defaults to now
        #[arg(long)]
        time: Option<f64>,
        /// Category, e.g. coding, debugging or building
        #[arg(long)]
        category: Option<String>,
        /// Project name
        #[arg(long)]
        project: Option<String>,
        /// Branch name
        #[arg(long)]
        branch: Option<String>,
        /// Language name
        #[arg(long)]
        language: Option<String>,
        /// Total number of lines in the entity
        #[arg(long)]
        lines: Option<u64>,
        /// Current cursor line number
        #[arg(long)]
        lineno: Option<u64>,
        /// Current cursor column position
        #[arg(long)]
        cursorpos: Option<u64>,
        /// Mark the heartbeat as triggered by a write
        #[arg(long)]
        is_write: bool,
    },
    /// Send multiple heartbeats from a JSON array; at most 25 per request
    SendBulk {
        /// Path to a JSON file with an array of heartbeats; reads stdin when omitted or "-"
        #[arg(long)]
        file: Option<PathBuf>,
    },
    /// Delete heartbeats; all ids must be from the given day
    Delete {
        /// The date the heartbeats belong to
        date: String,
        /// The heartbeat ids to delete
        #[arg(required = true)]
        ids: Vec<String>,
    },
}

/// Subcommands for external durations.
#[derive(Debug, Subcommand)]
pub enum ExternalDurationsCommand {
    /// List the external durations of a single day
    List {
        /// The date, e.g. 2026-06-01
        date: String,
        /// Only show durations for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
        /// Timezone for the given date
        #[arg(long)]
        timezone: Option<String>,
    },
    /// Log time spent in an external app, e.g. a meeting or code review
    Send {
        /// Unique id of this duration on the external provider
        #[arg(long)]
        external_id: String,
        /// The entity this duration is logging time against
        #[arg(long)]
        entity: String,
        /// Type of entity: file, app, event, url or domain
        #[arg(long = "type", value_name = "TYPE")]
        entity_type: String,
        /// Start of the duration as UNIX epoch
        #[arg(long)]
        start: f64,
        /// End of the duration as UNIX epoch
        #[arg(long)]
        end: f64,
        /// Category, e.g. coding, meeting or code reviewing
        #[arg(long)]
        category: Option<String>,
        /// Project name
        #[arg(long)]
        project: Option<String>,
        /// Branch name
        #[arg(long)]
        branch: Option<String>,
        /// Language name
        #[arg(long)]
        language: Option<String>,
        /// Additional metadata; max 2083 characters
        #[arg(long)]
        meta: Option<String>,
    },
    /// Log multiple external durations from a JSON array; at most 1000 per request
    SendBulk {
        /// Path to a JSON file with an array of external durations; reads stdin when omitted or "-"
        #[arg(long)]
        file: Option<PathBuf>,
    },
    /// Delete external durations; all ids must be from the given day
    Delete {
        /// The date the durations belong to
        date: String,
        /// The external duration ids to delete
        #[arg(required = true)]
        ids: Vec<String>,
    },
}

/// Subcommands for data dumps.
#[derive(Debug, Subcommand)]
pub enum DataDumpsCommand {
    /// List the user's data dump exports and their status
    List,
    /// Request a data dump export
    Create {
        /// Type of export: heartbeats or daily
        dump_type: String,
        /// Do not send an email when the export is ready
        #[arg(long)]
        no_email: bool,
    },
}

/// Subcommands for custom rules.
#[derive(Debug, Subcommand)]
pub enum CustomRulesCommand {
    /// List the user's custom rules
    List,
    /// Replace the user's custom rules with rules from a JSON array
    Set {
        /// Path to a JSON file with an array of custom rules; reads stdin when omitted or "-"
        #[arg(long)]
        file: Option<PathBuf>,
    },
    /// Delete a custom rule
    Delete {
        /// The rule id
        id: String,
    },
    /// Progress of a custom rules background job
    Progress {
        /// The background job id
        job_id: String,
    },
    /// Clear the progress of a finished custom rules job
    ClearProgress,
}

/// Subcommands for organizations.
#[derive(Debug, Subcommand)]
pub enum OrgCommand {
    /// List the organizations the user belongs to
    List,
    /// List the dashboards of an organization
    Dashboards {
        /// The organization id
        org: String,
    },
    /// List the members of an organization's dashboard
    Members {
        /// The organization id
        org: String,
        /// The dashboard id
        dashboard: String,
    },
    /// A dashboard's coding activity for a single day as durations
    Durations {
        /// The organization id
        org: String,
        /// The dashboard id
        dashboard: String,
        /// The date, e.g. 2026-06-01
        date: String,
        /// Only show durations for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
        /// Primary key to slice durations by; defaults to entity
        #[arg(long)]
        slice_by: Option<String>,
    },
    /// A dashboard's coding activity for a single day as a summary
    Summaries {
        /// The organization id
        org: String,
        /// The dashboard id
        dashboard: String,
        /// The date, e.g. 2026-06-01
        date: String,
        /// Only show summaries for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
    },
    /// A dashboard member's coding activity for a single day as durations
    MemberDurations {
        /// The organization id
        org: String,
        /// The dashboard id
        dashboard: String,
        /// The member id
        member: String,
        /// The date, e.g. 2026-06-01
        date: String,
        /// Only show durations for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
        /// Primary key to slice durations by; defaults to entity
        #[arg(long)]
        slice_by: Option<String>,
    },
    /// A dashboard member's coding activity for a date range as daily summaries
    MemberSummaries {
        /// The organization id
        org: String,
        /// The dashboard id
        dashboard: String,
        /// The member id
        member: String,
        /// Start date, e.g. 2026-01-01
        start: String,
        /// End date, e.g. 2026-01-08
        end: String,
        /// Only show summaries for this project
        #[arg(long)]
        project: Option<String>,
        /// Comma separated list of branch names
        #[arg(long)]
        branches: Option<String>,
        /// Alternative way to supply start and end dates, e.g. "Last 7 Days"
        #[arg(long)]
        range: Option<String>,
    },
    /// List the custom rules of an organization
    CustomRules {
        /// The organization id
        org: String,
    },
}