red64-cli 0.1.0 → 0.2.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 (103) hide show
  1. package/dist/cli/parseArgs.d.ts.map +1 -1
  2. package/dist/cli/parseArgs.js +5 -0
  3. package/dist/cli/parseArgs.js.map +1 -1
  4. package/dist/components/init/CompleteStep.d.ts.map +1 -1
  5. package/dist/components/init/CompleteStep.js +2 -2
  6. package/dist/components/init/CompleteStep.js.map +1 -1
  7. package/dist/components/init/TestCheckStep.d.ts +16 -0
  8. package/dist/components/init/TestCheckStep.d.ts.map +1 -0
  9. package/dist/components/init/TestCheckStep.js +120 -0
  10. package/dist/components/init/TestCheckStep.js.map +1 -0
  11. package/dist/components/init/index.d.ts +1 -0
  12. package/dist/components/init/index.d.ts.map +1 -1
  13. package/dist/components/init/index.js +1 -0
  14. package/dist/components/init/index.js.map +1 -1
  15. package/dist/components/init/types.d.ts +9 -0
  16. package/dist/components/init/types.d.ts.map +1 -1
  17. package/dist/components/screens/InitScreen.d.ts.map +1 -1
  18. package/dist/components/screens/InitScreen.js +69 -6
  19. package/dist/components/screens/InitScreen.js.map +1 -1
  20. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  21. package/dist/components/screens/StartScreen.js +89 -3
  22. package/dist/components/screens/StartScreen.js.map +1 -1
  23. package/dist/services/ConfigService.d.ts +1 -0
  24. package/dist/services/ConfigService.d.ts.map +1 -1
  25. package/dist/services/ConfigService.js.map +1 -1
  26. package/dist/services/ProjectDetector.d.ts +28 -0
  27. package/dist/services/ProjectDetector.d.ts.map +1 -0
  28. package/dist/services/ProjectDetector.js +236 -0
  29. package/dist/services/ProjectDetector.js.map +1 -0
  30. package/dist/services/TestRunner.d.ts +46 -0
  31. package/dist/services/TestRunner.d.ts.map +1 -0
  32. package/dist/services/TestRunner.js +85 -0
  33. package/dist/services/TestRunner.js.map +1 -0
  34. package/dist/services/index.d.ts +2 -0
  35. package/dist/services/index.d.ts.map +1 -1
  36. package/dist/services/index.js +2 -0
  37. package/dist/services/index.js.map +1 -1
  38. package/dist/types/index.d.ts +1 -0
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/index.js.map +1 -1
  41. package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
  42. package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
  43. package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
  44. package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
  45. package/framework/stacks/generic/feedback.md +80 -0
  46. package/framework/stacks/nextjs/accessibility.md +437 -0
  47. package/framework/stacks/nextjs/api.md +431 -0
  48. package/framework/stacks/nextjs/coding-style.md +282 -0
  49. package/framework/stacks/nextjs/commenting.md +226 -0
  50. package/framework/stacks/nextjs/components.md +411 -0
  51. package/framework/stacks/nextjs/conventions.md +333 -0
  52. package/framework/stacks/nextjs/css.md +310 -0
  53. package/framework/stacks/nextjs/error-handling.md +442 -0
  54. package/framework/stacks/nextjs/feedback.md +124 -0
  55. package/framework/stacks/nextjs/migrations.md +332 -0
  56. package/framework/stacks/nextjs/models.md +362 -0
  57. package/framework/stacks/nextjs/queries.md +410 -0
  58. package/framework/stacks/nextjs/responsive.md +338 -0
  59. package/framework/stacks/nextjs/tech-stack.md +177 -0
  60. package/framework/stacks/nextjs/test-writing.md +475 -0
  61. package/framework/stacks/nextjs/validation.md +467 -0
  62. package/framework/stacks/python/api.md +468 -0
  63. package/framework/stacks/python/authentication.md +342 -0
  64. package/framework/stacks/python/code-quality.md +283 -0
  65. package/framework/stacks/python/code-refactoring.md +315 -0
  66. package/framework/stacks/python/coding-style.md +462 -0
  67. package/framework/stacks/python/conventions.md +399 -0
  68. package/framework/stacks/python/error-handling.md +512 -0
  69. package/framework/stacks/python/feedback.md +92 -0
  70. package/framework/stacks/python/implement-ai-llm.md +468 -0
  71. package/framework/stacks/python/migrations.md +388 -0
  72. package/framework/stacks/python/models.md +399 -0
  73. package/framework/stacks/python/python.md +232 -0
  74. package/framework/stacks/python/queries.md +451 -0
  75. package/framework/stacks/python/structure.md +245 -58
  76. package/framework/stacks/python/tech.md +92 -35
  77. package/framework/stacks/python/testing.md +380 -0
  78. package/framework/stacks/python/validation.md +471 -0
  79. package/framework/stacks/rails/authentication.md +176 -0
  80. package/framework/stacks/rails/code-quality.md +287 -0
  81. package/framework/stacks/rails/code-refactoring.md +299 -0
  82. package/framework/stacks/rails/feedback.md +130 -0
  83. package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
  84. package/framework/stacks/rails/rails.md +301 -0
  85. package/framework/stacks/rails/rails8-best-practices.md +498 -0
  86. package/framework/stacks/rails/rails8-css.md +573 -0
  87. package/framework/stacks/rails/structure.md +140 -0
  88. package/framework/stacks/rails/tech.md +108 -0
  89. package/framework/stacks/react/code-quality.md +521 -0
  90. package/framework/stacks/react/components.md +625 -0
  91. package/framework/stacks/react/data-fetching.md +586 -0
  92. package/framework/stacks/react/feedback.md +110 -0
  93. package/framework/stacks/react/forms.md +694 -0
  94. package/framework/stacks/react/performance.md +640 -0
  95. package/framework/stacks/react/product.md +22 -9
  96. package/framework/stacks/react/state-management.md +472 -0
  97. package/framework/stacks/react/structure.md +351 -44
  98. package/framework/stacks/react/tech.md +219 -30
  99. package/framework/stacks/react/testing.md +690 -0
  100. package/package.json +1 -1
  101. package/framework/stacks/node/product.md +0 -27
  102. package/framework/stacks/node/structure.md +0 -82
  103. package/framework/stacks/node/tech.md +0 -63
