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,462 @@
1
+ # Python Coding Style
2
+
3
+ Coding style conventions beyond what ruff enforces automatically. Opinionated patterns for readable, maintainable Python.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Readability counts**: Code is read far more than written
10
+ - **Explicit over implicit**: No magic, no hidden behavior
11
+ - **Consistency over preference**: Follow the project convention, not personal style
12
+ - **Automate what you can**: Let ruff handle formatting; this doc covers judgment calls
13
+
14
+ ---
15
+
16
+ ## Naming Conventions
17
+
18
+ ### Standard Python Naming
19
+
20
+ | Element | Convention | Example |
21
+ |---|---|---|
22
+ | Variables, functions | `snake_case` | `user_count`, `get_user` |
23
+ | Classes | `PascalCase` | `UserService`, `CreateUserRequest` |
24
+ | Constants | `UPPER_SNAKE_CASE` | `MAX_RETRIES`, `DEFAULT_PAGE_SIZE` |
25
+ | Modules, packages | `snake_case` | `user_service.py`, `auth_utils` |
26
+ | Private members | `_leading_underscore` | `_validate_email`, `_cache` |
27
+ | Type variables | `PascalCase` or `T` | `T`, `ModelT`, `ResponseT` |
28
+ | Enums | `PascalCase` class, `UPPER_SNAKE_CASE` values | `Role.ADMIN` |
29
+
30
+ ### Naming Rules
31
+
32
+ ```python
33
+ # GOOD: Descriptive, reveals intent
34
+ user_count = len(active_users)
35
+ is_authenticated = token is not None
36
+ max_retry_attempts = 3
37
+
38
+ async def get_active_users(db: AsyncSession) -> list[User]:
39
+ ...
40
+
41
+ class PaymentProcessingError(AppError):
42
+ ...
43
+
44
+ # BAD: Abbreviated, unclear
45
+ uc = len(au)
46
+ auth = token is not None
47
+ n = 3
48
+
49
+ async def get_au(db):
50
+ ...
51
+ ```
52
+
53
+ ### Boolean Naming
54
+
55
+ Prefix with `is_`, `has_`, `can_`, `should_`:
56
+
57
+ ```python
58
+ is_active: bool
59
+ has_permission: bool
60
+ can_publish: bool
61
+ should_notify: bool
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Function Design
67
+
68
+ ### Size Limits
69
+
70
+ - **Target**: Under 20 lines of logic
71
+ - **Maximum**: 40 lines (extract if longer)
72
+ - **Parameters**: Maximum 5; use a Pydantic model for more
73
+
74
+ ```python
75
+ # GOOD: Small, focused
76
+ async def create_user(self, data: CreateUserRequest) -> User:
77
+ await self._check_email_available(data.email)
78
+ user = User(
79
+ email=data.email,
80
+ name=data.name,
81
+ hashed_password=hash_password(data.password),
82
+ )
83
+ return await self.repo.save(user)
84
+
85
+ async def _check_email_available(self, email: str) -> None:
86
+ existing = await self.repo.get_by_email(email)
87
+ if existing:
88
+ raise ConflictError("Email already registered")
89
+ ```
90
+
91
+ ```python
92
+ # BAD: Too many responsibilities
93
+ async def create_user(self, email, name, password, role, bio, avatar_url, ...):
94
+ # 60+ lines doing validation, hashing, saving, emailing, logging...
95
+ ```
96
+
97
+ ### Return Types
98
+
99
+ Always annotate return types for public functions:
100
+
101
+ ```python
102
+ # GOOD
103
+ async def get_user(self, user_id: int) -> User:
104
+ ...
105
+
106
+ async def find_user(self, email: str) -> User | None:
107
+ ...
108
+
109
+ async def list_users(self) -> list[User]:
110
+ ...
111
+
112
+ # BAD: Missing return type
113
+ async def get_user(self, user_id):
114
+ ...
115
+ ```
116
+
117
+ ### Early Returns
118
+
119
+ Prefer guard clauses over nested conditionals:
120
+
121
+ ```python
122
+ # GOOD: Guard clauses
123
+ async def publish(self, post: Post, user: User) -> Post:
124
+ if post.user_id != user.id:
125
+ raise AuthorizationError()
126
+ if post.status == "published":
127
+ raise ConflictError("Already published")
128
+ if not post.body:
129
+ raise ValidationError("Body required")
130
+
131
+ post.status = "published"
132
+ return await self.repo.save(post)
133
+
134
+ # BAD: Deeply nested
135
+ async def publish(self, post: Post, user: User) -> Post:
136
+ if post.user_id == user.id:
137
+ if post.status != "published":
138
+ if post.body:
139
+ post.status = "published"
140
+ return await self.repo.save(post)
141
+ else:
142
+ raise ValidationError("Body required")
143
+ else:
144
+ raise ConflictError("Already published")
145
+ else:
146
+ raise AuthorizationError()
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Module Organization
152
+
153
+ ### Standard Module Layout
154
+
155
+ ```python
156
+ """Module docstring describing purpose."""
157
+
158
+ # 1. Future imports
159
+ from __future__ import annotations
160
+
161
+ # 2. Standard library
162
+ import asyncio
163
+ from datetime import datetime, timezone
164
+ from typing import TYPE_CHECKING
165
+
166
+ # 3. Third-party
167
+ from sqlalchemy import select
168
+ from sqlalchemy.ext.asyncio import AsyncSession
169
+
170
+ # 4. Local imports
171
+ from app.exceptions import NotFoundError
172
+ from app.models.user import User
173
+
174
+ # 5. Type-checking only imports
175
+ if TYPE_CHECKING:
176
+ from app.services.email import EmailService
177
+
178
+ # 6. Module-level constants
179
+ MAX_RETRIES = 3
180
+ DEFAULT_PAGE_SIZE = 20
181
+
182
+ # 7. Classes and functions
183
+ class UserService:
184
+ ...
185
+ ```
186
+
187
+ ### Import Rules
188
+
189
+ - One import per line for `from` imports with multiple names (ruff handles this)
190
+ - Use `TYPE_CHECKING` block for imports used only in annotations
191
+ - Never use wildcard imports (`from module import *`)
192
+ - Group: stdlib, third-party, local (ruff `isort` enforces this)
193
+
194
+ ---
195
+
196
+ ## Type Annotations
197
+
198
+ ### Modern Syntax (Python 3.12+)
199
+
200
+ ```python
201
+ # GOOD: Modern syntax
202
+ def get_users() -> list[User]:
203
+ ...
204
+
205
+ def find_user(email: str) -> User | None:
206
+ ...
207
+
208
+ def process_items(items: dict[str, list[int]]) -> None:
209
+ ...
210
+
211
+ # Also acceptable: use `from __future__ import annotations` for older Python
212
+ ```
213
+
214
+ ### Common Patterns
215
+
216
+ ```python
217
+ from collections.abc import AsyncIterator, Callable, Sequence
218
+ from typing import Any, TypeVar
219
+
220
+ T = TypeVar("T")
221
+
222
+ # Generic function
223
+ async def get_or_404(model: type[T], id: int, db: AsyncSession) -> T:
224
+ ...
225
+
226
+ # Callable type
227
+ Handler = Callable[[Request], Awaitable[Response]]
228
+
229
+ # Optional with default
230
+ def paginate(page: int = 1, per_page: int = 20) -> tuple[int, int]:
231
+ ...
232
+ ```
233
+
234
+ ### When to Use `Any`
235
+
236
+ Almost never. Use `Any` only for:
237
+ - Interfacing with untyped third-party libraries
238
+ - Generic JSON data (prefer `dict[str, Any]` over bare `Any`)
239
+ - Temporary during migration to typed code
240
+
241
+ ---
242
+
243
+ ## Docstring Style (Google)
244
+
245
+ ### Functions
246
+
247
+ ```python
248
+ async def create_user(self, data: CreateUserRequest) -> User:
249
+ """Create a new user account.
250
+
251
+ Validates email uniqueness and hashes the password before
252
+ persisting to the database.
253
+
254
+ Args:
255
+ data: Validated user creation request containing email,
256
+ name, and plain-text password.
257
+
258
+ Returns:
259
+ The created User instance with generated ID and timestamps.
260
+
261
+ Raises:
262
+ ConflictError: If the email is already registered.
263
+ """
264
+ ```
265
+
266
+ ### Classes
267
+
268
+ ```python
269
+ class UserService:
270
+ """Service for user account management.
271
+
272
+ Handles registration, authentication, and profile operations.
273
+ Delegates data access to UserRepo.
274
+
275
+ Attributes:
276
+ repo: Repository for user data persistence.
277
+ """
278
+
279
+ def __init__(self, repo: UserRepo) -> None:
280
+ self.repo = repo
281
+ ```
282
+
283
+ ### When NOT to Docstring
284
+
285
+ ```python
286
+ # Self-documenting: no docstring needed
287
+ def hash_password(password: str) -> str:
288
+ return pwd_context.hash(password)
289
+
290
+ # Tests: name IS the documentation
291
+ async def test_create_user_with_duplicate_email_raises_conflict():
292
+ ...
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Common Anti-Patterns
298
+
299
+ ### Mutable Default Arguments
300
+
301
+ ```python
302
+ # BAD: Shared mutable default
303
+ def add_item(item: str, items: list[str] = []) -> list[str]:
304
+ items.append(item) # Mutates the default!
305
+ return items
306
+
307
+ # GOOD: Use None sentinel
308
+ def add_item(item: str, items: list[str] | None = None) -> list[str]:
309
+ if items is None:
310
+ items = []
311
+ items.append(item)
312
+ return items
313
+
314
+ # GOOD: Pydantic uses Field(default_factory=...)
315
+ class Config(BaseModel):
316
+ tags: list[str] = Field(default_factory=list)
317
+ ```
318
+
319
+ ### Bare Except
320
+
321
+ ```python
322
+ # BAD: Catches everything including SystemExit, KeyboardInterrupt
323
+ try:
324
+ result = await risky_operation()
325
+ except:
326
+ pass
327
+
328
+ # BAD: Too broad
329
+ try:
330
+ result = await risky_operation()
331
+ except Exception:
332
+ pass # Silently swallowed
333
+
334
+ # GOOD: Specific exceptions, proper handling
335
+ try:
336
+ result = await risky_operation()
337
+ except (ConnectionError, TimeoutError) as exc:
338
+ logger.warning("operation_failed", error=str(exc))
339
+ raise ExternalServiceError("service", str(exc)) from exc
340
+ ```
341
+
342
+ ### Global Mutable State
343
+
344
+ ```python
345
+ # BAD: Module-level mutable state
346
+ _cache = {}
347
+
348
+ def get_cached(key: str) -> str | None:
349
+ return _cache.get(key)
350
+
351
+ def set_cached(key: str, value: str) -> None:
352
+ _cache[key] = value
353
+
354
+ # GOOD: Encapsulate state in a class or use proper caching
355
+ class Cache:
356
+ def __init__(self) -> None:
357
+ self._store: dict[str, str] = {}
358
+
359
+ def get(self, key: str) -> str | None:
360
+ return self._store.get(key)
361
+ ```
362
+
363
+ ### String Concatenation in Loops
364
+
365
+ ```python
366
+ # BAD: O(n^2) string building
367
+ result = ""
368
+ for item in items:
369
+ result += f"{item.name}, "
370
+
371
+ # GOOD: Join
372
+ result = ", ".join(item.name for item in items)
373
+ ```
374
+
375
+ ### Overusing Inheritance
376
+
377
+ ```python
378
+ # BAD: Deep inheritance for code reuse
379
+ class BaseRepo:
380
+ ...
381
+ class CachedRepo(BaseRepo):
382
+ ...
383
+ class AuditedCachedRepo(CachedRepo):
384
+ ...
385
+ class UserRepo(AuditedCachedRepo):
386
+ ...
387
+
388
+ # GOOD: Composition and mixins
389
+ class UserRepo:
390
+ def __init__(self, db: AsyncSession, cache: Cache) -> None:
391
+ self.db = db
392
+ self.cache = cache
393
+ ```
394
+
395
+ ---
396
+
397
+ ## Async Patterns
398
+
399
+ ### Prefer `async` Throughout
400
+
401
+ ```python
402
+ # GOOD: Async all the way down
403
+ async def get_user_with_posts(user_id: int, db: AsyncSession) -> User:
404
+ stmt = select(User).options(selectinload(User.posts)).where(User.id == user_id)
405
+ result = await db.execute(stmt)
406
+ return result.scalar_one_or_none()
407
+
408
+ # BAD: Mixing sync and async
409
+ def get_user_sync(user_id: int) -> User:
410
+ # Blocks the event loop if called from async context
411
+ with Session() as db:
412
+ return db.get(User, user_id)
413
+ ```
414
+
415
+ ### Concurrent Operations
416
+
417
+ ```python
418
+ import asyncio
419
+
420
+ # Run independent async operations concurrently
421
+ user, posts, notifications = await asyncio.gather(
422
+ user_service.get_user(user_id),
423
+ post_service.get_user_posts(user_id),
424
+ notification_service.get_unread(user_id),
425
+ )
426
+ ```
427
+
428
+ ---
429
+
430
+ ## File and Class Size
431
+
432
+ ### Guidelines
433
+
434
+ | Element | Guideline |
435
+ |---|---|
436
+ | Function | Under 20 lines of logic, max 40 |
437
+ | Class | Under 200 lines, max 300 |
438
+ | Module | Under 300 lines, max 500 |
439
+ | Parameters | Max 5 per function; use model for more |
440
+
441
+ When a file exceeds limits, extract:
442
+ - Utility functions into a `utils` module
443
+ - Related classes into their own module
444
+ - Constants into a `constants` module
445
+
446
+ ---
447
+
448
+ ## Formatting (Handled by Ruff)
449
+
450
+ These are automated -- do not worry about them manually:
451
+
452
+ - Line length: 99 characters
453
+ - Indentation: 4 spaces
454
+ - Import sorting: stdlib, third-party, local
455
+ - Trailing commas in multi-line constructs
456
+ - Quote style: double quotes
457
+
458
+ Run `uv run ruff format .` and move on.
459
+
460
+ ---
461
+
462
+ _Style is a tool for communication. Write code that your future self and teammates will thank you for._