@su-record/vibe 2.4.34 → 2.4.36

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 (102) hide show
  1. package/CLAUDE.md +345 -351
  2. package/LICENSE +21 -21
  3. package/README.md +210 -210
  4. package/agents/compounder.md +261 -261
  5. package/agents/diagrammer.md +178 -178
  6. package/agents/e2e-tester.md +266 -266
  7. package/agents/explorer.md +48 -48
  8. package/agents/implementer.md +53 -53
  9. package/agents/research/best-practices-agent.md +139 -139
  10. package/agents/research/codebase-patterns-agent.md +147 -147
  11. package/agents/research/framework-docs-agent.md +178 -178
  12. package/agents/research/security-advisory-agent.md +164 -164
  13. package/agents/review/architecture-reviewer.md +107 -107
  14. package/agents/review/complexity-reviewer.md +116 -116
  15. package/agents/review/data-integrity-reviewer.md +88 -88
  16. package/agents/review/git-history-reviewer.md +103 -103
  17. package/agents/review/performance-reviewer.md +86 -86
  18. package/agents/review/python-reviewer.md +150 -150
  19. package/agents/review/rails-reviewer.md +139 -139
  20. package/agents/review/react-reviewer.md +144 -144
  21. package/agents/review/security-reviewer.md +80 -80
  22. package/agents/review/simplicity-reviewer.md +140 -140
  23. package/agents/review/test-coverage-reviewer.md +116 -116
  24. package/agents/review/typescript-reviewer.md +127 -127
  25. package/agents/searcher.md +54 -54
  26. package/agents/simplifier.md +119 -119
  27. package/agents/tester.md +49 -49
  28. package/agents/ui-previewer.md +129 -129
  29. package/commands/vibe.analyze.md +260 -260
  30. package/commands/vibe.reason.md +223 -223
  31. package/commands/vibe.review.md +213 -213
  32. package/commands/vibe.run.md +931 -931
  33. package/commands/vibe.spec.md +442 -442
  34. package/commands/vibe.utils.md +101 -101
  35. package/commands/vibe.verify.md +282 -282
  36. package/dist/cli/collaborator.js +52 -52
  37. package/dist/cli/detect.js +32 -32
  38. package/dist/cli/index.js +137 -137
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/llm.js +147 -147
  41. package/dist/cli/llm.js.map +1 -1
  42. package/dist/cli/setup.d.ts +1 -1
  43. package/dist/cli/setup.d.ts.map +1 -1
  44. package/dist/cli/setup.js +48 -54
  45. package/dist/cli/setup.js.map +1 -1
  46. package/dist/lib/MemoryManager.d.ts +4 -0
  47. package/dist/lib/MemoryManager.d.ts.map +1 -1
  48. package/dist/lib/MemoryManager.js +21 -2
  49. package/dist/lib/MemoryManager.js.map +1 -1
  50. package/dist/lib/PythonParser.js +108 -108
  51. package/dist/lib/gemini-api.d.ts +47 -3
  52. package/dist/lib/gemini-api.d.ts.map +1 -1
  53. package/dist/lib/gemini-api.js +253 -7
  54. package/dist/lib/gemini-api.js.map +1 -1
  55. package/dist/lib/gpt-api.d.ts +37 -5
  56. package/dist/lib/gpt-api.d.ts.map +1 -1
  57. package/dist/lib/gpt-api.js +396 -37
  58. package/dist/lib/gpt-api.js.map +1 -1
  59. package/dist/tools/memory/saveMemory.js +1 -1
  60. package/dist/tools/memory/saveMemory.js.map +1 -1
  61. package/dist/tools/reasoning/applyReasoningFramework.js +56 -56
  62. package/hooks/hooks.json +215 -195
  63. package/languages/dart-flutter.md +509 -0
  64. package/languages/go.md +396 -0
  65. package/languages/java-spring.md +586 -0
  66. package/languages/kotlin-android.md +491 -0
  67. package/languages/python-django.md +371 -0
  68. package/languages/python-fastapi.md +386 -0
  69. package/languages/rust.md +425 -0
  70. package/languages/swift-ios.md +516 -0
  71. package/languages/typescript-nextjs.md +441 -0
  72. package/languages/typescript-node.md +375 -0
  73. package/languages/typescript-nuxt.md +521 -0
  74. package/languages/typescript-react-native.md +446 -0
  75. package/languages/typescript-react.md +525 -0
  76. package/languages/typescript-vue.md +353 -0
  77. package/package.json +88 -87
  78. package/skills/context7-usage.md +82 -82
  79. package/skills/git-worktree.md +181 -181
  80. package/skills/multi-llm-orchestration.md +92 -92
  81. package/skills/parallel-research.md +77 -77
  82. package/skills/priority-todos.md +239 -239
  83. package/skills/tool-fallback.md +126 -126
  84. package/skills/vibe-capabilities.md +129 -129
  85. package/{.claude/vibe → vibe}/config.json +3 -3
  86. package/{.claude/vibe → vibe}/constitution.md +184 -184
  87. package/{.claude/vibe → vibe}/rules/core/communication-guide.md +104 -104
  88. package/{.claude/vibe → vibe}/rules/core/development-philosophy.md +52 -52
  89. package/{.claude/vibe → vibe}/rules/core/quick-start.md +120 -120
  90. package/{.claude/vibe → vibe}/rules/quality/bdd-contract-testing.md +388 -388
  91. package/{.claude/vibe → vibe}/rules/quality/checklist.md +276 -276
  92. package/{.claude/vibe → vibe}/rules/quality/testing-strategy.md +437 -437
  93. package/{.claude/vibe → vibe}/rules/standards/anti-patterns.md +369 -369
  94. package/{.claude/vibe → vibe}/rules/standards/code-structure.md +291 -291
  95. package/{.claude/vibe → vibe}/rules/standards/complexity-metrics.md +312 -312
  96. package/{.claude/vibe → vibe}/rules/standards/naming-conventions.md +198 -198
  97. package/{.claude/vibe → vibe}/setup.sh +31 -31
  98. package/{.claude/vibe → vibe}/templates/constitution-template.md +184 -184
  99. package/{.claude/vibe → vibe}/templates/contract-backend-template.md +517 -517
  100. package/{.claude/vibe → vibe}/templates/contract-frontend-template.md +594 -594
  101. package/{.claude/vibe → vibe}/templates/feature-template.md +96 -96
  102. package/{.claude/vibe → vibe}/templates/spec-template.md +199 -199
