pocket-cli 1.0.2

A CLI tool for saving, organizing, and retrieving code snippets with integrated version control
Documentation
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
use crate::cli::{Cli, Commands, CardOperation, BlendCommands};
use crate::cards::CardManager;
use crate::errors::{PocketError, PocketResult, IntoPocketError};
use crate::logging;
use log::{debug, info, warn, error, LevelFilter};
use std::path::PathBuf;
use colored::Colorize;

/// Handle the CLI command
pub fn handle_command(cli: Cli) -> PocketResult<()> {
    // Set up logging based on verbosity
    let log_level = match cli.verbose {
        0 => LevelFilter::Warn,
        1 => LevelFilter::Info,
        2 => LevelFilter::Debug,
        _ => LevelFilter::Trace,
    };
    logging::init(log_level);
    
    debug!("Starting pocket CLI with verbosity level {}", cli.verbose);
    
    // Get the home directory
    let home_dir = std::env::var("HOME")
        .map_err(|_| PocketError::Config("HOME environment variable not set".to_string()))?;
    let data_dir = PathBuf::from(&home_dir).join(".pocket");
    
    // Initialize the card manager
    let card_dir = data_dir.join("cards");
    let mut card_manager = CardManager::new(card_dir.clone());
    card_manager.load_cards()
        .map_err(|e| PocketError::Card(format!("Failed to load cards: {}", e)))?;
    
    // Handle the command
    match cli.command {
        Commands::Add { file, message, editor, backpack, clipboard, summarize } => {
            // Build the arguments for the snippet card
            let mut args = Vec::new();
            
            if let Some(f) = file {
                args.push(format!("--file={}", f));
            }
            
            if let Some(m) = message {
                args.push(format!("--message={}", m));
            }
            
            if editor {
                args.push("--editor".to_string());
            }
            
            if let Some(b) = backpack {
                args.push(format!("--backpack={}", b));
            }
            
            if clipboard {
                args.push("--clipboard".to_string());
            }
            
            if let Some(s) = summarize {
                args.push(format!("--summarize={}", s));
            }
            
            // Execute the command
            card_manager.execute_command("snippet", "add", &args)
                .map_err(|e| PocketError::Card(format!("Failed to add snippet: {}", e)))?;
        },
        
        Commands::List { all, backpack, json, limit } => {
            // Build the arguments for the core card
            let mut args = Vec::new();
            
            if all {
                args.push("--include-backpacks".to_string());
            }
            
            if let Some(b) = backpack {
                args.push("--backpack".to_string());
                args.push(b);
            }
            
            if json {
                args.push("--json".to_string());
            }
            
            args.push("--limit".to_string());
            args.push(limit.to_string());
            
            // Execute the command
            card_manager.execute_command("core", "list", &args)
                .map_err(|e| PocketError::Card(format!("Failed to list entries: {}", e)))?;
        },
        
        Commands::Remove { id, force, backpack } => {
            // Build the arguments for the core card
            let mut args = vec![id];
            
            if force {
                args.push("--force".to_string());
            }
            
            if let Some(b) = backpack {
                args.push("--backpack".to_string());
                args.push(b);
            }
            
            // Execute the command
            card_manager.execute_command("core", "remove", &args)
                .map_err(|e| PocketError::Card(format!("Failed to remove entry: {}", e)))?;
        },
        
        Commands::Create { name, description } => {
            // Build the arguments for the core card
            let mut args = vec![name];
            
            if let Some(d) = description {
                args.push("--description".to_string());
                args.push(d);
            }
            
            // Execute the command
            card_manager.execute_command("core", "create-backpack", &args)
                .map_err(|e| PocketError::Card(format!("Failed to create backpack: {}", e)))?;
        },
        
        Commands::Search { query, limit, backpack, exact, package } => {
            if package {
                // Special case for package search (not yet migrated to card system)
                logging::warning("Package search is not yet migrated to the card system");
                logging::warning("This will be implemented in a future version");
                return Ok(());
            }
            
            // Build the arguments for the core card
            let mut args = vec![query];
            
            args.push("--limit".to_string());
            args.push(limit.to_string());
            
            if let Some(b) = backpack {
                args.push("--backpack".to_string());
                args.push(b);
            }
            
            if exact {
                args.push("--exact".to_string());
            }
            
            // Execute the command
            card_manager.execute_command("core", "search", &args)
                .map_err(|e| PocketError::Card(format!("Failed to search entries: {}", e)))?;
        },
        
        Commands::Insert { id, file, top, no_confirm, delimiter } => {
            if let Some(id) = id {
                if let Some(file_path) = file {
                    // Build the arguments for the core card
                    let mut args = vec![id, file_path];
                    
                    if no_confirm {
                        args.push("--no-confirm".to_string());
                    }
                    
                    if let Some(d) = delimiter {
                        args.push("--delimiter".to_string());
                        args.push(d);
                    }
                    
                    // Execute the command
                    card_manager.execute_command("core", "insert", &args)
                        .map_err(|e| PocketError::Card(format!("Failed to insert entry: {}", e)))?;
                } else {
                    return Err(PocketError::Cli("Missing file path for insert".to_string()));
                }
            } else if top {
                // Handle top entry insertion (not yet fully migrated to card system)
                return Err(PocketError::Cli("Operation not yet supported in the card system".to_string()));
            } else {
                return Err(PocketError::Cli("Missing entry ID for insert".to_string()));
            }
        },
        
        Commands::Reload => {
            logging::info("Reloading all extensions and cards...");
            
            // Re-initialize the card manager
            card_manager = CardManager::new(card_dir.clone());
            card_manager.load_cards()
                .map_err(|e| PocketError::Card(format!("Failed to reload cards: {}", e)))?;
            
            logging::success("Extensions and cards reloaded successfully");
        },
        
        Commands::ShowHelp { command, extensions } => {
            if extensions {
                // Show card commands
                let commands = card_manager.list_commands();
                
                println!("{}", logging::header("Available extensions:"));
                for (card_name, card_commands) in commands {
                    println!("\n{}", logging::title(&card_name));
                    for cmd in card_commands {
                        println!("  {} - {}", logging::key(&cmd.name), cmd.description);
                        println!("    Usage: {}", cmd.usage);
                    }
                }
            } else if let Some(cmd) = command {
                // Show help for a specific command
                // TODO: Implement this with card system
                logging::warning("Command-specific help not yet implemented in the card system");
                logging::warning("This will be improved in a future version");
            } else {
                // Show general help
                print_custom_help();
            }
        },
        
        Commands::Lint { workflow } => {
            // TODO: Migrate to card system
            logging::warning("Lint command not yet migrated to the card system");
            logging::warning("This will be implemented in a future version");
        },
        
        Commands::DeleteWorkflow { name } => {
            // TODO: Migrate to card system
            logging::warning("DeleteWorkflow command not yet migrated to the card system");
            logging::warning("This will be implemented in a future version");
        },
        
        Commands::Version => {
            // Show version information
            println!("Pocket CLI v{}", env!("CARGO_PKG_VERSION"));
            println!("A powerful tool for managing code snippets and shell integrations");
        },
        
        Commands::Edit { id, force, backpack } => {
            // Build the arguments for the core card
            let mut args = vec![id];
            
            if force {
                args.push("--force".to_string());
            }
            
            if let Some(b) = backpack {
                args.push("--backpack".to_string());
                args.push(b);
            }
            
            // TODO: Migrate to card system
            logging::warning("Edit command not yet fully migrated to the card system");
            logging::warning("This will be improved in a future version");
        },
        
        Commands::Execute { name, args } => {
            // TODO: Migrate to card system
            logging::warning("Execute command not yet migrated to the card system");
            logging::warning("This will be implemented in a future version");
        },
        
        Commands::Cards { operation } => {
            match operation {
                Some(CardOperation::List { detail }) => {
                    // List all cards
                    println!("{}", logging::header("Available cards:"));
                    for (name, version, enabled) in card_manager.list_cards() {
                        let status = if enabled {
                            "[Enabled]".green().bold()
                        } else {
                            "[Disabled]".yellow().bold()
                        };
                        
                        println!("{} {} v{}", status, logging::title(&name), version);
                        
                        // List commands for this card
                        if detail {
                            if let Ok(commands) = card_manager.get_card_commands(&name) {
                                for cmd in commands {
                                    println!("  - {}: {}", cmd.name, cmd.description);
                                }
                            }
                        }
                        
                        println!();
                    }
                },
                
                Some(CardOperation::Enable { name }) => {
                    // Enable a card
                    card_manager.enable_card(&name)
                        .map_err(|e| PocketError::Card(format!("Failed to enable card {}: {}", name, e)))?;
                    
                    logging::success(&format!("Card {} enabled", name));
                },
                
                Some(CardOperation::Disable { name }) => {
                    // Disable a card
                    card_manager.disable_card(&name)
                        .map_err(|e| PocketError::Card(format!("Failed to disable card {}: {}", name, e)))?;
                    
                    logging::success(&format!("Card {} disabled", name));
                },
                
                Some(CardOperation::Add { name, url }) => {
                    // Add a new card
                    card_manager.register_card_config(&name, &url)
                        .map_err(|e| PocketError::Card(format!("Failed to add card {}: {}", name, e)))?;
                    
                    logging::success(&format!("Card {} added from {}", name, url));
                },
                
                Some(CardOperation::Remove { name, force }) => {
                    // Remove a card
                    if !force {
                        println!("Are you sure you want to remove card {}? [y/N]", name);
                        let mut input = String::new();
                        std::io::stdin().read_line(&mut input)
                            .map_err(|e| PocketError::Cli(format!("Failed to read input: {}", e)))?;
                        
                        if !input.trim().eq_ignore_ascii_case("y") {
                            logging::info("Operation cancelled");
                            return Ok(());
                        }
                    }
                    
                    card_manager.remove_card_config(&name)
                        .map_err(|e| PocketError::Card(format!("Failed to remove card {}: {}", name, e)))?;
                    
                    logging::success(&format!("Card {} removed", name));
                },
                
                Some(CardOperation::Build { name, release }) => {
                    // Build a card
                    card_manager.build_card(&name, release)
                        .map_err(|e| PocketError::Card(format!("Failed to build card {}: {}", name, e)))?;
                    
                    logging::success(&format!("Card {} built successfully", name));
                },
                
                Some(CardOperation::Create { name, description }) => {
                    // Create a new card
                    card_manager.create_card(&name, &description)
                        .map_err(|e| PocketError::Card(format!("Failed to create card {}: {}", name, e)))?;
                    
                    logging::success(&format!("Card {} created successfully", name));
                },
                
                None => {
                    // Show help for the cards command
                    println!("{}", logging::header("Card Management:"));
                    println!("  Use the following commands to manage cards:");
                    println!("    pocket cards list       - List all cards");
                    println!("    pocket cards enable     - Enable a card");
                    println!("    pocket cards disable    - Disable a card");
                    println!("    pocket cards add        - Add a new card");
                    println!("    pocket cards remove     - Remove a card");
                    println!("    pocket cards build      - Build a card");
                    println!("    pocket cards create     - Create a new card template");
                    println!("");
                    println!("  For more information, run: pocket help cards");
                }
            }
        },
        
        Commands::Blend { script_file, executable, command } => {
            match command {
                Some(BlendCommands::Edit { hook_name }) => {
                    // Build the arguments for the blend card
                    let args = vec![hook_name];
                    
                    // Execute the command
                    card_manager.execute_command("blend", "edit", &args)
                        .map_err(|e| PocketError::Card(format!("Failed to edit hook: {}", e)))?;
                },
                
                Some(BlendCommands::List) => {
                    // Execute the command
                    card_manager.execute_command("blend", "list", &[])
                        .map_err(|e| PocketError::Card(format!("Failed to list hooks: {}", e)))?;
                },
                
                Some(BlendCommands::Run { hook_name, args }) => {
                    // Build the arguments for the blend card
                    let mut run_args = vec![hook_name];
                    run_args.extend(args.iter().cloned());
                    
                    // Execute the command
                    card_manager.execute_command("blend", "run", &run_args)
                        .map_err(|e| PocketError::Card(format!("Failed to run hook: {}", e)))?;
                },
                
                None => {
                    // Add a script
                    if let Some(script_path) = script_file {
                        let mut args = vec![script_path];
                        
                        if executable {
                            args.push("--executable".to_string());
                        }
                        
                        // Execute the command
                        card_manager.execute_command("blend", "add", &args)
                            .map_err(|e| PocketError::Card(format!("Failed to add hook: {}", e)))?;
                    } else {
                        // Show help for the blend command
                        println!("{}", logging::header("Blend Command:"));
                        println!("  Use the following syntax to blend shell scripts:");
                        println!("    pocket blend <script_file>           - Add a shell extension (sourced at shell startup)");
                        println!("    pocket blend --executable <script>   - Add an executable hook command (run with @name)");
                        println!("");
                        println!("  Other commands:");
                        println!("    pocket blend list                    - List all installed hooks");
                        println!("    pocket blend edit <hook_name>        - Edit an existing hook");
                        println!("    pocket blend run <hook_name> [args]  - Run a hook directly");
                        println!("");
                        println!("  For more information, run: pocket help blend");
                    }
                }
            }
        },
    }
    
    Ok(())
}

