@girardmedia/bootspring 3.3.2 → 3.4.0

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.
Files changed (171) hide show
  1. package/assets/agents/accessibility-auditor.md +39 -0
  2. package/assets/agents/api-designer.md +40 -0
  3. package/assets/agents/auth-implementer.md +64 -0
  4. package/assets/agents/bug-hunter.md +42 -0
  5. package/assets/agents/bundle-analyzer.md +40 -0
  6. package/assets/agents/cache-optimizer.md +55 -0
  7. package/assets/agents/changelog-writer.md +55 -0
  8. package/assets/agents/ci-cd-builder.md +40 -0
  9. package/assets/agents/code-explainer.md +39 -0
  10. package/assets/agents/code-reviewer.md +39 -0
  11. package/assets/agents/cost-optimizer.md +57 -0
  12. package/assets/agents/cron-scheduler.md +51 -0
  13. package/assets/agents/data-seeder.md +56 -0
  14. package/assets/agents/database-architect.md +40 -0
  15. package/assets/agents/dependency-updater.md +40 -0
  16. package/assets/agents/deploy-checker.md +40 -0
  17. package/assets/agents/docker-optimizer.md +40 -0
  18. package/assets/agents/documentation-writer.md +40 -0
  19. package/assets/agents/email-builder.md +55 -0
  20. package/assets/agents/env-setup.md +40 -0
  21. package/assets/agents/error-handler.md +40 -0
  22. package/assets/agents/eslint-fixer.md +46 -0
  23. package/assets/agents/feature-flagger.md +69 -0
  24. package/assets/agents/git-detective.md +39 -0
  25. package/assets/agents/graphql-builder.md +60 -0
  26. package/assets/agents/incident-responder.md +59 -0
  27. package/assets/agents/log-analyzer.md +39 -0
  28. package/assets/agents/migration-planner.md +41 -0
  29. package/assets/agents/monorepo-navigator.md +39 -0
  30. package/assets/agents/nextjs-expert.md +57 -0
  31. package/assets/agents/notification-builder.md +56 -0
  32. package/assets/agents/onboarding-guide.md +39 -0
  33. package/assets/agents/performance-profiler.md +40 -0
  34. package/assets/agents/prisma-expert.md +57 -0
  35. package/assets/agents/rate-limiter.md +58 -0
  36. package/assets/agents/react-expert.md +58 -0
  37. package/assets/agents/refactorer.md +42 -0
  38. package/assets/agents/regex-builder.md +46 -0
  39. package/assets/agents/release-manager.md +40 -0
  40. package/assets/agents/s3-manager.md +58 -0
  41. package/assets/agents/schema-validator.md +40 -0
  42. package/assets/agents/search-builder.md +62 -0
  43. package/assets/agents/security-auditor.md +39 -0
  44. package/assets/agents/sitemap-generator.md +53 -0
  45. package/assets/agents/stripe-integrator.md +59 -0
  46. package/assets/agents/tailwind-expert.md +55 -0
  47. package/assets/agents/tech-debt-tracker.md +39 -0
  48. package/assets/agents/test-writer.md +42 -0
  49. package/assets/agents/type-fixer.md +45 -0
  50. package/assets/agents/webhook-builder.md +54 -0
  51. package/assets/rules/cpp.md +53 -0
  52. package/assets/rules/css.md +52 -0
  53. package/assets/rules/go.md +50 -0
  54. package/assets/rules/html.md +52 -0
  55. package/assets/rules/java.md +51 -0
  56. package/assets/rules/kotlin.md +50 -0
  57. package/assets/rules/php.md +51 -0
  58. package/assets/rules/python.md +51 -0
  59. package/assets/rules/ruby.md +51 -0
  60. package/assets/rules/rust.md +49 -0
  61. package/assets/rules/shell.md +52 -0
  62. package/assets/rules/sql.md +49 -0
  63. package/assets/rules/swift.md +50 -0
  64. package/assets/rules/typescript.md +52 -0
  65. package/assets/rules/yaml-json.md +51 -0
  66. package/assets/skills/accessibility.md +210 -0
  67. package/assets/skills/agent-patterns.md +387 -0
  68. package/assets/skills/ai-integration.md +263 -0
  69. package/assets/skills/animation-patterns.md +224 -0
  70. package/assets/skills/api-design.md +218 -0
  71. package/assets/skills/api-gateway.md +341 -0
  72. package/assets/skills/api-versioning.md +226 -0
  73. package/assets/skills/astro-patterns.md +233 -0
  74. package/assets/skills/auth-patterns.md +248 -0
  75. package/assets/skills/aws-patterns.md +171 -0
  76. package/assets/skills/background-jobs.md +162 -0
  77. package/assets/skills/browser-extensions.md +309 -0
  78. package/assets/skills/caching-patterns.md +253 -0
  79. package/assets/skills/ci-cd.md +251 -0
  80. package/assets/skills/cli-development.md +296 -0
  81. package/assets/skills/code-review.md +185 -0
  82. package/assets/skills/cron-patterns.md +327 -0
  83. package/assets/skills/data-fetching.md +231 -0
  84. package/assets/skills/database-migrations.md +346 -0
  85. package/assets/skills/database-patterns.md +219 -0
  86. package/assets/skills/debugging.md +281 -0
  87. package/assets/skills/design-system.md +289 -0
  88. package/assets/skills/django-patterns.md +182 -0
  89. package/assets/skills/docker-patterns.md +235 -0
  90. package/assets/skills/e2e-testing.md +287 -0
  91. package/assets/skills/edge-computing.md +268 -0
  92. package/assets/skills/electron-patterns.md +266 -0
  93. package/assets/skills/email-templates.md +206 -0
  94. package/assets/skills/error-handling.md +265 -0
  95. package/assets/skills/event-driven.md +232 -0
  96. package/assets/skills/express-patterns.md +239 -0
  97. package/assets/skills/fastapi-patterns.md +198 -0
  98. package/assets/skills/feature-flags.md +212 -0
  99. package/assets/skills/figma-to-code.md +298 -0
  100. package/assets/skills/file-upload.md +228 -0
  101. package/assets/skills/forms-patterns.md +264 -0
  102. package/assets/skills/gcp-patterns.md +189 -0
  103. package/assets/skills/git-workflow.md +187 -0
  104. package/assets/skills/golang-patterns.md +185 -0
  105. package/assets/skills/graphql-patterns.md +244 -0
  106. package/assets/skills/i18n-patterns.md +172 -0
  107. package/assets/skills/image-processing.md +350 -0
  108. package/assets/skills/java-springboot.md +226 -0
  109. package/assets/skills/kotlin-patterns.md +207 -0
  110. package/assets/skills/kubernetes-patterns.md +326 -0
  111. package/assets/skills/laravel-patterns.md +261 -0
  112. package/assets/skills/llm-fine-tuning.md +335 -0
  113. package/assets/skills/load-testing.md +303 -0
  114. package/assets/skills/logging-observability.md +228 -0
  115. package/assets/skills/markdown-processing.md +318 -0
  116. package/assets/skills/mcp-server-patterns.md +292 -0
  117. package/assets/skills/microservices.md +272 -0
  118. package/assets/skills/migration-patterns.md +239 -0
  119. package/assets/skills/mongodb-patterns.md +189 -0
  120. package/assets/skills/monorepo-patterns.md +287 -0
  121. package/assets/skills/nextjs-app-router.md +237 -0
  122. package/assets/skills/notification-patterns.md +348 -0
  123. package/assets/skills/oauth-patterns.md +246 -0
  124. package/assets/skills/payment-integration.md +222 -0
  125. package/assets/skills/pdf-generation.md +307 -0
  126. package/assets/skills/performance-optimization.md +277 -0
  127. package/assets/skills/php-patterns.md +210 -0
  128. package/assets/skills/prisma-patterns.md +241 -0
  129. package/assets/skills/prompt-engineering.md +193 -0
  130. package/assets/skills/pwa-patterns.md +247 -0
  131. package/assets/skills/python-patterns.md +158 -0
  132. package/assets/skills/python-testing.md +172 -0
  133. package/assets/skills/queue-patterns.md +295 -0
  134. package/assets/skills/rag-patterns.md +159 -0
  135. package/assets/skills/rate-limiting.md +319 -0
  136. package/assets/skills/react-components.md +201 -0
  137. package/assets/skills/react-native-patterns.md +299 -0
  138. package/assets/skills/real-time-patterns.md +181 -0
  139. package/assets/skills/redis-patterns.md +188 -0
  140. package/assets/skills/refactoring.md +218 -0
  141. package/assets/skills/regex-patterns.md +191 -0
  142. package/assets/skills/remix-patterns.md +262 -0
  143. package/assets/skills/responsive-design.md +199 -0
  144. package/assets/skills/ruby-rails-patterns.md +178 -0
  145. package/assets/skills/rust-patterns.md +211 -0
  146. package/assets/skills/search-patterns.md +227 -0
  147. package/assets/skills/security-hardening.md +237 -0
  148. package/assets/skills/seo-patterns.md +179 -0
  149. package/assets/skills/serverless-patterns.md +223 -0
  150. package/assets/skills/sql-optimization.md +154 -0
  151. package/assets/skills/state-management.md +254 -0
  152. package/assets/skills/storybook-patterns.md +330 -0
  153. package/assets/skills/svelte-patterns.md +258 -0
  154. package/assets/skills/swift-patterns.md +227 -0
  155. package/assets/skills/tailwind-patterns.md +272 -0
  156. package/assets/skills/tdd-workflow.md +199 -0
  157. package/assets/skills/terraform-patterns.md +270 -0
  158. package/assets/skills/testing-react.md +240 -0
  159. package/assets/skills/testing-vitest.md +232 -0
  160. package/assets/skills/typescript-strict.md +159 -0
  161. package/assets/skills/video-processing.md +340 -0
  162. package/assets/skills/vue-patterns.md +247 -0
  163. package/assets/skills/web-workers.md +327 -0
  164. package/assets/skills/webhooks-patterns.md +283 -0
  165. package/assets/skills/websocket-patterns.md +306 -0
  166. package/dist/cli/index.js +941 -958
  167. package/dist/core/index.d.ts +341 -11
  168. package/dist/core.js +58 -95
  169. package/dist/mcp/index.d.ts +33 -1
  170. package/dist/mcp-server.js +177 -255
  171. package/package.json +4 -1
