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
use std::path::PathBuf;
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(
name = "projm",
about = "Project organizer & navigator",
version = env!("CARGO_PKG_VERSION")
)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
/// Scan a directory and move projects into ~/projects/<category>/
Organize {
/// Directory to scan
dir: PathBuf,
/// Preview only — no files moved
#[arg(short = 'n', long)]
dry_run: bool,
},
/// Fuzzy-pick a project and jump to it (wrap with `eval` in shell)
G {
/// Optional search query or project name to match
query: Option<String>,
/// Jump to the last entered project
#[arg(short = 'l', long)]
last: bool,
},
/// Install shell integration, completions, and zoxide setup
Init {
/// Shell function/alias name
#[arg(short = 'a', long, default_value = "pg")]
alias: String,
/// Run in non-interactive mode, bypassing the onboarding wizard
#[arg(long)]
non_interactive: bool,
/// Override the shell target to configure
#[arg(short = 's', long, value_enum)]
shell: Option<crate::completions::CompletionShell>,
/// Override the shell profile path to update
#[arg(short = 'p', long)]
profile_path: Option<PathBuf>,
},
/// Print shell completion script for a shell
Completions {
#[arg(value_enum)]
shell: crate::completions::CompletionShell,
},
/// Override the base projects directory (default: ~/projects)
SetBase { path: PathBuf },
/// List detected editors on this machine
Editors,
/// Manage and run project creation blueprints
Blueprint {
#[command(subcommand)]
sub: Option<BlueprintSubcommands>,
},
/// Verify active development tools and environment health
Check,
/// Detect and run the project's dev command
Run {
/// Optional path or project name to run
path_or_query: Option<String>,
/// List the discovered runnable apps and exit (works without a TTY)
#[arg(short = 'l', long)]
list: bool,
/// Force the multi-app tabbed-log TUI runner
#[arg(long)]
tui: bool,
/// Launch the TUI and start every discovered app immediately
#[arg(short = 'a', long)]
all: bool,
/// Verify that stopping a project reaps its whole process group, then exit
#[arg(long)]
selftest: bool,
},
/// Show git health for all organized projects (branch, dirty, ahead/behind)
#[command(alias = "st")]
Status {
/// Show only projects that are dirty or out of sync with upstream
#[arg(short, long)]
dirty: bool,
/// Emit machine-readable JSON instead of a table
#[arg(long)]
json: bool,
},
/// Clone a git repository directly and organize it
Clone {
/// Git repository URL (HTTPS or SSH)
url: String,
/// Optional custom project name override
name: Option<String>,
/// Optional branch or tag to clone
#[arg(short, long)]
branch: Option<String>,
/// Open in preferred editor after cloning
#[arg(short, long)]
open: bool,
},
}
#[derive(Subcommand, Debug, Clone)]
pub enum BlueprintSubcommands {
/// Add a new blueprint interactively
Add,
/// List all saved blueprints
List,
/// Run a blueprint to create a new project
Run {
/// Optional name of the blueprint to run
name: Option<String>,
},
/// Edit an existing blueprint
#[command(alias = "update")]
Edit {
/// Optional name of the blueprint to edit
name: Option<String>,
},
/// Delete an existing blueprint
#[command(alias = "rm", alias = "remove")]
Delete {
/// Optional name of the blueprint to delete
name: Option<String>,
},
}