/// Print custom help message
fn print_custom_help() {
    println!("{}", logging::header("Pocket CLI Help"));
    println!("A CLI tool for saving, organizing, and retrieving code snippets");
    println!("with integrated version control and shell integration");
    println!("");
    
    println!("{}", logging::header("Core Commands:"));
    println!("  {} - Add content to your pocket storage", logging::key("add"));
    println!("  {} - Display all pocket entries", logging::key("list"));
    println!("  {} - Remove an entry from storage", logging::key("remove"));
    println!("  {} - Create a new backpack for organizing entries", logging::key("create"));
    println!("  {} - Find entries across all backpacks", logging::key("search"));
    println!("  {} - Insert an entry into a file", logging::key("insert"));
    println!("  {} - Reload all extensions", logging::key("reload"));
    println!("  {} - Display help information", logging::key("help"));
    println!("  {} - Lint code before adding", logging::key("lint"));
    println!("  {} - Display version information", logging::key("version"));
    println!("  {} - Edit an existing entry", logging::key("edit"));
    println!("  {} - Execute a script", logging::key("execute"));
    println!("");
    
    println!("{}", logging::header("Extension Commands:"));
    println!("  {} - Manage extensions/cards", logging::key("cards"));
    println!("  {} - Blend shell scripts into your environment", logging::key("blend"));
    println!("");
    
    println!("For more detailed help on a specific command, run:");
    println!("  pocket help <command>");
    println!("");
    
    println!("To see all extensions and their commands, run:");
    println!("  pocket help --extensions");
    println!("");
}