red64-cli 0.1.0 → 0.3.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 (125) hide show
  1. package/README.md +1 -2
  2. package/dist/cli/parseArgs.d.ts.map +1 -1
  3. package/dist/cli/parseArgs.js +5 -0
  4. package/dist/cli/parseArgs.js.map +1 -1
  5. package/dist/components/init/CompleteStep.d.ts.map +1 -1
  6. package/dist/components/init/CompleteStep.js +2 -2
  7. package/dist/components/init/CompleteStep.js.map +1 -1
  8. package/dist/components/init/TestCheckStep.d.ts +16 -0
  9. package/dist/components/init/TestCheckStep.d.ts.map +1 -0
  10. package/dist/components/init/TestCheckStep.js +120 -0
  11. package/dist/components/init/TestCheckStep.js.map +1 -0
  12. package/dist/components/init/index.d.ts +1 -0
  13. package/dist/components/init/index.d.ts.map +1 -1
  14. package/dist/components/init/index.js +1 -0
  15. package/dist/components/init/index.js.map +1 -1
  16. package/dist/components/init/types.d.ts +9 -0
  17. package/dist/components/init/types.d.ts.map +1 -1
  18. package/dist/components/screens/InitScreen.d.ts.map +1 -1
  19. package/dist/components/screens/InitScreen.js +69 -6
  20. package/dist/components/screens/InitScreen.js.map +1 -1
  21. package/dist/components/screens/ListScreen.d.ts.map +1 -1
  22. package/dist/components/screens/ListScreen.js +28 -3
  23. package/dist/components/screens/ListScreen.js.map +1 -1
  24. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  25. package/dist/components/screens/StartScreen.js +212 -13
  26. package/dist/components/screens/StartScreen.js.map +1 -1
  27. package/dist/components/ui/ArtifactsSidebar.d.ts +19 -0
  28. package/dist/components/ui/ArtifactsSidebar.d.ts.map +1 -0
  29. package/dist/components/ui/ArtifactsSidebar.js +51 -0
  30. package/dist/components/ui/ArtifactsSidebar.js.map +1 -0
  31. package/dist/components/ui/FeatureSidebar.d.ts.map +1 -1
  32. package/dist/components/ui/FeatureSidebar.js +1 -1
  33. package/dist/components/ui/FeatureSidebar.js.map +1 -1
  34. package/dist/components/ui/index.d.ts +1 -0
  35. package/dist/components/ui/index.d.ts.map +1 -1
  36. package/dist/components/ui/index.js +1 -0
  37. package/dist/components/ui/index.js.map +1 -1
  38. package/dist/services/ClaudeErrorDetector.js +3 -3
  39. package/dist/services/ClaudeErrorDetector.js.map +1 -1
  40. package/dist/services/ConfigService.d.ts +1 -0
  41. package/dist/services/ConfigService.d.ts.map +1 -1
  42. package/dist/services/ConfigService.js.map +1 -1
  43. package/dist/services/ProjectDetector.d.ts +28 -0
  44. package/dist/services/ProjectDetector.d.ts.map +1 -0
  45. package/dist/services/ProjectDetector.js +236 -0
  46. package/dist/services/ProjectDetector.js.map +1 -0
  47. package/dist/services/TestRunner.d.ts +46 -0
  48. package/dist/services/TestRunner.d.ts.map +1 -0
  49. package/dist/services/TestRunner.js +85 -0
  50. package/dist/services/TestRunner.js.map +1 -0
  51. package/dist/services/index.d.ts +2 -0
  52. package/dist/services/index.d.ts.map +1 -1
  53. package/dist/services/index.js +2 -0
  54. package/dist/services/index.js.map +1 -1
  55. package/dist/types/index.d.ts +13 -0
  56. package/dist/types/index.d.ts.map +1 -1
  57. package/dist/types/index.js.map +1 -1
  58. package/framework/.red64/settings/templates/specs/gap-analysis.md +163 -0
  59. package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
  60. package/framework/agents/claude/.claude/agents/red64/validate-gap.md +13 -7
  61. package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
  62. package/framework/agents/claude/.claude/commands/red64/validate-gap.md +4 -0
  63. package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
  64. package/framework/agents/codex/.codex/agents/red64/validate-gap.md +13 -7
  65. package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
  66. package/framework/agents/codex/.codex/commands/red64/validate-gap.md +4 -0
  67. package/framework/stacks/generic/feedback.md +80 -0
  68. package/framework/stacks/nextjs/accessibility.md +437 -0
  69. package/framework/stacks/nextjs/api.md +431 -0
  70. package/framework/stacks/nextjs/coding-style.md +282 -0
  71. package/framework/stacks/nextjs/commenting.md +226 -0
  72. package/framework/stacks/nextjs/components.md +411 -0
  73. package/framework/stacks/nextjs/conventions.md +333 -0
  74. package/framework/stacks/nextjs/css.md +310 -0
  75. package/framework/stacks/nextjs/error-handling.md +442 -0
  76. package/framework/stacks/nextjs/feedback.md +124 -0
  77. package/framework/stacks/nextjs/migrations.md +332 -0
  78. package/framework/stacks/nextjs/models.md +362 -0
  79. package/framework/stacks/nextjs/queries.md +410 -0
  80. package/framework/stacks/nextjs/responsive.md +338 -0
  81. package/framework/stacks/nextjs/tech-stack.md +177 -0
  82. package/framework/stacks/nextjs/test-writing.md +475 -0
  83. package/framework/stacks/nextjs/validation.md +467 -0
  84. package/framework/stacks/python/api.md +468 -0
  85. package/framework/stacks/python/authentication.md +342 -0
  86. package/framework/stacks/python/code-quality.md +283 -0
  87. package/framework/stacks/python/code-refactoring.md +315 -0
  88. package/framework/stacks/python/coding-style.md +462 -0
  89. package/framework/stacks/python/conventions.md +399 -0
  90. package/framework/stacks/python/error-handling.md +512 -0
  91. package/framework/stacks/python/feedback.md +92 -0
  92. package/framework/stacks/python/implement-ai-llm.md +468 -0
  93. package/framework/stacks/python/migrations.md +388 -0
  94. package/framework/stacks/python/models.md +399 -0
  95. package/framework/stacks/python/python.md +232 -0
  96. package/framework/stacks/python/queries.md +451 -0
  97. package/framework/stacks/python/structure.md +245 -58
  98. package/framework/stacks/python/tech.md +92 -35
  99. package/framework/stacks/python/testing.md +380 -0
  100. package/framework/stacks/python/validation.md +471 -0
  101. package/framework/stacks/rails/authentication.md +176 -0
  102. package/framework/stacks/rails/code-quality.md +287 -0
  103. package/framework/stacks/rails/code-refactoring.md +299 -0
  104. package/framework/stacks/rails/feedback.md +130 -0
  105. package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
  106. package/framework/stacks/rails/rails.md +301 -0
  107. package/framework/stacks/rails/rails8-best-practices.md +498 -0
  108. package/framework/stacks/rails/rails8-css.md +573 -0
  109. package/framework/stacks/rails/structure.md +140 -0
  110. package/framework/stacks/rails/tech.md +108 -0
  111. package/framework/stacks/react/code-quality.md +521 -0
  112. package/framework/stacks/react/components.md +625 -0
  113. package/framework/stacks/react/data-fetching.md +586 -0
  114. package/framework/stacks/react/feedback.md +110 -0
  115. package/framework/stacks/react/forms.md +694 -0
  116. package/framework/stacks/react/performance.md +640 -0
  117. package/framework/stacks/react/product.md +22 -9
  118. package/framework/stacks/react/state-management.md +472 -0
  119. package/framework/stacks/react/structure.md +351 -44
  120. package/framework/stacks/react/tech.md +219 -30
  121. package/framework/stacks/react/testing.md +690 -0
  122. package/package.json +1 -1
  123. package/framework/stacks/node/product.md +0 -27
  124. package/framework/stacks/node/structure.md +0 -82
  125. package/framework/stacks/node/tech.md +0 -63
