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
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "mps", version, about = "Plain-text personal productivity CLI")]
pub struct Cli {
/// Path to config file (default: ~/.mps_config.yaml)
#[arg(long, global = true)]
pub config_path: Option<String>,
/// Recreate config even if it exists
#[arg(long, global = true, default_value_t = false)]
pub force: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand)]
pub enum Commands {
/// Open a date's .mps file in $EDITOR (default: today)
Open {
/// Date to open (today, yesterday, YYYYMMDD, last friday, …)
datesign: Option<String>,
},
/// List elements for a date as an indented tree
List {
/// Date (default: today)
datesign: Option<String>,
/// Filter by element type: task, note, log, reminder
#[arg(short = 't', long)]
r#type: Option<String>,
/// Filter by tag name
#[arg(short = 'g', long)]
tag: Option<String>,
/// Filter tasks by status: open, done
#[arg(short = 's', long)]
status: Option<String>,
/// Show elements from SINCE up to DATESIGN
#[arg(short = 'S', long)]
since: Option<String>,
/// Show human-readable ref column (task-1, mps-1.2, …)
#[arg(short = 'r', long)]
refs: bool,
/// List elements across all dates in the archive
#[arg(short = 'a', long)]
all: bool,
/// Filter character entries by person name
#[arg(short = 'n', long)]
name: Option<String>,
},
/// Append an element to today's file without opening an editor
Append {
/// Element type: task, note, log, reminder (aliases from config are resolved)
kind: String,
/// Element body text
body: Vec<String>,
/// Comma-separated tags (e.g. work,backend)
#[arg(long)]
tags: Option<String>,
/// Task status: open (default) or done
#[arg(long)]
status: Option<String>,
/// Time for reminders (e.g. 5pm, 10:30)
#[arg(long)]
at: Option<String>,
/// Start time for logs (HH:MM)
#[arg(long)]
start_time: Option<String>,
/// End time for logs (HH:MM)
#[arg(long)]
end_time: Option<String>,
/// Person name for character entries
#[arg(short = 'n', long)]
name: Option<String>,
},
/// Update an element's attributes in-place
Update {
/// Element ref: human (task-1) or epoch (20260428.1)
ref_path: String,
/// Set task status: open or done
#[arg(long)]
status: Option<String>,
/// Set log start time (HH:MM)
#[arg(long = "start-time")]
start_time: Option<String>,
/// Set log end time (HH:MM)
#[arg(long = "end-time")]
end_time: Option<String>,
/// Set reminder time
#[arg(long)]
at: Option<String>,
/// Date context for human refs (default: today)
#[arg(short = 'd', long)]
date: Option<String>,
},
/// Mark a task as done (shorthand for update REFPATH --status done)
Done {
/// Element ref: human (task-1) or epoch (20260428.1)
ref_path: String,
/// Date context for human refs (default: today)
#[arg(short = 'd', long)]
date: Option<String>,
},
/// Full-text search across all .mps files
Search {
/// Search query
query: String,
/// Filter by element type
#[arg(short = 't', long)]
r#type: Option<String>,
/// Filter by tag
#[arg(short = 'g', long)]
tag: Option<String>,
/// Search from this date onward
#[arg(short = 'S', long)]
since: Option<String>,
/// Filter character entries by person name
#[arg(short = 'n', long)]
name: Option<String>,
},
/// Show element counts and log durations
Stats {
/// Date (default: today)
datesign: Option<String>,
/// Stats from SINCE up to DATESIGN
#[arg(short = 'S', long)]
since: Option<String>,
/// Stats across all dates in the archive
#[arg(short = 'a', long)]
all: bool,
},
/// Show tag usage frequency bar chart
Tags {
/// Date (default: today)
datesign: Option<String>,
/// Filter by element type
#[arg(short = 't', long)]
r#type: Option<String>,
/// Filter tasks by status
#[arg(short = 's', long)]
status: Option<String>,
/// Tags from SINCE up to DATESIGN
#[arg(short = 'S', long)]
since: Option<String>,
/// Count tags across all dates
#[arg(short = 'a', long)]
all: bool,
/// Filter character entries by person name
#[arg(short = 'n', long)]
name: Option<String>,
},
/// Export elements to JSON or CSV on stdout
Export {
/// Date (default: today)
datesign: Option<String>,
/// Output format: json (default), csv
#[arg(short = 'f', long, default_value = "json")]
format: String,
/// Filter by element type
#[arg(short = 't', long)]
r#type: Option<String>,
/// Export from SINCE up to DATESIGN
#[arg(short = 'S', long)]
since: Option<String>,
},
/// View or edit MPS configuration
Config {
/// Subcommand: show (default) or edit
subcommand: Option<String>,
},
/// Run git commands inside the storage directory
Git {
/// Git subcommand and args (auto = full cycle, autocommit = stage+commit)
#[arg(trailing_var_arg = true)]
args: Vec<String>,
},
/// Stage, commit, pull, and push (equivalent to git auto)
Autogit,
/// Run any shell command inside the storage directory
Cmd {
/// Command and arguments
#[arg(trailing_var_arg = true)]
args: Vec<String>,
},
/// Print version
Version,
}