@@ -0,0 +1,442 @@
1
+ # Error Handling
2
+
3
+ Comprehensive error handling patterns for Next.js 15 App Router with error boundaries, server actions, API routes, and monitoring.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Fail visibly**: Never swallow errors silently; always surface them to the user or monitoring
10
+ - **Boundaries everywhere**: Every route segment gets an `error.tsx` for graceful degradation
11
+ - **Typed errors**: Use custom error classes to distinguish expected from unexpected failures
12
+ - **User-friendly messages**: Show actionable text to users, log technical details for developers
13
+
14
+ ---
15
+
16
+ ## Error Boundary Hierarchy
17
+
18
+ ### Route-Level Error Boundary
19
+
20
+ ```typescript
21
+ // app/dashboard/error.tsx
22
+ "use client";
23
+
24
+ import { useEffect } from "react";
25
+ import { Button } from "@/components/ui/button";
26
+
27
+ interface ErrorProps {
28
+ error: Error & { digest?: string };
29
+ reset: () => void;
30
+ }
31
+
32
+ export default function DashboardError({ error, reset }: ErrorProps) {
33
+ useEffect(() => {
34
+ // Log to error monitoring service
35
+ console.error("Dashboard error:", error);
36
+ }, [error]);
37
+
38
+ return (
39
+ <div className="flex flex-col items-center justify-center gap-4 py-16" role="alert">
40
+ <h2 className="text-xl font-semibold">Something went wrong</h2>
41
+ <p className="text-muted-foreground max-w-md text-center">
42
+ We encountered an error loading the dashboard. This has been reported automatically.
43
+ </p>
44
+ <div className="flex gap-2">
45
+ <Button onClick={reset}>Try again</Button>
46
+ <Button variant="outline" onClick={() => window.location.reload()}>
47
+ Reload page
48
+ </Button>
49
+ </div>
50
+ {process.env.NODE_ENV === "development" && (
51
+ <pre className="mt-4 max-w-lg overflow-auto rounded bg-red-50 p-4 text-sm text-red-900">
52
+ {error.message}
53
+ {"\n"}
54
+ {error.stack}
55
+ </pre>
56
+ )}
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ### Global Error Boundary
63
+
64
+ ```typescript
65
+ // app/global-error.tsx
66
+ "use client";
67
+
68
+ export default function GlobalError({
69
+ error,
70
+ reset,
71
+ }: {
72
+ error: Error & { digest?: string };
73
+ reset: () => void;
74
+ }) {
75
+ return (
76
+ <html>
77
+ <body>
78
+ <div className="flex min-h-screen items-center justify-center p-4">
79
+ <div className="text-center">
80
+ <h1 className="text-2xl font-bold">Application Error</h1>
81
+ <p className="text-muted-foreground mt-2">
82
+ Something went wrong. Please try refreshing the page.
83
+ </p>
84
+ <button
85
+ onClick={reset}
86
+ className="mt-4 rounded-md bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
87
+ >
88
+ Try again
89
+ </button>
90
+ </div>
91
+ </div>
92
+ </body>
93
+ </html>
94
+ );
95
+ }
96
+ ```
97
+
98
+ ### Not Found
99
+
100
+ ```typescript
101
+ // app/not-found.tsx
102
+ import Link from "next/link";
103
+
104
+ export default function NotFound() {
105
+ return (
106
+ <div className="flex min-h-[60vh] flex-col items-center justify-center gap-4">
107
+ <h1 className="text-4xl font-bold">404</h1>
108
+ <p className="text-muted-foreground text-lg">Page not found</p>
109
+ <Link href="/" className="text-primary underline underline-offset-4">
110
+ Go back home
111
+ </Link>
112
+ </div>
113
+ );
114
+ }
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Custom Error Classes
120
+
121
+ ### Error Hierarchy
122
+
123
+ ```typescript
124
+ // lib/errors.ts
125
+ export class AppError extends Error {
126
+ constructor(
127
+ message: string,
128
+ public code: string,
129
+ public statusCode: number = 500,
130
+ public details?: Record<string, unknown>
131
+ ) {
132
+ super(message);
133
+ this.name = "AppError";
134
+ }
135
+ }
136
+
137
+ export class NotFoundError extends AppError {
138
+ constructor(resource: string, id: string | number) {
139
+ super(`${resource} not found: ${id}`, "NOT_FOUND", 404, { resource, id });
140
+ this.name = "NotFoundError";
141
+ }
142
+ }
143
+
144
+ export class ValidationError extends AppError {
145
+ constructor(message: string, public fieldErrors?: Record<string, string[]>) {
146
+ super(message, "VALIDATION_ERROR", 422, { fieldErrors });
147
+ this.name = "ValidationError";
148
+ }
149
+ }
150
+
151
+ export class UnauthorizedError extends AppError {
152
+ constructor(message = "Authentication required") {
153
+ super(message, "UNAUTHORIZED", 401);
154
+ this.name = "UnauthorizedError";
155
+ }
156
+ }
157
+
158
+ export class ForbiddenError extends AppError {
159
+ constructor(message = "Insufficient permissions") {
160
+ super(message, "FORBIDDEN", 403);
161
+ this.name = "ForbiddenError";
162
+ }
163
+ }
164
+
165
+ export class ConflictError extends AppError {
166
+ constructor(message: string) {
167
+ super(message, "CONFLICT", 409);
168
+ this.name = "ConflictError";
169
+ }
170
+ }
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Server Component Error Handling
176
+
177
+ ### Try/Catch in Async Components
178
+
179
+ ```typescript
180
+ // app/users/[id]/page.tsx
181
+ import { notFound } from "next/navigation";
182
+ import { prisma } from "@/lib/prisma";
183
+
184
+ export default async function UserPage({ params }: { params: Promise<{ id: string }> }) {
185
+ const { id } = await params;
186
+
187
+ const user = await prisma.user.findUnique({
188
+ where: { id },
189
+ include: { posts: { take: 10, orderBy: { createdAt: "desc" } } },
190
+ });
191
+
192
+ if (!user) {
193
+ notFound();
194
+ }
195
+
196
+ return <UserProfile user={user} />;
197
+ }
198
+ ```
199
+
200
+ ### Service-Level Error Handling
201
+
202
+ ```typescript
203
+ // lib/services/user-service.ts
204
+ import { NotFoundError, ConflictError } from "@/lib/errors";
205
+ import { prisma } from "@/lib/prisma";
206
+
207
+ export async function getUserById(id: string) {
208
+ const user = await prisma.user.findUnique({ where: { id } });
209
+ if (!user) {
210
+ throw new NotFoundError("User", id);
211
+ }
212
+ return user;
213
+ }
214
+
215
+ export async function createUser(data: { email: string; name: string }) {
216
+ const existing = await prisma.user.findUnique({ where: { email: data.email } });
217
+ if (existing) {
218
+ throw new ConflictError(`User with email ${data.email} already exists`);
219
+ }
220
+ return prisma.user.create({ data });
221
+ }
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Server Action Error Handling
227
+
228
+ ### Action Result Pattern
229
+
230
+ ```typescript
231
+ // types/actions.ts
232
+ export type ActionResult<T = void> =
233
+ | { success: true; data: T }
234
+ | { success: false; error: string; fieldErrors?: Record<string, string[]> };
235
+ ```
236
+
237
+ ### Safe Action Wrapper
238
+
239
+ ```typescript
240
+ // lib/safe-action.ts
241
+ import { AppError, ValidationError } from "@/lib/errors";
242
+ import type { ActionResult } from "@/types/actions";
243
+
244
+ export async function safeAction<T>(
245
+ fn: () => Promise<T>
246
+ ): Promise<ActionResult<T>> {
247
+ try {
248
+ const data = await fn();
249
+ return { success: true, data };
250
+ } catch (error) {
251
+ if (error instanceof ValidationError) {
252
+ return {
253
+ success: false,
254
+ error: error.message,
255
+ fieldErrors: error.fieldErrors,
256
+ };
257
+ }
258
+ if (error instanceof AppError) {
259
+ return { success: false, error: error.message };
260
+ }
261
+ console.error("Unexpected error in action:", error);
262
+ return { success: false, error: "An unexpected error occurred" };
263
+ }
264
+ }
265
+ ```
266
+
267
+ ### Usage in Server Actions
268
+
269
+ ```typescript
270
+ // actions/users.ts
271
+ "use server";
272
+
273
+ import { z } from "zod";
274
+ import { auth } from "@/lib/auth";
275
+ import { safeAction } from "@/lib/safe-action";
276
+ import { createUser } from "@/lib/services/user-service";
277
+ import { revalidatePath } from "next/cache";
278
+
279
+ const createUserSchema = z.object({
280
+ email: z.string().email("Invalid email address"),
281
+ name: z.string().min(1, "Name is required").max(255),
282
+ });
283
+
284
+ export async function createUserAction(formData: FormData) {
285
+ return safeAction(async () => {
286
+ const session = await auth();
287
+ if (!session?.user) throw new UnauthorizedError();
288
+
289
+ const parsed = createUserSchema.safeParse({
290
+ email: formData.get("email"),
291
+ name: formData.get("name"),
292
+ });
293
+
294
+ if (!parsed.success) {
295
+ throw new ValidationError("Invalid input", parsed.error.flatten().fieldErrors);
296
+ }
297
+
298
+ const user = await createUser(parsed.data);
299
+ revalidatePath("/users");
300
+ return user;
301
+ });
302
+ }
303
+ ```
304
+
305
+ ---
306
+
307
+ ## API Route Error Handling
308
+
309
+ ### Centralized Error Response
310
+
311
+ ```typescript
312
+ // lib/api-error.ts
313
+ import { NextResponse } from "next/server";
314
+ import { AppError } from "@/lib/errors";
315
+
316
+ export function handleApiError(error: unknown) {
317
+ if (error instanceof AppError) {
318
+ return NextResponse.json(
319
+ { error: { code: error.code, message: error.message, details: error.details } },
320
+ { status: error.statusCode }
321
+ );
322
+ }
323
+
324
+ console.error("Unhandled API error:", error);
325
+ return NextResponse.json(
326
+ { error: { code: "INTERNAL_ERROR", message: "An internal error occurred" } },
327
+ { status: 500 }
328
+ );
329
+ }
330
+ ```
331
+
332
+ ### Usage
333
+
334
+ ```typescript
335
+ // app/api/users/[id]/route.ts
336
+ import { handleApiError } from "@/lib/api-error";
337
+ import { getUserById } from "@/lib/services/user-service";
338
+
339
+ export async function GET(
340
+ _request: Request,
341
+ { params }: { params: Promise<{ id: string }> }
342
+ ) {
343
+ try {
344
+ const { id } = await params;
345
+ const user = await getUserById(id);
346
+ return Response.json(user);
347
+ } catch (error) {
348
+ return handleApiError(error);
349
+ }
350
+ }
351
+ ```
352
+
353
+ ---
354
+
355
+ ## Client-Side Error Handling
356
+
357
+ ### Toast Notifications
358
+
359
+ ```typescript
360
+ // components/forms/create-user-form.tsx
361
+ "use client";
362
+
363
+ import { useActionState } from "react";
364
+ import { createUserAction } from "@/actions/users";
365
+ import { toast } from "sonner";
366
+
367
+ export function CreateUserForm() {
368
+ const [state, formAction, isPending] = useActionState(
369
+ async (_prev: unknown, formData: FormData) => {
370
+ const result = await createUserAction(formData);
371
+ if (result.success) {
372
+ toast.success("User created successfully");
373
+ } else {
374
+ toast.error(result.error);
375
+ }
376
+ return result;
377
+ },
378
+ null
379
+ );
380
+
381
+ return (
382
+ <form action={formAction}>
383
+ <input name="email" type="email" required />
384
+ {state && !state.success && state.fieldErrors?.email && (
385
+ <p className="text-sm text-destructive">{state.fieldErrors.email[0]}</p>
386
+ )}
387
+ <input name="name" required />
388
+ <button type="submit" disabled={isPending}>
389
+ {isPending ? "Creating..." : "Create User"}
390
+ </button>
391
+ </form>
392
+ );
393
+ }
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Error Monitoring
399
+
400
+ ### Sentry Integration
401
+
402
+ ```typescript
403
+ // lib/sentry.ts
404
+ import * as Sentry from "@sentry/nextjs";
405
+
406
+ export function captureError(error: unknown, context?: Record<string, unknown>) {
407
+ if (error instanceof AppError && error.statusCode < 500) {
408
+ // Expected errors (4xx) - don't send to Sentry
409
+ return;
410
+ }
411
+ Sentry.captureException(error, { extra: context });
412
+ }
413
+ ```
414
+
415
+ ```typescript
416
+ // instrumentation.ts (Next.js instrumentation hook)
417
+ export async function register() {
418
+ if (process.env.NEXT_RUNTIME === "nodejs") {
419
+ await import("./sentry.server.config");
420
+ }
421
+ if (process.env.NEXT_RUNTIME === "edge") {
422
+ await import("./sentry.edge.config");
423
+ }
424
+ }
425
+ ```
426
+
427
+ ---
428
+
429
+ ## Anti-Patterns
430
+
431
+ | Anti-Pattern | Problem | Correct Approach |
432
+ |---|---|---|
433
+ | Empty catch blocks | Errors disappear silently | Log and re-throw or return error state |
434
+ | `try/catch` around every line | Unreadable, catch at boundaries | Catch at route/action level, let errors propagate |
435
+ | Showing stack traces to users | Security risk, bad UX | User-friendly message + log details server-side |
436
+ | Using `Error` for expected cases | Cannot distinguish expected vs unexpected | Custom error classes with codes |
437
+ | No `error.tsx` in route segments | White screen on failure | Add error boundaries to all route segments |
438
+ | Catching `redirect()` or `notFound()` | These are thrown intentionally by Next.js | Never catch Next.js navigation functions |
439
+
440
+ ---
441
+
442
+ _Errors are inevitable. Handle them at boundaries, classify them with types, and always tell the user what happened and what they can do about it._
@@ -0,0 +1,124 @@
1
+ # Feedback Configuration
2
+
3
+ Project-specific commands for automated feedback during Next.js implementation.
4
+
5
+ ---
6
+
7
+ ## Test Commands
8
+
9
+ Commands to run tests during implementation. The agent will use these to verify code changes.
10
+
11
+ ```yaml
12
+ # Primary test command (REQUIRED)
13
+ test: pnpm test
14
+
15
+ # Test with coverage report
16
+ test_coverage: pnpm test -- --coverage
17
+
18
+ # Run specific test file (use {file} as placeholder)
19
+ test_file: pnpm test {file}
20
+
21
+ # Watch mode (for development)
22
+ test_watch: pnpm test -- --watch
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Linting Commands
28
+
29
+ Commands for code quality checks.
30
+
31
+ ```yaml
32
+ # Primary lint command (Next.js built-in)
33
+ lint: pnpm lint
34
+
35
+ # Lint with auto-fix
36
+ lint_fix: pnpm lint --fix
37
+
38
+ # Type checking
39
+ type_check: pnpm tsc --noEmit
40
+
41
+ # Format check
42
+ format_check: pnpm prettier --check .
43
+
44
+ # Format fix
45
+ format_fix: pnpm prettier --write .
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Development Server
51
+
52
+ Commands for starting the development server (required for UI verification).
53
+
54
+ ```yaml
55
+ # Start dev server (Next.js)
56
+ dev_server: pnpm dev
57
+
58
+ # Dev server port
59
+ dev_port: 3000
60
+
61
+ # Dev server base URL
62
+ dev_url: http://localhost:3000
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Build Commands
68
+
69
+ Commands for production builds.
70
+
71
+ ```yaml
72
+ # Production build
73
+ build: pnpm build
74
+
75
+ # Start production server
76
+ start: pnpm start
77
+ ```
78
+
79
+ ---
80
+
81
+ ## UI Verification
82
+
83
+ Settings for agent-browser UI verification.
84
+
85
+ ```yaml
86
+ # Enable UI verification for this project
87
+ ui_verification_enabled: true
88
+
89
+ # Default wait time after navigation (milliseconds)
90
+ navigation_wait: 3000
91
+
92
+ # Screenshot directory
93
+ screenshot_dir: /tmp/ui-captures
94
+
95
+ # Common routes to verify
96
+ routes:
97
+ - /
98
+ - /api/health
99
+ ```
100
+
101
+ ---
102
+
103
+ ## E2E Testing
104
+
105
+ End-to-end testing with Playwright.
106
+
107
+ ```yaml
108
+ # Run E2E tests
109
+ e2e: pnpm test:e2e
110
+
111
+ # Run E2E with UI
112
+ e2e_ui: pnpm test:e2e --ui
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Notes
118
+
119
+ - Uses Jest or Vitest for unit tests (check package.json)
120
+ - Uses Playwright for E2E testing
121
+ - Next.js dev server on port 3000 by default
122
+ - Built-in ESLint configuration via `next lint`
123
+ - UI verification is enabled by default for Next.js projects
124
+ - API routes available at `/api/*`