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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/bin/codecruise.js +68 -0
  4. package/config/CLAUDE.md +107 -0
  5. package/config/agents/analyst.md +48 -0
  6. package/config/agents/architect-reviewer.md +161 -0
  7. package/config/agents/architect.md +119 -0
  8. package/config/agents/critic.md +63 -0
  9. package/config/agents/developer.md +96 -0
  10. package/config/agents/devops.md +81 -0
  11. package/config/agents/orchestrator.md +91 -0
  12. package/config/agents/planner.md +139 -0
  13. package/config/agents/retro.md +52 -0
  14. package/config/agents/reviewer.md +101 -0
  15. package/config/agents/security-reviewer.md +57 -0
  16. package/config/agents/stack/expo/AGENT.md +473 -0
  17. package/config/agents/stack/expo/rules/critical.md +427 -0
  18. package/config/agents/stack/expo/rules/native.md +455 -0
  19. package/config/agents/stack/expo/rules/navigation.md +445 -0
  20. package/config/agents/stack/expo/rules/performance.md +415 -0
  21. package/config/agents/stack/fastify/AGENT.md +397 -0
  22. package/config/agents/stack/fastify/rules/api-design.md +283 -0
  23. package/config/agents/stack/fastify/rules/critical.md +232 -0
  24. package/config/agents/stack/fastify/rules/queues.md +303 -0
  25. package/config/agents/stack/fastify/rules/security.md +384 -0
  26. package/config/agents/stack/index.yaml +48 -0
  27. package/config/agents/stack/nextjs/AGENT.md +421 -0
  28. package/config/agents/stack/nextjs/rules/components.md +413 -0
  29. package/config/agents/stack/nextjs/rules/critical.md +391 -0
  30. package/config/agents/stack/nextjs/rules/performance.md +403 -0
  31. package/config/agents/stack/nextjs/rules/styling.md +334 -0
  32. package/config/agents/stack/shared-ts/AGENT.md +384 -0
  33. package/config/agents/stack/shared-ts/rules/critical.md +315 -0
  34. package/config/agents/stack/shared-ts/rules/patterns.md +384 -0
  35. package/config/agents/stack/shared-ts/rules/zod.md +427 -0
  36. package/config/agents/tester.md +79 -0
  37. package/config/commands/architect-discuss.md +366 -0
  38. package/config/commands/architect-list.md +160 -0
  39. package/config/commands/architect-review.md +111 -0
  40. package/config/commands/architect.md +118 -0
  41. package/config/commands/compact.md +118 -0
  42. package/config/commands/companion.md +279 -0
  43. package/config/commands/dashboard.md +152 -0
  44. package/config/commands/doctor.md +227 -0
  45. package/config/commands/dogfood-report.md +101 -0
  46. package/config/commands/flags/run-autonomous.md +110 -0
  47. package/config/commands/flags/run-pause.md +80 -0
  48. package/config/commands/ingest.md +173 -0
  49. package/config/commands/init.md +128 -0
  50. package/config/commands/metrics.md +87 -0
  51. package/config/commands/parallel.md +320 -0
  52. package/config/commands/pause.md +55 -0
  53. package/config/commands/plan-review.md +130 -0
  54. package/config/commands/plan.md +216 -0
  55. package/config/commands/production-check.md +308 -0
  56. package/config/commands/refine.md +323 -0
  57. package/config/commands/resume.md +72 -0
  58. package/config/commands/retro.md +121 -0
  59. package/config/commands/retry.md +75 -0
  60. package/config/commands/role.md +310 -0
  61. package/config/commands/run.md +417 -0
  62. package/config/commands/scope.md +85 -0
  63. package/config/commands/setup-permissions.md +104 -0
  64. package/config/commands/skip.md +75 -0
  65. package/config/commands/spec-forge.md +213 -0
  66. package/config/commands/spec-help.md +194 -0
  67. package/config/commands/spec-patch.md +342 -0
  68. package/config/commands/spec-resolve.md +110 -0
  69. package/config/commands/spec-review.md +153 -0
  70. package/config/commands/status.md +114 -0
  71. package/config/commands/sync.md +131 -0
  72. package/config/commands/task.md +138 -0
  73. package/config/commands/verify.md +124 -0
  74. package/config/hooks/README.md +632 -0
  75. package/config/hooks/activity-log.sh +187 -0
  76. package/config/hooks/anti-rationalize.sh +52 -0
  77. package/config/hooks/capture-verification.sh +112 -0
  78. package/config/hooks/collect-metrics.sh +135 -0
  79. package/config/hooks/enforce-file-scope.sh +75 -0
  80. package/config/hooks/enforce-state-machine.sh +161 -0
  81. package/config/hooks/enforce-tdd.sh +180 -0
  82. package/config/hooks/format.sh +40 -0
  83. package/config/hooks/lib/activity-helpers.sh +162 -0
  84. package/config/hooks/lib/read-settings.sh +71 -0
  85. package/config/hooks/load-context-skills.sh +95 -0
  86. package/config/hooks/notify.sh +81 -0
  87. package/config/hooks/pre-commit.sample +35 -0
  88. package/config/hooks/protect-files.sh +63 -0
  89. package/config/hooks/track-agents.sh +41 -0
  90. package/config/hooks/track-commands.sh +37 -0
  91. package/config/hooks/track-enforcement.sh +44 -0
  92. package/config/hooks/track-ooda.sh +77 -0
  93. package/config/hooks/validate-commit-msg.sh +35 -0
  94. package/config/hooks/validate-plan.sh +213 -0
  95. package/config/hooks/verify-criteria.sh +46 -0
  96. package/config/hooks/verify-todo-completion.sh +140 -0
  97. package/config/rules/comments.md +25 -0
  98. package/config/rules/decision-rules.md +308 -0
  99. package/config/rules/hygiene.md +247 -0
  100. package/config/rules/pattern-detection.md +372 -0
  101. package/config/rules/profiles.md +193 -0
  102. package/config/rules/recovery.md +83 -0
  103. package/config/rules/scope-detection.md +213 -0
  104. package/config/rules/standards.md +127 -0
  105. package/config/rules/workflow.md +121 -0
  106. package/config/schemas.md +767 -0
  107. package/config/settings.json +195 -0
  108. package/config/skills/backend/SKILL.md +734 -0
  109. package/config/skills/database/SKILL.md +426 -0
  110. package/config/skills/frontend/SKILL.md +434 -0
  111. package/config/skills/git/SKILL.md +396 -0
  112. package/config/skills/index.yaml +36 -0
  113. package/config/skills/observability/SKILL.md +430 -0
  114. package/config/skills/package-dev/SKILL.md +498 -0
  115. package/config/skills/performance/SKILL.md +378 -0
  116. package/config/skills/resilience/SKILL.md +573 -0
  117. package/config/skills/testing/SKILL.md +398 -0
  118. package/config/skills/testing-patterns/SKILL.md +276 -0
  119. package/config/skills/typescript/SKILL.md +152 -0
  120. package/config/templates/CLAUDE.md +70 -0
  121. package/config/templates/README.md +117 -0
  122. package/config/templates/steering/adr-template.md +102 -0
  123. package/config/templates/steering/product.md +60 -0
  124. package/config/templates/steering/rfc-template.md +159 -0
  125. package/config/templates/steering/structure.md +146 -0
  126. package/config/templates/steering/tech.md +85 -0
  127. package/package.json +40 -0
  128. package/src/install.js +163 -0
  129. package/src/report.js +310 -0
