Skip to content

Commit 60b73fa

Browse files
committed
Check in copied README
1 parent ba2315d commit 60b73fa

3 files changed

Lines changed: 376 additions & 2 deletions

File tree

.changeset/crazy-berries-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@gud/cli": patch
3+
---
4+
5+
Added missing README.

packages/cli/README.md

Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
# Gud CLI
2+
3+
[![GitHub](https://img.shields.io/badge/ryangoree%2Fgud--cli-151b23?logo=github)](https://github.com/ryangoree/gud-cli)
4+
[![NPM
5+
Version](https://img.shields.io/badge/%40gud%2Fcli-cb3837?logo=npm)](https://npmjs.com/package/@gud/cli)
6+
[![License:
7+
Apache-2.0](https://img.shields.io/badge/Apache%202.0-23454d?logo=apache)](./LICENSE)
8+
9+
**Build delightful command-line tools that your users will actually enjoy
10+
using.**
11+
12+
Gud CLI is a modern TypeScript framework that makes creating interactive CLI
13+
applications effortless. Instead of forcing users to memorize complex commands,
14+
your CLI can guide them through an intuitive, conversational experience.
15+
16+
```sh
17+
npm install @gud/cli
18+
```
19+
20+
## Why Gud CLI? <!-- omit from toc -->
21+
22+
- **🎯 User-first design** – Missing a required option? Gud CLI automatically
23+
prompts for it instead of showing cryptic error messages.
24+
- **📁 Intuitive organization** – Commands are just files in folders. Want
25+
nested commands? Create nested folders. It's that simple.
26+
- **🔧 TypeScript-powered** – Full type safety with intelligent autocompletion
27+
for options and parameters.
28+
- **🔌 Extensible** – Plugin system and lifecycle hooks let you customize
29+
everything without touching core logic.
30+
31+
## Table of Contents <!-- omit from toc -->
32+
33+
- [Quick Start](#quick-start)
34+
- [1. Create your CLI entry point](#1-create-your-cli-entry-point)
35+
- [2. Add your first command](#2-add-your-first-command)
36+
- [3. Run it](#3-run-it)
37+
- [What makes it different?](#what-makes-it-different)
38+
- [Interactive by default](#interactive-by-default)
39+
- [File-based routing](#file-based-routing)
40+
- [TypeScript-first](#typescript-first)
41+
- [Examples](#examples)
42+
- [Interactive deployment](#interactive-deployment)
43+
- [Parameterized commands](#parameterized-commands)
44+
- [Advanced Features](#advanced-features)
45+
- [Plugins](#plugins)
46+
- [Lifecycle Hooks](#lifecycle-hooks)
47+
- [Flexible Option Handling](#flexible-option-handling)
48+
- [Built for Scale](#built-for-scale)
49+
- [Migration Guide](#migration-guide)
50+
- [From Commander.js](#from-commanderjs)
51+
- [From yargs](#from-yargs)
52+
- [Community](#community)
53+
- [Reference](#reference)
54+
55+
56+
57+
## Quick Start
58+
59+
### 1. Create your CLI entry point
60+
61+
```ts
62+
// src/cli.ts
63+
#!/usr/bin/env node
64+
import { run } from '@gud/cli';
65+
66+
// Uses ./commands by default
67+
run();
68+
```
69+
70+
### 2. Add your first command
71+
72+
```ts
73+
// src/commands/hello.ts
74+
import { command } from '@gud/cli';
75+
76+
export default command({
77+
description: 'Say hello to someone',
78+
options: {
79+
name: {
80+
description: 'Who to greet',
81+
type: 'string',
82+
default: 'World',
83+
},
84+
},
85+
handler: async ({ options, client }) => {
86+
// Prompts if you pass the prompt option
87+
const name = await options.name({
88+
prompt: "What's your name?",
89+
});
90+
91+
client.log(`Hello, ${name}! 👋`);
92+
},
93+
});
94+
```
95+
96+
### 3. Run it
97+
98+
```sh
99+
$ tsx src/cli.ts hello
100+
? What's your name? › Alice
101+
Hello, Alice! 👋
102+
```
103+
104+
## What makes it different?
105+
106+
### Interactive by default
107+
108+
Traditional CLIs fail hard when options are missing:
109+
110+
```sh
111+
$ mycli deploy
112+
Error: Missing required option --environment
113+
```
114+
115+
Gud CLI can guide users through required options:
116+
117+
```sh
118+
$ mycli deploy
119+
? Enter environment ›
120+
❯ dev
121+
staging
122+
prod
123+
```
124+
125+
*Add the [command menu
126+
plugin](https://github.com/ryangoree/gud-cli/tree/main/packages/cli-menu) to
127+
prompt for missing subcommands too.*
128+
129+
### File-based routing
130+
131+
Organize commands like you organize code:
132+
133+
```
134+
commands/
135+
├── hello.ts # mycli hello
136+
├── users/
137+
│ ├── list.ts # mycli users list
138+
│ ├── create.ts # mycli users create
139+
│ └── [id]/
140+
│ ├── show.ts # mycli users 123 show
141+
│ └── delete.ts # mycli users 123 delete
142+
└── deploy/
143+
└── [env].ts # mycli deploy prod
144+
```
145+
146+
### TypeScript-first
147+
148+
Get full intellisense and type checking:
149+
150+
```ts
151+
export default command({
152+
options: {
153+
port: { type: 'number', default: 3000 },
154+
watch: { type: 'boolean' }
155+
},
156+
handler: async ({ options }) => {
157+
const port = await options.port(); // TypeScript knows this is number
158+
const watch = await options.watch(); // TypeScript knows this is boolean | undefined
159+
}
160+
});
161+
```
162+
163+
## Examples
164+
165+
### Interactive deployment
166+
167+
```ts
168+
// commands/deploy.ts
169+
export default command({
170+
options: {
171+
environment: {
172+
type: 'string',
173+
choices: ['dev', 'staging', 'prod'],
174+
required: true
175+
},
176+
confirm: { type: 'boolean', default: false }
177+
},
178+
handler: async ({ options, client }) => {
179+
// Prompts "Enter environment" because required: true
180+
const env = await options.environment();
181+
182+
const confirmed = await options.confirm({
183+
prompt: `Deploy to ${env}?`,
184+
});
185+
186+
if (!confirmed) {
187+
client.log('Deployment cancelled');
188+
return;
189+
}
190+
191+
client.log(`🚀 Deploying to ${env}...`);
192+
}
193+
});
194+
```
195+
196+
### Parameterized commands
197+
198+
```ts
199+
// commands/users/[id]/delete.ts
200+
export default command({
201+
description: 'Delete a user by ID',
202+
options: {
203+
force: { type: 'boolean', description: 'Skip confirmation' }
204+
},
205+
handler: async ({ params, options, client }) => {
206+
const userId = params.id; // 123 from the command: users 123 delete
207+
const force = await options.force();
208+
209+
if (!force) {
210+
const confirmed = await client.confirm(
211+
`Really delete user ${userId}?`
212+
);
213+
if (!confirmed) return;
214+
}
215+
216+
// Delete user logic here
217+
client.log(`✅ User ${userId} deleted`);
218+
}
219+
});
220+
```
221+
222+
## Advanced Features
223+
224+
### Plugins
225+
226+
Extend functionality with plugins:
227+
228+
```ts
229+
import { run, help, logger } from '@gud/cli';
230+
231+
run({
232+
plugins: [
233+
help(), // Adds --help support
234+
logger(), // Logs command execution
235+
yourCustomPlugin()
236+
]
237+
});
238+
```
239+
240+
### Lifecycle Hooks
241+
242+
Hook into command execution:
243+
244+
```ts
245+
import { run } from '@gud/cli';
246+
247+
run({
248+
hooks: {
249+
beforeCommand: ({ command, data }) => {
250+
console.log(`Executing: ${command.commandName}`);
251+
},
252+
afterCommand: ({ command, data }) => {
253+
console.log(`Finished: ${command.commandName}`);
254+
}
255+
}
256+
});
257+
```
258+
259+
### Flexible Option Handling
260+
261+
```ts
262+
export default command({
263+
options: {
264+
username: {
265+
type: 'string',
266+
conflicts: ['email'],
267+
},
268+
email: {
269+
type: 'string',
270+
conflicts: ['username'],
271+
}
272+
},
273+
handler: async ({ options, client }) => {
274+
let account = await options.username();
275+
276+
if (!account) {
277+
account = await options.email({
278+
prompt: 'Enter your email',
279+
validate: (value) => {
280+
if (!value?.includes('@')) {
281+
return 'Must be a valid email';
282+
}
283+
return true;
284+
},
285+
});
286+
}
287+
288+
client.log(`Querying account: ${account}`);
289+
}
290+
});
291+
```
292+
293+
## Built for Scale
294+
295+
Gud CLI grows with your project:
296+
297+
- **Simple scripts**: Just `run()` and a single command file
298+
- **Complex tools**: Nested commands, plugins, custom validation
299+
- **Team CLIs**: Shared plugins, consistent patterns, full TypeScript support
300+
301+
Whether you're building a quick utility or the next great developer tool, Gud
302+
CLI gives you the structure and flexibility you need.
303+
304+
## Migration Guide
305+
306+
### From Commander.js
307+
308+
```ts
309+
// Before (Commander)
310+
program
311+
.command('hello')
312+
.option('-n, --name <name>', 'name to greet')
313+
.action((options) => {
314+
console.log(`Hello ${options.name || 'World'}`);
315+
});
316+
317+
// After (Gud CLI)
318+
export default command({
319+
options: {
320+
name: {
321+
alias: ['n'],
322+
type: 'string',
323+
description: 'Name to greet',
324+
default: 'World',
325+
},
326+
},
327+
handler: async ({ options }) => {
328+
const name = await options.name();
329+
console.log(`Hello ${name}`);
330+
},
331+
});
332+
```
333+
334+
### From yargs
335+
336+
```ts
337+
// Before (yargs)
338+
yargs(hideBin(process.argv))
339+
.command(
340+
'deploy <env>',
341+
'Deploy to environment',
342+
{
343+
env: { describe: 'Environment name', type: 'string' },
344+
},
345+
(argv) => {
346+
console.log(`Deploying to ${argv.env}`);
347+
},
348+
);
349+
350+
// After (Gud CLI) - file: commands/deploy/[env].ts
351+
export default command({
352+
description: 'Deploy to environment',
353+
handler: async ({ params }) => {
354+
console.log(`Deploying to ${params.env}`);
355+
}
356+
});
357+
```
358+
359+
## Community
360+
361+
- **Examples**: Check out [real-world examples](examples/)
362+
- **Contributing**: See our [Contributing Guide](.github/CONTRIBUTING.md)
363+
- **Issues**: Found a bug? [Let us
364+
know](https://github.com/ryangoree/gud-cli/issues)
365+
366+
## Reference
367+
368+
- [API Documentation](https://ryangoree.github.io/gud-cli/)
369+
- [Examples Repository](examples/)
370+
- [Plugin Development Guide](docs/plugins.md)

scripts/release.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22
set -e
33
cp README.md packages/cli/README.md
44
yarn build
5-
changeset publish
6-
rm packages/cli/README.md
5+
changeset publish

0 commit comments

Comments
 (0)