red64-cli 0.5.0 → 0.6.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 (62) hide show
  1. package/README.md +64 -58
  2. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  3. package/dist/components/screens/StartScreen.js +2 -2
  4. package/dist/components/screens/StartScreen.js.map +1 -1
  5. package/dist/services/AgentInvoker.js +4 -4
  6. package/dist/services/AgentInvoker.js.map +1 -1
  7. package/dist/services/ClaudeHealthCheck.d.ts +5 -0
  8. package/dist/services/ClaudeHealthCheck.d.ts.map +1 -1
  9. package/dist/services/ClaudeHealthCheck.js +43 -5
  10. package/dist/services/ClaudeHealthCheck.js.map +1 -1
  11. package/dist/services/index.d.ts +1 -1
  12. package/dist/services/index.d.ts.map +1 -1
  13. package/dist/services/index.js +1 -1
  14. package/dist/services/index.js.map +1 -1
  15. package/framework/stacks/c/code-quality.md +326 -0
  16. package/framework/stacks/c/coding-style.md +347 -0
  17. package/framework/stacks/c/conventions.md +513 -0
  18. package/framework/stacks/c/error-handling.md +350 -0
  19. package/framework/stacks/c/feedback.md +158 -0
  20. package/framework/stacks/c/memory-safety.md +408 -0
  21. package/framework/stacks/c/tech.md +122 -0
  22. package/framework/stacks/c/testing.md +472 -0
  23. package/framework/stacks/cpp/code-quality.md +282 -0
  24. package/framework/stacks/cpp/coding-style.md +363 -0
  25. package/framework/stacks/cpp/conventions.md +420 -0
  26. package/framework/stacks/cpp/error-handling.md +264 -0
  27. package/framework/stacks/cpp/feedback.md +104 -0
  28. package/framework/stacks/cpp/memory-safety.md +351 -0
  29. package/framework/stacks/cpp/tech.md +160 -0
  30. package/framework/stacks/cpp/testing.md +323 -0
  31. package/framework/stacks/java/code-quality.md +357 -0
  32. package/framework/stacks/java/coding-style.md +400 -0
  33. package/framework/stacks/java/conventions.md +437 -0
  34. package/framework/stacks/java/error-handling.md +408 -0
  35. package/framework/stacks/java/feedback.md +180 -0
  36. package/framework/stacks/java/tech.md +126 -0
  37. package/framework/stacks/java/testing.md +485 -0
  38. package/framework/stacks/javascript/async-patterns.md +216 -0
  39. package/framework/stacks/javascript/code-quality.md +182 -0
  40. package/framework/stacks/javascript/coding-style.md +293 -0
  41. package/framework/stacks/javascript/conventions.md +268 -0
  42. package/framework/stacks/javascript/error-handling.md +216 -0
  43. package/framework/stacks/javascript/feedback.md +80 -0
  44. package/framework/stacks/javascript/tech.md +114 -0
  45. package/framework/stacks/javascript/testing.md +209 -0
  46. package/framework/stacks/loco/code-quality.md +156 -0
  47. package/framework/stacks/loco/coding-style.md +247 -0
  48. package/framework/stacks/loco/error-handling.md +225 -0
  49. package/framework/stacks/loco/feedback.md +35 -0
  50. package/framework/stacks/loco/loco.md +342 -0
  51. package/framework/stacks/loco/structure.md +193 -0
  52. package/framework/stacks/loco/tech.md +129 -0
  53. package/framework/stacks/loco/testing.md +211 -0
  54. package/framework/stacks/rust/code-quality.md +370 -0
  55. package/framework/stacks/rust/coding-style.md +475 -0
  56. package/framework/stacks/rust/conventions.md +430 -0
  57. package/framework/stacks/rust/error-handling.md +399 -0
  58. package/framework/stacks/rust/feedback.md +152 -0
  59. package/framework/stacks/rust/memory-safety.md +398 -0
  60. package/framework/stacks/rust/tech.md +121 -0
  61. package/framework/stacks/rust/testing.md +528 -0
  62. package/package.json +14 -2
