autoworkflow 3.1.4 → 3.5.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 (123) hide show
  1. package/.claude/commands/analyze.md +19 -0
  2. package/.claude/commands/audit.md +174 -11
  3. package/.claude/commands/build.md +39 -0
  4. package/.claude/commands/commit.md +25 -0
  5. package/.claude/commands/fix.md +23 -0
  6. package/.claude/commands/plan.md +18 -0
  7. package/.claude/commands/suggest.md +23 -0
  8. package/.claude/commands/verify.md +18 -0
  9. package/.claude/hooks/post-bash-router.sh +20 -0
  10. package/.claude/hooks/post-commit.sh +140 -0
  11. package/.claude/hooks/pre-edit.sh +129 -0
  12. package/.claude/hooks/session-check.sh +79 -0
  13. package/.claude/settings.json +40 -6
  14. package/.claude/settings.local.json +3 -1
  15. package/.claude/skills/actix.md +337 -0
  16. package/.claude/skills/alembic.md +504 -0
  17. package/.claude/skills/angular.md +237 -0
  18. package/.claude/skills/api-design.md +187 -0
  19. package/.claude/skills/aspnet-core.md +377 -0
  20. package/.claude/skills/astro.md +245 -0
  21. package/.claude/skills/auth-clerk.md +327 -0
  22. package/.claude/skills/auth-firebase.md +367 -0
  23. package/.claude/skills/auth-nextauth.md +359 -0
  24. package/.claude/skills/auth-supabase.md +368 -0
  25. package/.claude/skills/axum.md +386 -0
  26. package/.claude/skills/blazor.md +456 -0
  27. package/.claude/skills/chi.md +348 -0
  28. package/.claude/skills/code-review.md +133 -0
  29. package/.claude/skills/csharp.md +296 -0
  30. package/.claude/skills/css-modules.md +325 -0
  31. package/.claude/skills/cypress.md +343 -0
  32. package/.claude/skills/debugging.md +133 -0
  33. package/.claude/skills/diesel.md +392 -0
  34. package/.claude/skills/django.md +301 -0
  35. package/.claude/skills/docker.md +319 -0
  36. package/.claude/skills/doctrine.md +473 -0
  37. package/.claude/skills/documentation.md +182 -0
  38. package/.claude/skills/dotnet.md +409 -0
  39. package/.claude/skills/drizzle.md +293 -0
  40. package/.claude/skills/echo.md +321 -0
  41. package/.claude/skills/eloquent.md +256 -0
  42. package/.claude/skills/emotion.md +426 -0
  43. package/.claude/skills/entity-framework.md +370 -0
  44. package/.claude/skills/express.md +316 -0
  45. package/.claude/skills/fastapi.md +329 -0
  46. package/.claude/skills/fastify.md +299 -0
  47. package/.claude/skills/fiber.md +315 -0
  48. package/.claude/skills/flask.md +322 -0
  49. package/.claude/skills/gin.md +342 -0
  50. package/.claude/skills/git.md +116 -0
  51. package/.claude/skills/github-actions.md +353 -0
  52. package/.claude/skills/go.md +377 -0
  53. package/.claude/skills/gorm.md +409 -0
  54. package/.claude/skills/graphql.md +478 -0
  55. package/.claude/skills/hibernate.md +379 -0
  56. package/.claude/skills/hono.md +306 -0
  57. package/.claude/skills/java.md +400 -0
  58. package/.claude/skills/jest.md +313 -0
  59. package/.claude/skills/jpa.md +282 -0
  60. package/.claude/skills/kotlin.md +347 -0
  61. package/.claude/skills/kubernetes.md +363 -0
  62. package/.claude/skills/laravel.md +414 -0
  63. package/.claude/skills/mcp-browser.md +320 -0
  64. package/.claude/skills/mcp-database.md +219 -0
  65. package/.claude/skills/mcp-fetch.md +241 -0
  66. package/.claude/skills/mcp-filesystem.md +204 -0
  67. package/.claude/skills/mcp-github.md +217 -0
  68. package/.claude/skills/mcp-memory.md +240 -0
  69. package/.claude/skills/mcp-search.md +218 -0
  70. package/.claude/skills/mcp-slack.md +262 -0
  71. package/.claude/skills/micronaut.md +388 -0
  72. package/.claude/skills/mongodb.md +319 -0
  73. package/.claude/skills/mongoose.md +355 -0
  74. package/.claude/skills/mysql.md +281 -0
  75. package/.claude/skills/nestjs.md +335 -0
  76. package/.claude/skills/nextjs-app-router.md +260 -0
  77. package/.claude/skills/nextjs-pages.md +172 -0
  78. package/.claude/skills/nuxt.md +202 -0
  79. package/.claude/skills/openapi.md +489 -0
  80. package/.claude/skills/performance.md +199 -0
  81. package/.claude/skills/php.md +398 -0
  82. package/.claude/skills/playwright.md +371 -0
  83. package/.claude/skills/postgresql.md +257 -0
  84. package/.claude/skills/prisma.md +293 -0
  85. package/.claude/skills/pydantic.md +304 -0
  86. package/.claude/skills/pytest.md +313 -0
  87. package/.claude/skills/python.md +272 -0
  88. package/.claude/skills/quarkus.md +377 -0
  89. package/.claude/skills/react.md +230 -0
  90. package/.claude/skills/redis.md +391 -0
  91. package/.claude/skills/refactoring.md +143 -0
  92. package/.claude/skills/remix.md +246 -0
  93. package/.claude/skills/rest-api.md +490 -0
  94. package/.claude/skills/rocket.md +366 -0
  95. package/.claude/skills/rust.md +341 -0
  96. package/.claude/skills/sass.md +380 -0
  97. package/.claude/skills/sea-orm.md +382 -0
  98. package/.claude/skills/security.md +167 -0
  99. package/.claude/skills/sequelize.md +395 -0
  100. package/.claude/skills/spring-boot.md +416 -0
  101. package/.claude/skills/sqlalchemy.md +269 -0
  102. package/.claude/skills/sqlx-rust.md +408 -0
  103. package/.claude/skills/state-jotai.md +346 -0
  104. package/.claude/skills/state-mobx.md +353 -0
  105. package/.claude/skills/state-pinia.md +431 -0
  106. package/.claude/skills/state-redux.md +337 -0
  107. package/.claude/skills/state-tanstack-query.md +434 -0
  108. package/.claude/skills/state-zustand.md +340 -0
  109. package/.claude/skills/styled-components.md +403 -0
  110. package/.claude/skills/svelte.md +238 -0
  111. package/.claude/skills/sveltekit.md +207 -0
  112. package/.claude/skills/symfony.md +437 -0
  113. package/.claude/skills/tailwind.md +279 -0
  114. package/.claude/skills/terraform.md +394 -0
  115. package/.claude/skills/testing-library.md +371 -0
  116. package/.claude/skills/trpc.md +426 -0
  117. package/.claude/skills/typeorm.md +368 -0
  118. package/.claude/skills/vitest.md +330 -0
  119. package/.claude/skills/vue.md +202 -0
  120. package/.claude/skills/warp.md +365 -0
  121. package/README.md +135 -52
  122. package/package.json +1 -1
  123. package/system/triggers.md +152 -11