@@ -0,0 +1,296 @@
1
+ ---
2
+ name: cli-development
3
+ description: Build CLI tools — Commander.js, Inquirer prompts, chalk output, progress bars, configuration, and packaging.
4
+ ---
5
+
6
+ # CLI Development Patterns
7
+
8
+ ## When to Use
9
+
10
+ Apply these patterns when building command-line tools in Node.js. Covers
11
+ argument parsing with Commander, interactive prompts with Inquirer, styled
12
+ output with chalk, progress indicators, configuration management, and
13
+ packaging for distribution via npm or standalone binaries. Use this skill
14
+ when creating developer tools, build scripts, or automation CLIs.
15
+
16
+ ## How It Works
17
+
18
+ ### 1. Commander.js — Argument Parsing
19
+
20
+ ```typescript
21
+ import { Command, Option } from 'commander';
22
+
23
+ const program = new Command();
24
+
25
+ program
26
+ .name('mycli')
27
+ .version('1.0.0')
28
+ .description('A developer productivity tool');
29
+
30
+ // Subcommand with options and arguments
31
+ program
32
+ .command('deploy')
33
+ .description('Deploy to environment')
34
+ .argument('<environment>', 'Target environment (staging|production)')
35
+ .option('-f, --force', 'Skip confirmation prompt')
36
+ .option('-t, --tag <tag>', 'Deploy specific tag', 'latest')
37
+ .option('--dry-run', 'Show what would be deployed without deploying')
38
+ .addOption(
39
+ new Option('--strategy <strategy>', 'Deployment strategy')
40
+ .choices(['rolling', 'blue-green', 'canary'])
41
+ .default('rolling')
42
+ )
43
+ .action(async (environment, options) => {
44
+ if (!options.force && environment === 'production') {
45
+ const confirmed = await confirmProduction();
46
+ if (!confirmed) process.exit(0);
47
+ }
48
+ await deploy(environment, options);
49
+ });
50
+
51
+ // Global options
52
+ program
53
+ .option('--json', 'Output as JSON')
54
+ .option('-v, --verbose', 'Verbose logging')
55
+ .hook('preAction', (thisCommand) => {
56
+ if (thisCommand.opts().verbose) {
57
+ setLogLevel('debug');
58
+ }
59
+ });
60
+
61
+ program.parse();
62
+ ```
63
+
64
+ ### 2. Inquirer — Interactive Prompts
65
+
66
+ ```typescript
67
+ import { input, select, confirm, checkbox, password } from '@inquirer/prompts';
68
+
69
+ async function setupProject(): Promise<ProjectConfig> {
70
+ const name = await input({
71
+ message: 'Project name:',
72
+ default: path.basename(process.cwd()),
73
+ validate: (val) => /^[a-z0-9-]+$/.test(val) || 'Use lowercase letters, numbers, and hyphens',
74
+ });
75
+
76
+ const framework = await select({
77
+ message: 'Framework:',
78
+ choices: [
79
+ { name: 'Next.js', value: 'nextjs', description: 'Full-stack React' },
80
+ { name: 'Express', value: 'express', description: 'Minimal API server' },
81
+ { name: 'Fastify', value: 'fastify', description: 'High-performance API' },
82
+ ],
83
+ });
84
+
85
+ const features = await checkbox({
86
+ message: 'Features:',
87
+ choices: [
88
+ { name: 'TypeScript', value: 'typescript', checked: true },
89
+ { name: 'ESLint', value: 'eslint', checked: true },
90
+ { name: 'Docker', value: 'docker' },
91
+ { name: 'CI/CD', value: 'ci' },
92
+ ],
93
+ });
94
+
95
+ const proceed = await confirm({ message: 'Create project?', default: true });
96
+ if (!proceed) process.exit(0);
97
+
98
+ return { name, framework, features };
99
+ }
100
+ ```
101
+
102
+ ### 3. Chalk — Styled Output
103
+
104
+ ```typescript
105
+ import chalk from 'chalk';
106
+
107
+ // Status messages
108
+ function logSuccess(msg: string) { console.log(chalk.green('OK') + ' ' + msg); }
109
+ function logError(msg: string) { console.error(chalk.red('ERR') + ' ' + msg); }
110
+ function logWarn(msg: string) { console.log(chalk.yellow('WARN') + ' ' + msg); }
111
+ function logInfo(msg: string) { console.log(chalk.blue('INFO') + ' ' + msg); }
112
+
113
+ // Formatted output
114
+ console.log(chalk.bold.underline('Deployment Summary'));
115
+ console.log(` Environment: ${chalk.cyan('production')}`);
116
+ console.log(` Version: ${chalk.green('v1.2.3')}`);
117
+ console.log(` Status: ${chalk.bgGreen.black(' DEPLOYED ')}`);
118
+
119
+ // Tables (without dependencies)
120
+ function printTable(headers: string[], rows: string[][]) {
121
+ const widths = headers.map((h, i) =>
122
+ Math.max(h.length, ...rows.map(r => r[i]?.length ?? 0))
123
+ );
124
+ const line = widths.map(w => '-'.repeat(w + 2)).join('+');
125
+
126
+ console.log(headers.map((h, i) => ` ${h.padEnd(widths[i])} `).join('|'));
127
+ console.log(line);
128
+ rows.forEach(row => {
129
+ console.log(row.map((c, i) => ` ${(c ?? '').padEnd(widths[i])} `).join('|'));
130
+ });
131
+ }
132
+ ```
133
+
134
+ ### 4. Progress Indicators
135
+
136
+ ```typescript
137
+ import ora from 'ora';
138
+ import cliProgress from 'cli-progress';
139
+
140
+ // Spinner for indeterminate operations
141
+ async function withSpinner<T>(message: string, fn: () => Promise<T>): Promise<T> {
142
+ const spinner = ora(message).start();
143
+ try {
144
+ const result = await fn();
145
+ spinner.succeed();
146
+ return result;
147
+ } catch (err) {
148
+ spinner.fail();
149
+ throw err;
150
+ }
151
+ }
152
+
153
+ await withSpinner('Deploying...', () => deploy());
154
+
155
+ // Progress bar for determinate operations
156
+ const bar = new cliProgress.SingleBar({
157
+ format: 'Uploading |{bar}| {percentage}% | {value}/{total} files',
158
+ barCompleteChar: '\u2588',
159
+ barIncompleteChar: '\u2591',
160
+ });
161
+
162
+ bar.start(files.length, 0);
163
+ for (const file of files) {
164
+ await upload(file);
165
+ bar.increment();
166
+ }
167
+ bar.stop();
168
+ ```
169
+
170
+ ### 5. Configuration Management
171
+
172
+ ```typescript
173
+ import Conf from 'conf';
174
+
175
+ interface Config {
176
+ apiKey: string;
177
+ defaultEnvironment: 'staging' | 'production';
178
+ outputFormat: 'json' | 'table' | 'text';
179
+ }
180
+
181
+ const config = new Conf<Config>({
182
+ projectName: 'mycli',
183
+ schema: {
184
+ apiKey: { type: 'string', default: '' },
185
+ defaultEnvironment: { type: 'string', enum: ['staging', 'production'], default: 'staging' },
186
+ outputFormat: { type: 'string', enum: ['json', 'table', 'text'], default: 'table' },
187
+ },
188
+ });
189
+
190
+ // Config subcommand
191
+ program
192
+ .command('config')
193
+ .description('Manage configuration')
194
+ .command('set')
195
+ .argument('<key>', 'Configuration key')
196
+ .argument('<value>', 'Configuration value')
197
+ .action((key, value) => {
198
+ config.set(key, value);
199
+ logSuccess(`Set ${key} = ${value}`);
200
+ });
201
+
202
+ program
203
+ .command('config')
204
+ .command('get')
205
+ .argument('<key>', 'Configuration key')
206
+ .action((key) => {
207
+ const value = config.get(key);
208
+ console.log(value ?? chalk.dim('(not set)'));
209
+ });
210
+
211
+ program
212
+ .command('config')
213
+ .command('path')
214
+ .action(() => console.log(config.path));
215
+ ```
216
+
217
+ ### 6. Error Handling and Exit Codes
218
+
219
+ ```typescript
220
+ // Wrap the top-level action to handle errors consistently
221
+ function handleErrors(fn: (...args: any[]) => Promise<void>) {
222
+ return async (...args: any[]) => {
223
+ try {
224
+ await fn(...args);
225
+ } catch (err) {
226
+ if (err instanceof UserError) {
227
+ logError(err.message);
228
+ if (err.hint) logInfo(`Hint: ${err.hint}`);
229
+ process.exit(1);
230
+ }
231
+ if (err instanceof NetworkError) {
232
+ logError(`Network error: ${err.message}`);
233
+ logInfo('Check your connection and try again');
234
+ process.exit(2);
235
+ }
236
+ // Unexpected error — show stack trace
237
+ console.error(err);
238
+ process.exit(99);
239
+ }
240
+ };
241
+ }
242
+
243
+ program
244
+ .command('deploy')
245
+ .action(handleErrors(async (env, opts) => {
246
+ await deploy(env, opts);
247
+ }));
248
+ ```
249
+
250
+ ### 7. Packaging and Distribution
251
+
252
+ ```json
253
+ {
254
+ "name": "mycli",
255
+ "version": "1.0.0",
256
+ "bin": { "mycli": "./dist/index.js" },
257
+ "type": "module",
258
+ "files": ["dist"],
259
+ "engines": { "node": ">=18" },
260
+ "scripts": {
261
+ "build": "tsup src/index.ts --format cjs --target node18 --clean",
262
+ "prepublishOnly": "npm run build"
263
+ }
264
+ }
265
+ ```
266
+
267
+ For standalone binaries (no Node.js required):
268
+
269
+ ```bash
270
+ # Using pkg or @vercel/ncc
271
+ npx pkg dist/index.js --targets node18-macos-arm64,node18-linux-x64,node18-win-x64
272
+ ```
273
+
274
+ ## Examples
275
+
276
+ | Tool | Purpose | Key Feature |
277
+ |------|---------|-------------|
278
+ | Commander | Argument parsing | Subcommands, options, validation |
279
+ | Inquirer | Interactive prompts | Select, checkbox, confirm |
280
+ | chalk | Styled terminal output | Colors, bold, underline |
281
+ | ora | Spinners | Indeterminate progress |
282
+ | Conf | Config persistence | JSON schema validation |
283
+ | tsup | Bundle for distribution | Single CJS file |
284
+
285
+ ## Checklist
286
+
287
+ - [ ] Subcommands organized by domain (`deploy`, `config`, `status`)
288
+ - [ ] All commands support `--json` flag for scripting/piping
289
+ - [ ] Interactive prompts have non-interactive fallbacks via flags
290
+ - [ ] Help text is clear, with examples for complex commands
291
+ - [ ] Exit codes are consistent (0 = success, 1 = user error, 2 = network)
292
+ - [ ] Configuration stored with schema validation
293
+ - [ ] Errors show actionable hints, not raw stack traces
294
+ - [ ] Spinners/progress bars used for operations longer than 1 second
295
+ - [ ] `bin` field in package.json points to built output
296
+ - [ ] Shell completions generated with `program.completions()`
@@ -0,0 +1,185 @@
1
+ ---
2
+ name: code-review
3
+ description: Code review patterns with review checklist, PR sizing, automated checks, constructive feedback, and security review.
4
+ ---
5
+
6
+ # Code Review
7
+
8
+ ## When to Use
9
+ Apply to every pull request before merge. Use the structured checklist to catch bugs, security holes, and maintainability issues that automated tools miss. Also useful for self-review before opening a PR, and for training junior developers on what to look for.
10
+
11
+ ## How It Works
12
+
13
+ ### Start with the Big Picture
14
+
15
+ Before reading line-by-line, understand what the PR is doing:
16
+
17
+ ```
18
+ 1. Read the PR title and description -- what problem does this solve?
19
+ 2. Check the file list -- does the scope match the described change?
20
+ 3. Look for unexpected files (config changes, new dependencies, migrations)
21
+ 4. Verify the change has tests proportional to its risk
22
+ 5. Check if the PR can be split into smaller, focused changes
23
+ ```
24
+
25
+ If a PR touches 20+ files across unrelated domains, ask to split it. Large PRs get rubber-stamped; small PRs get real review.
26
+
27
+ ### Security Review Checklist
28
+
29
+ Check every PR for these patterns, especially in routes and data handling:
30
+
31
+ ```typescript
32
+ // SQL injection -- use parameterized queries
33
+ // BAD: db.query(`SELECT * FROM users WHERE id = '${userId}'`)
34
+ // GOOD:
35
+ const user = await db.query("SELECT * FROM users WHERE id = $1", [userId]);
36
+
37
+ // XSS -- sanitize user content before rendering
38
+ // BAD: <div dangerouslySetInnerHTML={{ __html: userComment }} />
39
+ // GOOD:
40
+ import DOMPurify from "dompurify";
41
+ <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userComment) }} />
42
+
43
+ // Auth bypass -- verify ownership, not just authentication
44
+ // BAD: const order = await db.orders.findById(req.params.id);
45
+ // GOOD:
46
+ const order = await db.orders.findOne({
47
+ id: req.params.id,
48
+ userId: req.user.id,
49
+ });
50
+
51
+ // Mass assignment -- whitelist allowed fields
52
+ // BAD: await db.users.update(req.params.id, req.body);
53
+ // GOOD:
54
+ const { name, email } = req.body;
55
+ await db.users.update(req.params.id, { name, email });
56
+ ```
57
+
58
+ ### Performance Review
59
+
60
+ Look for patterns that will cause problems at scale:
61
+
62
+ ```typescript
63
+ // N+1 queries -- fetch related data in one query
64
+ // BAD:
65
+ for (const order of orders) {
66
+ order.user = await db.users.findById(order.userId);
67
+ }
68
+ // GOOD:
69
+ const userIds = [...new Set(orders.map((o) => o.userId))];
70
+ const users = await db.users.findByIds(userIds);
71
+ const userMap = new Map(users.map((u) => [u.id, u]));
72
+ orders.forEach((o) => (o.user = userMap.get(o.userId)));
73
+
74
+ // Unbounded queries -- always paginate
75
+ // BAD: const allUsers = await db.users.findAll();
76
+ // GOOD: const users = await db.users.findAll({ limit: 50, cursor });
77
+
78
+ // Memory leaks -- event listeners without cleanup
79
+ // BAD: useEffect(() => { window.addEventListener("resize", handler); }, []);
80
+ // GOOD:
81
+ useEffect(() => {
82
+ window.addEventListener("resize", handler);
83
+ return () => window.removeEventListener("resize", handler);
84
+ }, []);
85
+ ```
86
+
87
+ ### Readability Review
88
+
89
+ ```
90
+ - Functions: does the name describe what it does, not how?
91
+ BAD: loopAndFilter() GOOD: getActiveUsers()
92
+
93
+ - Variables: would a new team member understand this?
94
+ BAD: const d = new Date() GOOD: const createdAt = new Date()
95
+
96
+ - Comments: explain WHY, not WHAT
97
+ BAD: // increment counter
98
+ GOOD: // Retry up to 3 times -- the payment gateway has transient failures
99
+
100
+ - Magic numbers: named constants, not inline literals
101
+ BAD: if (retries > 3) GOOD: if (retries > MAX_RETRIES)
102
+ ```
103
+
104
+ ### Automated Checks as First Pass
105
+
106
+ Set up CI to catch mechanical issues before human review:
107
+
108
+ ```yaml
109
+ # .github/workflows/pr-checks.yml
110
+ name: PR Checks
111
+ on: [pull_request]
112
+ jobs:
113
+ checks:
114
+ runs-on: ubuntu-latest
115
+ steps:
116
+ - uses: actions/checkout@v4
117
+ - run: npm ci
118
+ - run: npm run typecheck
119
+ - run: npm run lint
120
+ - run: npm test -- --coverage
121
+ - run: npx audit-ci --moderate
122
+ - uses: danger/danger-js@v1
123
+ env:
124
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
125
+ ```
126
+
127
+ ```typescript
128
+ // dangerfile.ts -- automated PR feedback
129
+ import { danger, warn, fail } from "danger";
130
+
131
+ if (danger.github.pr.body.length < 10) {
132
+ fail("PR description is too short. Explain what and why.");
133
+ }
134
+ if (danger.github.pr.additions > 500) {
135
+ warn("Large PR. Consider splitting into smaller changes.");
136
+ }
137
+ const hasTests = danger.git.created_files.some((f) => f.includes(".test."));
138
+ if (!hasTests && danger.github.pr.additions > 50) {
139
+ warn("No test files added. Is this change covered by existing tests?");
140
+ }
141
+ ```
142
+
143
+ ### Constructive Feedback Patterns
144
+
145
+ ```markdown
146
+ ## Ask, don't demand
147
+ BAD: "This is wrong. Use a Map instead."
148
+ GOOD: "Have you considered using a Map here? It would give O(1)
149
+ lookup instead of the O(n) filter on line 42."
150
+
151
+ ## Distinguish blocking from non-blocking
152
+ - "nit: rename `d` to `createdAt`" -> nice to have
153
+ - "issue: this query is missing LIMIT" -> must fix
154
+ - "question: what happens if `user` is null?" -> need clarification
155
+
156
+ ## Offer alternatives with code
157
+ "This works, but a reduce() might be clearer:
158
+ ```ts
159
+ const byId = items.reduce<Record<string, Item>>(
160
+ (acc, item) => ({ ...acc, [item.id]: item }),
161
+ {}
162
+ );
163
+ ```"
164
+ ```
165
+
166
+ ## Examples
167
+
168
+ | What You Catch | How to Spot It | Impact |
169
+ |---------------|---------------|--------|
170
+ | SQL injection | String interpolation in queries | Data breach |
171
+ | N+1 query | Loop with await inside | 200ms -> 5s page load |
172
+ | Missing error handling | No try/catch on external calls | Unhandled crash |
173
+ | Auth bypass | findById without userId check | Users access others' data |
174
+ | Memory leak | Event listener without cleanup | App degrades over time |
175
+ | Large PR | 20+ files across domains | Missed bugs, rubber-stamped |
176
+
177
+ ## Checklist
178
+ - [ ] PR description explains WHAT and WHY (not just HOW)
179
+ - [ ] Scope is focused -- one concern per PR, under 400 lines changed
180
+ - [ ] No hardcoded secrets, API keys, or credentials
181
+ - [ ] SQL queries use parameterized inputs
182
+ - [ ] User input is validated and sanitized
183
+ - [ ] Database queries have LIMIT and appropriate indexes
184
+ - [ ] Error cases handled, not swallowed silently
185
+ - [ ] No N+1 query patterns