sonamu 0.8.24 → 0.8.26

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 (88) hide show
  1. package/dist/api/__tests__/config.test.js +189 -0
  2. package/dist/api/config.d.ts.map +1 -1
  3. package/dist/api/config.js +7 -2
  4. package/dist/api/sonamu.d.ts.map +1 -1
  5. package/dist/api/sonamu.js +14 -10
  6. package/dist/auth/index.d.ts +1 -0
  7. package/dist/auth/index.d.ts.map +1 -1
  8. package/dist/auth/index.js +2 -1
  9. package/dist/auth/knex-adapter.d.ts +23 -0
  10. package/dist/auth/knex-adapter.d.ts.map +1 -0
  11. package/dist/auth/knex-adapter.js +163 -0
  12. package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
  13. package/dist/bin/__tests__/ts-loader-register.test.js +45 -0
  14. package/dist/bin/cli.js +47 -9
  15. package/dist/bin/ts-loader-register.js +3 -29
  16. package/dist/bin/ts-loader-registration.d.ts +2 -0
  17. package/dist/bin/ts-loader-registration.d.ts.map +1 -0
  18. package/dist/bin/ts-loader-registration.js +42 -0
  19. package/dist/cone/cone-generator.js +3 -3
  20. package/dist/database/puri-subset.test-d.js +9 -1
  21. package/dist/database/puri-subset.types.d.ts +1 -1
  22. package/dist/database/puri-subset.types.d.ts.map +1 -1
  23. package/dist/database/puri-subset.types.js +1 -1
  24. package/dist/testing/fixture-generator.js +5 -5
  25. package/dist/ui/ai-client.js +2 -2
  26. package/dist/ui/api.d.ts.map +1 -1
  27. package/dist/ui/api.js +14 -14
  28. package/dist/ui/cdd-service.d.ts +15 -18
  29. package/dist/ui/cdd-service.d.ts.map +1 -1
  30. package/dist/ui/cdd-service.js +246 -222
  31. package/dist/ui/cdd-types.d.ts +41 -68
  32. package/dist/ui/cdd-types.d.ts.map +1 -1
  33. package/dist/ui/cdd-types.js +2 -2
  34. package/dist/ui-web/assets/index-CKo0Z2Iu.css +1 -0
  35. package/dist/ui-web/assets/{index-CxiydzeC.js → index-DK-2aacv.js} +83 -83
  36. package/dist/ui-web/index.html +2 -2
  37. package/package.json +6 -2
  38. package/src/api/__tests__/config.test.ts +225 -0
  39. package/src/api/config.ts +10 -4
  40. package/src/api/sonamu.ts +16 -13
  41. package/src/auth/index.ts +1 -0
  42. package/src/auth/knex-adapter.ts +208 -0
  43. package/src/bin/__tests__/ts-loader-register.test.ts +62 -0
  44. package/src/bin/cli.ts +52 -9
  45. package/src/bin/ts-loader-register.ts +2 -32
  46. package/src/bin/ts-loader-registration.ts +55 -0
  47. package/src/cone/cone-generator.ts +2 -2
  48. package/src/database/puri-subset.test-d.ts +102 -0
  49. package/src/database/puri-subset.types.ts +1 -1
  50. package/src/skills/commands/sonamu-skills.md +20 -0
  51. package/src/skills/sonamu/SKILL.md +179 -137
  52. package/src/skills/sonamu/ai-agents.md +69 -69
  53. package/src/skills/sonamu/api.md +147 -147
  54. package/src/skills/sonamu/auth-migration.md +220 -220
  55. package/src/skills/sonamu/auth-plugins.md +83 -83
  56. package/src/skills/sonamu/auth.md +106 -106
  57. package/src/skills/sonamu/cdd.md +65 -200
  58. package/src/skills/sonamu/cone.md +138 -138
  59. package/src/skills/sonamu/config.md +191 -191
  60. package/src/skills/sonamu/create-sonamu.md +66 -66
  61. package/src/skills/sonamu/database.md +158 -158
  62. package/src/skills/sonamu/entity-basic.md +292 -293
  63. package/src/skills/sonamu/entity-relations.md +246 -246
  64. package/src/skills/sonamu/entity-validation-checklist.md +124 -124
  65. package/src/skills/sonamu/fixture-cli.md +231 -231
  66. package/src/skills/sonamu/framework-change.md +37 -37
  67. package/src/skills/sonamu/frontend.md +223 -223
  68. package/src/skills/sonamu/i18n.md +82 -82
  69. package/src/skills/sonamu/migration.md +77 -77
  70. package/src/skills/sonamu/model.md +222 -222
  71. package/src/skills/sonamu/naite.md +86 -86
  72. package/src/skills/sonamu/project-init.md +228 -228
  73. package/src/skills/sonamu/puri.md +122 -122
  74. package/src/skills/sonamu/scaffolding.md +154 -154
  75. package/src/skills/sonamu/skill-contribution.md +124 -124
  76. package/src/skills/sonamu/subset.md +46 -46
  77. package/src/skills/sonamu/tasks.md +82 -82
  78. package/src/skills/sonamu/testing-devrunner.md +147 -147
  79. package/src/skills/sonamu/testing.md +673 -673
  80. package/src/skills/sonamu/upsert.md +79 -79
  81. package/src/skills/sonamu/vector.md +67 -67
  82. package/src/testing/fixture-generator.ts +4 -4
  83. package/src/ui/ai-client.ts +1 -1
  84. package/src/ui/api.ts +18 -17
  85. package/src/ui/cdd-service.ts +264 -254
  86. package/src/ui/cdd-types.ts +40 -75
  87. package/dist/ui-web/assets/index-BrQKU3j9.css +0 -1
  88. package/src/skills/sonamu/workflow.md +0 -317
