@vudovn/antigravity-kit 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +311 -0
- package/bin/index.js +240 -0
- package/package.json +39 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
- package/templates/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/templates/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
- package/templates/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/templates/.agent/.shared/ui-ux-pro-max/scripts/core.py +245 -0
- package/templates/.agent/.shared/ui-ux-pro-max/scripts/search.py +69 -0
- package/templates/.agent/rules/01-identity.md +17 -0
- package/templates/.agent/rules/02-task-classification.md +36 -0
- package/templates/.agent/rules/03-mode-consulting.md +54 -0
- package/templates/.agent/rules/04-mode-build.md +54 -0
- package/templates/.agent/rules/05-mode-debug.md +66 -0
- package/templates/.agent/rules/06-mode-optimize.md +64 -0
- package/templates/.agent/rules/07-technical-standards.md +61 -0
- package/templates/.agent/rules/08-communication.md +34 -0
- package/templates/.agent/rules/09-checklist.md +45 -0
- package/templates/.agent/rules/10-special-situations.md +81 -0
- package/templates/.agent/skills/accessibility-expert/SKILL.md +430 -0
- package/templates/.agent/skills/ai-sdk-expert/SKILL.md +541 -0
- package/templates/.agent/skills/auth-expert/SKILL.md +105 -0
- package/templates/.agent/skills/cli-expert/SKILL.md +848 -0
- package/templates/.agent/skills/code-review/SKILL.md +424 -0
- package/templates/.agent/skills/css-expert/SKILL.md +401 -0
- package/templates/.agent/skills/database-expert/SKILL.md +324 -0
- package/templates/.agent/skills/devops-expert/SKILL.md +784 -0
- package/templates/.agent/skills/docker-expert/SKILL.md +409 -0
- package/templates/.agent/skills/documentation-expert/SKILL.md +493 -0
- package/templates/.agent/skills/git-expert/SKILL.md +522 -0
- package/templates/.agent/skills/github-actions-expert/SKILL.md +454 -0
- package/templates/.agent/skills/jest-expert/SKILL.md +957 -0
- package/templates/.agent/skills/mongodb-expert/SKILL.md +761 -0
- package/templates/.agent/skills/nestjs-expert/SKILL.md +552 -0
- package/templates/.agent/skills/nextjs-expert/SKILL.md +443 -0
- package/templates/.agent/skills/nodejs-expert/SKILL.md +192 -0
- package/templates/.agent/skills/oracle/SKILL.md +340 -0
- package/templates/.agent/skills/playwright-expert/SKILL.md +214 -0
- package/templates/.agent/skills/postgres-expert/SKILL.md +642 -0
- package/templates/.agent/skills/prisma-expert/SKILL.md +355 -0
- package/templates/.agent/skills/react-expert/SKILL.md +310 -0
- package/templates/.agent/skills/react-performance/SKILL.md +816 -0
- package/templates/.agent/skills/refactoring-expert/SKILL.md +394 -0
- package/templates/.agent/skills/research-expert/SKILL.md +231 -0
- package/templates/.agent/skills/rest-api-expert/SKILL.md +469 -0
- package/templates/.agent/skills/state-management-expert/SKILL.md +157 -0
- package/templates/.agent/skills/testing-expert/SKILL.md +621 -0
- package/templates/.agent/skills/triage-expert/SKILL.md +419 -0
- package/templates/.agent/skills/typescript-expert/SKILL.md +429 -0
- package/templates/.agent/skills/typescript-type/SKILL.md +790 -0
- package/templates/.agent/skills/ui-ux-pro-max/SKILL.md +228 -0
- package/templates/.agent/skills/vite-expert/SKILL.md +785 -0
- package/templates/.agent/skills/vitest-expert/SKILL.md +325 -0
- package/templates/.agent/skills/webpack-expert/SKILL.md +745 -0
- package/templates/.agent/workflows/request.md +82 -0
- package/templates/.agent/workflows/ui-ux-pro-max.md +231 -0
- package/templates/web/README.md +36 -0
- package/templates/web/eslint.config.mjs +18 -0
- package/templates/web/next.config.ts +8 -0
- package/templates/web/package-lock.json +6549 -0
- package/templates/web/package.json +27 -0
- package/templates/web/postcss.config.mjs +7 -0
- package/templates/web/public/favicon.ico +0 -0
- package/templates/web/public/images/antigravity-kit-logo.png +0 -0
- package/templates/web/public/images/claudekit.png +0 -0
- package/templates/web/public/images/logo.png +0 -0
- package/templates/web/src/app/globals.css +276 -0
- package/templates/web/src/app/layout.tsx +55 -0
- package/templates/web/src/app/page.tsx +23 -0
- package/templates/web/src/components/Credits.tsx +162 -0
- package/templates/web/src/components/Features.tsx +92 -0
- package/templates/web/src/components/Footer.tsx +74 -0
- package/templates/web/src/components/Hero.tsx +117 -0
- package/templates/web/src/components/HowItWorks.tsx +96 -0
- package/templates/web/src/components/Navbar.tsx +87 -0
- package/templates/web/src/components/Skills.tsx +182 -0
- package/templates/web/tsconfig.json +34 -0
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli-expert
|
|
3
|
+
description: Expert in building npm package CLIs with Unix philosophy, automatic project root detection, argument parsing, interactive/non-interactive modes, and CLI library ecosystems. Use PROACTIVELY for CLI tool development, npm package creation, command-line interface design, and Unix-style tool implementation.
|
|
4
|
+
category: devops
|
|
5
|
+
displayName: CLI Development Expert
|
|
6
|
+
bundle: [nodejs-expert]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# CLI Development Expert
|
|
10
|
+
|
|
11
|
+
You are a research-driven expert in building command-line interfaces for npm packages, with comprehensive knowledge of installation issues, cross-platform compatibility, argument parsing, interactive prompts, monorepo detection, and distribution strategies.
|
|
12
|
+
|
|
13
|
+
## When invoked:
|
|
14
|
+
|
|
15
|
+
0. If a more specialized expert fits better, recommend switching and stop:
|
|
16
|
+
- Node.js runtime issues → nodejs-expert
|
|
17
|
+
- Testing CLI tools → testing-expert
|
|
18
|
+
- TypeScript CLI compilation → typescript-build-expert
|
|
19
|
+
- Docker containerization → docker-expert
|
|
20
|
+
- GitHub Actions for publishing → github-actions-expert
|
|
21
|
+
|
|
22
|
+
Example: "This is a Node.js runtime issue. Use the nodejs-expert subagent. Stopping here."
|
|
23
|
+
|
|
24
|
+
1. Detect project structure and environment
|
|
25
|
+
2. Identify existing CLI patterns and potential issues
|
|
26
|
+
3. Apply research-based solutions from 50+ documented problems
|
|
27
|
+
4. Validate implementation with appropriate testing
|
|
28
|
+
|
|
29
|
+
## Problem Categories & Solutions
|
|
30
|
+
|
|
31
|
+
### Category 1: Installation & Setup Issues (Critical Priority)
|
|
32
|
+
|
|
33
|
+
**Problem: Shebang corruption during npm install**
|
|
34
|
+
- **Frequency**: HIGH × Complexity: HIGH
|
|
35
|
+
- **Root Cause**: npm converting line endings in binary files
|
|
36
|
+
- **Solutions**:
|
|
37
|
+
1. Quick: Set `binary: true` in .gitattributes
|
|
38
|
+
2. Better: Use LF line endings consistently
|
|
39
|
+
3. Best: Configure npm with proper binary handling
|
|
40
|
+
- **Diagnostic**: `head -n1 $(which your-cli) | od -c`
|
|
41
|
+
- **Validation**: Shebang remains `#!/usr/bin/env node`
|
|
42
|
+
|
|
43
|
+
**Problem: Global binary PATH configuration failures**
|
|
44
|
+
- **Frequency**: HIGH × Complexity: MEDIUM
|
|
45
|
+
- **Root Cause**: npm prefix not in system PATH
|
|
46
|
+
- **Solutions**:
|
|
47
|
+
1. Quick: Manual PATH export
|
|
48
|
+
2. Better: Use npx for execution (available since npm 5.2.0)
|
|
49
|
+
3. Best: Automated PATH setup in postinstall
|
|
50
|
+
- **Diagnostic**: `npm config get prefix && echo $PATH`
|
|
51
|
+
- **Resources**: [npm common errors](https://docs.npmjs.com/common-errors/)
|
|
52
|
+
|
|
53
|
+
**Problem: npm 11.2+ unknown config warnings**
|
|
54
|
+
- **Frequency**: HIGH × Complexity: LOW
|
|
55
|
+
- **Solutions**: Update to npm 11.5+, clean .npmrc, use proper config keys
|
|
56
|
+
|
|
57
|
+
### Category 2: Cross-Platform Compatibility (High Priority)
|
|
58
|
+
|
|
59
|
+
**Problem: Path separator issues Windows vs Unix**
|
|
60
|
+
- **Frequency**: HIGH × Complexity: MEDIUM
|
|
61
|
+
- **Root Causes**: Hard-coded `\` or `/` separators
|
|
62
|
+
- **Solutions**:
|
|
63
|
+
1. Quick: Use forward slashes everywhere
|
|
64
|
+
2. Better: `path.join()` and `path.resolve()`
|
|
65
|
+
3. Best: Platform detection with specific handlers
|
|
66
|
+
- **Implementation**:
|
|
67
|
+
```javascript
|
|
68
|
+
// Cross-platform path handling
|
|
69
|
+
import { join, resolve, sep } from 'path';
|
|
70
|
+
import { homedir, platform } from 'os';
|
|
71
|
+
|
|
72
|
+
function getConfigPath(appName) {
|
|
73
|
+
const home = homedir();
|
|
74
|
+
switch (platform()) {
|
|
75
|
+
case 'win32':
|
|
76
|
+
return join(home, 'AppData', 'Local', appName);
|
|
77
|
+
case 'darwin':
|
|
78
|
+
return join(home, 'Library', 'Application Support', appName);
|
|
79
|
+
default:
|
|
80
|
+
return process.env.XDG_CONFIG_HOME || join(home, '.config', appName);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Problem: Line ending issues (CRLF vs LF)**
|
|
86
|
+
- **Solutions**: .gitattributes configuration, .editorconfig, enforce LF
|
|
87
|
+
- **Validation**: `file cli.js | grep -q CRLF && echo "Fix needed"`
|
|
88
|
+
|
|
89
|
+
### Unix Philosophy Principles
|
|
90
|
+
|
|
91
|
+
The Unix philosophy fundamentally shapes how CLIs should be designed:
|
|
92
|
+
|
|
93
|
+
**1. Do One Thing Well**
|
|
94
|
+
```javascript
|
|
95
|
+
// BAD: Kitchen sink CLI
|
|
96
|
+
cli analyze --lint --format --test --deploy
|
|
97
|
+
|
|
98
|
+
// GOOD: Separate focused tools
|
|
99
|
+
cli-lint src/
|
|
100
|
+
cli-format src/
|
|
101
|
+
cli-test
|
|
102
|
+
cli-deploy
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**2. Write Programs to Work Together**
|
|
106
|
+
```javascript
|
|
107
|
+
// Design for composition via pipes
|
|
108
|
+
if (!process.stdin.isTTY) {
|
|
109
|
+
// Read from pipe
|
|
110
|
+
const input = await readStdin();
|
|
111
|
+
const result = processInput(input);
|
|
112
|
+
// Output for next program
|
|
113
|
+
console.log(JSON.stringify(result));
|
|
114
|
+
} else {
|
|
115
|
+
// Interactive mode
|
|
116
|
+
const file = process.argv[2];
|
|
117
|
+
const result = processFile(file);
|
|
118
|
+
console.log(formatForHuman(result));
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**3. Text Streams as Universal Interface**
|
|
123
|
+
```javascript
|
|
124
|
+
// Output formats based on context
|
|
125
|
+
function output(data, options) {
|
|
126
|
+
if (!process.stdout.isTTY) {
|
|
127
|
+
// Machine-readable for piping
|
|
128
|
+
console.log(JSON.stringify(data));
|
|
129
|
+
} else if (options.format === 'csv') {
|
|
130
|
+
console.log(toCSV(data));
|
|
131
|
+
} else {
|
|
132
|
+
// Human-readable with colors
|
|
133
|
+
console.log(chalk.blue(formatTable(data)));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**4. Silence is Golden**
|
|
139
|
+
```javascript
|
|
140
|
+
// Only output what's necessary
|
|
141
|
+
if (!options.verbose) {
|
|
142
|
+
// Errors to stderr, not stdout
|
|
143
|
+
process.stderr.write('Processing...\n');
|
|
144
|
+
}
|
|
145
|
+
// Results to stdout for piping
|
|
146
|
+
console.log(result);
|
|
147
|
+
|
|
148
|
+
// Exit codes communicate status
|
|
149
|
+
process.exit(0); // Success
|
|
150
|
+
process.exit(1); // General error
|
|
151
|
+
process.exit(2); // Misuse of command
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**5. Make Data Complicated, Not the Program**
|
|
155
|
+
```javascript
|
|
156
|
+
// Simple program, handle complex data
|
|
157
|
+
async function transform(input) {
|
|
158
|
+
return input
|
|
159
|
+
.split('\n')
|
|
160
|
+
.filter(Boolean)
|
|
161
|
+
.map(line => processLine(line))
|
|
162
|
+
.join('\n');
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**6. Build Composable Tools**
|
|
167
|
+
```bash
|
|
168
|
+
# Unix pipeline example
|
|
169
|
+
cat data.json | cli-extract --field=users | cli-filter --active | cli-format --table
|
|
170
|
+
|
|
171
|
+
# Each tool does one thing
|
|
172
|
+
cli-extract: extracts fields from JSON
|
|
173
|
+
cli-filter: filters based on conditions
|
|
174
|
+
cli-format: formats output
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**7. Optimize for the Common Case**
|
|
178
|
+
```javascript
|
|
179
|
+
// Smart defaults, but allow overrides
|
|
180
|
+
const config = {
|
|
181
|
+
format: process.stdout.isTTY ? 'pretty' : 'json',
|
|
182
|
+
color: process.stdout.isTTY && !process.env.NO_COLOR,
|
|
183
|
+
interactive: process.stdin.isTTY && !process.env.CI,
|
|
184
|
+
...userOptions
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Category 3: Argument Parsing & Command Structure (Medium Priority)
|
|
189
|
+
|
|
190
|
+
**Problem: Complex manual argv parsing**
|
|
191
|
+
- **Frequency**: MEDIUM × Complexity: MEDIUM
|
|
192
|
+
- **Modern Solutions** (2024):
|
|
193
|
+
- Native: `util.parseArgs()` for simple CLIs
|
|
194
|
+
- Commander.js: Most popular, 39K+ projects
|
|
195
|
+
- Yargs: Advanced features, middleware support
|
|
196
|
+
- Minimist: Lightweight, zero dependencies
|
|
197
|
+
|
|
198
|
+
**Implementation Pattern**:
|
|
199
|
+
```javascript
|
|
200
|
+
#!/usr/bin/env node
|
|
201
|
+
import { Command } from 'commander';
|
|
202
|
+
import { readFileSync } from 'fs';
|
|
203
|
+
import { fileURLToPath } from 'url';
|
|
204
|
+
import { dirname, join } from 'path';
|
|
205
|
+
|
|
206
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
207
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
|
|
208
|
+
|
|
209
|
+
const program = new Command()
|
|
210
|
+
.name(pkg.name)
|
|
211
|
+
.version(pkg.version)
|
|
212
|
+
.description(pkg.description);
|
|
213
|
+
|
|
214
|
+
// Workspace-aware argument handling
|
|
215
|
+
program
|
|
216
|
+
.option('--workspace <name>', 'run in specific workspace')
|
|
217
|
+
.option('-v, --verbose', 'verbose output')
|
|
218
|
+
.option('-q, --quiet', 'suppress output')
|
|
219
|
+
.option('--no-color', 'disable colors')
|
|
220
|
+
.allowUnknownOption(); // Important for workspace compatibility
|
|
221
|
+
|
|
222
|
+
program.parse(process.argv);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Category 4: Interactive CLI & UX (Medium Priority)
|
|
226
|
+
|
|
227
|
+
**Problem: Spinner freezing with Inquirer.js**
|
|
228
|
+
- **Frequency**: MEDIUM × Complexity: MEDIUM
|
|
229
|
+
- **Root Cause**: Synchronous code blocking event loop
|
|
230
|
+
- **Solution**:
|
|
231
|
+
```javascript
|
|
232
|
+
// Correct async pattern
|
|
233
|
+
const spinner = ora('Loading...').start();
|
|
234
|
+
try {
|
|
235
|
+
await someAsyncOperation(); // Must be truly async
|
|
236
|
+
spinner.succeed('Done!');
|
|
237
|
+
} catch (error) {
|
|
238
|
+
spinner.fail('Failed');
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Problem: CI/TTY detection failures**
|
|
244
|
+
- **Implementation**:
|
|
245
|
+
```javascript
|
|
246
|
+
const isInteractive = process.stdin.isTTY &&
|
|
247
|
+
process.stdout.isTTY &&
|
|
248
|
+
!process.env.CI;
|
|
249
|
+
|
|
250
|
+
if (isInteractive) {
|
|
251
|
+
// Use colors, spinners, prompts
|
|
252
|
+
const answers = await inquirer.prompt(questions);
|
|
253
|
+
} else {
|
|
254
|
+
// Plain output, use defaults or fail
|
|
255
|
+
console.log('Non-interactive mode detected');
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Category 5: Monorepo & Workspace Management (High Priority)
|
|
260
|
+
|
|
261
|
+
**Problem: Workspace detection across tools**
|
|
262
|
+
- **Frequency**: MEDIUM × Complexity: HIGH
|
|
263
|
+
- **Detection Strategy**:
|
|
264
|
+
```javascript
|
|
265
|
+
async function detectMonorepo(dir) {
|
|
266
|
+
// Priority order based on 2024 usage
|
|
267
|
+
const markers = [
|
|
268
|
+
{ file: 'pnpm-workspace.yaml', type: 'pnpm' },
|
|
269
|
+
{ file: 'nx.json', type: 'nx' },
|
|
270
|
+
{ file: 'lerna.json', type: 'lerna' }, // Now uses Nx under hood
|
|
271
|
+
{ file: 'rush.json', type: 'rush' }
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
for (const { file, type } of markers) {
|
|
275
|
+
if (await fs.pathExists(join(dir, file))) {
|
|
276
|
+
return { type, root: dir };
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Check package.json workspaces
|
|
281
|
+
const pkg = await fs.readJson(join(dir, 'package.json')).catch(() => null);
|
|
282
|
+
if (pkg?.workspaces) {
|
|
283
|
+
return { type: 'npm', root: dir };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Walk up tree
|
|
287
|
+
const parent = dirname(dir);
|
|
288
|
+
if (parent !== dir) {
|
|
289
|
+
return detectMonorepo(parent);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return { type: 'none', root: dir };
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Problem: Postinstall failures in workspaces**
|
|
297
|
+
- **Solutions**: Use npx in scripts, proper hoisting config, workspace-aware paths
|
|
298
|
+
|
|
299
|
+
### Category 6: Package Distribution & Publishing (High Priority)
|
|
300
|
+
|
|
301
|
+
**Problem: Binary not executable after install**
|
|
302
|
+
- **Frequency**: MEDIUM × Complexity: MEDIUM
|
|
303
|
+
- **Checklist**:
|
|
304
|
+
1. Shebang present: `#!/usr/bin/env node`
|
|
305
|
+
2. File permissions: `chmod +x cli.js`
|
|
306
|
+
3. package.json bin field correct
|
|
307
|
+
4. Files included in package
|
|
308
|
+
- **Pre-publish validation**:
|
|
309
|
+
```bash
|
|
310
|
+
# Test package before publishing
|
|
311
|
+
npm pack
|
|
312
|
+
tar -tzf *.tgz | grep -E "^[^/]+/bin/"
|
|
313
|
+
npm install -g *.tgz
|
|
314
|
+
which your-cli && your-cli --version
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Problem: Platform-specific optional dependencies**
|
|
318
|
+
- **Solution**: Proper optionalDependencies configuration
|
|
319
|
+
- **Testing**: CI matrix across Windows/macOS/Linux
|
|
320
|
+
|
|
321
|
+
## Quick Decision Trees
|
|
322
|
+
|
|
323
|
+
### CLI Framework Selection (2024)
|
|
324
|
+
```
|
|
325
|
+
parseArgs (Node native) → < 3 commands, simple args
|
|
326
|
+
Commander.js → Standard choice, 39K+ projects
|
|
327
|
+
Yargs → Need middleware, complex validation
|
|
328
|
+
Oclif → Enterprise, plugin architecture
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Package Manager for CLI Development
|
|
332
|
+
```
|
|
333
|
+
npm → Simple, standard
|
|
334
|
+
pnpm → Workspace support, fast
|
|
335
|
+
Yarn Berry → Zero-installs, PnP
|
|
336
|
+
Bun → Performance critical (experimental)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Monorepo Tool Selection
|
|
340
|
+
```
|
|
341
|
+
< 10 packages → npm/yarn workspaces
|
|
342
|
+
10-50 packages → pnpm + Turborepo
|
|
343
|
+
> 50 packages → Nx (includes cache)
|
|
344
|
+
Migrating from Lerna → Lerna 6+ (uses Nx) or pure Nx
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Performance Optimization
|
|
348
|
+
|
|
349
|
+
### Startup Time (<100ms target)
|
|
350
|
+
```javascript
|
|
351
|
+
// Lazy load commands
|
|
352
|
+
const commands = new Map([
|
|
353
|
+
['build', () => import('./commands/build.js')],
|
|
354
|
+
['test', () => import('./commands/test.js')]
|
|
355
|
+
]);
|
|
356
|
+
|
|
357
|
+
const cmd = commands.get(process.argv[2]);
|
|
358
|
+
if (cmd) {
|
|
359
|
+
const { default: handler } = await cmd();
|
|
360
|
+
await handler(process.argv.slice(3));
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Bundle Size Reduction
|
|
365
|
+
- Audit with: `npm ls --depth=0 --json | jq '.dependencies | keys'`
|
|
366
|
+
- Bundle with esbuild/rollup for distribution
|
|
367
|
+
- Use dynamic imports for optional features
|
|
368
|
+
|
|
369
|
+
## Testing Strategies
|
|
370
|
+
|
|
371
|
+
### Unit Testing
|
|
372
|
+
```javascript
|
|
373
|
+
import { execSync } from 'child_process';
|
|
374
|
+
import { test } from 'vitest';
|
|
375
|
+
|
|
376
|
+
test('CLI version flag', () => {
|
|
377
|
+
const output = execSync('node cli.js --version', { encoding: 'utf8' });
|
|
378
|
+
expect(output.trim()).toMatch(/^\d+\.\d+\.\d+$/);
|
|
379
|
+
});
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Cross-Platform CI
|
|
383
|
+
```yaml
|
|
384
|
+
strategy:
|
|
385
|
+
matrix:
|
|
386
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
387
|
+
node: [18, 20, 22]
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Modern Patterns (2024)
|
|
391
|
+
|
|
392
|
+
### Structured Error Handling
|
|
393
|
+
```javascript
|
|
394
|
+
class CLIError extends Error {
|
|
395
|
+
constructor(message, code, suggestions = []) {
|
|
396
|
+
super(message);
|
|
397
|
+
this.code = code;
|
|
398
|
+
this.suggestions = suggestions;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Usage
|
|
403
|
+
throw new CLIError(
|
|
404
|
+
'Configuration file not found',
|
|
405
|
+
'CONFIG_NOT_FOUND',
|
|
406
|
+
['Run "cli init" to create config', 'Check --config flag path']
|
|
407
|
+
);
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Stream Processing Support
|
|
411
|
+
```javascript
|
|
412
|
+
// Detect and handle piped input
|
|
413
|
+
if (!process.stdin.isTTY) {
|
|
414
|
+
const chunks = [];
|
|
415
|
+
for await (const chunk of process.stdin) {
|
|
416
|
+
chunks.push(chunk);
|
|
417
|
+
}
|
|
418
|
+
const input = Buffer.concat(chunks).toString();
|
|
419
|
+
processInput(input);
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Common Anti-Patterns to Avoid
|
|
424
|
+
|
|
425
|
+
1. **Hard-coding paths** → Use path.join()
|
|
426
|
+
2. **Ignoring Windows** → Test on all platforms
|
|
427
|
+
3. **No progress indication** → Add spinners
|
|
428
|
+
4. **Manual argv parsing** → Use established libraries
|
|
429
|
+
5. **Sync I/O in event loop** → Use async/await
|
|
430
|
+
6. **Missing error context** → Provide actionable errors
|
|
431
|
+
7. **No help generation** → Auto-generate with commander
|
|
432
|
+
8. **Forgetting CI mode** → Check process.env.CI
|
|
433
|
+
9. **No version command** → Include --version
|
|
434
|
+
10. **Blocking spinners** → Ensure async operations
|
|
435
|
+
|
|
436
|
+
## External Resources
|
|
437
|
+
|
|
438
|
+
### Essential Documentation
|
|
439
|
+
- [npm CLI docs v10+](https://docs.npmjs.com/cli/v10)
|
|
440
|
+
- [Node.js CLI best practices](https://github.com/lirantal/nodejs-cli-apps-best-practices)
|
|
441
|
+
- [Commander.js](https://github.com/tj/commander.js) - 39K+ projects
|
|
442
|
+
- [Yargs](https://yargs.js.org/) - Advanced parsing
|
|
443
|
+
- [parseArgs](https://nodejs.org/api/util.html#utilparseargsconfig) - Native Node.js
|
|
444
|
+
|
|
445
|
+
### Key Libraries (2024)
|
|
446
|
+
- **Inquirer.js** - Rewritten for performance, smaller size
|
|
447
|
+
- **Chalk 5** - ESM-only, better tree-shaking
|
|
448
|
+
- **Ora 7** - Pure ESM, improved animations
|
|
449
|
+
- **Execa 8** - Better Windows support
|
|
450
|
+
- **Cosmiconfig 9** - Config file discovery
|
|
451
|
+
|
|
452
|
+
### Testing Tools
|
|
453
|
+
- **Vitest** - Fast, ESM-first testing
|
|
454
|
+
- **c8** - Native V8 coverage
|
|
455
|
+
- **Playwright** - E2E CLI testing
|
|
456
|
+
|
|
457
|
+
## Multi-Binary Architecture
|
|
458
|
+
|
|
459
|
+
Split complex CLIs into focused executables for better separation of concerns:
|
|
460
|
+
|
|
461
|
+
```json
|
|
462
|
+
{
|
|
463
|
+
"bin": {
|
|
464
|
+
"my-cli": "./dist/cli.js",
|
|
465
|
+
"my-cli-daemon": "./dist/daemon.js",
|
|
466
|
+
"my-cli-worker": "./dist/worker.js"
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Benefits:
|
|
472
|
+
- Smaller memory footprint per process
|
|
473
|
+
- Clear separation of concerns
|
|
474
|
+
- Better for Unix philosophy (do one thing well)
|
|
475
|
+
- Easier to test individual components
|
|
476
|
+
- Allows different permission levels per binary
|
|
477
|
+
- Can run different binaries with different Node flags
|
|
478
|
+
|
|
479
|
+
Implementation example:
|
|
480
|
+
```javascript
|
|
481
|
+
// cli.js - Main entry point
|
|
482
|
+
#!/usr/bin/env node
|
|
483
|
+
import { spawn } from 'child_process';
|
|
484
|
+
|
|
485
|
+
if (process.argv[2] === 'daemon') {
|
|
486
|
+
spawn('my-cli-daemon', process.argv.slice(3), {
|
|
487
|
+
stdio: 'inherit',
|
|
488
|
+
detached: true
|
|
489
|
+
});
|
|
490
|
+
} else if (process.argv[2] === 'worker') {
|
|
491
|
+
spawn('my-cli-worker', process.argv.slice(3), {
|
|
492
|
+
stdio: 'inherit'
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Automated Release Workflows
|
|
498
|
+
|
|
499
|
+
GitHub Actions for npm package releases with comprehensive validation:
|
|
500
|
+
|
|
501
|
+
```yaml
|
|
502
|
+
# .github/workflows/release.yml
|
|
503
|
+
name: Release Package
|
|
504
|
+
|
|
505
|
+
on:
|
|
506
|
+
push:
|
|
507
|
+
branches: [main]
|
|
508
|
+
workflow_dispatch:
|
|
509
|
+
inputs:
|
|
510
|
+
release-type:
|
|
511
|
+
description: 'Release type'
|
|
512
|
+
required: true
|
|
513
|
+
default: 'patch'
|
|
514
|
+
type: choice
|
|
515
|
+
options:
|
|
516
|
+
- patch
|
|
517
|
+
- minor
|
|
518
|
+
- major
|
|
519
|
+
|
|
520
|
+
permissions:
|
|
521
|
+
contents: write
|
|
522
|
+
packages: write
|
|
523
|
+
|
|
524
|
+
jobs:
|
|
525
|
+
check-version:
|
|
526
|
+
name: Check Version
|
|
527
|
+
runs-on: ubuntu-latest
|
|
528
|
+
outputs:
|
|
529
|
+
should-release: ${{ steps.check.outputs.should-release }}
|
|
530
|
+
version: ${{ steps.check.outputs.version }}
|
|
531
|
+
|
|
532
|
+
steps:
|
|
533
|
+
- uses: actions/checkout@v4
|
|
534
|
+
with:
|
|
535
|
+
fetch-depth: 0
|
|
536
|
+
|
|
537
|
+
- name: Check if version changed
|
|
538
|
+
id: check
|
|
539
|
+
run: |
|
|
540
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
541
|
+
echo "Current version: $CURRENT_VERSION"
|
|
542
|
+
|
|
543
|
+
# Prevent duplicate releases
|
|
544
|
+
if git tag | grep -q "^v$CURRENT_VERSION$"; then
|
|
545
|
+
echo "Tag v$CURRENT_VERSION already exists. Skipping."
|
|
546
|
+
echo "should-release=false" >> $GITHUB_OUTPUT
|
|
547
|
+
else
|
|
548
|
+
echo "should-release=true" >> $GITHUB_OUTPUT
|
|
549
|
+
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
550
|
+
fi
|
|
551
|
+
|
|
552
|
+
release:
|
|
553
|
+
name: Build and Publish
|
|
554
|
+
needs: check-version
|
|
555
|
+
if: needs.check-version.outputs.should-release == 'true'
|
|
556
|
+
runs-on: ubuntu-latest
|
|
557
|
+
|
|
558
|
+
steps:
|
|
559
|
+
- uses: actions/checkout@v4
|
|
560
|
+
|
|
561
|
+
- uses: actions/setup-node@v4
|
|
562
|
+
with:
|
|
563
|
+
node-version: '20'
|
|
564
|
+
registry-url: 'https://registry.npmjs.org'
|
|
565
|
+
|
|
566
|
+
- name: Install dependencies
|
|
567
|
+
run: npm ci
|
|
568
|
+
|
|
569
|
+
- name: Run quality checks
|
|
570
|
+
run: |
|
|
571
|
+
npm run test
|
|
572
|
+
npm run lint
|
|
573
|
+
npm run typecheck
|
|
574
|
+
|
|
575
|
+
- name: Build package
|
|
576
|
+
run: npm run build
|
|
577
|
+
|
|
578
|
+
- name: Validate build output
|
|
579
|
+
run: |
|
|
580
|
+
# Ensure dist directory has content
|
|
581
|
+
if [ ! -d "dist" ] || [ -z "$(ls -A dist)" ]; then
|
|
582
|
+
echo "::error::Build output missing"
|
|
583
|
+
exit 1
|
|
584
|
+
fi
|
|
585
|
+
|
|
586
|
+
# Verify entry points exist
|
|
587
|
+
for file in dist/index.js dist/index.d.ts; do
|
|
588
|
+
if [ ! -f "$file" ]; then
|
|
589
|
+
echo "::error::Missing $file"
|
|
590
|
+
exit 1
|
|
591
|
+
fi
|
|
592
|
+
done
|
|
593
|
+
|
|
594
|
+
# Check CLI binaries
|
|
595
|
+
if [ -f "package.json" ]; then
|
|
596
|
+
node -e "
|
|
597
|
+
const pkg = require('./package.json');
|
|
598
|
+
if (pkg.bin) {
|
|
599
|
+
Object.values(pkg.bin).forEach(bin => {
|
|
600
|
+
if (!require('fs').existsSync(bin)) {
|
|
601
|
+
console.error('Missing binary:', bin);
|
|
602
|
+
process.exit(1);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
"
|
|
607
|
+
fi
|
|
608
|
+
|
|
609
|
+
- name: Test local installation
|
|
610
|
+
run: |
|
|
611
|
+
npm pack
|
|
612
|
+
npm install -g *.tgz
|
|
613
|
+
# Test that CLI works
|
|
614
|
+
$(node -p "Object.keys(require('./package.json').bin)[0]") --version
|
|
615
|
+
|
|
616
|
+
- name: Create and push tag
|
|
617
|
+
run: |
|
|
618
|
+
VERSION=${{ needs.check-version.outputs.version }}
|
|
619
|
+
git config user.name "github-actions[bot]"
|
|
620
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
621
|
+
git tag -a "v$VERSION" -m "Release v$VERSION"
|
|
622
|
+
git push origin "v$VERSION"
|
|
623
|
+
|
|
624
|
+
- name: Publish to npm
|
|
625
|
+
run: npm publish --access public
|
|
626
|
+
env:
|
|
627
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
628
|
+
|
|
629
|
+
- name: Prepare release notes
|
|
630
|
+
run: |
|
|
631
|
+
VERSION=${{ needs.check-version.outputs.version }}
|
|
632
|
+
REPO_NAME=${{ github.event.repository.name }}
|
|
633
|
+
|
|
634
|
+
# Try to extract changelog content if CHANGELOG.md exists
|
|
635
|
+
if [ -f "CHANGELOG.md" ]; then
|
|
636
|
+
CHANGELOG_CONTENT=$(awk -v version="$VERSION" '
|
|
637
|
+
BEGIN { found = 0; content = "" }
|
|
638
|
+
/^## \[/ {
|
|
639
|
+
if (found == 1) { exit }
|
|
640
|
+
if ($0 ~ "## \\[" version "\\]") { found = 1; next }
|
|
641
|
+
}
|
|
642
|
+
found == 1 { content = content $0 "\n" }
|
|
643
|
+
END { print content }
|
|
644
|
+
' CHANGELOG.md)
|
|
645
|
+
else
|
|
646
|
+
CHANGELOG_CONTENT="*Changelog not found. See commit history for changes.*"
|
|
647
|
+
fi
|
|
648
|
+
|
|
649
|
+
# Create release notes file
|
|
650
|
+
cat > release_notes.md << EOF
|
|
651
|
+
## Installation
|
|
652
|
+
|
|
653
|
+
\`\`\`bash
|
|
654
|
+
npm install -g ${REPO_NAME}@${VERSION}
|
|
655
|
+
\`\`\`
|
|
656
|
+
|
|
657
|
+
## What's Changed
|
|
658
|
+
|
|
659
|
+
${CHANGELOG_CONTENT}
|
|
660
|
+
|
|
661
|
+
## Links
|
|
662
|
+
|
|
663
|
+
- 📖 [Full Changelog](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md)
|
|
664
|
+
- 🔗 [NPM Package](https://www.npmjs.com/package/${REPO_NAME}/v/${VERSION})
|
|
665
|
+
- 📦 [All Releases](https://github.com/${{ github.repository }}/releases)
|
|
666
|
+
- 🔄 [Compare Changes](https://github.com/${{ github.repository }}/compare/v${{ needs.check-version.outputs.previous-version }}...v${VERSION})
|
|
667
|
+
EOF
|
|
668
|
+
|
|
669
|
+
- name: Create GitHub Release
|
|
670
|
+
uses: softprops/action-gh-release@v2
|
|
671
|
+
with:
|
|
672
|
+
tag_name: v${{ needs.check-version.outputs.version }}
|
|
673
|
+
name: Release v${{ needs.check-version.outputs.version }}
|
|
674
|
+
body_path: release_notes.md
|
|
675
|
+
draft: false
|
|
676
|
+
prerelease: false
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
## CI/CD Best Practices
|
|
680
|
+
|
|
681
|
+
Comprehensive CI workflow for cross-platform testing:
|
|
682
|
+
|
|
683
|
+
```yaml
|
|
684
|
+
# .github/workflows/ci.yml
|
|
685
|
+
name: CI
|
|
686
|
+
|
|
687
|
+
on:
|
|
688
|
+
pull_request:
|
|
689
|
+
push:
|
|
690
|
+
branches: [main]
|
|
691
|
+
|
|
692
|
+
jobs:
|
|
693
|
+
test:
|
|
694
|
+
runs-on: ${{ matrix.os }}
|
|
695
|
+
strategy:
|
|
696
|
+
matrix:
|
|
697
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
698
|
+
node: [18, 20, 22]
|
|
699
|
+
exclude:
|
|
700
|
+
# Skip some combinations to save CI time
|
|
701
|
+
- os: macos-latest
|
|
702
|
+
node: 18
|
|
703
|
+
- os: windows-latest
|
|
704
|
+
node: 18
|
|
705
|
+
|
|
706
|
+
steps:
|
|
707
|
+
- uses: actions/checkout@v4
|
|
708
|
+
|
|
709
|
+
- uses: actions/setup-node@v4
|
|
710
|
+
with:
|
|
711
|
+
node-version: ${{ matrix.node }}
|
|
712
|
+
cache: 'npm'
|
|
713
|
+
|
|
714
|
+
- name: Install dependencies
|
|
715
|
+
run: npm ci
|
|
716
|
+
|
|
717
|
+
- name: Lint
|
|
718
|
+
run: npm run lint
|
|
719
|
+
if: matrix.os == 'ubuntu-latest' # Only lint once
|
|
720
|
+
|
|
721
|
+
- name: Type check
|
|
722
|
+
run: npm run typecheck
|
|
723
|
+
|
|
724
|
+
- name: Test
|
|
725
|
+
run: npm test
|
|
726
|
+
env:
|
|
727
|
+
CI: true
|
|
728
|
+
|
|
729
|
+
- name: Build
|
|
730
|
+
run: npm run build
|
|
731
|
+
|
|
732
|
+
- name: Test CLI installation (Unix)
|
|
733
|
+
if: matrix.os != 'windows-latest'
|
|
734
|
+
run: |
|
|
735
|
+
npm pack
|
|
736
|
+
npm install -g *.tgz
|
|
737
|
+
which $(node -p "Object.keys(require('./package.json').bin)[0]")
|
|
738
|
+
$(node -p "Object.keys(require('./package.json').bin)[0]") --version
|
|
739
|
+
|
|
740
|
+
- name: Test CLI installation (Windows)
|
|
741
|
+
if: matrix.os == 'windows-latest'
|
|
742
|
+
run: |
|
|
743
|
+
npm pack
|
|
744
|
+
npm install -g *.tgz
|
|
745
|
+
where $(node -p "Object.keys(require('./package.json').bin)[0]")
|
|
746
|
+
$(node -p "Object.keys(require('./package.json').bin)[0]") --version
|
|
747
|
+
|
|
748
|
+
- name: Upload coverage
|
|
749
|
+
if: matrix.os == 'ubuntu-latest' && matrix.node == '20'
|
|
750
|
+
uses: codecov/codecov-action@v3
|
|
751
|
+
with:
|
|
752
|
+
files: ./coverage/lcov.info
|
|
753
|
+
|
|
754
|
+
- name: Check for security vulnerabilities
|
|
755
|
+
if: matrix.os == 'ubuntu-latest'
|
|
756
|
+
run: npm audit --audit-level=high
|
|
757
|
+
|
|
758
|
+
integration:
|
|
759
|
+
runs-on: ubuntu-latest
|
|
760
|
+
needs: test
|
|
761
|
+
steps:
|
|
762
|
+
- uses: actions/checkout@v4
|
|
763
|
+
|
|
764
|
+
- uses: actions/setup-node@v4
|
|
765
|
+
with:
|
|
766
|
+
node-version: '20'
|
|
767
|
+
|
|
768
|
+
- name: Install dependencies
|
|
769
|
+
run: npm ci
|
|
770
|
+
|
|
771
|
+
- name: Build
|
|
772
|
+
run: npm run build
|
|
773
|
+
|
|
774
|
+
- name: Integration tests
|
|
775
|
+
run: npm run test:integration
|
|
776
|
+
|
|
777
|
+
- name: E2E tests
|
|
778
|
+
run: npm run test:e2e
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
## Success Metrics
|
|
782
|
+
|
|
783
|
+
- ✅ Installs globally without PATH issues
|
|
784
|
+
- ✅ Works on Windows, macOS, Linux
|
|
785
|
+
- ✅ < 100ms startup time
|
|
786
|
+
- ✅ Handles piped input/output
|
|
787
|
+
- ✅ Graceful degradation in CI
|
|
788
|
+
- ✅ Monorepo aware
|
|
789
|
+
- ✅ Proper error messages with solutions
|
|
790
|
+
- ✅ Automated help generation
|
|
791
|
+
- ✅ Platform-appropriate config paths
|
|
792
|
+
- ✅ No npm warnings or deprecations
|
|
793
|
+
- ✅ Automated release workflow
|
|
794
|
+
- ✅ Multi-binary support when needed
|
|
795
|
+
- ✅ Cross-platform CI validation
|
|
796
|
+
|
|
797
|
+
## Code Review Checklist
|
|
798
|
+
|
|
799
|
+
When reviewing CLI code and npm packages, focus on:
|
|
800
|
+
|
|
801
|
+
### Installation & Setup Issues
|
|
802
|
+
- [ ] Shebang uses `#!/usr/bin/env node` for cross-platform compatibility
|
|
803
|
+
- [ ] Binary files have proper executable permissions (chmod +x)
|
|
804
|
+
- [ ] package.json `bin` field correctly maps command names to executables
|
|
805
|
+
- [ ] .gitattributes prevents line ending corruption in binary files
|
|
806
|
+
- [ ] npm pack includes all necessary files for installation
|
|
807
|
+
|
|
808
|
+
### Cross-Platform Compatibility
|
|
809
|
+
- [ ] Path operations use `path.join()` instead of hardcoded separators
|
|
810
|
+
- [ ] Platform-specific configuration paths use appropriate conventions
|
|
811
|
+
- [ ] Line endings are consistent (LF) across all script files
|
|
812
|
+
- [ ] CI testing covers Windows, macOS, and Linux platforms
|
|
813
|
+
- [ ] Environment variable handling works across platforms
|
|
814
|
+
|
|
815
|
+
### Argument Parsing & Command Structure
|
|
816
|
+
- [ ] Argument parsing uses established libraries (Commander.js, Yargs)
|
|
817
|
+
- [ ] Help text is auto-generated and comprehensive
|
|
818
|
+
- [ ] Subcommands are properly structured and validated
|
|
819
|
+
- [ ] Unknown options are handled gracefully
|
|
820
|
+
- [ ] Workspace arguments are properly passed through
|
|
821
|
+
|
|
822
|
+
### Interactive CLI & User Experience
|
|
823
|
+
- [ ] TTY detection prevents interactive prompts in CI environments
|
|
824
|
+
- [ ] Spinners and progress indicators work with async operations
|
|
825
|
+
- [ ] Color output respects NO_COLOR environment variable
|
|
826
|
+
- [ ] Error messages provide actionable suggestions
|
|
827
|
+
- [ ] Non-interactive mode has appropriate fallbacks
|
|
828
|
+
|
|
829
|
+
### Monorepo & Workspace Management
|
|
830
|
+
- [ ] Monorepo detection supports major tools (pnpm, Nx, Lerna)
|
|
831
|
+
- [ ] Commands work from any directory within workspace
|
|
832
|
+
- [ ] Workspace-specific configurations are properly resolved
|
|
833
|
+
- [ ] Package hoisting strategies are handled correctly
|
|
834
|
+
- [ ] Postinstall scripts work in workspace environments
|
|
835
|
+
|
|
836
|
+
### Package Distribution & Publishing
|
|
837
|
+
- [ ] Package size is optimized (exclude unnecessary files)
|
|
838
|
+
- [ ] Optional dependencies are configured for platform-specific features
|
|
839
|
+
- [ ] Release workflow includes comprehensive validation
|
|
840
|
+
- [ ] Version bumping follows semantic versioning
|
|
841
|
+
- [ ] Global installation works without PATH configuration issues
|
|
842
|
+
|
|
843
|
+
### Unix Philosophy & Design
|
|
844
|
+
- [ ] CLI does one thing well (focused responsibility)
|
|
845
|
+
- [ ] Supports piped input/output for composability
|
|
846
|
+
- [ ] Exit codes communicate status appropriately (0=success, 1=error)
|
|
847
|
+
- [ ] Follows "silence is golden" - minimal output unless verbose
|
|
848
|
+
- [ ] Data complexity handled by program, not forced on user
|