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
//! Subcommand enums for nested CLI commands
//!
//! Contains all subcommand enums used by the main Commands enum.
use clap::Subcommand;
#[derive(Subcommand)]
pub enum SkillsAction {
/// Install every skill from `[skills.install]`, or a single named skill
Install {
/// Only install this skill name (otherwise installs all configured)
#[clap(long)]
name: Option<String>,
},
/// List skills declared in jarvy.toml + their installation status across agents
List {},
/// Drift check: which configured skills are missing / out-of-version per agent
Status {},
/// Show which AI agents are detected on disk
Agents {},
}
#[derive(Subcommand)]
pub enum HooksAction {
/// Install the configured git hook framework into `.git/hooks/`
Install {},
/// Run `pre-commit autoupdate` then reinstall hooks
Update {},
/// Show framework + installation status
Status {},
/// List configured hooks from `.pre-commit-config.yaml`
List {},
/// Run hooks once (defaults to changed files; `--all-files` for whole tree)
Run {
/// Run against every tracked file, not just staged changes
#[clap(long)]
all_files: bool,
/// Run a single hook by id (e.g. `--hook black`)
#[clap(long)]
hook: Option<String>,
},
/// Remove jarvy-installed hooks (calls `pre-commit uninstall`)
Uninstall {},
}
#[derive(Subcommand)]
pub enum McpRegisterAction {
/// Show what's in jarvy.toml + agent → path mapping
List {},
/// Register the Jarvy MCP server with every targeted agent
Apply {
/// Override scope: `user` or `project`
#[clap(long)]
scope: Option<String>,
},
/// Diff desired vs. on-disk state (exit 1 if drift)
Check {
#[clap(long)]
scope: Option<String>,
},
/// Strip jarvy-managed entries from every targeted agent
Remove {
#[clap(long)]
scope: Option<String>,
},
}
#[derive(Subcommand)]
pub enum AiHooksAction {
/// List provisioned hooks or the built-in library
List {
/// Show the built-in hook library instead of project config
#[clap(long)]
library: bool,
},
/// Write hook configs to every targeted AI agent
Apply {
/// Override scope: `user` or `project`
#[clap(long)]
scope: Option<String>,
},
/// Diff desired vs. on-disk state (exit 1 if drift)
Check {
#[clap(long)]
scope: Option<String>,
},
/// Strip jarvy-managed entries from every targeted agent
Remove {
#[clap(long)]
scope: Option<String>,
},
/// Inspect a single library hook (event, matcher, script bodies)
Test {
/// Library hook name (e.g. block-rm-rf)
name: String,
},
}
#[derive(Subcommand)]
pub enum TemplatesSubcommand {
/// List all available templates
List {},
/// Show details of a specific template
Show {
/// Template name to show
name: String,
},
/// Use a template to create jarvy.toml
Use {
/// Template name to use
name: String,
/// Output file path (default: jarvy.toml)
#[clap(short, long)]
output: Option<String>,
/// Run setup immediately after creating config
#[clap(long)]
setup: bool,
},
}
#[derive(Subcommand)]
pub enum RegistryAction {
/// Fetch the remote registry: verify signature, sha-verify each tool
/// TOML, and cache under ~/.jarvy/tools.d/.remote/. The next
/// `jarvy setup` / `jarvy validate` run picks up the synced tools
/// via the plugin loader.
Sync {},
/// Show the last sync's metadata (URL, count, timestamp,
/// signature-verified flag).
Status {},
/// Clear the local registry cache. Synced tools disappear on next
/// startup until you run `jarvy registry sync` again.
Clear {},
}
#[derive(Subcommand)]
pub enum TelemetryAction {
/// Show current telemetry configuration
Status {},
/// Enable telemetry
Enable {},
/// Disable telemetry
Disable {},
/// Set OTLP endpoint URL
SetEndpoint {
/// OTLP endpoint URL (e.g., http://localhost:4318)
url: String,
},
/// Test telemetry connectivity
Test {},
/// Preview what telemetry would be sent
Preview {},
}
#[derive(Subcommand)]
pub enum ServicesAction {
/// Start project services
Start {
/// Run services in the foreground (attached)
#[clap(long)]
foreground: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Stop project services
Stop {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Show service status
Status {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Restart project services
Restart {
/// Run services in the foreground (attached)
#[clap(long)]
foreground: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}
#[derive(Subcommand)]
pub enum TeamAction {
/// Add a team configuration source
Add {
/// Name for this source (e.g., 'company', 'team-frontend')
name: String,
/// Base URL for the config repository
url: String,
/// Description of this source
#[clap(short, long)]
description: Option<String>,
},
/// List registered team sources
List {},
/// Browse available configs from a source
Browse {
/// Source name to browse
source: String,
},
/// Sync config index from a source
Sync {
/// Source name to sync (syncs all if not specified)
source: Option<String>,
},
/// Remove a team source
Remove {
/// Source name to remove
name: String,
},
/// Initialize project with a team config
Init {
/// Config to use (format: source/config-name)
#[clap(long)]
from: String,
/// Output file path
#[clap(short, long, default_value = "./jarvy.toml")]
output: String,
},
}
#[derive(Subcommand)]
pub enum LockAction {
/// Generate a lock file from current environment
Generate {
/// Path to the configuration file
#[clap(short, long, default_value = "./jarvy.toml")]
file: String,
/// Output lock file path
#[clap(short, long, default_value = "./jarvy.lock")]
output: String,
},
/// Show lock file status (compare with installed versions)
Status {
/// Path to the lock file
#[clap(short, long, default_value = "./jarvy.lock")]
lock_file: String,
/// Show detailed output
#[clap(short, long)]
verbose: bool,
},
/// Verify installed tools match lock file
Verify {
/// Path to the lock file
#[clap(short, long, default_value = "./jarvy.lock")]
lock_file: String,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}
#[derive(Subcommand)]
pub enum ConfigAction {
/// Show resolved configuration (with inheritance applied)
Show {
/// Path to the configuration file
#[clap(short, long, default_value = "./jarvy.toml")]
file: String,
/// Show resolved config (after inheritance)
#[clap(long)]
resolved: bool,
/// Show the extends chain
#[clap(long)]
extends_chain: bool,
/// Output format: toml, json, yaml
#[clap(short = 'F', long = "format", default_value = "toml")]
output_format: String,
},
/// Refresh cached remote configs
Refresh {
/// Path to the configuration file
#[clap(short, long, default_value = "./jarvy.toml")]
file: String,
/// Force refresh even if cache is valid
#[clap(long)]
force: bool,
},
}
#[derive(Subcommand)]
pub enum UpdateSubcommand {
/// Check for available updates
Check {
/// Check specific channel instead of configured
#[clap(long)]
channel: Option<String>,
},
/// Show update history
History {},
/// Show update configuration
Config {},
/// Enable auto-updates
Enable {},
/// Disable auto-updates
Disable {},
}
#[derive(Subcommand)]
pub enum DriftAction {
/// Check for configuration drift
Check {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Show current state baseline
Status {
/// Show detailed tool information
#[clap(short, long)]
verbose: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Accept current state as new baseline
Accept {
/// Accept specific tools only (comma-separated)
#[clap(long)]
tools: Option<String>,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Fix detected drift issues
Fix {
/// Show what would be fixed without making changes
#[clap(long)]
dry_run: bool,
/// Force fix non-auto-fixable issues (may require confirmation)
#[clap(long)]
force: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}
#[derive(Clone, Subcommand)]
pub enum LogsAction {
/// View recent log entries
View {
/// Number of lines to show (default: 100)
#[clap(short = 'n', long, default_value = "100")]
lines: usize,
/// Filter by log level (error, warn, info, debug, trace)
#[clap(short, long)]
level: Option<String>,
/// Filter logs containing this text
#[clap(short, long)]
grep: Option<String>,
/// Output format: text, json
#[clap(short = 'F', long = "format", default_value = "text")]
output_format: String,
},
/// Show log statistics
Stats {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Clean old log files
Clean {
/// Remove all log files (not just old ones)
#[clap(long)]
all: bool,
/// Show what would be removed without removing
#[clap(long)]
dry_run: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Show logging configuration
Config {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}
#[derive(Subcommand)]
pub enum LibraryAction {
/// List every cached library (URL, publisher, item counts)
List {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Show the items inside one cached library
Show {
/// Library URL (or shorthand `github:owner/repo@<ref>`) — as declared in [<subsystem>.library_sources]
url: String,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Wipe the on-disk library cache (`~/.jarvy/library.d/`)
Clean {
/// Show what would be removed without removing
#[clap(long)]
dry_run: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Force-refresh every cached library_sources entry declared in jarvy.toml
Sync {
/// Path to the configuration file
#[clap(short, long, default_value = "./jarvy.toml")]
file: String,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}
#[derive(Subcommand)]
pub enum WorkspaceAction {
/// List all workspace members and their tools
List {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Show the resolved tool set for one member (with inheritance applied)
Show {
/// Member name as declared in `[workspace] members`
name: String,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Validate the workspace (members exist, each jarvy.toml parses)
Validate {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}
#[derive(Clone, Subcommand)]
pub enum TicketAction {
/// Create a new debug ticket
Create {
/// Focus on a specific tool
#[clap(short, long)]
tool: Option<String>,
/// Number of log lines to include (default: 500)
#[clap(short = 'n', long, default_value = "500")]
logs: usize,
/// Output path (default: ~/.jarvy/tickets/)
#[clap(short, long)]
output: Option<String>,
/// Show what would be collected without creating ticket
#[clap(long)]
dry_run: bool,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Show contents of a ticket
Show {
/// Ticket ID or path to ticket ZIP
ticket: String,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// List existing tickets
List {
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
/// Clean old tickets
Clean {
/// Remove tickets older than this many days (default: 30)
#[clap(long, default_value = "30")]
older_than: u32,
/// Output format: json, pretty
#[clap(short = 'F', long = "format", default_value = "pretty")]
output_format: String,
},
}