@@ -1,94 +1,94 @@
1
1
  ---
2
2
  name: sonamu-upsert
3
- description: Sonamu UpsertBuilder로 복잡한 관계 데이터 저장. ubRegister, ubUpsert, insertOnly, updateBatch 패턴, FK 순서, cleanOrphans. Use when saving related data with foreign key dependencies.
3
+ description: Saving complex relational data with Sonamu UpsertBuilder. ubRegister, ubUpsert, insertOnly, updateBatch patterns, FK ordering, cleanOrphans. Use when saving related data with foreign key dependencies.
4
4
  ---
5
5
 
6
6
  # UpsertBuilder
7
7
 
8
- ## UBRef 타입
8
+ ## UBRef Type
9
9
 
10
- `ubRegister()`가 반환하는 참조 객체:
10
+ The reference object returned by `ubRegister()`:
11
11
 
12
12
  ```typescript
13
13
  type UBRef = {
14
- uuid: string; // 고유 식별자
15
- of: string; // 테이블명
16
- use?: string; // 참조할 필드 (기본값: "id")
14
+ uuid: string; // unique identifier
15
+ of: string; // table name
16
+ use?: string; // field to reference (default: "id")
17
17
  };
18
18
  ```
19
19
 
20
- ## 기본 패턴
20
+ ## Basic Pattern
21
21
 
22
22
  ```typescript
23
23
  const wdb = this.getPuri("w");
24
24
 
25
- // 데이터 등록 (UBRef 반환)
25
+ // Register data (returns UBRef)
26
26
  const userRef = wdb.ubRegister("users", { email: "john@test.com", username: "john" });
27
27
 
28
- // 관계 데이터에 UBRef 사용
28
+ // Use UBRef in related data
29
29
  wdb.ubRegister("employees", { user_id: userRef, department_id: deptId });
30
30
 
31
- // 트랜잭션 내에서 순서대로 저장
31
+ // Save in order inside a transaction
32
32
  return wdb.transaction(async (trx) => {
33
- await trx.ubUpsert("users"); // 먼저 저장 (FK 참조됨)
34
- return trx.ubUpsert("employees"); // 나중에 저장 (FK 사용)
33
+ await trx.ubUpsert("users"); // Save first (referenced by FK)
34
+ return trx.ubUpsert("employees"); // Save after (uses FK)
35
35
  });
36
36
  ```
37
37
 
38
- ## CRITICAL: 필수 필드 포함 필수
38
+ ## CRITICAL: All Required Fields Must Be Included
39
39
 
40
- **ubUpsert PostgreSQL `ON CONFLICT ... DO UPDATE` 쿼리를 사용합니다.**
40
+ **ubUpsert uses PostgreSQL's `ON CONFLICT ... DO UPDATE` query.**
41
41
 
42
- 업데이트 시에도 **모든 필수 필드(NOT NULL 제약이 있는 필드)**를 포함해야 합니다.
42
+ Even when updating, **all required fields (fields with NOT NULL constraints)** must be included.
43
43
 
44
44
  ```typescript
45
- // BAD - 필수 필드 누락
45
+ // BAD - missing required field
46
46
  wdb.ubRegister("posts", {
47
47
  id: 1,
48
48
  title: "Updated Title",
49
- // content 필수 필드 누락! → ON CONFLICT UPDATE NULL 설정 시도 → DB 에러
49
+ // content required field missing! → ON CONFLICT UPDATE tries to set NULL → DB error
50
50
  });
51
51
  // Error: null value in column "content" violates not-null constraint
52
52
 
53
- // GOOD - 모든 필수 필드 포함
53
+ // GOOD - all required fields included
54
54
  wdb.ubRegister("posts", {
55
55
  id: 1,
56
56
  title: "Updated Title",
57
- content: "Updated Content", // 필수 필드 포함!
58
- author_id: 1, // FK 필수 필드면 포함!
57
+ content: "Updated Content", // required field included!
58
+ author_id: 1, // FK also included if required!
59
59
  });
60
60
  ```