@@ -0,0 +1,391 @@
1
+ # Critical Rules - Next.js
2
+
3
+ Must-follow rules. Violations block PR merge.
4
+
5
+ ---
6
+
7
+ ## Component Model
8
+
9
+ ### NEXT-001: Default to Server Components
10
+
11
+ ```typescript
12
+ // GOOD - Server Component (default)
13
+ async function UserList() {
14
+ const users = await getUsers(); // Direct server fetch
15
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
16
+ }
17
+
18
+ // BAD - Unnecessary client component
19
+ 'use client';
20
+ import { useEffect, useState } from 'react';
21
+
22
+ function UserList() {
23
+ const [users, setUsers] = useState([]);
24
+ useEffect(() => {
25
+ fetch('/api/users').then(r => r.json()).then(setUsers);
26
+ }, []);
27
+ // ... waterfall, slower
28
+ }
29
+ ```
30
+
31
+ ### NEXT-002: Mark client components explicitly
32
+
33
+ ```typescript
34
+ // Required for:
35
+ // - useState, useEffect, useRef
36
+ // - onClick, onChange, onSubmit
37
+ // - Browser APIs (localStorage, window)
38
+ // - Third-party hooks
39
+
40
+ 'use client'; // Must be first line
41
+
42
+ import { useState } from 'react';
43
+
44
+ export function Counter() {
45
+ const [count, setCount] = useState(0);
46
+ return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
47
+ }
48
+ ```
49
+
50
+ ### NEXT-003: Minimize client component boundaries
51
+
52
+ ```typescript
53
+ // BAD - Entire page is client
54
+ 'use client';
55
+ export default function DashboardPage() {
56
+ const [filter, setFilter] = useState('all');
57
+ const users = useUsers(); // All rendering on client
58
+ return <div>...</div>;
59
+ }
60
+
61
+ // GOOD - Only interactive parts are client
62
+ export default async function DashboardPage() {
63
+ const users = await getUsers(); // Server fetch
64
+
65
+ return (
66
+ <div>
67
+ <FilterBar /> {/* Client component for interactivity */}
68
+ <UserList users={users} /> {/* Server component with data */}
69
+ </div>
70
+ );
71
+ }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Data Fetching
77
+
78
+ ### NEXT-004: Use Server Actions for mutations
79
+
80
+ ```typescript
81
+ // BAD - API route for simple mutation
82
+ // app/api/users/route.ts + client fetch
83
+
84
+ // GOOD - Server Action
85
+ // app/actions/user.ts
86
+ 'use server';
87
+
88
+ import { revalidatePath } from 'next/cache';
89
+
90
+ export async function createUser(formData: FormData) {
91
+ const data = Object.fromEntries(formData);
92
+ await db.user.create({ data });
93
+ revalidatePath('/users');
94
+ }
95
+
96
+ // In component
97
+ <form action={createUser}>...</form>
98
+ ```
99
+
100
+ ### NEXT-005: Validate all inputs in Server Actions
101
+
102
+ ```typescript
103
+ 'use server';
104
+
105
+ import { z } from 'zod';
106
+
107
+ const schema = z.object({
108
+ email: z.string().email(),
109
+ name: z.string().min(2),
110
+ });
111
+
112
+ export async function createUser(formData: FormData) {
113
+ const raw = Object.fromEntries(formData);
114
+
115
+ // Always validate - formData can be spoofed
116
+ const result = schema.safeParse(raw);
117
+ if (!result.success) {
118
+ return { error: 'Invalid input', details: result.error.flatten() };
119
+ }
120
+
121
+ await db.user.create({ data: result.data });
122
+ return { success: true };
123
+ }
124
+ ```
125
+
126
+ ### NEXT-006: Handle loading and error states
127
+
128
+ ```typescript
129
+ // With Suspense
130
+ import { Suspense } from 'react';
131
+ import { ErrorBoundary } from 'react-error-boundary';
132
+
133
+ export default function Page() {
134
+ return (
135
+ <ErrorBoundary fallback={<ErrorState />}>
136
+ <Suspense fallback={<LoadingState />}>
137
+ <AsyncComponent />
138
+ </Suspense>
139
+ </ErrorBoundary>
140
+ );
141
+ }
142
+
143
+ // With loading.tsx and error.tsx
144
+ // app/dashboard/loading.tsx
145
+ export default function Loading() {
146
+ return <Skeleton className="h-96" />;
147
+ }
148
+
149
+ // app/dashboard/error.tsx
150
+ 'use client';
151
+ export default function Error({ error, reset }) {
152
+ return (
153
+ <div>
154
+ <p>Something went wrong</p>
155
+ <Button onClick={reset}>Try again</Button>
156
+ </div>
157
+ );
158
+ }
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Security
164
+
165
+ ### NEXT-007: Never expose secrets to client
166
+
167
+ ```typescript
168
+ // BAD - Exposed to client bundle
169
+ const API_KEY = process.env.API_KEY;
170
+
171
+ // GOOD - Server-only
172
+ // In Server Component or Server Action
173
+ const API_KEY = process.env.API_KEY; // Only accessible on server
174
+
175
+ // Or explicitly mark
176
+ import 'server-only';
177
+ export const secret = process.env.SECRET;
178
+ ```
179
+
180
+ ### NEXT-008: Validate auth in Server Actions
181
+
182
+ ```typescript
183
+ 'use server';
184
+
185
+ import { getSession } from '@/lib/auth';
186
+ import { redirect } from 'next/navigation';
187
+
188
+ export async function deleteUser(userId: string) {
189
+ const session = await getSession();
190
+
191
+ // Always check auth
192
+ if (!session) {
193
+ redirect('/login');
194
+ }
195
+
196
+ // Check authorization
197
+ if (session.user.role !== 'ADMIN') {
198
+ throw new Error('Unauthorized');
199
+ }
200
+
201
+ await db.user.delete({ where: { id: userId } });
202
+ }
203
+ ```
204
+
205
+ ### NEXT-009: Sanitize user-generated content
206
+
207
+ ```typescript
208
+ import DOMPurify from 'isomorphic-dompurify';
209
+
210
+ // For rendering user HTML
211
+ function UserContent({ html }: { html: string }) {
212
+ const clean = DOMPurify.sanitize(html, {
213
+ ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p'],
214
+ ALLOWED_ATTR: ['href'],
215
+ });
216
+
217
+ return <div dangerouslySetInnerHTML={{ __html: clean }} />;
218
+ }
219
+
220
+ // Prefer structured content over raw HTML
221
+ function UserBio({ bio }: { bio: string }) {
222
+ // Just text, no HTML
223
+ return <p className="whitespace-pre-wrap">{bio}</p>;
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Routing
230
+
231
+ ### NEXT-010: Use proper navigation methods
232
+
233
+ ```typescript
234
+ // For links - use Link component
235
+ import Link from 'next/link';
236
+ <Link href="/dashboard">Dashboard</Link>
237
+
238
+ // For programmatic navigation in Client Components
239
+ 'use client';
240
+ import { useRouter } from 'next/navigation';
241
+ const router = useRouter();
242
+ router.push('/dashboard');
243
+
244
+ // For Server Actions/Components
245
+ import { redirect } from 'next/navigation';
246
+ redirect('/dashboard'); // Throws, stops execution
247
+ ```
248
+
249
+ ### NEXT-011: Protect routes at layout level
250
+
251
+ ```typescript
252
+ // app/dashboard/layout.tsx
253
+ import { getSession } from '@/lib/auth';
254
+ import { redirect } from 'next/navigation';
255
+
256
+ export default async function DashboardLayout({
257
+ children,
258
+ }: {
259
+ children: React.ReactNode;
260
+ }) {
261
+ const session = await getSession();
262
+
263
+ if (!session) {
264
+ redirect('/login');
265
+ }
266
+
267
+ return (
268
+ <div className="flex">
269
+ <Sidebar user={session.user} />
270
+ <main className="flex-1">{children}</main>
271
+ </div>
272
+ );
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Rendering
279
+
280
+ ### NEXT-012: Add proper metadata
281
+
282
+ ```typescript
283
+ // Static metadata
284
+ export const metadata = {
285
+ title: 'Dashboard',
286
+ description: 'Your dashboard overview',
287
+ };
288
+
289
+ // Dynamic metadata
290
+ export async function generateMetadata({ params }) {
291
+ const user = await getUser(params.id);
292
+ return {
293
+ title: user.name,
294
+ description: `Profile of ${user.name}`,
295
+ };
296
+ }
297
+
298
+ // With template
299
+ // app/layout.tsx
300
+ export const metadata = {
301
+ title: {
302
+ template: '%s | MyApp',
303
+ default: 'MyApp',
304
+ },
305
+ };
306
+ ```
307
+
308
+ ### NEXT-013: Use Image component for images
309
+
310
+ ```typescript
311
+ // BAD
312
+ <img src="/hero.jpg" alt="Hero" />
313
+
314
+ // GOOD
315
+ import Image from 'next/image';
316
+
317
+ <Image
318
+ src="/hero.jpg"
319
+ alt="Hero image"
320
+ width={1200}
321
+ height={600}
322
+ priority // For above-the-fold images
323
+ />
324
+
325
+ // For fill mode
326
+ <div className="relative h-64">
327
+ <Image
328
+ src={user.avatar}
329
+ alt={user.name}
330
+ fill
331
+ className="object-cover"
332
+ sizes="(max-width: 768px) 100vw, 50vw"
333
+ />
334
+ </div>
335
+ ```
336
+
337
+ ---
338
+
339
+ ## State Management
340
+
341
+ ### NEXT-014: Avoid unnecessary client state
342
+
343
+ ```typescript
344
+ // BAD - Client state for server data
345
+ 'use client';
346
+ const [users, setUsers] = useState([]);
347
+ useEffect(() => {
348
+ fetchUsers().then(setUsers);
349
+ }, []);
350
+
351
+ // GOOD - Server fetch, no client state needed
352
+ async function UserList() {
353
+ const users = await getUsers();
354
+ return <ul>...</ul>;
355
+ }
356
+
357
+ // OK - Client state for UI state only
358
+ 'use client';
359
+ const [isOpen, setIsOpen] = useState(false);
360
+ const [filter, setFilter] = useState('all');
361
+ ```
362
+
363
+ ### NEXT-015: Use URL state for shareable state
364
+
365
+ ```typescript
366
+ 'use client';
367
+
368
+ import { useSearchParams, useRouter, usePathname } from 'next/navigation';
369
+
370
+ function FilterBar() {
371
+ const searchParams = useSearchParams();
372
+ const router = useRouter();
373
+ const pathname = usePathname();
374
+
375
+ function setFilter(value: string) {
376
+ const params = new URLSearchParams(searchParams);
377
+ params.set('filter', value);
378
+ router.push(`${pathname}?${params.toString()}`);
379
+ }
380
+
381
+ return (
382
+ <select
383
+ value={searchParams.get('filter') ?? 'all'}
384
+ onChange={(e) => setFilter(e.target.value)}
385
+ >
386
+ <option value="all">All</option>
387
+ <option value="active">Active</option>
388
+ </select>
389
+ );
390
+ }
391
+ ```