@kood/claude-code 0.1.2 → 0.1.3

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 (61) hide show
  1. package/dist/index.js +12 -3
  2. package/package.json +2 -2
  3. package/templates/hono/CLAUDE.md +20 -2
  4. package/templates/hono/docs/architecture/architecture.md +909 -0
  5. package/templates/hono/docs/deployment/cloudflare.md +537 -190
  6. package/templates/hono/docs/deployment/docker.md +517 -0
  7. package/templates/hono/docs/deployment/index.md +181 -213
  8. package/templates/hono/docs/deployment/railway.md +416 -0
  9. package/templates/hono/docs/deployment/vercel.md +572 -0
  10. package/templates/hono/docs/git/git.md +285 -0
  11. package/templates/hono/docs/library/ai-sdk/index.md +427 -0
  12. package/templates/hono/docs/library/ai-sdk/openrouter.md +479 -0
  13. package/templates/hono/docs/library/ai-sdk/providers.md +468 -0
  14. package/templates/hono/docs/library/ai-sdk/streaming.md +447 -0
  15. package/templates/hono/docs/library/ai-sdk/structured-output.md +493 -0
  16. package/templates/hono/docs/library/ai-sdk/tools.md +513 -0
  17. package/templates/hono/docs/library/hono/env-setup.md +458 -0
  18. package/templates/hono/docs/library/hono/index.md +1 -0
  19. package/templates/hono/docs/library/pino/index.md +437 -0
  20. package/templates/hono/docs/library/prisma/cloudflare-d1.md +503 -0
  21. package/templates/hono/docs/library/prisma/config.md +362 -0
  22. package/templates/hono/docs/library/prisma/index.md +86 -13
  23. package/templates/hono/docs/skills/gemini-review/SKILL.md +116 -116
  24. package/templates/hono/docs/skills/gemini-review/references/checklists.md +125 -125
  25. package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +191 -191
  26. package/templates/npx/CLAUDE.md +309 -0
  27. package/templates/npx/docs/git/git.md +307 -0
  28. package/templates/npx/docs/library/commander/index.md +164 -0
  29. package/templates/npx/docs/library/fs-extra/index.md +171 -0
  30. package/templates/npx/docs/library/prompts/index.md +253 -0
  31. package/templates/npx/docs/mcp/index.md +60 -0
  32. package/templates/npx/docs/skills/gemini-review/SKILL.md +220 -0
  33. package/templates/npx/docs/skills/gemini-review/references/checklists.md +134 -0
  34. package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +301 -0
  35. package/templates/tanstack-start/CLAUDE.md +43 -5
  36. package/templates/tanstack-start/docs/architecture/architecture.md +134 -4
  37. package/templates/tanstack-start/docs/deployment/cloudflare.md +234 -51
  38. package/templates/tanstack-start/docs/deployment/index.md +322 -32
  39. package/templates/tanstack-start/docs/deployment/nitro.md +201 -20
  40. package/templates/tanstack-start/docs/deployment/railway.md +305 -153
  41. package/templates/tanstack-start/docs/deployment/vercel.md +353 -78
  42. package/templates/tanstack-start/docs/git/{index.md → git.md} +81 -7
  43. package/templates/tanstack-start/docs/guides/best-practices.md +203 -1
  44. package/templates/tanstack-start/docs/guides/env-setup.md +450 -0
  45. package/templates/tanstack-start/docs/library/ai-sdk/hooks.md +472 -0
  46. package/templates/tanstack-start/docs/library/ai-sdk/index.md +264 -0
  47. package/templates/tanstack-start/docs/library/ai-sdk/openrouter.md +371 -0
  48. package/templates/tanstack-start/docs/library/ai-sdk/providers.md +403 -0
  49. package/templates/tanstack-start/docs/library/ai-sdk/streaming.md +320 -0
  50. package/templates/tanstack-start/docs/library/ai-sdk/structured-output.md +454 -0
  51. package/templates/tanstack-start/docs/library/ai-sdk/tools.md +473 -0
  52. package/templates/tanstack-start/docs/library/pino/index.md +320 -0
  53. package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +404 -0
  54. package/templates/tanstack-start/docs/library/prisma/config.md +377 -0
  55. package/templates/tanstack-start/docs/library/prisma/index.md +3 -1
  56. package/templates/tanstack-start/docs/library/prisma/schema.md +123 -25
  57. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +80 -2
  58. package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +116 -116
  59. package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +138 -144
  60. package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +186 -187
  61. package/templates/hono/docs/git/index.md +0 -180
