codecruise 0.1.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.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/bin/codecruise.js +68 -0
- package/config/CLAUDE.md +107 -0
- package/config/agents/analyst.md +48 -0
- package/config/agents/architect-reviewer.md +161 -0
- package/config/agents/architect.md +119 -0
- package/config/agents/critic.md +63 -0
- package/config/agents/developer.md +96 -0
- package/config/agents/devops.md +81 -0
- package/config/agents/orchestrator.md +91 -0
- package/config/agents/planner.md +139 -0
- package/config/agents/retro.md +52 -0
- package/config/agents/reviewer.md +101 -0
- package/config/agents/security-reviewer.md +57 -0
- package/config/agents/stack/expo/AGENT.md +473 -0
- package/config/agents/stack/expo/rules/critical.md +427 -0
- package/config/agents/stack/expo/rules/native.md +455 -0
- package/config/agents/stack/expo/rules/navigation.md +445 -0
- package/config/agents/stack/expo/rules/performance.md +415 -0
- package/config/agents/stack/fastify/AGENT.md +397 -0
- package/config/agents/stack/fastify/rules/api-design.md +283 -0
- package/config/agents/stack/fastify/rules/critical.md +232 -0
- package/config/agents/stack/fastify/rules/queues.md +303 -0
- package/config/agents/stack/fastify/rules/security.md +384 -0
- package/config/agents/stack/index.yaml +48 -0
- package/config/agents/stack/nextjs/AGENT.md +421 -0
- package/config/agents/stack/nextjs/rules/components.md +413 -0
- package/config/agents/stack/nextjs/rules/critical.md +391 -0
- package/config/agents/stack/nextjs/rules/performance.md +403 -0
- package/config/agents/stack/nextjs/rules/styling.md +334 -0
- package/config/agents/stack/shared-ts/AGENT.md +384 -0
- package/config/agents/stack/shared-ts/rules/critical.md +315 -0
- package/config/agents/stack/shared-ts/rules/patterns.md +384 -0
- package/config/agents/stack/shared-ts/rules/zod.md +427 -0
- package/config/agents/tester.md +79 -0
- package/config/commands/architect-discuss.md +366 -0
- package/config/commands/architect-list.md +160 -0
- package/config/commands/architect-review.md +111 -0
- package/config/commands/architect.md +118 -0
- package/config/commands/compact.md +118 -0
- package/config/commands/companion.md +279 -0
- package/config/commands/dashboard.md +152 -0
- package/config/commands/doctor.md +227 -0
- package/config/commands/dogfood-report.md +101 -0
- package/config/commands/flags/run-autonomous.md +110 -0
- package/config/commands/flags/run-pause.md +80 -0
- package/config/commands/ingest.md +173 -0
- package/config/commands/init.md +128 -0
- package/config/commands/metrics.md +87 -0
- package/config/commands/parallel.md +320 -0
- package/config/commands/pause.md +55 -0
- package/config/commands/plan-review.md +130 -0
- package/config/commands/plan.md +216 -0
- package/config/commands/production-check.md +308 -0
- package/config/commands/refine.md +323 -0
- package/config/commands/resume.md +72 -0
- package/config/commands/retro.md +121 -0
- package/config/commands/retry.md +75 -0
- package/config/commands/role.md +310 -0
- package/config/commands/run.md +417 -0
- package/config/commands/scope.md +85 -0
- package/config/commands/setup-permissions.md +104 -0
- package/config/commands/skip.md +75 -0
- package/config/commands/spec-forge.md +213 -0
- package/config/commands/spec-help.md +194 -0
- package/config/commands/spec-patch.md +342 -0
- package/config/commands/spec-resolve.md +110 -0
- package/config/commands/spec-review.md +153 -0
- package/config/commands/status.md +114 -0
- package/config/commands/sync.md +131 -0
- package/config/commands/task.md +138 -0
- package/config/commands/verify.md +124 -0
- package/config/hooks/README.md +632 -0
- package/config/hooks/activity-log.sh +187 -0
- package/config/hooks/anti-rationalize.sh +52 -0
- package/config/hooks/capture-verification.sh +112 -0
- package/config/hooks/collect-metrics.sh +135 -0
- package/config/hooks/enforce-file-scope.sh +75 -0
- package/config/hooks/enforce-state-machine.sh +161 -0
- package/config/hooks/enforce-tdd.sh +180 -0
- package/config/hooks/format.sh +40 -0
- package/config/hooks/lib/activity-helpers.sh +162 -0
- package/config/hooks/lib/read-settings.sh +71 -0
- package/config/hooks/load-context-skills.sh +95 -0
- package/config/hooks/notify.sh +81 -0
- package/config/hooks/pre-commit.sample +35 -0
- package/config/hooks/protect-files.sh +63 -0
- package/config/hooks/track-agents.sh +41 -0
- package/config/hooks/track-commands.sh +37 -0
- package/config/hooks/track-enforcement.sh +44 -0
- package/config/hooks/track-ooda.sh +77 -0
- package/config/hooks/validate-commit-msg.sh +35 -0
- package/config/hooks/validate-plan.sh +213 -0
- package/config/hooks/verify-criteria.sh +46 -0
- package/config/hooks/verify-todo-completion.sh +140 -0
- package/config/rules/comments.md +25 -0
- package/config/rules/decision-rules.md +308 -0
- package/config/rules/hygiene.md +247 -0
- package/config/rules/pattern-detection.md +372 -0
- package/config/rules/profiles.md +193 -0
- package/config/rules/recovery.md +83 -0
- package/config/rules/scope-detection.md +213 -0
- package/config/rules/standards.md +127 -0
- package/config/rules/workflow.md +121 -0
- package/config/schemas.md +767 -0
- package/config/settings.json +195 -0
- package/config/skills/backend/SKILL.md +734 -0
- package/config/skills/database/SKILL.md +426 -0
- package/config/skills/frontend/SKILL.md +434 -0
- package/config/skills/git/SKILL.md +396 -0
- package/config/skills/index.yaml +36 -0
- package/config/skills/observability/SKILL.md +430 -0
- package/config/skills/package-dev/SKILL.md +498 -0
- package/config/skills/performance/SKILL.md +378 -0
- package/config/skills/resilience/SKILL.md +573 -0
- package/config/skills/testing/SKILL.md +398 -0
- package/config/skills/testing-patterns/SKILL.md +276 -0
- package/config/skills/typescript/SKILL.md +152 -0
- package/config/templates/CLAUDE.md +70 -0
- package/config/templates/README.md +117 -0
- package/config/templates/steering/adr-template.md +102 -0
- package/config/templates/steering/product.md +60 -0
- package/config/templates/steering/rfc-template.md +159 -0
- package/config/templates/steering/structure.md +146 -0
- package/config/templates/steering/tech.md +85 -0
- package/package.json +40 -0
- package/src/install.js +163 -0
- package/src/report.js +310 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: performance-patterns
|
|
3
|
+
description: Caching, optimization, scaling - cache strategies, lazy loading, profiling
|
|
4
|
+
keywords: [performance, caching, optimization, lazy load, profiling, bundle size, redis, cdn]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Performance Patterns
|
|
8
|
+
|
|
9
|
+
Caching, optimization, and scaling strategies.
|
|
10
|
+
|
|
11
|
+
## Priority Order
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Measure → Profile → Optimize → Measure Again
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Never optimize without data. Premature optimization is the root of evil.
|
|
18
|
+
|
|
19
|
+
## Caching Strategy
|
|
20
|
+
|
|
21
|
+
### Cache Hierarchy
|
|
22
|
+
|
|
23
|
+
| Layer | Use Case | TTL | Invalidation |
|
|
24
|
+
|-------|----------|-----|--------------|
|
|
25
|
+
| Browser | Static assets | Long (1 year) | Versioned URLs |
|
|
26
|
+
| CDN | Public pages, images | Medium (1 hour) | Purge API |
|
|
27
|
+
| Redis | Session, hot data | Short (5-15 min) | On write |
|
|
28
|
+
| Memory | Computed values | Very short (1 min) | Process restart |
|
|
29
|
+
|
|
30
|
+
### Cache-Aside Pattern
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
async function getUser(id: string): Promise<User> {
|
|
34
|
+
const cacheKey = `user:${id}`;
|
|
35
|
+
|
|
36
|
+
// Try cache first
|
|
37
|
+
const cached = await redis.get(cacheKey);
|
|
38
|
+
if (cached) {
|
|
39
|
+
return JSON.parse(cached);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Cache miss - fetch from DB
|
|
43
|
+
const user = await db.user.findUnique({ where: { id } });
|
|
44
|
+
|
|
45
|
+
if (user) {
|
|
46
|
+
// Write to cache (non-blocking)
|
|
47
|
+
redis.setex(cacheKey, 300, JSON.stringify(user)).catch(() => {});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return user;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Invalidate on update
|
|
54
|
+
async function updateUser(id: string, data: UpdateUserInput): Promise<User> {
|
|
55
|
+
const user = await db.user.update({
|
|
56
|
+
where: { id },
|
|
57
|
+
data,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Invalidate cache
|
|
61
|
+
await redis.del(`user:${id}`);
|
|
62
|
+
|
|
63
|
+
return user;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Stale-While-Revalidate
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
interface CacheOptions {
|
|
71
|
+
ttl: number; // Fresh duration
|
|
72
|
+
staleTTL: number; // Stale-but-usable duration
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function getWithSWR<T>(
|
|
76
|
+
key: string,
|
|
77
|
+
fetcher: () => Promise<T>,
|
|
78
|
+
options: CacheOptions
|
|
79
|
+
): Promise<T> {
|
|
80
|
+
const cached = await redis.get(key);
|
|
81
|
+
|
|
82
|
+
if (cached) {
|
|
83
|
+
const { data, timestamp } = JSON.parse(cached);
|
|
84
|
+
const age = Date.now() - timestamp;
|
|
85
|
+
|
|
86
|
+
// Fresh - return immediately
|
|
87
|
+
if (age < options.ttl) {
|
|
88
|
+
return data;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Stale but usable - return and revalidate
|
|
92
|
+
if (age < options.staleTTL) {
|
|
93
|
+
// Revalidate in background (non-blocking)
|
|
94
|
+
fetcher().then((fresh) => {
|
|
95
|
+
redis.setex(key, options.staleTTL / 1000, JSON.stringify({
|
|
96
|
+
data: fresh,
|
|
97
|
+
timestamp: Date.now(),
|
|
98
|
+
}));
|
|
99
|
+
}).catch(() => {});
|
|
100
|
+
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// No cache or expired - fetch fresh
|
|
106
|
+
const fresh = await fetcher();
|
|
107
|
+
|
|
108
|
+
await redis.setex(key, options.staleTTL / 1000, JSON.stringify({
|
|
109
|
+
data: fresh,
|
|
110
|
+
timestamp: Date.now(),
|
|
111
|
+
}));
|
|
112
|
+
|
|
113
|
+
return fresh;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Database Optimization
|
|
118
|
+
|
|
119
|
+
### Query Performance
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// ❌ N+1 Query (blocker)
|
|
123
|
+
const users = await db.user.findMany();
|
|
124
|
+
for (const user of users) {
|
|
125
|
+
const posts = await db.post.findMany({ where: { userId: user.id } });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ✅ Eager loading
|
|
129
|
+
const users = await db.user.findMany({
|
|
130
|
+
include: { posts: true },
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ✅ Selective fields
|
|
134
|
+
const users = await db.user.findMany({
|
|
135
|
+
select: {
|
|
136
|
+
id: true,
|
|
137
|
+
email: true,
|
|
138
|
+
posts: {
|
|
139
|
+
select: { id: true, title: true },
|
|
140
|
+
take: 5,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Pagination
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// ❌ OFFSET (slow on large datasets)
|
|
150
|
+
const page10 = await db.post.findMany({
|
|
151
|
+
skip: 900,
|
|
152
|
+
take: 100,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// ✅ Cursor-based (constant time)
|
|
156
|
+
const page10 = await db.post.findMany({
|
|
157
|
+
take: 100,
|
|
158
|
+
cursor: { id: lastSeenId },
|
|
159
|
+
skip: 1,
|
|
160
|
+
orderBy: { createdAt: 'desc' },
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Indexing Rules
|
|
165
|
+
|
|
166
|
+
| Query Pattern | Index |
|
|
167
|
+
|---------------|-------|
|
|
168
|
+
| WHERE column = value | Single column index |
|
|
169
|
+
| WHERE a = x AND b = y | Composite index (a, b) |
|
|
170
|
+
| ORDER BY column | Index on column |
|
|
171
|
+
| Foreign key | Always index |
|
|
172
|
+
| Full-text search | GIN/GIST index |
|
|
173
|
+
|
|
174
|
+
## API Response Optimization
|
|
175
|
+
|
|
176
|
+
### Field Selection
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// Allow clients to select fields
|
|
180
|
+
// GET /users?fields=id,name,email
|
|
181
|
+
export async function GET(request: NextRequest) {
|
|
182
|
+
const fields = request.nextUrl.searchParams.get('fields')?.split(',');
|
|
183
|
+
|
|
184
|
+
const select = fields?.reduce((acc, field) => {
|
|
185
|
+
acc[field] = true;
|
|
186
|
+
return acc;
|
|
187
|
+
}, {} as Record<string, boolean>);
|
|
188
|
+
|
|
189
|
+
const users = await db.user.findMany({
|
|
190
|
+
select: select || undefined,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return NextResponse.json({ data: users });
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Compression
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// Next.js config
|
|
201
|
+
module.exports = {
|
|
202
|
+
compress: true,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Manual for API routes
|
|
206
|
+
import { gzip } from 'zlib';
|
|
207
|
+
import { promisify } from 'util';
|
|
208
|
+
|
|
209
|
+
const gzipAsync = promisify(gzip);
|
|
210
|
+
|
|
211
|
+
export async function GET() {
|
|
212
|
+
const data = await getLargeDataset();
|
|
213
|
+
const compressed = await gzipAsync(JSON.stringify(data));
|
|
214
|
+
|
|
215
|
+
return new Response(compressed, {
|
|
216
|
+
headers: {
|
|
217
|
+
'Content-Type': 'application/json',
|
|
218
|
+
'Content-Encoding': 'gzip',
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Frontend Performance
|
|
225
|
+
|
|
226
|
+
### Code Splitting
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Dynamic imports for heavy components
|
|
230
|
+
import dynamic from 'next/dynamic';
|
|
231
|
+
|
|
232
|
+
const HeavyChart = dynamic(() => import('@/components/Chart'), {
|
|
233
|
+
loading: () => <ChartSkeleton />,
|
|
234
|
+
ssr: false,
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Image Optimization
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import Image from 'next/image';
|
|
242
|
+
|
|
243
|
+
// Always use next/image
|
|
244
|
+
<Image
|
|
245
|
+
src="/hero.jpg"
|
|
246
|
+
alt="Hero"
|
|
247
|
+
width={1200}
|
|
248
|
+
height={600}
|
|
249
|
+
priority // Above the fold
|
|
250
|
+
placeholder="blur" // Smooth loading
|
|
251
|
+
/>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Bundle Analysis
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Analyze bundle size
|
|
258
|
+
ANALYZE=true pnpm build
|
|
259
|
+
|
|
260
|
+
# Size limits in package.json
|
|
261
|
+
{
|
|
262
|
+
"size-limit": [
|
|
263
|
+
{ "path": ".next/static/chunks/*.js", "limit": "200 KB" }
|
|
264
|
+
]
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Async Patterns
|
|
269
|
+
|
|
270
|
+
### Background Jobs
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Don't block response for non-critical work
|
|
274
|
+
export async function POST(request: NextRequest) {
|
|
275
|
+
const order = await createOrder(request);
|
|
276
|
+
|
|
277
|
+
// Non-blocking: queue for later
|
|
278
|
+
await queue.add('send-confirmation', { orderId: order.id });
|
|
279
|
+
await queue.add('update-inventory', { items: order.items });
|
|
280
|
+
await queue.add('notify-warehouse', { orderId: order.id });
|
|
281
|
+
|
|
282
|
+
// Return immediately
|
|
283
|
+
return NextResponse.json({ data: order }, { status: 201 });
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Parallel Fetching
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// ❌ Sequential (slow)
|
|
291
|
+
const user = await getUser(id);
|
|
292
|
+
const orders = await getOrders(id);
|
|
293
|
+
const recommendations = await getRecommendations(id);
|
|
294
|
+
|
|
295
|
+
// ✅ Parallel (fast)
|
|
296
|
+
const [user, orders, recommendations] = await Promise.all([
|
|
297
|
+
getUser(id),
|
|
298
|
+
getOrders(id),
|
|
299
|
+
getRecommendations(id),
|
|
300
|
+
]);
|
|
301
|
+
|
|
302
|
+
// ✅ With error isolation
|
|
303
|
+
const [user, orders, recommendations] = await Promise.allSettled([
|
|
304
|
+
getUser(id),
|
|
305
|
+
getOrders(id),
|
|
306
|
+
getRecommendations(id),
|
|
307
|
+
]);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Rate Limiting
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { Ratelimit } from '@upstash/ratelimit';
|
|
314
|
+
import { Redis } from '@upstash/redis';
|
|
315
|
+
|
|
316
|
+
const ratelimit = new Ratelimit({
|
|
317
|
+
redis: Redis.fromEnv(),
|
|
318
|
+
limiter: Ratelimit.slidingWindow(10, '10 s'),
|
|
319
|
+
analytics: true,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
export async function middleware(request: NextRequest) {
|
|
323
|
+
const ip = request.ip ?? '127.0.0.1';
|
|
324
|
+
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
|
|
325
|
+
|
|
326
|
+
if (!success) {
|
|
327
|
+
return NextResponse.json(
|
|
328
|
+
{ error: 'Too many requests' },
|
|
329
|
+
{
|
|
330
|
+
status: 429,
|
|
331
|
+
headers: {
|
|
332
|
+
'X-RateLimit-Limit': limit.toString(),
|
|
333
|
+
'X-RateLimit-Remaining': remaining.toString(),
|
|
334
|
+
'X-RateLimit-Reset': reset.toString(),
|
|
335
|
+
},
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return NextResponse.next();
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Profiling Commands
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Node.js profiling
|
|
348
|
+
node --inspect dist/server.js
|
|
349
|
+
# Then open chrome://inspect
|
|
350
|
+
|
|
351
|
+
# Database query logging
|
|
352
|
+
DATABASE_URL="...?log=query"
|
|
353
|
+
|
|
354
|
+
# Bundle analysis
|
|
355
|
+
ANALYZE=true next build
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Performance Budgets
|
|
359
|
+
|
|
360
|
+
| Metric | Target | Maximum |
|
|
361
|
+
|--------|--------|---------|
|
|
362
|
+
| First Contentful Paint | < 1.5s | < 2.5s |
|
|
363
|
+
| Time to Interactive | < 3s | < 5s |
|
|
364
|
+
| API Response (p95) | < 200ms | < 500ms |
|
|
365
|
+
| DB Query (p95) | < 50ms | < 200ms |
|
|
366
|
+
| Bundle Size (JS) | < 150KB | < 300KB |
|
|
367
|
+
|
|
368
|
+
## Quality Checklist
|
|
369
|
+
|
|
370
|
+
- [ ] No N+1 queries
|
|
371
|
+
- [ ] Cache strategy for hot data
|
|
372
|
+
- [ ] Cursor pagination for lists
|
|
373
|
+
- [ ] Images optimized (next/image)
|
|
374
|
+
- [ ] Code splitting for heavy components
|
|
375
|
+
- [ ] API responses compressed
|
|
376
|
+
- [ ] Rate limiting in place
|
|
377
|
+
- [ ] Performance budgets defined
|
|
378
|
+
- [ ] Profiling done before optimization
|