@@ -0,0 +1,498 @@
1
+ # Rails 8 Best Practices and Anti-Patterns
2
+
3
+ Project memory for Rails 8 development patterns, common pitfalls, and modern conventions.
4
+
5
+ ---
6
+
7
+ ## Rails 8 Specific Features
8
+
9
+ ### Solid Stack (Database-Backed Infrastructure)
10
+
11
+ Rails 8 replaces Redis dependencies with database-backed adapters:
12
+
13
+ ```ruby
14
+ # config/application.rb - Production configuration
15
+ config.active_job.queue_adapter = :solid_queue
16
+ config.cache_store = :solid_cache_store
17
+ config.action_cable.adapter = :solid_cable
18
+ ```
19
+
20
+ **Best Practice**: Use Solid Stack for simpler operations (no Redis dependency).
21
+
22
+ **Anti-Pattern**: Adding Redis for simple queue/cache needs when Solid Stack suffices.
23
+
24
+ ### Modern Browser Enforcement
25
+
26
+ ```ruby
27
+ # ApplicationController - Rails 8.1 default
28
+ allow_browser versions: :modern
29
+ ```
30
+
31
+ **Best Practice**: Keep this default; it gracefully handles legacy browser warnings.
32
+
33
+ **Anti-Pattern**: Removing this and manually checking browser capabilities.
34
+
35
+ ### Importmap-Based JavaScript
36
+
37
+ ```ruby
38
+ # config/importmap.rb - ESM imports without bundler
39
+ pin "application"
40
+ pin "@hotwired/turbo-rails", to: "turbo.min.js"
41
+ pin "@hotwired/stimulus", to: "stimulus.min.js"
42
+ ```
43
+
44
+ **Best Practice**: Use importmaps for application JS; avoid bundlers unless necessary.
45
+
46
+ **Anti-Pattern**: Adding Webpack/esbuild for simple JS needs that importmaps handle.
47
+
48
+ ---
49
+
50
+ ## Hotwire Best Practices
51
+
52
+ ### Turbo Frames
53
+
54
+ Use Turbo Frames for partial page updates without custom JavaScript:
55
+
56
+ ```erb
57
+ <%# Best Practice: Scoped updates %>
58
+ <%= turbo_frame_tag "sources" do %>
59
+ <%= render @sources %>
60
+ <% end %>
61
+ ```
62
+
63
+ **Anti-Pattern**: Using JavaScript fetch() for simple HTML replacements.
64
+
65
+ ### Turbo Streams
66
+
67
+ Use for real-time broadcasts from models:
68
+
69
+ ```ruby
70
+ # Model callback pattern (as seen in Source model)
71
+ class Source < ApplicationRecord
72
+ include Turbo::Broadcastable
73
+
74
+ after_update_commit :broadcast_status_change, if: :saved_change_to_status?
75
+
76
+ private
77
+
78
+ def broadcast_status_change
79
+ broadcast_replace_later_to(
80
+ project,
81
+ target: dom_target,
82
+ partial: "sources/source",
83
+ locals: { source: self }
84
+ )
85
+ end
86
+ end
87
+ ```
88
+
89
+ **Best Practice**: Use `broadcast_replace_later_to` for async broadcasts from jobs.
90
+
91
+ **Anti-Pattern**: Synchronous broadcasts in model callbacks (blocks request).
92
+
93
+ ### Stimulus Controllers
94
+
95
+ ```javascript
96
+ // Best Practice: Minimal, focused controllers
97
+ import { Controller } from "@hotwired/stimulus"
98
+
99
+ export default class extends Controller {
100
+ static targets = ["indicator"]
101
+
102
+ connect() {
103
+ // Clean setup with bound handlers
104
+ this.handleLoad = this.handleLoad.bind(this)
105
+ this.element.addEventListener("turbo:frame-load", this.handleLoad)
106
+ }
107
+
108
+ disconnect() {
109
+ // Always clean up listeners
110
+ this.element.removeEventListener("turbo:frame-load", this.handleLoad)
111
+ }
112
+ }
113
+ ```
114
+
115
+ **Anti-Pattern**: Large Stimulus controllers doing too much (split into multiple).
116
+
117
+ **Anti-Pattern**: Not cleaning up event listeners in `disconnect()`.
118
+
119
+ ---
120
+
121
+ ## Controller Patterns
122
+
123
+ ### RESTful Design
124
+
125
+ ```ruby
126
+ # Best Practice: Standard REST actions with respond_to
127
+ def create
128
+ @source = @project.sources.build(source_params)
129
+
130
+ respond_to do |format|
131
+ if @source.save
132
+ format.html { redirect_to @source, notice: "Created." }
133
+ format.turbo_stream
134
+ else
135
+ format.html { render :new, status: :unprocessable_entity }
136
+ format.turbo_stream { render :form_update, status: :unprocessable_entity }
137
+ end
138
+ end
139
+ end
140
+ ```
141
+
142
+ **Anti-Pattern**: Custom action names when REST actions work (avoid `do_create`, `process_form`).
143
+
144
+ ### Strong Parameters
145
+
146
+ ```ruby
147
+ # Best Practice: Separate params for create vs update when needed
148
+ def source_params
149
+ params.require(:source).permit(:url, :title, :notes)
150
+ end
151
+
152
+ def update_params
153
+ # URL is immutable after creation
154
+ params.require(:source).permit(:title, :notes)
155
+ end
156
+ ```
157
+
158
+ **Anti-Pattern**: Permitting `.permit!` or overly broad parameters.
159
+
160
+ ### Scoped Queries Through Current User
161
+
162
+ ```ruby
163
+ # Best Practice: Always scope through authenticated user
164
+ def set_source
165
+ @source = Source.joins(:project)
166
+ .where(projects: { user_id: Current.user.id })
167
+ .find(params[:id])
168
+ end
169
+ ```
170
+
171
+ **Anti-Pattern**: `Source.find(params[:id])` without user scoping (authorization bypass).
172
+
173
+ ### Global Exception Handling
174
+
175
+ ```ruby
176
+ # Best Practice: Centralized error handling with format awareness
177
+ class ApplicationController < ActionController::Base
178
+ rescue_from ActiveRecord::RecordNotFound do |exception|
179
+ respond_to do |format|
180
+ format.html { render file: Rails.public_path.join("404.html"), status: :not_found }
181
+ format.turbo_stream { head :not_found }
182
+ format.json { render json: { error: "Not found" }, status: :not_found }
183
+ end
184
+ end
185
+ end
186
+ ```
187
+
188
+ **Anti-Pattern**: Handling exceptions in every controller action.
189
+
190
+ ---
191
+
192
+ ## Model Patterns
193
+
194
+ ### Organization Structure
195
+
196
+ ```ruby
197
+ class Source < ApplicationRecord
198
+ # 1. Includes
199
+ include Turbo::Broadcastable
200
+
201
+ # 2. Associations
202
+ belongs_to :project
203
+ has_many :ideas, through: :idea_sources
204
+
205
+ # 3. Enums
206
+ enum :status, { pending: 0, collecting: 1, collected: 2, failed: 3 }
207
+
208
+ # 4. Validations
209
+ validates :url, presence: true
210
+
211
+ # 5. Scopes
212
+ scope :pending_processing, -> { where(processing_status: :pending) }
213
+
214
+ # 6. Callbacks (use sparingly)
215
+ after_create_commit :enqueue_processing, if: :should_process?
216
+
217
+ # 7. Public instance methods
218
+ def needs_processing?
219
+ processing_pending? || processing_failed?
220
+ end
221
+
222
+ private
223
+
224
+ # 8. Private methods
225
+ def enqueue_processing
226
+ ProcessingJob.perform_later(id)
227
+ end
228
+ end
229
+ ```
230
+
231
+ ### Enum Best Practices
232
+
233
+ ```ruby
234
+ # Best Practice: Use symbol keys, add prefix for conflicts
235
+ enum :status, { pending: 0, failed: 3 }
236
+ enum :processing_status, { pending: "pending", failed: "failed" }, prefix: :processing
237
+
238
+ # Usage: source.pending? vs source.processing_pending?
239
+ ```
240
+
241
+ **Anti-Pattern**: String-based enums without prefix when names conflict.
242
+
243
+ ### Scopes Over Query Methods
244
+
245
+ ```ruby
246
+ # Best Practice: Chainable scopes
247
+ scope :from_feed, ->(feed) { where(feed: feed) }
248
+ scope :with_full_metadata, -> { where.not(title: [nil, ""]).where.not(description: [nil, ""]) }
249
+
250
+ # Usage: Source.from_feed(feed).with_full_metadata.collected
251
+ ```
252
+
253
+ **Anti-Pattern**: Class methods that return single records or non-chainable results.
254
+
255
+ ### Callback Discipline
256
+
257
+ ```ruby
258
+ # Best Practice: Callbacks for model-internal concerns only
259
+ after_create_commit :enqueue_job, if: :should_enqueue? # Acceptable
260
+ before_validation :normalize_url, on: :create # Acceptable
261
+
262
+ # Anti-Pattern: Business logic in callbacks
263
+ after_save :send_notification_email # Move to service/controller
264
+ after_save :update_related_records # Use transactions in service
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Background Job Patterns
270
+
271
+ ### Job Structure
272
+
273
+ ```ruby
274
+ class CollectContentJob < ApplicationJob
275
+ queue_as :default
276
+
277
+ # Retry transient errors with backoff
278
+ retry_on ApiClient::ApiError,
279
+ wait: :polynomially_longer,
280
+ attempts: 3 do |job, error|
281
+ job.send(:mark_failed, error)
282
+ end
283
+
284
+ # Discard non-retryable errors
285
+ discard_on ApiClient::ConfigurationError do |job, error|
286
+ job.send(:mark_failed, error)
287
+ end
288
+
289
+ discard_on ActiveRecord::RecordNotFound
290
+
291
+ def perform(source_id)
292
+ source = Source.find_by(id: source_id)
293
+ return if source.nil? # Deleted while queued
294
+
295
+ # Job logic here
296
+ end
297
+
298
+ private
299
+
300
+ def mark_failed(error)
301
+ # Handle failure state
302
+ end
303
+ end
304
+ ```
305
+
306
+ **Best Practice**: Use `find_by` + nil check for records that might be deleted.
307
+
308
+ **Anti-Pattern**: Using `find` without handling `RecordNotFound` in jobs.
309
+
310
+ ### Rate Limit Handling
311
+
312
+ ```ruby
313
+ # Best Practice: Extract wait time from rate limit errors
314
+ retry_on ApiClient::RateLimitError,
315
+ wait: ->(executions, exception) { exception.retry_after || (executions**4) + 2 },
316
+ attempts: 3
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Service Object Patterns
322
+
323
+ ### Result Objects
324
+
325
+ ```ruby
326
+ # Best Practice: Explicit result types
327
+ class ContentCollectionService
328
+ class Result
329
+ attr_reader :job_id, :error_type, :error_message
330
+
331
+ def success? = @success
332
+ def error? = !@success
333
+
334
+ def self.success(job_id:)
335
+ new(success: true, job_id: job_id)
336
+ end
337
+
338
+ def self.error(type:, message:)
339
+ new(success: false, error_type: type, error_message: message)
340
+ end
341
+ end
342
+ end
343
+ ```
344
+
345
+ **Anti-Pattern**: Returning `true`/`false` or raising exceptions for expected failures.
346
+
347
+ ### Error Hierarchy
348
+
349
+ ```ruby
350
+ # Best Practice: Domain-specific error classes
351
+ class LlmService
352
+ class Error < StandardError; end
353
+ class ConfigurationError < Error; end
354
+ class AuthenticationError < Error; end
355
+ class RateLimitError < Error; end
356
+
357
+ def call
358
+ # Map external errors to domain errors
359
+ rescue ExternalLib::UnauthorizedError => e
360
+ raise AuthenticationError, e.message
361
+ end
362
+ end
363
+ ```
364
+
365
+ ---
366
+
367
+ ## Security Practices
368
+
369
+ ### Current User Pattern
370
+
371
+ ```ruby
372
+ # Best Practice: Thread-safe current user via Current
373
+ class Current < ActiveSupport::CurrentAttributes
374
+ attribute :user, :session
375
+ end
376
+
377
+ # Set in controller
378
+ Current.user = user_from_session
379
+ ```
380
+
381
+ ### Credential Sanitization
382
+
383
+ ```ruby
384
+ # Best Practice: Sanitize error messages
385
+ def log_error_safely(message)
386
+ sanitized = message.gsub(/[a-zA-Z0-9_-]{20,}/, "[FILTERED]")
387
+ Rails.logger.error(sanitized)
388
+ end
389
+ ```
390
+
391
+ **Anti-Pattern**: Logging raw API responses that may contain keys.
392
+
393
+ ### Input Validation
394
+
395
+ ```ruby
396
+ # Best Practice: Validate URLs explicitly
397
+ validates :url, format: { with: URI::DEFAULT_PARSER.make_regexp(%w[http https]) }
398
+ validates :image_url, format: { with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_blank: true }
399
+ ```
400
+
401
+ ---
402
+
403
+ ## Performance Anti-Patterns
404
+
405
+ ### N+1 Queries
406
+
407
+ ```ruby
408
+ # Anti-Pattern
409
+ @sources.each { |s| s.project.name }
410
+
411
+ # Best Practice
412
+ @sources = Source.includes(:project)
413
+ ```
414
+
415
+ ### Unbounded Queries
416
+
417
+ ```ruby
418
+ # Anti-Pattern
419
+ Source.all.each { |s| process(s) }
420
+
421
+ # Best Practice
422
+ Source.find_each(batch_size: 100) { |s| process(s) }
423
+ ```
424
+
425
+ ### Missing Indexes
426
+
427
+ ```ruby
428
+ # Best Practice: Index foreign keys and common query columns
429
+ add_index :sources, [:project_id, :status]
430
+ add_index :sources, [:feed_id, :created_at]
431
+ ```
432
+
433
+ ---
434
+
435
+ ## Testing Anti-Patterns
436
+
437
+ ### Testing Implementation Instead of Behavior
438
+
439
+ ```ruby
440
+ # Anti-Pattern
441
+ test "calls the right method" do
442
+ expect(service).to receive(:internal_method)
443
+ service.call
444
+ end
445
+
446
+ # Best Practice
447
+ test "returns success when valid" do
448
+ result = service.call
449
+ assert result.success?
450
+ end
451
+ ```
452
+
453
+ ### Missing HTTP Stubs
454
+
455
+ ```ruby
456
+ # Best Practice: Stub external requests in setup
457
+ setup do
458
+ stub_request(:head, /example\.com/).to_return(status: 200)
459
+ end
460
+ ```
461
+
462
+ ---
463
+
464
+ ## Common Pitfalls
465
+
466
+ | Pitfall | Solution |
467
+ |---------|----------|
468
+ | Forgetting `status: :unprocessable_entity` on render | Always include for form errors |
469
+ | Using `find` in jobs for deletable records | Use `find_by` with nil check |
470
+ | Inline Turbo Stream logic | Create `.turbo_stream.erb` views |
471
+ | Synchronous broadcasts in callbacks | Use `broadcast_*_later_to` |
472
+ | Raw SQL with user input | Use parameterized queries or scopes |
473
+ | Large service objects | Split by responsibility |
474
+ | Callbacks for business logic | Move to services |
475
+
476
+ ---
477
+
478
+ ## Quick Reference
479
+
480
+ ```bash
481
+ # Development commands
482
+ bin/rails server
483
+ bin/rails console
484
+ bin/rails test
485
+ bin/rails test:system
486
+
487
+ # Code quality
488
+ bundle exec rubocop
489
+ bundle exec brakeman
490
+
491
+ # Database
492
+ bin/rails db:migrate
493
+ bin/rails db:seed
494
+ ```
495
+
496
+ ---
497
+
498
+ _Focus on Rails 8 conventions and modern patterns. See `rails.md` for additional conventions._