@@ -0,0 +1,425 @@
1
+ # 🦀 Rust 품질 규칙
2
+
3
+ ## 핵심 원칙 (core에서 상속)
4
+
5
+ ```markdown
6
+ ✅ 단일 책임 (SRP)
7
+ ✅ 중복 제거 (DRY)
8
+ ✅ 재사용성
9
+ ✅ 낮은 복잡도
10
+ ✅ 함수 ≤ 30줄
11
+ ✅ 중첩 ≤ 3단계
12
+ ✅ Cyclomatic complexity ≤ 10
13
+ ```
14
+
15
+ ## Rust 특화 규칙
16
+
17
+ ### 1. 에러 처리 (Result, Option)
18
+
19
+ ```rust
20
+ // ❌ unwrap() 남용
21
+ let content = fs::read_to_string("config.json").unwrap();
22
+
23
+ // ✅ ? 연산자와 적절한 에러 처리
24
+ fn read_config(path: &str) -> Result<Config, ConfigError> {
25
+ let content = fs::read_to_string(path)
26
+ .map_err(|e| ConfigError::IoError(e))?;
27
+
28
+ let config: Config = serde_json::from_str(&content)
29
+ .map_err(|e| ConfigError::ParseError(e))?;
30
+
31
+ Ok(config)
32
+ }
33
+
34
+ // ✅ 커스텀 에러 타입 (thiserror)
35
+ use thiserror::Error;
36
+
37
+ #[derive(Error, Debug)]
38
+ pub enum AppError {
39
+ #[error("설정 파일을 읽을 수 없습니다: {0}")]
40
+ ConfigError(#[from] std::io::Error),
41
+
42
+ #[error("잘못된 요청입니다: {0}")]
43
+ BadRequest(String),
44
+
45
+ #[error("리소스를 찾을 수 없습니다: {resource} (ID: {id})")]
46
+ NotFound { resource: String, id: String },
47
+
48
+ #[error("데이터베이스 오류: {0}")]
49
+ DatabaseError(#[from] sqlx::Error),
50
+ }
51
+
52
+ // ✅ anyhow로 간편한 에러 처리 (애플리케이션 레벨)
53
+ use anyhow::{Context, Result};
54
+
55
+ fn process_file(path: &str) -> Result<String> {
56
+ let content = fs::read_to_string(path)
57
+ .context(format!("파일을 읽을 수 없습니다: {}", path))?;
58
+
59
+ Ok(content)
60
+ }
61
+ ```
62
+
63
+ ### 2. 구조체와 트레이트
64
+
65
+ ```rust
66
+ // ✅ 구조체 정의
67
+ use chrono::{DateTime, Utc};
68
+ use serde::{Deserialize, Serialize};
69
+ use uuid::Uuid;
70
+
71
+ #[derive(Debug, Clone, Serialize, Deserialize)]
72
+ pub struct User {
73
+ pub id: Uuid,
74
+ pub email: String,
75
+ pub name: String,
76
+ pub created_at: DateTime<Utc>,
77
+ pub updated_at: DateTime<Utc>,
78
+ }
79
+
80
+ impl User {
81
+ pub fn new(email: String, name: String) -> Self {
82
+ let now = Utc::now();
83
+ Self {
84
+ id: Uuid::new_v4(),
85
+ email,
86
+ name,
87
+ created_at: now,
88
+ updated_at: now,
89
+ }
90
+ }
91
+ }
92
+
93
+ // ✅ 트레이트 정의
94
+ #[async_trait]
95
+ pub trait UserRepository: Send + Sync {
96
+ async fn find_by_id(&self, id: Uuid) -> Result<Option<User>, AppError>;
97
+ async fn find_by_email(&self, email: &str) -> Result<Option<User>, AppError>;
98
+ async fn create(&self, user: &User) -> Result<User, AppError>;
99
+ async fn update(&self, user: &User) -> Result<User, AppError>;
100
+ async fn delete(&self, id: Uuid) -> Result<(), AppError>;
101
+ }
102
+
103
+ // ✅ 트레이트 구현
104
+ pub struct PostgresUserRepository {
105
+ pool: PgPool,
106
+ }
107
+
108
+ #[async_trait]
109
+ impl UserRepository for PostgresUserRepository {
110
+ async fn find_by_id(&self, id: Uuid) -> Result<Option<User>, AppError> {
111
+ let user = sqlx::query_as!(
112
+ User,
113
+ "SELECT * FROM users WHERE id = $1",
114
+ id
115
+ )
116
+ .fetch_optional(&self.pool)
117
+ .await?;
118
+
119
+ Ok(user)
120
+ }
121
+
122
+ // ... 다른 메서드 구현
123
+ }
124
+ ```
125
+
126
+ ### 3. Actix-web / Axum 핸들러
127
+
128
+ ```rust
129
+ // ✅ Axum 핸들러
130
+ use axum::{
131
+ extract::{Path, State, Json},
132
+ http::StatusCode,
133
+ response::IntoResponse,
134
+ };
135
+
136
+ pub async fn get_user(
137
+ State(repo): State<Arc<dyn UserRepository>>,
138
+ Path(id): Path<Uuid>,
139
+ ) -> Result<Json<User>, AppError> {
140
+ let user = repo
141
+ .find_by_id(id)
142
+ .await?
143
+ .ok_or(AppError::NotFound {
144
+ resource: "사용자".to_string(),
145
+ id: id.to_string(),
146
+ })?;
147
+
148
+ Ok(Json(user))
149
+ }
150
+
151
+ pub async fn create_user(
152
+ State(repo): State<Arc<dyn UserRepository>>,
153
+ Json(dto): Json<CreateUserDto>,
154
+ ) -> Result<(StatusCode, Json<User>), AppError> {
155
+ let user = User::new(dto.email, dto.name);
156
+ let created = repo.create(&user).await?;
157
+
158
+ Ok((StatusCode::CREATED, Json(created)))
159
+ }
160
+
161
+ // ✅ Actix-web 핸들러
162
+ use actix_web::{web, HttpResponse, Result};
163
+
164
+ pub async fn get_user(
165
+ repo: web::Data<dyn UserRepository>,
166
+ path: web::Path<Uuid>,
167
+ ) -> Result<HttpResponse, AppError> {
168
+ let id = path.into_inner();
169
+ let user = repo
170
+ .find_by_id(id)
171
+ .await?
172
+ .ok_or(AppError::NotFound {
173
+ resource: "사용자".to_string(),
174
+ id: id.to_string(),
175
+ })?;
176
+
177
+ Ok(HttpResponse::Ok().json(user))
178
+ }
179
+ ```
180
+
181
+ ### 4. 소유권과 생명주기
182
+
183
+ ```rust
184
+ // ❌ 불필요한 클론
185
+ fn process(data: &Vec<String>) -> Vec<String> {
186
+ let cloned = data.clone(); // 불필요
187
+ cloned.iter().map(|s| s.to_uppercase()).collect()
188
+ }
189
+
190
+ // ✅ 참조 활용
191
+ fn process(data: &[String]) -> Vec<String> {
192
+ data.iter().map(|s| s.to_uppercase()).collect()
193
+ }
194
+
195
+ // ✅ 생명주기 명시
196
+ pub struct UserService<'a> {
197
+ repo: &'a dyn UserRepository,
198
+ cache: &'a dyn CacheRepository,
199
+ }
200
+
201
+ impl<'a> UserService<'a> {
202
+ pub fn new(
203
+ repo: &'a dyn UserRepository,
204
+ cache: &'a dyn CacheRepository,
205
+ ) -> Self {
206
+ Self { repo, cache }
207
+ }
208
+ }
209
+
210
+ // ✅ 소유권 이전 vs 빌려오기
211
+ fn take_ownership(s: String) { /* s의 소유권을 가짐 */ }
212
+ fn borrow(s: &str) { /* s를 빌려옴 */ }
213
+ fn borrow_mut(s: &mut String) { /* s를 가변 빌려옴 */ }
214
+ ```
215
+
216
+ ### 5. 비동기 처리 (Tokio)
217
+
218
+ ```rust
219
+ // ✅ 비동기 함수
220
+ use tokio::time::{sleep, Duration};
221
+
222
+ pub async fn fetch_with_retry<T, F, Fut>(
223
+ f: F,
224
+ max_retries: u32,
225
+ ) -> Result<T, AppError>
226
+ where
227
+ F: Fn() -> Fut,
228
+ Fut: std::future::Future<Output = Result<T, AppError>>,
229
+ {
230
+ let mut attempts = 0;
231
+
232
+ loop {
233
+ match f().await {
234
+ Ok(result) => return Ok(result),
235
+ Err(e) if attempts < max_retries => {
236
+ attempts += 1;
237
+ let delay = Duration::from_millis(100 * 2_u64.pow(attempts));
238
+ sleep(delay).await;
239
+ }
240
+ Err(e) => return Err(e),
241
+ }
242
+ }
243
+ }
244
+
245
+ // ✅ 동시 실행
246
+ use futures::future::join_all;
247
+
248
+ pub async fn fetch_users(ids: Vec<Uuid>) -> Vec<Result<User, AppError>> {
249
+ let futures: Vec<_> = ids
250
+ .into_iter()
251
+ .map(|id| fetch_user(id))
252
+ .collect();
253
+
254
+ join_all(futures).await
255
+ }
256
+
257
+ // ✅ tokio::spawn으로 태스크 생성
258
+ pub async fn background_job() {
259
+ tokio::spawn(async {
260
+ loop {
261
+ process_queue().await;
262
+ sleep(Duration::from_secs(60)).await;
263
+ }
264
+ });
265
+ }
266
+ ```
267
+
268
+ ### 6. 테스트
269
+
270
+ ```rust
271
+ #[cfg(test)]
272
+ mod tests {
273
+ use super::*;
274
+ use mockall::predicate::*;
275
+ use mockall::mock;
276
+
277
+ // ✅ Mock 생성
278
+ mock! {
279
+ pub UserRepo {}
280
+
281
+ #[async_trait]
282
+ impl UserRepository for UserRepo {
283
+ async fn find_by_id(&self, id: Uuid) -> Result<Option<User>, AppError>;
284
+ async fn create(&self, user: &User) -> Result<User, AppError>;
285
+ }
286
+ }
287
+
288
+ // ✅ 단위 테스트
289
+ #[tokio::test]
290
+ async fn test_get_user_success() {
291
+ let mut mock_repo = MockUserRepo::new();
292
+ let user_id = Uuid::new_v4();
293
+ let expected_user = User::new("test@example.com".into(), "테스트".into());
294
+
295
+ mock_repo
296
+ .expect_find_by_id()
297
+ .with(eq(user_id))
298
+ .returning(move |_| Ok(Some(expected_user.clone())));
299
+
300
+ let service = UserService::new(Arc::new(mock_repo));
301
+ let result = service.get_user(user_id).await;
302
+
303
+ assert!(result.is_ok());
304
+ assert_eq!(result.unwrap().email, "test@example.com");
305
+ }
306
+
307
+ // ✅ 에러 케이스 테스트
308
+ #[tokio::test]
309
+ async fn test_get_user_not_found() {
310
+ let mut mock_repo = MockUserRepo::new();
311
+ let user_id = Uuid::new_v4();
312
+
313
+ mock_repo
314
+ .expect_find_by_id()
315
+ .returning(|_| Ok(None));
316
+
317
+ let service = UserService::new(Arc::new(mock_repo));
318
+ let result = service.get_user(user_id).await;
319
+
320
+ assert!(matches!(result, Err(AppError::NotFound { .. })));
321
+ }
322
+ }
323
+ ```
324
+
325
+ ### 7. 의존성 주입
326
+
327
+ ```rust
328
+ // ✅ 생성자 주입
329
+ pub struct UserService {
330
+ repo: Arc<dyn UserRepository>,
331
+ cache: Arc<dyn CacheRepository>,
332
+ }
333
+
334
+ impl UserService {
335
+ pub fn new(
336
+ repo: Arc<dyn UserRepository>,
337
+ cache: Arc<dyn CacheRepository>,
338
+ ) -> Self {
339
+ Self { repo, cache }
340
+ }
341
+ }
342
+
343
+ // ✅ Builder 패턴
344
+ #[derive(Default)]
345
+ pub struct ServerBuilder {
346
+ port: Option<u16>,
347
+ host: Option<String>,
348
+ timeout: Option<Duration>,
349
+ }
350
+
351
+ impl ServerBuilder {
352
+ pub fn new() -> Self {
353
+ Self::default()
354
+ }
355
+
356
+ pub fn port(mut self, port: u16) -> Self {
357
+ self.port = Some(port);
358
+ self
359
+ }
360
+
361
+ pub fn host(mut self, host: impl Into<String>) -> Self {
362
+ self.host = Some(host.into());
363
+ self
364
+ }
365
+
366
+ pub fn timeout(mut self, timeout: Duration) -> Self {
367
+ self.timeout = Some(timeout);
368
+ self
369
+ }
370
+
371
+ pub fn build(self) -> Server {
372
+ Server {
373
+ port: self.port.unwrap_or(8080),
374
+ host: self.host.unwrap_or_else(|| "127.0.0.1".into()),
375
+ timeout: self.timeout.unwrap_or(Duration::from_secs(30)),
376
+ }
377
+ }
378
+ }
379
+
380
+ // 사용
381
+ let server = ServerBuilder::new()
382
+ .port(3000)
383
+ .host("0.0.0.0")
384
+ .timeout(Duration::from_secs(60))
385
+ .build();
386
+ ```
387
+
388
+ ## 파일 구조
389
+
390
+ ```
391
+ project/
392
+ ├── src/
393
+ │ ├── main.rs # 엔트리포인트
394
+ │ ├── lib.rs # 라이브러리 루트
395
+ │ ├── config.rs # 설정
396
+ │ ├── error.rs # 에러 정의
397
+ │ ├── domain/ # 도메인 모델
398
+ │ │ ├── mod.rs
399
+ │ │ └── user.rs
400
+ │ ├── handlers/ # HTTP 핸들러
401
+ │ │ ├── mod.rs
402
+ │ │ └── user.rs
403
+ │ ├── services/ # 비즈니스 로직
404
+ │ │ ├── mod.rs
405
+ │ │ └── user.rs
406
+ │ ├── repositories/ # 데이터 액세스
407
+ │ │ ├── mod.rs
408
+ │ │ └── user.rs
409
+ │ └── middleware/ # 미들웨어
410
+ ├── tests/ # 통합 테스트
411
+ ├── migrations/ # DB 마이그레이션
412
+ ├── Cargo.toml
413
+ └── Cargo.lock
414
+ ```
415
+
416
+ ## 체크리스트
417
+
418
+ - [ ] unwrap()/expect() 최소화, ? 연산자 활용
419
+ - [ ] thiserror/anyhow로 에러 처리
420
+ - [ ] 트레이트로 추상화, 의존성 주입
421
+ - [ ] Clone 최소화, 참조 활용
422
+ - [ ] async/await 적절히 사용
423
+ - [ ] clippy 경고 해결
424
+ - [ ] cargo fmt 적용
425
+ - [ ] #[cfg(test)] 모듈로 테스트 작성