@@ -0,0 +1,391 @@
1
+ # Redis Skill
2
+
3
+ ## Connection Setup
4
+ \`\`\`typescript
5
+ import Redis from 'ioredis';
6
+
7
+ // Single instance
8
+ const redis = new Redis({
9
+ host: process.env.REDIS_HOST || 'localhost',
10
+ port: parseInt(process.env.REDIS_PORT || '6379'),
11
+ password: process.env.REDIS_PASSWORD,
12
+ db: 0,
13
+ retryDelayOnFailover: 100,
14
+ maxRetriesPerRequest: 3,
15
+ });
16
+
17
+ // Cluster mode
18
+ const cluster = new Redis.Cluster([
19
+ { host: 'node1', port: 6379 },
20
+ { host: 'node2', port: 6379 },
21
+ ]);
22
+
23
+ // Connection events
24
+ redis.on('connect', () => console.log('Redis connected'));
25
+ redis.on('error', (err) => console.error('Redis error:', err));
26
+ redis.on('reconnecting', () => console.log('Redis reconnecting'));
27
+ \`\`\`
28
+
29
+ ## Data Structures
30
+
31
+ ### Strings (Key-Value)
32
+ \`\`\`typescript
33
+ // Basic operations
34
+ await redis.set('key', 'value');
35
+ await redis.set('key', 'value', 'EX', 3600); // Expires in 1 hour
36
+ await redis.set('key', 'value', 'NX'); // Only if not exists
37
+ await redis.set('key', 'value', 'XX'); // Only if exists
38
+
39
+ const value = await redis.get('key');
40
+ const values = await redis.mget('key1', 'key2', 'key3');
41
+
42
+ // Atomic operations
43
+ await redis.incr('counter');
44
+ await redis.incrby('counter', 5);
45
+ await redis.decr('counter');
46
+ await redis.incrbyfloat('price', 0.5);
47
+
48
+ // Expiration
49
+ await redis.expire('key', 3600); // Set TTL
50
+ await redis.ttl('key'); // Get remaining TTL
51
+ await redis.persist('key'); // Remove expiration
52
+ \`\`\`
53
+
54
+ ### Hashes (Objects)
55
+ \`\`\`typescript
56
+ // Store object fields
57
+ await redis.hset('user:123', 'name', 'John', 'email', 'john@example.com');
58
+ await redis.hset('user:123', { name: 'John', email: 'john@example.com', age: '30' });
59
+
60
+ // Get fields
61
+ const name = await redis.hget('user:123', 'name');
62
+ const user = await redis.hgetall('user:123'); // All fields
63
+ const fields = await redis.hmget('user:123', 'name', 'email');
64
+
65
+ // Atomic increment
66
+ await redis.hincrby('user:123', 'loginCount', 1);
67
+
68
+ // Check/delete fields
69
+ await redis.hexists('user:123', 'name');
70
+ await redis.hdel('user:123', 'tempField');
71
+ \`\`\`
72
+
73
+ ### Lists (Queues)
74
+ \`\`\`typescript
75
+ // Add to list
76
+ await redis.lpush('queue', 'item1', 'item2'); // Add to front
77
+ await redis.rpush('queue', 'item3'); // Add to back
78
+
79
+ // Remove from list
80
+ const item = await redis.lpop('queue'); // Remove from front
81
+ const item = await redis.rpop('queue'); // Remove from back
82
+ const item = await redis.blpop('queue', 30); // Blocking pop (30s timeout)
83
+
84
+ // Access elements
85
+ const items = await redis.lrange('queue', 0, -1); // All items
86
+ const length = await redis.llen('queue');
87
+
88
+ // Trim list (keep recent N)
89
+ await redis.ltrim('recent:views', 0, 99); // Keep last 100
90
+ \`\`\`
91
+
92
+ ### Sets (Unique Collections)
93
+ \`\`\`typescript
94
+ // Add/remove members
95
+ await redis.sadd('tags:post:123', 'redis', 'database', 'cache');
96
+ await redis.srem('tags:post:123', 'cache');
97
+
98
+ // Check membership
99
+ const isMember = await redis.sismember('tags:post:123', 'redis');
100
+ const members = await redis.smembers('tags:post:123');
101
+ const count = await redis.scard('tags:post:123');
102
+
103
+ // Set operations
104
+ const common = await redis.sinter('user:1:skills', 'user:2:skills'); // Intersection
105
+ const all = await redis.sunion('user:1:skills', 'user:2:skills'); // Union
106
+ const diff = await redis.sdiff('user:1:skills', 'user:2:skills'); // Difference
107
+
108
+ // Random member
109
+ const random = await redis.srandmember('tags:post:123');
110
+ \`\`\`
111
+
112
+ ### Sorted Sets (Ranked Data)
113
+ \`\`\`typescript
114
+ // Add with scores
115
+ await redis.zadd('leaderboard', 100, 'player1', 85, 'player2', 120, 'player3');
116
+
117
+ // Get rankings
118
+ const top10 = await redis.zrevrange('leaderboard', 0, 9, 'WITHSCORES'); // Highest first
119
+ const bottom10 = await redis.zrange('leaderboard', 0, 9, 'WITHSCORES'); // Lowest first
120
+
121
+ // Get rank
122
+ const rank = await redis.zrevrank('leaderboard', 'player1'); // 0-indexed from top
123
+ const score = await redis.zscore('leaderboard', 'player1');
124
+
125
+ // Range by score
126
+ const players = await redis.zrangebyscore('leaderboard', 50, 100, 'WITHSCORES');
127
+
128
+ // Increment score
129
+ await redis.zincrby('leaderboard', 10, 'player1');
130
+
131
+ // Remove
132
+ await redis.zrem('leaderboard', 'player1');
133
+ await redis.zremrangebyrank('leaderboard', 0, 9); // Remove bottom 10
134
+ \`\`\`
135
+
136
+ ## Common Patterns
137
+
138
+ ### Caching
139
+ \`\`\`typescript
140
+ async function getCachedUser(userId: string): Promise<User | null> {
141
+ const cacheKey = \`user:\${userId}\`;
142
+
143
+ // Try cache first
144
+ const cached = await redis.get(cacheKey);
145
+ if (cached) {
146
+ return JSON.parse(cached);
147
+ }
148
+
149
+ // Fetch from database
150
+ const user = await db.users.findById(userId);
151
+ if (user) {
152
+ // Cache for 1 hour
153
+ await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600);
154
+ }
155
+
156
+ return user;
157
+ }
158
+
159
+ // Cache invalidation
160
+ async function updateUser(userId: string, data: Partial<User>) {
161
+ await db.users.update(userId, data);
162
+ await redis.del(\`user:\${userId}\`); // Invalidate cache
163
+ }
164
+
165
+ // Cache aside with lock (prevent stampede)
166
+ async function getCachedWithLock(key: string, fetchFn: () => Promise<any>) {
167
+ const cached = await redis.get(key);
168
+ if (cached) return JSON.parse(cached);
169
+
170
+ const lockKey = \`lock:\${key}\`;
171
+ const acquired = await redis.set(lockKey, '1', 'NX', 'EX', 10);
172
+
173
+ if (acquired) {
174
+ const data = await fetchFn();
175
+ await redis.set(key, JSON.stringify(data), 'EX', 3600);
176
+ await redis.del(lockKey);
177
+ return data;
178
+ }
179
+
180
+ // Wait and retry if lock not acquired
181
+ await new Promise(resolve => setTimeout(resolve, 100));
182
+ return getCachedWithLock(key, fetchFn);
183
+ }
184
+ \`\`\`
185
+
186
+ ### Rate Limiting
187
+ \`\`\`typescript
188
+ // Fixed window rate limiting
189
+ async function rateLimit(userId: string, limit: number, windowSec: number): Promise<boolean> {
190
+ const key = \`ratelimit:\${userId}:\${Math.floor(Date.now() / (windowSec * 1000))}\`;
191
+
192
+ const count = await redis.incr(key);
193
+ if (count === 1) {
194
+ await redis.expire(key, windowSec);
195
+ }
196
+
197
+ return count <= limit;
198
+ }
199
+
200
+ // Sliding window rate limiting (more accurate)
201
+ async function slidingWindowRateLimit(
202
+ userId: string,
203
+ limit: number,
204
+ windowMs: number
205
+ ): Promise<{ allowed: boolean; remaining: number }> {
206
+ const key = \`ratelimit:\${userId}\`;
207
+ const now = Date.now();
208
+ const windowStart = now - windowMs;
209
+
210
+ // Remove old entries and add new one
211
+ await redis.zremrangebyscore(key, 0, windowStart);
212
+ const count = await redis.zcard(key);
213
+
214
+ if (count < limit) {
215
+ await redis.zadd(key, now, \`\${now}-\${Math.random()}\`);
216
+ await redis.expire(key, Math.ceil(windowMs / 1000));
217
+ return { allowed: true, remaining: limit - count - 1 };
218
+ }
219
+
220
+ return { allowed: false, remaining: 0 };
221
+ }
222
+ \`\`\`
223
+
224
+ ### Session Storage
225
+ \`\`\`typescript
226
+ // Store session
227
+ async function createSession(userId: string, data: SessionData): Promise<string> {
228
+ const sessionId = crypto.randomUUID();
229
+ const key = \`session:\${sessionId}\`;
230
+
231
+ await redis.hset(key, {
232
+ userId,
233
+ ...data,
234
+ createdAt: Date.now().toString(),
235
+ });
236
+ await redis.expire(key, 86400); // 24 hours
237
+
238
+ return sessionId;
239
+ }
240
+
241
+ // Get session
242
+ async function getSession(sessionId: string): Promise<SessionData | null> {
243
+ const key = \`session:\${sessionId}\`;
244
+ const data = await redis.hgetall(key);
245
+
246
+ if (!data || Object.keys(data).length === 0) {
247
+ return null;
248
+ }
249
+
250
+ // Refresh TTL on access
251
+ await redis.expire(key, 86400);
252
+ return data as SessionData;
253
+ }
254
+
255
+ // Destroy session
256
+ async function destroySession(sessionId: string): Promise<void> {
257
+ await redis.del(\`session:\${sessionId}\`);
258
+ }
259
+ \`\`\`
260
+
261
+ ### Pub/Sub
262
+ \`\`\`typescript
263
+ // Publisher
264
+ const publisher = new Redis();
265
+ await publisher.publish('notifications', JSON.stringify({
266
+ type: 'message',
267
+ userId: '123',
268
+ content: 'Hello!'
269
+ }));
270
+
271
+ // Subscriber
272
+ const subscriber = new Redis();
273
+ subscriber.subscribe('notifications', 'alerts');
274
+
275
+ subscriber.on('message', (channel, message) => {
276
+ console.log(\`Received on \${channel}:\`, JSON.parse(message));
277
+ });
278
+
279
+ // Pattern subscription
280
+ subscriber.psubscribe('events:*');
281
+ subscriber.on('pmessage', (pattern, channel, message) => {
282
+ console.log(\`Pattern \${pattern}, channel \${channel}:\`, message);
283
+ });
284
+ \`\`\`
285
+
286
+ ### Distributed Locking
287
+ \`\`\`typescript
288
+ // Acquire lock with Redlock algorithm (simplified)
289
+ async function acquireLock(
290
+ resource: string,
291
+ ttlMs: number
292
+ ): Promise<string | null> {
293
+ const lockKey = \`lock:\${resource}\`;
294
+ const lockValue = crypto.randomUUID();
295
+
296
+ const acquired = await redis.set(lockKey, lockValue, 'NX', 'PX', ttlMs);
297
+
298
+ return acquired ? lockValue : null;
299
+ }
300
+
301
+ // Release lock (only if we own it)
302
+ async function releaseLock(resource: string, lockValue: string): Promise<boolean> {
303
+ const script = \`
304
+ if redis.call("get", KEYS[1]) == ARGV[1] then
305
+ return redis.call("del", KEYS[1])
306
+ else
307
+ return 0
308
+ end
309
+ \`;
310
+
311
+ const result = await redis.eval(script, 1, \`lock:\${resource}\`, lockValue);
312
+ return result === 1;
313
+ }
314
+
315
+ // Usage
316
+ const lockValue = await acquireLock('order:123', 30000);
317
+ if (lockValue) {
318
+ try {
319
+ // Do critical work
320
+ } finally {
321
+ await releaseLock('order:123', lockValue);
322
+ }
323
+ }
324
+ \`\`\`
325
+
326
+ ### Streams (Event Log)
327
+ \`\`\`typescript
328
+ // Add to stream
329
+ await redis.xadd('events', '*', 'type', 'order_created', 'orderId', '123');
330
+
331
+ // Read from stream
332
+ const events = await redis.xrange('events', '-', '+', 'COUNT', 100);
333
+
334
+ // Consumer group
335
+ await redis.xgroup('CREATE', 'events', 'workers', '$', 'MKSTREAM');
336
+
337
+ // Read as consumer
338
+ const messages = await redis.xreadgroup(
339
+ 'GROUP', 'workers', 'worker-1',
340
+ 'COUNT', 10,
341
+ 'BLOCK', 5000,
342
+ 'STREAMS', 'events', '>'
343
+ );
344
+
345
+ // Acknowledge processed message
346
+ await redis.xack('events', 'workers', messageId);
347
+ \`\`\`
348
+
349
+ ## Transactions & Pipelines
350
+ \`\`\`typescript
351
+ // Pipeline (batch commands, no atomicity)
352
+ const pipeline = redis.pipeline();
353
+ pipeline.set('key1', 'value1');
354
+ pipeline.set('key2', 'value2');
355
+ pipeline.get('key1');
356
+ const results = await pipeline.exec();
357
+
358
+ // Transaction (atomic)
359
+ const multi = redis.multi();
360
+ multi.incr('counter');
361
+ multi.set('lastUpdated', Date.now().toString());
362
+ const results = await multi.exec();
363
+
364
+ // Watch for optimistic locking
365
+ await redis.watch('balance');
366
+ const balance = parseInt(await redis.get('balance') || '0');
367
+ if (balance >= 100) {
368
+ const multi = redis.multi();
369
+ multi.decrby('balance', 100);
370
+ multi.incr('purchases');
371
+ await multi.exec(); // Returns null if balance changed
372
+ }
373
+ \`\`\`
374
+
375
+ ## ❌ DON'T
376
+ - Store large values (>100KB)
377
+ - Use KEYS command in production (use SCAN)
378
+ - Forget to set TTL on cache keys
379
+ - Store sensitive data without encryption
380
+ - Use blocking operations on main connection
381
+ - Ignore connection errors/reconnection
382
+
383
+ ## ✅ DO
384
+ - Use appropriate data structures for use case
385
+ - Set TTL for all cache/temporary keys
386
+ - Use pipelines for multiple operations
387
+ - Use connection pooling in high-traffic apps
388
+ - Monitor memory usage
389
+ - Use Lua scripts for complex atomic operations
390
+ - Design clear key naming conventions (namespace:id:field)
391
+ - Use separate connections for pub/sub
@@ -0,0 +1,143 @@
1
+ # Refactoring Skill
2
+
3
+ ## When to Refactor
4
+ - Before adding new features
5
+ - After getting tests passing
6
+ - When you see duplication
7
+ - When code is hard to understand
8
+ - During code review feedback
9
+
10
+ ## Code Smells to Watch For
11
+
12
+ ### Complexity Smells
13
+ - **Long Method**: > 20 lines, hard to understand
14
+ - **Large Class**: Too many responsibilities
15
+ - **Long Parameter List**: > 3 parameters
16
+ - **Deep Nesting**: > 3 levels of indentation
17
+ - **Complex Conditionals**: Hard to follow logic
18
+
19
+ ### Duplication Smells
20
+ - **Repeated Code**: Same logic in multiple places
21
+ - **Similar Classes**: Near-identical structures
22
+ - **Magic Numbers**: Unexplained numeric values
23
+
24
+ ### Coupling Smells
25
+ - **Feature Envy**: Method uses another class's data excessively
26
+ - **Inappropriate Intimacy**: Classes too dependent on each other
27
+ - **Message Chains**: a.getB().getC().getD()
28
+
29
+ ## Common Refactorings
30
+
31
+ ### Extract Function
32
+ \`\`\`typescript
33
+ // ❌ BEFORE
34
+ function processOrder(order) {
35
+ // 30 lines of validation
36
+ // 20 lines of calculation
37
+ // 15 lines of notification
38
+ }
39
+
40
+ // ✅ AFTER
41
+ function processOrder(order) {
42
+ validateOrder(order);
43
+ const total = calculateTotal(order);
44
+ notifyCustomer(order, total);
45
+ }
46
+ \`\`\`
47
+
48
+ ### Replace Conditional with Polymorphism
49
+ \`\`\`typescript
50
+ // ❌ BEFORE
51
+ function getPrice(type) {
52
+ if (type === 'basic') return 10;
53
+ if (type === 'premium') return 20;
54
+ if (type === 'enterprise') return 50;
55
+ }
56
+
57
+ // ✅ AFTER
58
+ const PRICES = { basic: 10, premium: 20, enterprise: 50 };
59
+ const getPrice = (type) => PRICES[type];
60
+ \`\`\`
61
+
62
+ ### Early Return (Guard Clauses)
63
+ \`\`\`typescript
64
+ // ❌ BEFORE
65
+ function process(user) {
66
+ if (user) {
67
+ if (user.isActive) {
68
+ // deep nesting...
69
+ }
70
+ }
71
+ }
72
+
73
+ // ✅ AFTER
74
+ function process(user) {
75
+ if (!user) return;
76
+ if (!user.isActive) return;
77
+ // flat code...
78
+ }
79
+ \`\`\`
80
+
81
+ ### Introduce Parameter Object
82
+ \`\`\`typescript
83
+ // ❌ BEFORE
84
+ function createUser(name, email, age, role, department) { }
85
+
86
+ // ✅ AFTER
87
+ interface CreateUserParams {
88
+ name: string;
89
+ email: string;
90
+ age?: number;
91
+ role: string;
92
+ department: string;
93
+ }
94
+ function createUser(params: CreateUserParams) { }
95
+ \`\`\`
96
+
97
+ ### Replace Magic Numbers
98
+ \`\`\`typescript
99
+ // ❌ BEFORE
100
+ if (user.age >= 18) { }
101
+ setTimeout(fn, 86400000);
102
+
103
+ // ✅ AFTER
104
+ const MINIMUM_AGE = 18;
105
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
106
+ if (user.age >= MINIMUM_AGE) { }
107
+ setTimeout(fn, ONE_DAY_MS);
108
+ \`\`\`
109
+
110
+ ### Strangler Fig Pattern (Large Refactors)
111
+ \`\`\`
112
+ 1. Create new implementation alongside old
113
+ 2. Route traffic gradually to new code
114
+ 3. Monitor for issues
115
+ 4. Remove old code when confident
116
+ \`\`\`
117
+
118
+ ## IDE Shortcuts (VS Code)
119
+
120
+ | Action | Windows/Linux | Mac |
121
+ |--------|---------------|-----|
122
+ | Rename Symbol | F2 | F2 |
123
+ | Extract Function | Ctrl+Shift+R | Cmd+Shift+R |
124
+ | Extract Variable | Ctrl+Shift+R | Cmd+Shift+R |
125
+ | Move Line Up/Down | Alt+↑/↓ | Opt+↑/↓ |
126
+ | Duplicate Line | Shift+Alt+↓ | Shift+Opt+↓ |
127
+ | Delete Line | Ctrl+Shift+K | Cmd+Shift+K |
128
+ | Quick Fix | Ctrl+. | Cmd+. |
129
+ | Go to Definition | F12 | F12 |
130
+ | Find All References | Shift+F12 | Shift+F12 |
131
+
132
+ ## ❌ DON'T
133
+ - Refactor without tests
134
+ - Refactor and add features at same time
135
+ - Make huge changes in one commit
136
+ - Refactor code you don't understand
137
+
138
+ ## ✅ DO
139
+ - Small, incremental changes
140
+ - Run tests after each change
141
+ - Commit frequently
142
+ - Use IDE refactoring tools (safer than manual)
143
+ - Leave code cleaner than you found it