@@ -0,0 +1,475 @@
1
+ # Rust Coding Style
2
+
3
+ Coding style conventions for idiomatic, expressive Rust. Opinionated patterns that go beyond what `cargo fmt` enforces automatically.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Leverage the type system**: Encode invariants in types, not runtime checks
10
+ - **Iterator chains over loops**: Functional composition is clearer and often faster
11
+ - **Clippy is law**: If Clippy warns, fix it or explicitly allow with justification
12
+ - **Explicitness over cleverness**: Prefer readable code; the compiler optimizes for you
13
+
14
+ ---
15
+
16
+ ## Naming Conventions
17
+
18
+ ### Standard Rust Naming
19
+
20
+ | Element | Convention | Example |
21
+ |---|---|---|
22
+ | Variables, functions | `snake_case` | `user_count`, `get_user` |
23
+ | Types, traits, enums | `PascalCase` | `UserService`, `Serialize` |
24
+ | Constants, statics | `SCREAMING_SNAKE_CASE` | `MAX_RETRIES`, `DEFAULT_PORT` |
25
+ | Modules, crates | `snake_case` | `user_service`, `auth_utils` |
26
+ | Type parameters | Single uppercase or `PascalCase` | `T`, `E`, `Item` |
27
+ | Lifetimes | Short lowercase with `'` | `'a`, `'ctx`, `'conn` |
28
+ | Macros | `snake_case!` | `vec!`, `println!`, `query!` |
29
+ | Feature flags | `kebab-case` | `full`, `serde-support` |
30
+
31
+ ### Naming Rules
32
+
33
+ ```rust
34
+ // GOOD: Descriptive, reveals intent
35
+ let active_user_count = users.iter().filter(|u| u.is_active).count();
36
+ let is_authenticated = token.is_some();
37
+ const MAX_RETRY_ATTEMPTS: u32 = 3;
38
+
39
+ fn find_user_by_email(email: &str) -> Option<User> {
40
+ // ...
41
+ }
42
+
43
+ struct PaymentProcessingError;
44
+
45
+ // BAD: Abbreviated, unclear
46
+ let uc = users.iter().filter(|u| u.is_active).count();
47
+ let auth = token.is_some();
48
+ const N: u32 = 3;
49
+
50
+ fn find_u(e: &str) -> Option<User> {
51
+ // ...
52
+ }
53
+ ```
54
+
55
+ ### Boolean Naming
56
+
57
+ Prefix with `is_`, `has_`, `can_`, `should_`:
58
+
59
+ ```rust
60
+ struct User {
61
+ is_active: bool,
62
+ has_verified_email: bool,
63
+ can_publish: bool,
64
+ }
65
+ ```
66
+
67
+ ### Conversion Method Naming
68
+
69
+ Follow the standard library conventions:
70
+
71
+ | Pattern | Ownership | Example |
72
+ |---|---|---|
73
+ | `as_*` | Borrowed -> borrowed (cheap) | `as_str()`, `as_bytes()` |
74
+ | `to_*` | Borrowed -> owned (expensive) | `to_string()`, `to_vec()` |
75
+ | `into_*` | Owned -> owned (consuming) | `into_inner()`, `into_bytes()` |
76
+ | `from_*` | Associated function constructor | `from_str()`, `from_parts()` |
77
+
78
+ ---
79
+
80
+ ## Function Design
81
+
82
+ ### Size Limits
83
+
84
+ - **Target**: Under 25 lines of logic
85
+ - **Maximum**: 50 lines (extract if longer)
86
+ - **Parameters**: Maximum 5; use a builder or config struct for more
87
+
88
+ ```rust
89
+ // GOOD: Small, focused
90
+ async fn create_user(pool: &PgPool, data: &CreateUserRequest) -> Result<User> {
91
+ validate_email_available(pool, &data.email).await?;
92
+ let password_hash = hash_password(&data.password)?;
93
+ let user = sqlx::query_as!(
94
+ User,
95
+ "INSERT INTO users (email, name, password_hash) VALUES ($1, $2, $3) RETURNING *",
96
+ data.email,
97
+ data.name,
98
+ password_hash,
99
+ )
100
+ .fetch_one(pool)
101
+ .await?;
102
+ Ok(user)
103
+ }
104
+
105
+ // BAD: Too many parameters, too many responsibilities
106
+ async fn create_user(
107
+ pool: &PgPool,
108
+ email: &str,
109
+ name: &str,
110
+ password: &str,
111
+ role: &str,
112
+ bio: Option<&str>,
113
+ avatar_url: Option<&str>,
114
+ send_email: bool,
115
+ ) -> Result<User> {
116
+ // 80+ lines doing validation, hashing, saving, emailing...
117
+ }
118
+ ```
119
+
120
+ ### Prefer `&str` Over `String` in Parameters
121
+
122
+ ```rust
123
+ // GOOD: Accepts both &str and &String
124
+ fn validate_email(email: &str) -> bool {
125
+ email.contains('@')
126
+ }
127
+
128
+ // BAD: Forces caller to allocate
129
+ fn validate_email(email: String) -> bool {
130
+ email.contains('@')
131
+ }
132
+
133
+ // GOOD: Use String when ownership is needed
134
+ fn set_name(&mut self, name: String) {
135
+ self.name = name;
136
+ }
137
+ ```
138
+
139
+ ### Early Returns with `?`
140
+
141
+ ```rust
142
+ // GOOD: Flat with ? operator
143
+ async fn publish_post(pool: &PgPool, post_id: i64, user_id: i64) -> Result<Post> {
144
+ let post = get_post(pool, post_id).await?.ok_or(AppError::NotFound("Post"))?;
145
+ if post.user_id != user_id {
146
+ return Err(AppError::Forbidden("Cannot publish another user's post"));
147
+ }
148
+ if post.status == PostStatus::Published {
149
+ return Err(AppError::Conflict("Post is already published"));
150
+ }
151
+ update_post_status(pool, post_id, PostStatus::Published).await
152
+ }
153
+
154
+ // BAD: Deeply nested
155
+ async fn publish_post(pool: &PgPool, post_id: i64, user_id: i64) -> Result<Post> {
156
+ if let Some(post) = get_post(pool, post_id).await? {
157
+ if post.user_id == user_id {
158
+ if post.status != PostStatus::Published {
159
+ update_post_status(pool, post_id, PostStatus::Published).await
160
+ } else {
161
+ Err(AppError::Conflict("Already published"))
162
+ }
163
+ } else {
164
+ Err(AppError::Forbidden("Not your post"))
165
+ }
166
+ } else {
167
+ Err(AppError::NotFound("Post"))
168
+ }
169
+ }
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Iterator Chains Over Loops
175
+
176
+ ### Prefer Functional Style
177
+
178
+ ```rust
179
+ // GOOD: Iterator chain
180
+ let active_emails: Vec<String> = users
181
+ .iter()
182
+ .filter(|u| u.is_active)
183
+ .map(|u| u.email.clone())
184
+ .collect();
185
+
186
+ // BAD: Imperative loop
187
+ let mut active_emails = Vec::new();
188
+ for user in &users {
189
+ if user.is_active {
190
+ active_emails.push(user.email.clone());
191
+ }
192
+ }
193
+
194
+ // GOOD: Complex chain with intermediate operations
195
+ let report: Vec<CategoryReport> = orders
196
+ .iter()
197
+ .filter(|o| o.status == OrderStatus::Completed)
198
+ .fold(HashMap::new(), |mut acc, o| {
199
+ *acc.entry(&o.category).or_insert(Decimal::ZERO) += o.amount;
200
+ acc
201
+ })
202
+ .into_iter()
203
+ .map(|(category, total)| CategoryReport { category: category.clone(), total })
204
+ .collect();
205
+ ```
206
+
207
+ ### When Loops Are Fine
208
+
209
+ Use loops when the body has complex control flow (early returns, multiple mutations, error handling with side effects):
210
+
211
+ ```rust
212
+ // Loop is clearer here due to error handling with context
213
+ for (i, item) in items.iter().enumerate() {
214
+ match process_item(item).await {
215
+ Ok(result) => results.push(result),
216
+ Err(e) => {
217
+ tracing::warn!(index = i, error = %e, "Skipping failed item");
218
+ failures.push((i, e));
219
+ }
220
+ }
221
+ }
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Type State Pattern
227
+
228
+ Encode state transitions in the type system so invalid states are unrepresentable:
229
+
230
+ ```rust
231
+ // GOOD: Type state pattern
232
+ use std::marker::PhantomData;
233
+
234
+ struct Order<S: OrderState> {
235
+ id: i64,
236
+ items: Vec<OrderItem>,
237
+ _state: PhantomData<S>,
238
+ }
239
+
240
+ struct Draft;
241
+ struct Confirmed;
242
+ struct Shipped;
243
+
244
+ trait OrderState {}
245
+ impl OrderState for Draft {}
246
+ impl OrderState for Confirmed {}
247
+ impl OrderState for Shipped {}
248
+
249
+ impl Order<Draft> {
250
+ fn confirm(self, payment: Payment) -> Result<Order<Confirmed>> {
251
+ // Only drafts can be confirmed
252
+ Ok(Order {
253
+ id: self.id,
254
+ items: self.items,
255
+ _state: PhantomData,
256
+ })
257
+ }
258
+ }
259
+
260
+ impl Order<Confirmed> {
261
+ fn ship(self, tracking: &str) -> Order<Shipped> {
262
+ // Only confirmed orders can be shipped
263
+ Order {
264
+ id: self.id,
265
+ items: self.items,
266
+ _state: PhantomData,
267
+ }
268
+ }
269
+ }
270
+
271
+ // Compile error: cannot ship a draft
272
+ // let shipped = draft_order.ship("TRACK123"); // ERROR: method not found
273
+
274
+ // BAD: Runtime state check
275
+ struct OrderBad {
276
+ status: OrderStatus,
277
+ }
278
+
279
+ impl OrderBad {
280
+ fn ship(&mut self, tracking: &str) -> Result<()> {
281
+ if self.status != OrderStatus::Confirmed {
282
+ return Err(anyhow!("Cannot ship order in {:?} state", self.status));
283
+ }
284
+ self.status = OrderStatus::Shipped;
285
+ Ok(())
286
+ }
287
+ }
288
+ ```
289
+
290
+ ---
291
+
292
+ ## Builder Pattern
293
+
294
+ Use builders for constructing complex types with many optional fields:
295
+
296
+ ```rust
297
+ // GOOD: Builder pattern
298
+ #[derive(Default)]
299
+ struct QueryBuilder {
300
+ filter: Option<String>,
301
+ sort_by: Option<String>,
302
+ page: u32,
303
+ per_page: u32,
304
+ }
305
+
306
+ impl QueryBuilder {
307
+ fn new() -> Self {
308
+ Self {
309
+ page: 1,
310
+ per_page: 20,
311
+ ..Default::default()
312
+ }
313
+ }
314
+
315
+ fn filter(mut self, filter: impl Into<String>) -> Self {
316
+ self.filter = Some(filter.into());
317
+ self
318
+ }
319
+
320
+ fn sort_by(mut self, field: impl Into<String>) -> Self {
321
+ self.sort_by = Some(field.into());
322
+ self
323
+ }
324
+
325
+ fn page(mut self, page: u32) -> Self {
326
+ self.page = page;
327
+ self
328
+ }
329
+
330
+ fn build(self) -> Query {
331
+ Query {
332
+ filter: self.filter,
333
+ sort_by: self.sort_by,
334
+ page: self.page,
335
+ per_page: self.per_page,
336
+ }
337
+ }
338
+ }
339
+
340
+ // Usage
341
+ let query = QueryBuilder::new()
342
+ .filter("active")
343
+ .sort_by("created_at")
344
+ .page(2)
345
+ .build();
346
+ ```
347
+
348
+ ---
349
+
350
+ ## Newtype Pattern
351
+
352
+ Wrap primitive types to add type safety and domain meaning:
353
+
354
+ ```rust
355
+ // GOOD: Newtype prevents mixing up IDs
356
+ struct UserId(i64);
357
+ struct PostId(i64);
358
+
359
+ fn get_post(user_id: UserId, post_id: PostId) -> Result<Post> {
360
+ // Cannot accidentally swap user_id and post_id
361
+ }
362
+
363
+ // BAD: Easy to mix up bare i64 parameters
364
+ fn get_post_bad(user_id: i64, post_id: i64) -> Result<Post> {
365
+ // Caller might swap arguments -- compiles fine, fails at runtime
366
+ }
367
+
368
+ // Newtype with validation
369
+ struct Email(String);
370
+
371
+ impl Email {
372
+ fn new(value: impl Into<String>) -> Result<Self> {
373
+ let value = value.into();
374
+ if !value.contains('@') {
375
+ return Err(anyhow!("Invalid email: {}", value));
376
+ }
377
+ Ok(Self(value))
378
+ }
379
+
380
+ fn as_str(&self) -> &str {
381
+ &self.0
382
+ }
383
+ }
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Turbofish Syntax
389
+
390
+ Use turbofish (`::<Type>`) when the compiler cannot infer types:
391
+
392
+ ```rust
393
+ // GOOD: Turbofish for parse
394
+ let port = "8080".parse::<u16>()?;
395
+
396
+ // GOOD: Turbofish for collect
397
+ let ids = raw_ids.iter().map(|s| s.parse::<i64>()).collect::<Result<Vec<_>, _>>()?;
398
+
399
+ // GOOD: No turbofish needed -- type annotation on binding
400
+ let port: u16 = "8080".parse()?;
401
+
402
+ // BAD: Ambiguous without turbofish or annotation
403
+ // let port = "8080".parse()?; // ERROR: cannot infer type
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Module Organization
409
+
410
+ ```rust
411
+ // GOOD: Flat, explicit re-exports
412
+ // src/models/mod.rs
413
+ mod user;
414
+ mod post;
415
+ mod comment;
416
+
417
+ pub use user::User;
418
+ pub use post::Post;
419
+ pub use comment::Comment;
420
+
421
+ // GOOD: File-based modules (Rust 2024 preferred)
422
+ // src/models.rs (instead of src/models/mod.rs for simple cases)
423
+
424
+ // BAD: Deep nesting with re-exports at every level
425
+ // src/domain/models/entities/user/mod.rs
426
+ ```
427
+
428
+ ---
429
+
430
+ ## File and Type Size
431
+
432
+ ### Guidelines
433
+
434
+ | Element | Guideline |
435
+ |---|---|
436
+ | Function | Under 25 lines of logic, max 50 |
437
+ | Struct impl block | Under 200 lines, max 300 |
438
+ | Module file | Under 300 lines, max 500 |
439
+ | Parameters | Max 5 per function; use struct for more |
440
+
441
+ When a file exceeds limits, extract:
442
+ - Helper functions into a submodule
443
+ - Trait implementations into separate impl blocks
444
+ - Related types into their own module
445
+
446
+ ---
447
+
448
+ ## Anti-Patterns
449
+
450
+ | Anti-Pattern | Problem | Correct Approach |
451
+ |---|---|---|
452
+ | `.unwrap()` in production | Panics on `None`/`Err` | Use `?`, `.ok_or()`, `.unwrap_or_default()` |
453
+ | `clone()` everywhere | Hidden performance cost | Borrow with `&` or use `Arc` for shared ownership |
454
+ | Stringly-typed APIs | No compile-time safety | Use enums or newtype pattern |
455
+ | Massive match arms | Hard to read, easy to miss cases | Extract into methods, use trait dispatch |
456
+ | `pub` on everything | Leaks implementation details | Default to `pub(crate)`, expose minimal API |
457
+ | Ignoring Clippy lints | Misses idiomatic patterns | Run `cargo clippy -- -D warnings` in CI |
458
+ | `Box<dyn Error>` in libraries | Loses type info for callers | Use `thiserror` custom error enums |
459
+
460
+ ---
461
+
462
+ ## Formatting (Handled by `cargo fmt`)
463
+
464
+ These are automated -- do not worry about them manually:
465
+
466
+ - Line length: 100 characters (configurable in `rustfmt.toml`)
467
+ - Indentation: 4 spaces
468
+ - Trailing commas in multi-line constructs
469
+ - Brace style: same line for functions, next line for control flow only if multi-line
470
+
471
+ Run `cargo fmt` and move on.
472
+
473
+ ---
474
+
475
+ _The Rust compiler is your strictest reviewer. Lean into its type system to make illegal states unrepresentable, and let Clippy handle the rest._