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,315 @@
1
+ # Code Refactoring Patterns
2
+
3
+ Project memory for safe code refactoring strategies in Python.
4
+
5
+ ---
6
+
7
+ ## Refactoring Philosophy
8
+
9
+ 1. **Safety first**: Tests pass before and after every change
10
+ 2. **Small steps**: Incremental changes that can be reverted independently
11
+ 3. **Preserve behavior**: Refactoring changes structure, not functionality
12
+
13
+ ---
14
+
15
+ ## Extraction Patterns
16
+
17
+ ### Service Extraction
18
+
19
+ Extract business logic from route handlers when it spans multiple concerns:
20
+
21
+ **Pattern**: Route Handler to Service
22
+ ```python
23
+ # Before: Fat route handler
24
+ @router.post("/users/{user_id}/content")
25
+ async def create_content(
26
+ user_id: int,
27
+ data: CreateContentRequest,
28
+ db: AsyncSession = Depends(get_db),
29
+ ):
30
+ user = await db.get(User, user_id)
31
+ if not user:
32
+ raise HTTPException(404)
33
+ content = Content(title=data.title, body=data.body, user_id=user.id)
34
+ db.add(content)
35
+ await db.commit()
36
+ await notify_subscribers(user, content)
37
+ await update_search_index(content)
38
+ return ContentResponse.model_validate(content)
39
+
40
+ # After: Thin handler, extracted service
41
+ @router.post("/users/{user_id}/content")
42
+ async def create_content(
43
+ user_id: int,
44
+ data: CreateContentRequest,
45
+ service: ContentService = Depends(get_content_service),
46
+ ):
47
+ result = await service.create(user_id=user_id, data=data)
48
+ if not result.is_ok:
49
+ raise HTTPException(400, detail=result.error)
50
+ return ContentResponse.model_validate(result.value)
51
+ ```
52
+
53
+ ### Protocol Extraction
54
+
55
+ Extract shared behavior into protocols when multiple implementations exist:
56
+
57
+ ```python
58
+ # Before: Concrete dependency
59
+ class ContentService:
60
+ def __init__(self, db: AsyncSession):
61
+ self._db = db
62
+
63
+ async def get(self, id: int) -> Content:
64
+ return await self._db.get(Content, id)
65
+
66
+ # After: Protocol-based abstraction
67
+ from typing import Protocol
68
+
69
+ class ContentRepository(Protocol):
70
+ async def get(self, id: int) -> Content | None: ...
71
+ async def save(self, content: Content) -> Content: ...
72
+
73
+ class SQLContentRepository:
74
+ def __init__(self, db: AsyncSession) -> None:
75
+ self._db = db
76
+
77
+ async def get(self, id: int) -> Content | None:
78
+ return await self._db.get(Content, id)
79
+
80
+ async def save(self, content: Content) -> Content:
81
+ self._db.add(content)
82
+ await self._db.flush()
83
+ return content
84
+
85
+ class ContentService:
86
+ def __init__(self, repo: ContentRepository) -> None:
87
+ self._repo = repo
88
+ ```
89
+
90
+ ### Strategy Pattern
91
+
92
+ Use when type-based conditionals grow:
93
+
94
+ ```python
95
+ # Before: Growing if/elif chain
96
+ def process_source(source: Source) -> str:
97
+ if source.type == "youtube":
98
+ # 30 lines
99
+ elif source.type == "web":
100
+ # 25 lines
101
+ elif source.type == "rss":
102
+ # 20 lines
103
+
104
+ # After: Strategy registry
105
+ from typing import Protocol
106
+
107
+ class Extractor(Protocol):
108
+ async def extract(self, source: Source) -> ExtractedContent: ...
109
+
110
+ EXTRACTORS: dict[str, type[Extractor]] = {
111
+ "youtube": YoutubeExtractor,
112
+ "web": WebExtractor,
113
+ "rss": RssExtractor,
114
+ }
115
+
116
+ async def process_source(source: Source) -> ExtractedContent:
117
+ extractor_cls = EXTRACTORS.get(source.type)
118
+ if not extractor_cls:
119
+ raise ValueError(f"Unknown source type: {source.type}")
120
+ return await extractor_cls().extract(source)
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Dependency Injection for Testability
126
+
127
+ ### Constructor Injection
128
+
129
+ ```python
130
+ class NotificationService:
131
+ def __init__(
132
+ self,
133
+ email_client: EmailClient | None = None,
134
+ event_bus: EventBus | None = None,
135
+ ) -> None:
136
+ self._email = email_client or SmtpEmailClient()
137
+ self._events = event_bus or RedisEventBus()
138
+
139
+ # Production: uses defaults
140
+ service = NotificationService()
141
+
142
+ # Test: inject mocks
143
+ service = NotificationService(
144
+ email_client=FakeEmailClient(),
145
+ event_bus=FakeEventBus(),
146
+ )
147
+ ```
148
+
149
+ ### FastAPI Dependency Overrides
150
+
151
+ ```python
152
+ # In tests: override dependencies
153
+ from app.dependencies import get_user_service
154
+
155
+ app.dependency_overrides[get_user_service] = lambda: mock_service
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Pydantic Model Refactoring
161
+
162
+ ### Flatten Nested Logic into Models
163
+
164
+ ```python
165
+ # Before: Validation scattered in service
166
+ class ContentService:
167
+ async def create(self, title: str, body: str, tags: list[str]):
168
+ if not title.strip():
169
+ raise ValueError("Title required")
170
+ if len(tags) > 10:
171
+ raise ValueError("Too many tags")
172
+ ...
173
+
174
+ # After: Validation in Pydantic model
175
+ class CreateContentRequest(BaseModel):
176
+ title: str = Field(..., min_length=1, max_length=200)
177
+ body: str = Field(default="")
178
+ tags: list[str] = Field(default_factory=list, max_length=10)
179
+
180
+ @field_validator("title")
181
+ @classmethod
182
+ def strip_title(cls, v: str) -> str:
183
+ return v.strip()
184
+ ```
185
+
186
+ ### Extract Shared Fields with Base Models
187
+
188
+ ```python
189
+ class TimestampMixin(BaseModel):
190
+ created_at: datetime
191
+ updated_at: datetime
192
+
193
+ class UserResponse(TimestampMixin):
194
+ id: int
195
+ email: str
196
+ name: str
197
+
198
+ class ContentResponse(TimestampMixin):
199
+ id: int
200
+ title: str
201
+ status: str
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Safe Refactoring Workflow
207
+
208
+ ### Step 1: Ensure Test Coverage
209
+
210
+ ```bash
211
+ # Check coverage for the module being refactored
212
+ uv run pytest tests/unit/services/test_content_service.py --cov=src/app/services/content_service
213
+
214
+ # Add characterization tests if missing
215
+ def test_current_create_behavior():
216
+ """Document existing behavior before refactoring."""
217
+ ...
218
+ ```
219
+
220
+ ### Step 2: Small, Reversible Changes
221
+
222
+ **Good**: One concept per commit
223
+ ```
224
+ commit 1: Extract ContentRepository protocol
225
+ commit 2: Implement SQLContentRepository
226
+ commit 3: Update ContentService to use repository
227
+ commit 4: Update dependency injection wiring
228
+ ```
229
+
230
+ ### Step 3: Verify After Each Change
231
+
232
+ ```bash
233
+ uv run pytest tests/ -x # Stop on first failure
234
+ uv run mypy src/ # Type safety preserved
235
+ uv run ruff check . # Style maintained
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Refactoring Signals
241
+
242
+ ### When to Extract
243
+
244
+ | Signal | Action |
245
+ |--------|--------|
246
+ | Route handler > 15 lines | Extract to service |
247
+ | Service > 200 lines | Split by responsibility |
248
+ | if/elif > 3 branches on type | Strategy pattern |
249
+ | Same 5+ lines in multiple places | Extract to utility/mixin |
250
+ | External API call in service | Extract to client class |
251
+ | Complex query logic | Extract to repository |
252
+
253
+ ### When NOT to Extract
254
+
255
+ - Single-use logic that fits naturally in one place
256
+ - Simple CRUD without business rules
257
+ - Premature abstraction (wait for 3+ uses)
258
+ - Adding layers just for the sake of layers
259
+
260
+ ---
261
+
262
+ ## Common Refactoring Targets
263
+
264
+ ### Fat Services
265
+
266
+ Split by responsibility:
267
+ ```
268
+ content_service.py (500 lines) ->
269
+ content_service.py # CRUD operations
270
+ content_publisher.py # Publishing logic
271
+ content_enricher.py # AI enrichment
272
+ ```
273
+
274
+ ### Complex Conditionals
275
+
276
+ Replace with:
277
+ - Guard clauses (early returns)
278
+ - Strategy/registry patterns
279
+ - `match` statements (Python 3.10+)
280
+
281
+ ```python
282
+ # Pattern: match statement for clean branching
283
+ match source.type:
284
+ case "youtube":
285
+ return await extract_youtube(source)
286
+ case "web":
287
+ return await extract_web(source)
288
+ case _:
289
+ raise ValueError(f"Unknown type: {source.type}")
290
+ ```
291
+
292
+ ---
293
+
294
+ ## Refactoring Checklist
295
+
296
+ Before starting:
297
+ - [ ] Tests pass for affected code
298
+ - [ ] Understand current behavior fully
299
+ - [ ] Plan incremental steps
300
+
301
+ During:
302
+ - [ ] One logical change per commit
303
+ - [ ] Tests pass after each step
304
+ - [ ] Types check after each step
305
+ - [ ] No behavior changes (unless intentional)
306
+
307
+ After:
308
+ - [ ] Full test suite passes
309
+ - [ ] mypy passes
310
+ - [ ] Ruff passes
311
+ - [ ] Manual smoke test of affected features
312
+
313
+ ---
314
+
315
+ _Refactoring improves code structure while preserving behavior. Small, typed, tested steps over large rewrites._