61
61
 
62
- **필수 필드 확인 방법**:
63
- 1. entity.json의 props 확인
64
- 2. `nullable: true`가 **없는** 필드 = 필수 필드
65
- 3. `id`, `created_at`, `dbDefault` 있는 필드는 제외 가능
62
+ **How to identify required fields**:
63
+ 1. Check props in entity.json
64
+ 2. Fields without `nullable: true` = required fields
65
+ 3. `id`, `created_at`, fields with `dbDefault` can be omitted
66
66
 
67
67
  ```json
68
- // entity.json 예시
68
+ // entity.json example
69
69
  {
70
70
  "props": [
71
- { "name": "id", "type": "integer" }, // 제외 가능
72
- { "name": "title", "type": "string" }, // 필수! (nullable 없음)
73
- { "name": "content", "type": "string" }, // 필수! (nullable 없음)
74
- { "name": "category", "type": "string", "nullable": true }, // 선택
75
- { "name": "created_at", "type": "date", "dbDefault": "CURRENT_TIMESTAMP" } // 제외 가능
71
+ { "name": "id", "type": "integer" }, // can be omitted
72
+ { "name": "title", "type": "string" }, // required! (no nullable)
73
+ { "name": "content", "type": "string" }, // required! (no nullable)
74
+ { "name": "category", "type": "string", "nullable": true }, // optional
75
+ { "name": "created_at", "type": "date", "dbDefault": "CURRENT_TIMESTAMP" } // can be omitted
76
76
  ]
77
77
  }
78
78
  ```
79
79
 
80
- ## 저장 순서 (중요!)
80
+ ## Save Order (Important!)
81
81
 
82
- FK가 참조하는 테이블을 먼저 저장:
82
+ Save the table referenced by FK first:
83
83
 
84
84
  ```typescript
85
- await trx.ubUpsert("companies"); // 1. 의존성 없음
86
- await trx.ubUpsert("departments"); // 2. company_id 필요
87
- await trx.ubUpsert("users"); // 3. 의존성 없음
88
- await trx.ubUpsert("employees"); // 4. user_id, department_id 필요
85
+ await trx.ubUpsert("companies"); // 1. No dependencies
86
+ await trx.ubUpsert("departments"); // 2. Needs company_id
87
+ await trx.ubUpsert("users"); // 3. No dependencies
88
+ await trx.ubUpsert("employees"); // 4. Needs user_id, department_id
89
89
  ```
90
90
 
91
- ## Model save 패턴
91
+ ## Model save Pattern
92
92
 
93
93
  ```typescript
94
94
  @api({ httpMethod: "POST" })
@@ -102,25 +102,25 @@ async save(spa: UserSaveParams[]): Promise<number[]> {
102
102
  }
103
103
  ```
104
104
 
105
- ## 관계 데이터 저장
105
+ ## Saving Related Data
106
106
 
107
107
  ```typescript
108
108
  await this.getPuri("w").transaction(async (trx) => {
109
- // User 등록
109
+ // Register User
110
110
  const userRef = trx.ubRegister("users", {
111
111
  email: data.email,
112
112
  username: data.username,
113
113
  password: bcrypt.hashSync(data.password, 10),
114
114
  });
115
115
 
116
- // Employee 등록 (userRef 사용)
116
+ // Register Employee (using userRef)
117
117
  trx.ubRegister("employees", {
118
118
  user_id: userRef,
119
119
  department_id: data.departmentId,
120
120
  salary: data.salary,
121
121
  });
122
122
 
123
- // 순서대로 저장
123
+ // Save in order
124
124
  await trx.ubUpsert("users");
125
125
  const [employeeId] = await trx.ubUpsert("employees");
126
126
  return employeeId;
@@ -130,16 +130,16 @@ await this.getPuri("w").transaction(async (trx) => {
130
130
  ## Upsert (Insert or Update)
131
131
 
132
132
  ```typescript
133
- // id 없으면 INSERT
133
+ // INSERT when no id
134
134
  wdb.ubRegister("users", { email: "new@test.com", username: "new" });
135
135
 
136
- // id 있으면 UPDATE
136
+ // UPDATE when id is present
137
137
  wdb.ubRegister("users", { id: 1, email: "updated@test.com" });