@@ -0,0 +1,493 @@
1
+ # AI SDK - 구조화된 출력 (Hono)
2
+
3
+ > **상위 문서**: [AI SDK](./index.md)
4
+
5
+ ---
6
+
7
+ ## 개요
8
+
9
+ AI SDK의 `generateObject`와 `streamObject`를 Hono에서 사용하면 타입 안전한 구조화된 데이터를 생성할 수 있습니다. Zod 스키마를 사용하여 출력 형식을 정의합니다.
10
+
11
+ ---
12
+
13
+ ## generateObject
14
+
15
+ ### 기본 사용
16
+
17
+ ```typescript
18
+ import { Hono } from 'hono'
19
+ import { generateObject } from 'ai'
20
+ import { openai } from '@ai-sdk/openai'
21
+ import { z } from 'zod'
22
+
23
+ const app = new Hono()
24
+
25
+ app.post('/api/generate-user', async (c) => {
26
+ const { prompt } = await c.req.json()
27
+
28
+ const { object } = await generateObject({
29
+ model: openai('gpt-4o'),
30
+ schema: z.object({
31
+ name: z.string(),
32
+ age: z.number(),
33
+ email: z.string().email(),
34
+ }),
35
+ prompt,
36
+ })
37
+
38
+ // object는 타입 안전: { name: string, age: number, email: string }
39
+ return c.json(object)
40
+ })
41
+ ```
42
+
43
+ ### 복잡한 스키마
44
+
45
+ ```typescript
46
+ import { Hono } from 'hono'
47
+ import { generateObject } from 'ai'
48
+ import { openai } from '@ai-sdk/openai'
49
+ import { z } from 'zod'
50
+
51
+ const app = new Hono()
52
+
53
+ const recipeSchema = z.object({
54
+ name: z.string().describe('Recipe name'),
55
+ ingredients: z.array(
56
+ z.object({
57
+ name: z.string(),
58
+ amount: z.string(),
59
+ unit: z.string().optional(),
60
+ })
61
+ ),
62
+ steps: z.array(z.string()),
63
+ prepTime: z.number().describe('Preparation time in minutes'),
64
+ cookTime: z.number().describe('Cooking time in minutes'),
65
+ servings: z.number(),
66
+ difficulty: z.enum(['easy', 'medium', 'hard']),
67
+ })
68
+
69
+ app.post('/api/generate-recipe', async (c) => {
70
+ const { dish } = await c.req.json()
71
+
72
+ const { object: recipe } = await generateObject({
73
+ model: openai('gpt-4o'),
74
+ schema: recipeSchema,
75
+ prompt: `Generate a recipe for ${dish}.`,
76
+ })
77
+
78
+ return c.json(recipe)
79
+ })
80
+ ```
81
+
82
+ ---
83
+
84
+ ## 출력 모드
85
+
86
+ ### Object (기본)
87
+
88
+ ```typescript
89
+ app.post('/api/object', async (c) => {
90
+ const { prompt } = await c.req.json()
91
+
92
+ const { object } = await generateObject({
93
+ model: openai('gpt-4o'),
94
+ schema: z.object({
95
+ name: z.string(),
96
+ age: z.number(),
97
+ }),
98
+ prompt,
99
+ })
100
+
101
+ return c.json(object)
102
+ })
103
+ ```
104
+
105
+ ### Array
106
+
107
+ 배열 형태의 출력:
108
+
109
+ ```typescript
110
+ app.post('/api/array', async (c) => {
111
+ const { prompt } = await c.req.json()
112
+
113
+ const { object } = await generateObject({
114
+ model: openai('gpt-4o'),
115
+ output: 'array',
116
+ schema: z.object({
117
+ name: z.string(),
118
+ class: z.string().describe('Character class'),
119
+ description: z.string(),
120
+ }),
121
+ prompt,
122
+ })
123
+
124
+ // object는 배열
125
+ return c.json({ characters: object })
126
+ })
127
+ ```
128
+
129
+ ### Enum
130
+
131
+ 분류 작업에 유용:
132
+
133
+ ```typescript
134
+ app.post('/api/classify', async (c) => {
135
+ const { text } = await c.req.json()
136
+
137
+ const { object } = await generateObject({
138
+ model: openai('gpt-4o'),
139
+ output: 'enum',
140
+ enum: ['action', 'comedy', 'drama', 'horror', 'sci-fi'],
141
+ prompt: `Classify this movie: "${text}"`,
142
+ })
143
+
144
+ return c.json({ genre: object })
145
+ })
146
+ ```
147
+
148
+ ### No Schema
149
+
150
+ 스키마 없이 자유 형식 JSON 생성:
151
+
152
+ ```typescript
153
+ app.post('/api/freeform', async (c) => {
154
+ const { prompt } = await c.req.json()
155
+
156
+ const { object } = await generateObject({
157
+ model: openai('gpt-4o'),
158
+ output: 'no-schema',
159
+ prompt,
160
+ })
161
+
162
+ // object는 any 타입
163
+ return c.json(object)
164
+ })
165
+ ```
166
+
167
+ ---
168
+
169
+ ## streamObject
170
+
171
+ 스트리밍으로 객체를 점진적으로 생성:
172
+
173
+ ```typescript
174
+ import { Hono } from 'hono'
175
+ import { streamObject } from 'ai'
176
+ import { openai } from '@ai-sdk/openai'
177
+ import { z } from 'zod'
178
+
179
+ const app = new Hono()
180
+
181
+ const profileSchema = z.object({
182
+ name: z.string(),
183
+ bio: z.string(),
184
+ skills: z.array(z.string()),
185
+ })
186
+
187
+ app.post('/api/stream-profile', async (c) => {
188
+ const { prompt } = await c.req.json()
189
+
190
+ const result = streamObject({
191
+ model: openai('gpt-4o'),
192
+ schema: profileSchema,
193
+ prompt,
194
+ })
195
+
196
+ return result.toTextStreamResponse()
197
+ })
198
+ ```
199
+
200
+ ### 부분 객체 처리
201
+
202
+ ```typescript
203
+ import { Hono } from 'hono'
204
+ import { streamObject } from 'ai'
205
+ import { openai } from '@ai-sdk/openai'
206
+ import { z } from 'zod'
207
+ import { stream } from 'hono/streaming'
208
+
209
+ const app = new Hono()
210
+
211
+ app.post('/api/stream-partial', async (c) => {
212
+ const { prompt } = await c.req.json()
213
+
214
+ const result = streamObject({
215
+ model: openai('gpt-4o'),
216
+ schema: z.object({
217
+ name: z.string(),
218
+ bio: z.string(),
219
+ skills: z.array(z.string()),
220
+ }),
221
+ prompt,
222
+ })
223
+
224
+ return stream(c, async (stream) => {
225
+ for await (const partialObject of result.partialObjectStream) {
226
+ await stream.write(JSON.stringify(partialObject) + '\n')
227
+ }
228
+ })
229
+ })
230
+ ```
231
+
232
+ ---
233
+
234
+ ## 스키마 설계 팁
235
+
236
+ ### 필드 설명 추가
237
+
238
+ ```typescript
239
+ const schema = z.object({
240
+ title: z.string().describe('A catchy title for the article'),
241
+ summary: z.string().describe('A 2-3 sentence summary'),
242
+ tags: z.array(z.string()).describe('Relevant topic tags'),
243
+ })
244
+ ```
245
+
246
+ ### Optional 필드
247
+
248
+ ```typescript
249
+ const schema = z.object({
250
+ name: z.string(),
251
+ nickname: z.string().optional(),
252
+ age: z.number().nullable(),
253
+ })
254
+ ```
255
+
256
+ ### 기본값
257
+
258
+ ```typescript
259
+ const schema = z.object({
260
+ name: z.string(),
261
+ role: z.string().default('user'),
262
+ isActive: z.boolean().default(true),
263
+ })
264
+ ```
265
+
266
+ ### Enum 사용
267
+
268
+ ```typescript
269
+ const schema = z.object({
270
+ status: z.enum(['pending', 'approved', 'rejected']),
271
+ priority: z.enum(['low', 'medium', 'high', 'critical']),
272
+ })
273
+ ```
274
+
275
+ ### 중첩 객체
276
+
277
+ ```typescript
278
+ const schema = z.object({
279
+ user: z.object({
280
+ name: z.string(),
281
+ email: z.string().email(),
282
+ }),
283
+ address: z.object({
284
+ street: z.string(),
285
+ city: z.string(),
286
+ country: z.string(),
287
+ }),
288
+ })
289
+ ```
290
+
291
+ ---
292
+
293
+ ## 실용 예제
294
+
295
+ ### 데이터 추출
296
+
297
+ ```typescript
298
+ app.post('/api/extract', async (c) => {
299
+ const { text } = await c.req.json()
300
+
301
+ const { object } = await generateObject({
302
+ model: openai('gpt-4o'),
303
+ schema: z.object({
304
+ people: z.array(
305
+ z.object({
306
+ name: z.string(),
307
+ role: z.string().optional(),
308
+ })
309
+ ),
310
+ organizations: z.array(z.string()),
311
+ locations: z.array(z.string()),
312
+ dates: z.array(z.string()),
313
+ }),
314
+ prompt: `Extract entities from this text: ${text}`,
315
+ })
316
+
317
+ return c.json(object)
318
+ })
319
+ ```
320
+
321
+ ### 요약 생성
322
+
323
+ ```typescript
324
+ app.post('/api/summarize', async (c) => {
325
+ const { content } = await c.req.json()
326
+
327
+ const { object } = await generateObject({
328
+ model: openai('gpt-4o'),
329
+ schema: z.object({
330
+ summary: z.string().describe('One paragraph summary'),
331
+ keyPoints: z.array(z.string()).describe('3-5 key points'),
332
+ sentiment: z.enum(['positive', 'neutral', 'negative']),
333
+ topics: z.array(z.string()),
334
+ }),
335
+ prompt: `Summarize this content: ${content}`,
336
+ })
337
+
338
+ return c.json(object)
339
+ })
340
+ ```
341
+
342
+ ### 폼 데이터 생성
343
+
344
+ ```typescript
345
+ app.post('/api/generate-form', async (c) => {
346
+ const { description } = await c.req.json()
347
+
348
+ const { object } = await generateObject({
349
+ model: openai('gpt-4o'),
350
+ schema: z.object({
351
+ fields: z.array(
352
+ z.object({
353
+ name: z.string(),
354
+ type: z.enum(['text', 'email', 'number', 'select', 'textarea']),
355
+ label: z.string(),
356
+ required: z.boolean(),
357
+ placeholder: z.string().optional(),
358
+ options: z.array(z.string()).optional(),
359
+ })
360
+ ),
361
+ }),
362
+ prompt: `Generate form fields for: ${description}`,
363
+ })
364
+
365
+ return c.json(object)
366
+ })
367
+ ```
368
+
369
+ ---
370
+
371
+ ## 에러 처리
372
+
373
+ ```typescript
374
+ import { Hono } from 'hono'
375
+ import { HTTPException } from 'hono/http-exception'
376
+ import { generateObject } from 'ai'
377
+ import { openai } from '@ai-sdk/openai'
378
+ import { z } from 'zod'
379
+
380
+ const app = new Hono()
381
+
382
+ app.post('/api/generate', async (c) => {
383
+ const { prompt } = await c.req.json()
384
+
385
+ try {
386
+ const { object } = await generateObject({
387
+ model: openai('gpt-4o'),
388
+ schema: z.object({
389
+ name: z.string(),
390
+ age: z.number(),
391
+ }),
392
+ prompt,
393
+ })
394
+
395
+ return c.json(object)
396
+ } catch (error) {
397
+ if (error instanceof z.ZodError) {
398
+ // 스키마 검증 실패
399
+ return c.json(
400
+ { error: 'Validation error', details: error.errors },
401
+ 400
402
+ )
403
+ }
404
+
405
+ console.error('Generation error:', error)
406
+ throw new HTTPException(500, { message: 'Failed to generate object' })
407
+ }
408
+ })
409
+ ```
410
+
411
+ ---
412
+
413
+ ## 반환값
414
+
415
+ ### generateObject
416
+
417
+ ```typescript
418
+ const result = await generateObject({
419
+ model: openai('gpt-4o'),
420
+ schema,
421
+ prompt,
422
+ })
423
+
424
+ result.object // 생성된 객체 (타입 안전)
425
+ result.usage // 토큰 사용량
426
+ result.finishReason // 완료 이유
427
+ ```
428
+
429
+ ### streamObject
430
+
431
+ ```typescript
432
+ const result = streamObject({
433
+ model: openai('gpt-4o'),
434
+ schema,
435
+ prompt,
436
+ })
437
+
438
+ result.partialObjectStream // AsyncIterable<PartialObject>
439
+ result.object // Promise<FinalObject>
440
+ result.usage // Promise<Usage>
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Cloudflare Workers 예제
446
+
447
+ ```typescript
448
+ import { Hono } from 'hono'
449
+ import { generateObject, streamObject } from 'ai'
450
+ import { createOpenAI } from '@ai-sdk/openai'
451
+ import { z } from 'zod'
452
+
453
+ type Bindings = {
454
+ OPENAI_API_KEY: string
455
+ }
456
+
457
+ const app = new Hono<{ Bindings: Bindings }>()
458
+
459
+ const productSchema = z.object({
460
+ name: z.string(),
461
+ description: z.string(),
462
+ price: z.number(),
463
+ features: z.array(z.string()),
464
+ })
465
+
466
+ app.post('/api/generate-product', async (c) => {
467
+ const openai = createOpenAI({ apiKey: c.env.OPENAI_API_KEY })
468
+ const { category } = await c.req.json()
469
+
470
+ const { object } = await generateObject({
471
+ model: openai('gpt-4o'),
472
+ schema: productSchema,
473
+ prompt: `Generate a product in the ${category} category.`,
474
+ })
475
+
476
+ return c.json(object)
477
+ })
478
+
479
+ app.post('/api/stream-product', async (c) => {
480
+ const openai = createOpenAI({ apiKey: c.env.OPENAI_API_KEY })
481
+ const { category } = await c.req.json()
482
+
483
+ const result = streamObject({
484
+ model: openai('gpt-4o'),
485
+ schema: productSchema,
486
+ prompt: `Generate a product in the ${category} category.`,
487
+ })
488
+
489
+ return result.toTextStreamResponse()
490
+ })
491
+
492
+ export default app
493
+ ```