Skip to main content

run_stack/
commands.rs

1//! `rst commands` — every CLI entry in a terminal table.
2
3use anyhow::Result;
4
5/// One row in the command catalogue.
6struct Entry {
7    command: &'static str,
8    aliases: &'static str,
9    group: &'static str,
10    description: &'static str,
11}
12
13const CATALOG: &[Entry] = &[
14    Entry {
15        command: "create",
16        aliases: "new",
17        group: "Global",
18        description: "Write .run/run.config.toml and run init",
19    },
20    Entry {
21        command: "migrate",
22        aliases: "—",
23        group: "Global",
24        description: "Convert legacy run/ to .run/ (config + env)",
25    },
26    Entry {
27        command: "upgrade",
28        aliases: "update",
29        group: "Global",
30        description: "Refresh legacy run/ or self-update",
31    },
32    Entry {
33        command: "self-update",
34        aliases: "—",
35        group: "Global",
36        description: "Install latest from crates.io and migrate configs",
37    },
38    Entry {
39        command: "completion",
40        aliases: "—",
41        group: "Global",
42        description: "Shell / Kiro autocompletion (bash|zsh|fig|install|services)",
43    },
44    Entry {
45        command: "init",
46        aliases: "—",
47        group: "Setup",
48        description: "Write .run/run.config.toml and .run/.env",
49    },
50    Entry {
51        command: "init --update",
52        aliases: "—",
53        group: "Setup",
54        description: "Find and add apps added to the workspace since setup",
55    },
56    Entry {
57        command: "up",
58        aliases: "run",
59        group: "Lifecycle",
60        description: "Build if needed and start (--essential = config essentials)",
61    },
62    Entry {
63        command: "down",
64        aliases: "—",
65        group: "Lifecycle",
66        description: "Stop everything, or named services (keeps data)",
67    },
68    Entry {
69        command: "restart",
70        aliases: "—",
71        group: "Lifecycle",
72        description: "Stop then start (down + up); --build, --essential",
73    },
74    Entry {
75        command: "rebuild",
76        aliases: "—",
77        group: "Lifecycle",
78        description: "Rebuild images from scratch and recreate containers",
79    },
80    Entry {
81        command: "clean",
82        aliases: "—",
83        group: "Lifecycle",
84        description: "Stop and DELETE all volumes",
85    },
86    Entry {
87        command: "commands",
88        aliases: "—",
89        group: "Inspection",
90        description: "List every CLI command in a table",
91    },
92    Entry {
93        command: "apps",
94        aliases: "list",
95        group: "Inspection",
96        description: "List configured apps (backend, web, mobile, …)",
97    },
98    Entry {
99        command: "services",
100        aliases: "—",
101        group: "Inspection",
102        description: "List compose services (and status when Docker is up)",
103    },
104    Entry {
105        command: "ps",
106        aliases: "status",
107        group: "Inspection",
108        description: "Service status",
109    },
110    Entry {
111        command: "ports",
112        aliases: "—",
113        group: "Inspection",
114        description: "Host ports + env URLs table",
115    },
116    Entry {
117        command: "logs",
118        aliases: "—",
119        group: "Inspection",
120        description: "Follow logs",
121    },
122    Entry {
123        command: "shell",
124        aliases: "sh",
125        group: "Inspection",
126        description: "Shell into a container (default: backend)",
127    },
128    Entry {
129        command: "config",
130        aliases: "—",
131        group: "Inspection",
132        description: "Print the resolved configuration",
133    },
134    Entry {
135        command: "explain",
136        aliases: "—",
137        group: "Inspection",
138        description: "Print the docker compose command, run nothing",
139    },
140    Entry {
141        command: "env",
142        aliases: "—",
143        group: "Inspection",
144        description: "Print the environment compose is given",
145    },
146    Entry {
147        command: "generate",
148        aliases: "—",
149        group: "Inspection",
150        description: "Write the compose overlays, start nothing",
151    },
152    Entry {
153        command: "backend",
154        aliases: "—",
155        group: "Backend",
156        description: "Run any command inside the backend container",
157    },
158    Entry {
159        command: "migrate",
160        aliases: "—",
161        group: "Backend",
162        description: "Run pending migrations",
163    },
164    Entry {
165        command: "seed",
166        aliases: "—",
167        group: "Backend",
168        description: "Run database seeders",
169    },
170    Entry {
171        command: "fresh",
172        aliases: "—",
173        group: "Backend",
174        description: "Rebuild the schema and seed it (destroys data)",
175    },
176    Entry {
177        command: "artisan",
178        aliases: "—",
179        group: "Backend",
180        description: "php artisan … (BACKEND_STACK=laravel)",
181    },
182    Entry {
183        command: "composer",
184        aliases: "—",
185        group: "Backend",
186        description: "composer … (BACKEND_STACK=laravel)",
187    },
188    Entry {
189        command: "pnpm",
190        aliases: "—",
191        group: "Frontend",
192        description: "pnpm … inside the frontend workspace",
193    },
194    Entry {
195        command: "ios",
196        aliases: "—",
197        group: "Mobile",
198        description: "Open mobile-client in the iOS Simulator",
199    },
200    Entry {
201        command: "android",
202        aliases: "—",
203        group: "Mobile",
204        description: "Open mobile-client on an Android emulator",
205    },
206    Entry {
207        command: "device",
208        aliases: "—",
209        group: "Mobile",
210        description: "Open on a USB phone, or print the Expo Go URL",
211    },
212    Entry {
213        command: "mobile",
214        aliases: "—",
215        group: "Mobile",
216        description: "Restart mobile-deps / mobile-packages / Metro",
217    },
218    Entry {
219        command: "reload",
220        aliases: "—",
221        group: "Mobile",
222        description: "Metro /status + /reload; --clear wipes caches",
223    },
224    Entry {
225        command: "prebuild",
226        aliases: "—",
227        group: "Mobile",
228        description: "expo prebuild (Expo apps only)",
229    },
230    Entry {
231        command: "sync-mobile-port",
232        aliases: "—",
233        group: "Mobile",
234        description: "Sync MOBILE_CLIENT_PORT into the mobile app configs",
235    },
236    Entry {
237        command: "bundler",
238        aliases: "configure-bundler",
239        group: "Mobile",
240        description: "Point the simulator at Metro",
241    },
242    Entry {
243        command: "desktop",
244        aliases: "—",
245        group: "Desktop",
246        description: "Launch the Electron / Tauri shell on the host",
247    },
248    Entry {
249        command: "deploy",
250        aliases: "—",
251        group: "Deploy",
252        description: "Deploy web, mobile or desktop",
253    },
254    Entry {
255        command: "dash",
256        aliases: "dashboard",
257        group: "Dashboard",
258        description: "Open the status dashboard in a browser",
259    },
260];
261
262pub fn run(raw: bool) -> Result<i32> {
263    if raw {
264        let mut seen = std::collections::BTreeSet::new();
265        for entry in CATALOG {
266            if seen.insert(entry.command) {
267                println!("{}", entry.command);
268            }
269        }
270        return Ok(0);
271    }
272    print_table();
273    Ok(0)
274}
275
276fn print_table() {
277    let cmd_w = width(CATALOG.iter().map(|e| e.command), "COMMAND");
278    let alias_w = width(CATALOG.iter().map(|e| e.aliases), "ALIASES");
279    let group_w = width(CATALOG.iter().map(|e| e.group), "GROUP");
280
281    println!("Commands");
282    println!(
283        "{:<cmd_w$}  {:<alias_w$}  {:<group_w$}  {}",
284        "COMMAND", "ALIASES", "GROUP", "DESCRIPTION"
285    );
286    let rule = cmd_w + alias_w + group_w + 6 + 40;
287    println!("{}", "-".repeat(rule.max(24)));
288    for entry in CATALOG {
289        println!(
290            "{:<cmd_w$}  {:<alias_w$}  {:<group_w$}  {}",
291            entry.command, entry.aliases, entry.group, entry.description
292        );
293    }
294    println!();
295}
296
297fn width<'a>(values: impl Iterator<Item = &'a str>, header: &str) -> usize {
298    values
299        .map(str::len)
300        .chain(std::iter::once(header.len()))
301        .max()
302        .unwrap_or(header.len())
303}