138
138
  ```
139
139
 
140
- **충돌 처리**: Entity unique index 있으면 자동으로 사전 조회하여 기존 레코드의 id 채운 UPDATE 수행
140
+ **Conflict handling**: If the Entity has a unique index, automatically pre-fetches to populate the existing record's id, then performs UPDATE
141
141
 
142
- ## ManyToMany 관계
142
+ ## ManyToMany Relationships
143
143
 
144
144
  ```typescript
145
145
  await wdb.transaction(async (trx) => {
@@ -157,52 +157,52 @@ await wdb.transaction(async (trx) => {
157
157
  });
158
158
  ```
159
159
 
160
- ## 자기 참조 (Self-Reference)
160
+ ## Self-Reference
161
161
 
162
- 계층 구조(예: 카테고리, 조직도)에서 자기 참조 관계는 자동으로 레벨별 순차 처리:
162
+ In hierarchical structures (e.g. categories, org charts), self-referential relationships are automatically processed level by level:
163
163
 
164
164
  ```typescript
165
165
  await wdb.transaction(async (trx) => {
166
- // 루트 카테고리
166
+ // Root category
167
167
  const rootRef = trx.ubRegister("categories", { name: "Root", parent_id: null });
168
168
 
169
- // 자식 카테고리 (rootRef 참조)
169
+ // Child category (references rootRef)
170
170
  const childRef = trx.ubRegister("categories", { name: "Child", parent_id: rootRef });
171
171
 
172
- // 손자 카테고리 (childRef 참조)
172
+ // Grandchild category (references childRef)
173
173
  trx.ubRegister("categories", { name: "Grandchild", parent_id: childRef });
174
174
 
175
- // 내부적으로 레벨별 순차 처리 (Root → Child → Grandchild)
175
+ // Internally processed level by level (Root → Child → Grandchild)
176
176
  await trx.ubUpsert("categories");
177
177
  });
178
178
  ```
179
179
 
180
- ## insertOnly (INSERT 전용)
180
+ ## insertOnly (INSERT Only)
181
181
 
182
- UPDATE 없이 INSERT 수행:
182
+ Perform INSERT without UPDATE:
183
183
 
184
184
  ```typescript
185
185
  await trx.insertOnly("logs", { chunkSize: 1000 });
186
186
  ```
187
187
 
188
- ## updateBatch (배치 업데이트)
188
+ ## updateBatch (Batch Update)
189
189
 
190
- 대량 UPDATE 작업:
190
+ Bulk UPDATE operations:
191
191
 
192
192
  ```typescript
193
- // 여러 레코드 등록
193
+ // Register multiple records
194
194
  wdb.ubRegister("users", { id: 1, status: "active" });
195
195
  wdb.ubRegister("users", { id: 2, status: "active" });
196
196
  wdb.ubRegister("users", { id: 3, status: "inactive" });
197
197
 
198
198
  await wdb.transaction(async (trx) => {
199
199
  await trx.updateBatch("users", {
200
- chunkSize: 500, // 배치 크기 (기본값: 500)
201
- where: "id", // WHERE 조건 컬럼 (기본값: "id")
200
+ chunkSize: 500, // batch size (default: 500)
201
+ where: "id", // WHERE condition column (default: "id")
202
202
  });
203
203
  });
204
204
 
205
- // 복합 키로 WHERE 조건
205
+ // Composite key for WHERE condition
206
206
  await trx.updateBatch("user_settings", {
207
207
  where: ["user_id", "setting_key"],
208
208
  });
@@ -210,19 +210,19 @@ await trx.updateBatch("user_settings", {
210
210
 
211
211
  ## UpsertOptions
212
212
 
213
- `ubUpsert()`의 옵션:
213
+ Options for `ubUpsert()`:
214
214
 
215
215
  ```typescript
216
216
  type UpsertOptions = {
217
- chunkSize?: number; // 배치 크기
218
- cleanOrphans?: string | string[]; // 고아 레코드 삭제 기준 FK 컬럼
219
- inherit?: string[]; // UPDATE 기존 유지할 컬럼
217
+ chunkSize?: number; // batch size
218
+ cleanOrphans?: string | string[]; // FK column(s) to use as basis for deleting orphan records
219
+ inherit?: string[]; // columns to preserve existing values on UPDATE
220
220
  };
221
221
  ```
222
222
 
223
223
  ### chunkSize
224
224
 
225
- 대량 데이터 처리 배치 크기 지정:
225
+ Specify batch size for large data processing:
226
226
 
227
227
  ```typescript
228
228
  await trx.ubUpsert("logs", { chunkSize: 1000 });
@@ -230,15 +230,15 @@ await trx.ubUpsert("logs", { chunkSize: 1000 });
230
230
 
231
231
  ### cleanOrphans
232
232
 
233
- FK 기준으로 고아 레코드 자동 삭제:
233
+ Automatically delete orphan records based on FK:
234
234
 
235
235
  ```typescript
236
- // 단일 FK
236
+ // Single FK
237
237
  await trx.ubUpsert("order_items", {
238
- cleanOrphans: "order_id", // order_id 같고 이번에 upsert 레코드 삭제
238
+ cleanOrphans: "order_id", // delete records with the same order_id that were not upserted this time
239
239
  });
240
240
 
241
- // 복합 FK
241
+ // Composite FK
242
242
  await trx.ubUpsert("project_members", {
243
243
  cleanOrphans: ["project_id", "team_id"],
244
244
  });
@@ -246,31 +246,31 @@ await trx.ubUpsert("project_members", {
246
246
 
247
247
  ### inherit
248
248
 
249
- UPDATE 특정 컬럼은 기존 유지:
249
+ Preserve existing values for specific columns on UPDATE:
250
250
 
251
251
  ```typescript
252
252
  await trx.ubUpsert("users", {
253
- inherit: ["created_at", "password"], // 컬럼들은 UPDATE에서 제외
253
+ inherit: ["created_at", "password"], // these columns are excluded from UPDATE
254
254
  });
255
255
  ```
256
256
 
257
- ## ubUpsertOrInsert (조건부 모드)
257
+ ## ubUpsertOrInsert (Conditional Mode)
258
258
 
259
- upsert 또는 insert 모드를 런타임에 선택합니다.
259
+ Select upsert or insert mode at runtime.
260
260
 
261
261
  ```typescript
262
- await trx.ubUpsertOrInsert("logs", "insert"); // INSERT 전용
263
- await trx.ubUpsertOrInsert("users", "upsert"); // UPSERT (기본)
262
+ await trx.ubUpsertOrInsert("logs", "insert"); // INSERT only
263
+ await trx.ubUpsertOrInsert("users", "upsert"); // UPSERT (default)
264
264
  await trx.ubUpsertOrInsert("users", "upsert", { cleanOrphans: "team_id" });
265
265
  ```
266
266
 
267
- | 파라미터 | 타입 | 설명 |
267
+ | Parameter | Type | Description |
268
268
  |----------|------|------|
269
- | `tableName` | string | 테이블명 |
270
- | `mode` | `"upsert"` \| `"insert"` | 동작 모드 |
271
- | `options` | `UpsertOptions` | chunkSize, cleanOrphans, inherit (ubUpsert와 동일) |
269
+ | `tableName` | string | table name |
270
+ | `mode` | `"upsert"` \| `"insert"` | operation mode |
271
+ | `options` | `UpsertOptions` | chunkSize, cleanOrphans, inherit (same as ubUpsert) |
272
272
 
273
- `mode: "insert"`일 `insertOnly`와 달리 `UpsertOptions` (cleanOrphans, inherit) 사용할 있습니다.
273
+ When `mode: "insert"`, unlike `insertOnly`, `UpsertOptions` (cleanOrphans, inherit) can be used.
274
274
 
275
275
  ## Rules
276
276
 
@@ -1,43 +1,43 @@
1
1
  ---
2
2
  name: sonamu-vector
3
- description: pgvector 기반 벡터 검색. Embedding(Voyage AI/OpenAI), Chunking, 하이브리드 검색(Vector+FTS) 지원. Use when implementing vector search, semantic search, or text embedding features.
3
+ description: pgvector-based vector search. Embedding (Voyage AI/OpenAI), Chunking, hybrid search (Vector+FTS) support. Use when implementing vector search, semantic search, or text embedding features.
4
4
  ---
5
5
 
6
- # 벡터 검색 가이드
6
+ # Vector Search Guide
7
7
 
8
- Sonamu pgvector 기반 벡터 검색을 지원합니다. Voyage AI OpenAI 임베딩 프로바이더를 통합 지원하며, 하이브리드 검색(Vector + Full-Text Search)도 가능합니다.
8
+ Sonamu supports pgvector-based vector search. It integrates both Voyage AI and OpenAI embedding providers, and also supports hybrid search (Vector + Full-Text Search).
9
9
 
10
- **소스코드:** `modules/sonamu/src/vector/`
10
+ **Source code:** `modules/sonamu/src/vector/`
11
11
 
12
12
  ---
13
13
 
14
- ## 구조
14
+ ## Structure
15
15
 
16
- | 파일 | 역할 |
16
+ | File | Role |
17
17
  |------|------|
18
- | `types.ts` | 전체 타입 정의 (EmbeddingProvider, VectorSearchResult, VectorConfig ) |
19
- | `config.ts` | 기본 설정값 + `createVectorConfig()` 헬퍼 |
20
- | `embedding.ts` | Embedding 클라이언트 (Voyage AI, OpenAI 통합) |
21
- | `chunking.ts` | 텍스트 청킹 ( 문서 분할) |
18
+ | `types.ts` | Full type definitions (EmbeddingProvider, VectorSearchResult, VectorConfig, etc.) |
19
+ | `config.ts` | Default configuration values + `createVectorConfig()` helper |
20
+ | `embedding.ts` | Embedding client (Voyage AI and OpenAI integration) |
21
+ | `chunking.ts` | Text chunking (splitting long documents) |
22
22
 
23
23
  ---
24
24
 
25
- ## 임베딩 프로바이더
25
+ ## Embedding Providers
26
26
 
27
- | 프로바이더 | 모델 | 차원 | maxTokens | batchSize | 패키지 |
27
+ | Provider | Model | Dimensions | maxTokens | batchSize | Package |
28
28
  |-----------|------|------|-----------|-----------|--------|
29
29
  | `voyage` | `voyage-3` | 1024 | 32000 | 128 | `voyageai` |
30
30
  | `openai` | `text-embedding-3-small` | 1536 | 8191 | 100 | `@ai-sdk/openai` |
31
31
 
32
- ### API 설정
32
+ ### API Key Configuration
33
33
 
34
34
  ```bash
35
- # 환경변수
35
+ # Environment variables
36
36
  export VOYAGE_API_KEY=pa-...
37
37
  export OPENAI_API_KEY=sk-...
38
38
  ```
39
39
 
40
- 또는 `sonamu.config.ts`:
40
+ Or in `sonamu.config.ts`:
41
41
  ```typescript
42
42
  export default defineConfig({
43
43
  secret: {
@@ -47,80 +47,80 @@ export default defineConfig({
47
47
  });
48
48
  ```
49
49
 
50
- 우선순위: `Sonamu.secrets.voyage_api_key` → `process.env.VOYAGE_API_KEY`
50
+ Key priority: `Sonamu.secrets.voyage_api_key` → `process.env.VOYAGE_API_KEY`
51
51
 
52
52
  ---
53
53
 
54
- ## Embedding 사용법
54
+ ## Embedding Usage
55
55
 
56
56
  ```typescript
57
57
  import { Embedding } from "sonamu/vector";
58
58
 
59
- // 단일 텍스트
60
- const result = await Embedding.embedOne("검색할 텍스트", "voyage", "query");
59
+ // Single text
60
+ const result = await Embedding.embedOne("text to search", "voyage", "query");
61
61
  // result: { embedding: number[], model: "voyage-3", tokenCount: 15 }
62
62
 
63
- // 다수 텍스트 (batchSize 초과 자동 분할)
63
+ // Multiple texts (auto-splits when exceeding batchSize)
64
64
  const results = await Embedding.embed(
65
- ["텍스트1", "텍스트2", ...],
65
+ ["text1", "text2", ...],
66
66
  "voyage",
67
67
  "document", // inputType: "document" | "query"
68
- (processed, total) => console.log(`${processed}/${total}`), // 진행률 콜백
68
+ (processed, total) => console.log(`${processed}/${total}`), // progress callback
69
69
  );
70
70
 
71
- // 차원 확인
71
+ // Check number of dimensions
72
72
  Embedding.getDimensions("voyage"); // 1024
73
73
  Embedding.getDimensions("openai"); // 1536
74
74
  ```
75
75
 
76
- ### Voyage AI inputType (비대칭 임베딩)
76
+ ### Voyage AI inputType (Asymmetric Embedding)
77
77
 
78
- | inputType | 용도 |
78
+ | inputType | Use case |
79
79
  |-----------|------|
80
- | `"document"` | DB에 저장할 문서 임베딩 |
81
- | `"query"` | 검색 쿼리 임베딩 |
80
+ | `"document"` | When embedding documents to store in DB |
81
+ | `"query"` | When embedding search queries |
82
82
 
83
- **CRITICAL: 저장 `"document"`, 검색 `"query"`를 사용해야 비대칭 임베딩이 올바르게 작동합니다.**
83
+ **CRITICAL: Use `"document"` when storing and `"query"` when searching for asymmetric embedding to work correctly.**
84
84
 
85
85
  ---
86
86
 
87
- ## Chunking 사용법
87
+ ## Chunking Usage
88
88
 
89
- 문서를 적절한 크기로 분할합니다.
89
+ Splits long documents into appropriately-sized pieces.
90
90
 
91
91
  ```typescript
92
92
  import { Chunking } from "sonamu/vector";
93
93
 
94
94
  const chunker = new Chunking({
95
- chunkSize: 500, // 청크 최대 크기 (문자 )
96
- chunkOverlap: 50, // 청크 겹침
97
- minChunkSize: 50, // 최소 청크 크기
95
+ chunkSize: 500, // Maximum chunk size (character count)
96
+ chunkOverlap: 50, // Overlap between chunks
97
+ minChunkSize: 50, // Minimum chunk size
98
98
  });
99
99
 
100
- // 청킹 필요 여부
101
- chunker.needsChunking("짧은 텍스트"); // false
100
+ // Check if chunking is needed
101
+ chunker.needsChunking("short text"); // false
102
102
 
103
- // 청크 분할
103
+ // Split into chunks
104
104
  const chunks = chunker.chunk(longText);
105
105
  // chunks: [{ index: 0, text: "...", startOffset: 0, endOffset: 500 }, ...]
106
106
 
107
- // 예상 청크
107
+ // Estimate number of chunks
108
108
  chunker.estimateChunkCount(longText); // 5
109
109
  ```
110
110
 
111
- ### 청킹 기본 설정
111
+ ### Chunking Default Settings
112
112
 
113
- | 옵션 | 기본값 | 설명 |
113
+ | Option | Default | Description |
114
114
  |------|--------|------|
115
- | `chunkSize` | 500 | 청크 최대 크기 (문자 ) |
116
- | `chunkOverlap` | 50 | 청크 겹침 |
117
- | `minChunkSize` | 50 | 최소 청크 크기 |
118
- | `skipThreshold` | 200 | 크기 이하면 청킹 없이 통과 |
119
- | `separators` | `["\n\n", "\n", "。", ". ", ...]` | 분할 기준 (우선순위 ) |
115
+ | `chunkSize` | 500 | Maximum chunk size (character count) |
116
+ | `chunkOverlap` | 50 | Overlap between chunks |
117
+ | `minChunkSize` | 50 | Minimum chunk size |
118
+ | `skipThreshold` | 200 | Passes through without chunking if at or below this size |
119
+ | `separators` | `["\n\n", "\n", "。", ". ", ...]` | Split delimiters (in priority order) |
120
120
 
121
121
  ---
122
122
 
123
- ## 검색 설정
123
+ ## Search Configuration
124
124
 
125
125
  ```typescript
126
126
  import { createVectorConfig } from "sonamu/vector";
@@ -128,20 +128,20 @@ import { createVectorConfig } from "sonamu/vector";
128
128
  const config = createVectorConfig({
129
129
  search: {
130
130
  defaultLimit: 10,
131
- similarityThreshold: 0.5, // 이하는 결과에서 제외
132
- vectorWeight: 0.7, // 하이브리드 검색 벡터 가중치
133
- ftsWeight: 0.3, // 하이브리드 검색 FTS 가중치
131
+ similarityThreshold: 0.5, // Results below this value are excluded
132
+ vectorWeight: 0.7, // Vector weight in hybrid search
133
+ ftsWeight: 0.3, // FTS weight in hybrid search
134
134
  },
135
135
  pgvector: {
136
- iterativeScan: true, // pgvector iterative scan 사용
137
- efSearch: 100, // HNSW 인덱스 검색 정확도
136
+ iterativeScan: true, // Use pgvector iterative scan
137
+ efSearch: 100, // HNSW index search accuracy
138
138
  },
139
139
  });
140
140
  ```
141
141
 
142
142
  ---
143
143
 
144
- ## 타입 정의
144
+ ## Type Definitions
145
145
 
146
146
  ### VectorSearchResult
147
147
 
@@ -166,10 +166,10 @@ interface HybridSearchResult<T> extends VectorSearchResult<T> {
166
166
 
167
167
  ```typescript
168
168
  interface VectorSearchOptions {
169
- embeddingColumn?: string; // 임베딩 컬럼명 (기본: "embedding")
169
+ embeddingColumn?: string; // Embedding column name (default: "embedding")
170
170
  limit?: number;
171
- threshold?: number; // 유사도 임계값
172
- where?: string; // SQL WHERE 조건
171
+ threshold?: number; // Similarity threshold
172
+ where?: string; // SQL WHERE condition
173
173
  }
174
174
  ```
175
175
 
@@ -177,36 +177,36 @@ interface VectorSearchOptions {
177
177
 
178
178
  ```typescript
179
179
  interface HybridSearchOptions extends VectorSearchOptions {
180
- vectorWeight?: number; // 벡터 검색 가중치
181
- ftsWeight?: number; // FTS 가중치
182
- ftsColumn?: string; // FTS 대상 컬럼명
180
+ vectorWeight?: number; // Vector search weight
181
+ ftsWeight?: number; // FTS weight
182
+ ftsColumn?: string; // Target column name for FTS
183
183
  }
184
184
  ```
185
185
 
186
186
  ---
187
187
 
188
- ## pgvector DB 설정
188
+ ## pgvector DB Setup
189
189
 
190
- ### 확장 설치
190
+ ### Install Extension
191
191
 
192
192
  ```sql
193
193
  CREATE EXTENSION IF NOT EXISTS vector;
194
194
  ```
195
195
 
196
- ### 임베딩 컬럼 추가
196
+ ### Add Embedding Column
197
197
 
198
198
  ```sql
199
- -- Voyage AI (1024차원)
199
+ -- Voyage AI (1024 dimensions)
200
200
  ALTER TABLE documents ADD COLUMN embedding vector(1024);
201
201
 
202
- -- OpenAI (1536차원)
202
+ -- OpenAI (1536 dimensions)
203
203
  ALTER TABLE documents ADD COLUMN embedding vector(1536);
204
204
  ```
205
205
 
206
- ### HNSW 인덱스
206
+ ### HNSW Index
207
207
 
208
208
  ```sql
209
- -- 코사인 유사도 기반 인덱스
209
+ -- Cosine similarity-based index
210
210
  CREATE INDEX ON documents
211
211
  USING hnsw (embedding vector_cosine_ops)
212
212
  WITH (m = 16, ef_construction = 64);
@@ -214,8 +214,8 @@ WITH (m = 16, ef_construction = 64);
214
214
 
215
215
  ---
216
216
 
217
- ## 참고
217
+ ## References
218
218
 
219
- - **소스코드**: `modules/sonamu/src/vector/`
220
- - **pgvector 공식**: https://github.com/pgvector/pgvector
219
+ - **Source code**: `modules/sonamu/src/vector/`
220
+ - **pgvector official**: https://github.com/pgvector/pgvector
221
221
  - **Voyage AI**: https://docs.voyageai.com/
@@ -57,7 +57,7 @@ export class FixtureGenerator {
57
57
  locale: options?.locale || "ko",
58
58
  useLLM: options?.useLLM || false,
59
59
  enableLLMCache: options?.enableLLMCache !== false,
60
- llmModel: options?.llmModel || "claude-sonnet-4-5",
60
+ llmModel: options?.llmModel || "claude-sonnet-4-6",
61
61
  };
62
62
  }
63
63
 
@@ -825,7 +825,7 @@ export class FixtureGenerator {
825
825
  const { generateText } = await import("ai");
826
826
 
827
827
  const rowResponse = await generateText({
828
- model: createAnthropic({ apiKey })(this.options.llmModel || "claude-sonnet-4-5"),
828
+ model: createAnthropic({ apiKey })(this.options.llmModel || "claude-sonnet-4-6"),
829
829
  prompt: this.buildRowLLMPrompt(llmProps, entity),
830
830
  });
831
831
  if (!rowResponse || typeof rowResponse.text !== "string") {
@@ -869,7 +869,7 @@ export class FixtureGenerator {
869
869
  const { generateText } = await import("ai");
870
870
 
871
871
  const singleResponse = await generateText({
872
- model: createAnthropic({ apiKey })(this.options.llmModel || "claude-sonnet-4-5"),
872
+ model: createAnthropic({ apiKey })(this.options.llmModel || "claude-sonnet-4-6"),
873
873
  prompt: this.buildLLMPrompt(fixtureHint, prop, entity),
874
874
  });
875
875
  if (!singleResponse || typeof singleResponse.text !== "string") {
@@ -1208,7 +1208,7 @@ Rules:
1208
1208
 
1209
1209
  try {
1210
1210
  const { Sonamu } = require("../api");
1211
- apiKey = Sonamu.secret?.anthropic_api_key;
1211
+ apiKey = Sonamu.secrets?.anthropic_api_key;
1212
1212
  } catch {
1213
1213
  // Sonamu가 초기화되지 않은 경우 (테스트 환경 등)
1214
1214
  }
@@ -34,7 +34,7 @@ class AIClient {
34
34
  const { anthropic } = await import("@ai-sdk/anthropic");
35
35
  const aiModule = await import("ai");
36
36
  this.aiSdk = { ...aiModule, anthropic };
37
- this.model = anthropic("claude-sonnet-4-5");
37
+ this.model = anthropic("claude-sonnet-4-6");
38
38
  } catch (error) {
39
39
  console.warn(
40
40
  "AI SDK packages not installed. Install @ai-sdk/anthropic and ai to use AI features.",