@rex0220/llm-task-router 0.1.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.
@@ -0,0 +1,479 @@
1
+ # 薄い ModelRouter 実装計画書
2
+
3
+ 作成日: 2026-06-16
4
+ 参照設計書: [thin-model-router-design.md](./thin-model-router-design.md)
5
+
6
+ ## 1. 目的
7
+
8
+ Qiita記事作成などの個人・小規模用途に限定した、TypeScript製の薄いModelRouter CLIを実装する。
9
+
10
+ この計画では、設計書のMVPスコープを優先し、以下を満たす最小構成を段階的に作る。
11
+
12
+ - タスク別にモデルを選択する
13
+ - OpenAI / Anthropic をProviderとして呼び分ける
14
+ - rate limit / timeout / overloaded / 一時的な5xx系エラーのみフォールバックする
15
+ - 中間成果物を `runs/<runId>/` に保存し、途中再開できる
16
+ - ZodでJSON成果物を検証する
17
+ - ログにAPIキーや全文プロンプトを残さない
18
+ - Web UI、外部公開API、任意コード実行、任意URL取得は実装しない
19
+
20
+ ## 2. 実装方針
21
+
22
+ ### 2.1 基本方針
23
+
24
+ - CLI専用ツールとして実装する
25
+ - `ModelRouter` はProvider固有APIを知らない構造にする
26
+ - 設定は `config/models.yaml` から読み込む
27
+ - APIキーは `.env` から読み込み、`.env.example` のみコミット対象にする
28
+ - 成果物とメタ情報はファイル保存に限定する
29
+ - DB、HTTPサーバー、Web管理画面は導入しない
30
+
31
+ ### 2.2 過剰実装を避ける項目
32
+
33
+ - 動的な設定変更APIは作らない
34
+ - プラグイン機構は作らない
35
+ - 任意シェル実行やコード実行機能は作らない
36
+ - 外部URL取得機能は作らない
37
+ - プロンプト全文をログDBに蓄積する仕組みは作らない
38
+ - 複雑なコスト最適化やモデル自動評価はMVPに入れない
39
+
40
+ ## 3. 成果物
41
+
42
+ MVP完了時点で、次のファイルと機能を用意する。
43
+
44
+ ```text
45
+ package.json
46
+ tsconfig.json
47
+ .gitignore
48
+ .env.example
49
+ config/
50
+ models.yaml
51
+ src/
52
+ index.ts
53
+ router/
54
+ ModelRouter.ts
55
+ config.ts
56
+ errors.ts
57
+ types.ts
58
+ providers/
59
+ ModelProvider.ts
60
+ OpenAIProvider.ts
61
+ AnthropicProvider.ts
62
+ schemas/
63
+ ArticleBriefSchema.ts
64
+ ArticleOutlineSchema.ts
65
+ ReviewResultSchema.ts
66
+ index.ts
67
+ workflows/
68
+ createQiitaArticle.ts
69
+ resumeQiitaArticle.ts
70
+ storage/
71
+ RunStore.ts
72
+ logger/
73
+ RunLogger.ts
74
+ utils/
75
+ cost.ts
76
+ hash.ts
77
+ json.ts
78
+ timeout.ts
79
+ tests/
80
+ router/
81
+ ModelRouter.test.ts
82
+ storage/
83
+ RunStore.test.ts
84
+ workflows/
85
+ createQiitaArticle.test.ts
86
+ runs/
87
+ .gitkeep
88
+ README.md
89
+ ```
90
+
91
+ ## 4. 依存関係
92
+
93
+ ### 4.1 実行・ビルド依存
94
+
95
+ - `typescript`
96
+ - `tsx`
97
+ - `commander`
98
+ - `yaml`
99
+ - `zod`
100
+ - `dotenv`
101
+ - `openai`
102
+ - `@anthropic-ai/sdk`
103
+
104
+ ### 4.2 開発・テスト依存
105
+
106
+ - `vitest`
107
+ - `@types/node`
108
+
109
+ ### 4.3 npm script
110
+
111
+ ```json
112
+ {
113
+ "scripts": {
114
+ "build": "tsc -p tsconfig.json",
115
+ "test": "vitest run",
116
+ "article:create": "tsx src/index.ts article:create",
117
+ "article:resume": "tsx src/index.ts article:resume",
118
+ "article:review": "tsx src/index.ts article:review"
119
+ }
120
+ }
121
+ ```
122
+
123
+ ## 5. フェーズ別実装計画
124
+
125
+ ### Phase 0: プロジェクト初期化
126
+
127
+ 目的: TypeScript CLIとして動く最小土台を作る。
128
+
129
+ 作業:
130
+
131
+ - `package.json` を作成する
132
+ - `tsconfig.json` を作成する
133
+ - `.gitignore` を作成し、`.env` と `runs/*` を除外する
134
+ - `.env.example` を作成する
135
+ - `src/index.ts` にCLIエントリポイントを作成する
136
+ - `runs/.gitkeep` を追加する
137
+
138
+ 受け入れ条件:
139
+
140
+ - `npm run build` が成功する
141
+ - `npm test` が空または最小テストで成功する
142
+ - `.env` がGit管理対象にならない
143
+
144
+ ### Phase 1: 型定義と設定読み込み
145
+
146
+ 目的: ルーティングに必要な共通型と `models.yaml` 読み込みを実装する。
147
+
148
+ 作業:
149
+
150
+ - `ModelTask`、`ModelRequest`、`ModelResponse` を定義する
151
+ - `ProviderRequest`、`ProviderResponse`、`ModelProvider` を定義する
152
+ - `RouterErrorKind`、`RouterError`、`normalizeProviderError` の型を定義する
153
+ - `RouterConfig`、`TaskConfig`、`ModelCandidate` を定義する
154
+ - `config/models.yaml` のMVP用初期設定を作成する
155
+ - `models.yaml` にproviderごとの `api_key_env` と、任意の `prices` を持てる余地を作る
156
+ - YAML読み込みとZod検証を `src/router/config.ts` に実装する
157
+ - 未定義タスク、primary未指定、不正providerを検出する
158
+ - `priority` はMVPでは実装しないため、初期型には入れない
159
+
160
+ 受け入れ条件:
161
+
162
+ - 正常な `models.yaml` を読み込める
163
+ - 不正な設定でわかりやすいエラーを返す
164
+ - 実際のモデル名は設定値として扱い、コードに固定しない
165
+ - APIキーの参照先env名を設定から解決できる
166
+ - コスト概算は単価がある場合だけベストエフォートで計算できる
167
+
168
+ ### Phase 2: Provider実装
169
+
170
+ 目的: OpenAI / Anthropic のAPI差分をProvider層に閉じ込める。
171
+
172
+ 作業:
173
+
174
+ - `OpenAIProvider` を実装する
175
+ - `AnthropicProvider` を実装する
176
+ - `.env` からAPIキーを読み込む
177
+ - Providerごとの `api_key_env` を優先し、未指定時だけ標準env名を使う
178
+ - Providerごとのレスポンスを共通 `ProviderResponse` に変換する
179
+ - token使用量が取得できる場合は `usage` に詰める
180
+ - APIキー未設定時は認証系エラーとして扱う
181
+ - SDK固有例外を `RouterErrorKind` に正規化する
182
+ - ProviderごとにSDKのリトライ回数とタイムアウト方針を明示する
183
+ - `AbortSignal` またはSDKのtimeout指定で中断できるようにする
184
+ - AnthropicProviderではモデル仕様に応じて未対応の `temperature` などを送らない
185
+ - AnthropicProviderでは `maxTokens` 未指定時に安全なデフォルトを補う
186
+
187
+ 受け入れ条件:
188
+
189
+ - Router側がSDK固有型をimportしない
190
+ - Provider単位の単体テストはSDK呼び出しをmockする
191
+ - APIキーやリクエスト本文を例外ログに直接出さない
192
+ - rate limit、timeout、overloaded、5xx、認証、課金枠不足を型またはstatus/codeで区別できる
193
+ - 未対応パラメータ送信による400を避ける、または設定エラーとして明示的に返せる
194
+
195
+ ### Phase 3: ModelRouter中核処理
196
+
197
+ 目的: タスク別候補選択、リトライ、タイムアウト、フォールバックを実装する。
198
+
199
+ 作業:
200
+
201
+ - `ModelRouter.run()` を実装する
202
+ - primaryとfallbackを順に試行する
203
+ - リクエストの `temperature` / `maxTokens` があれば設定値より優先する
204
+ - timeout処理をProvider呼び出しに適用し、`AbortSignal` をProviderへ渡す
205
+ - 一時的な失敗のみfallbackする
206
+ - 認証エラー、設定ミス、入力過大、schemaName不正、料金上限超過はfallbackしない
207
+ - 成功・失敗を `RunLogger` に渡す
208
+ - fallback判定は文字列マッチではなく `RouterErrorKind` で行う
209
+ - SDK内リトライはProvider責務、candidate切り替えはRouter責務として分離する
210
+ - `schemaName` 指定時はRouter内で検証・修復を呼び出す
211
+
212
+ 受け入れ条件:
213
+
214
+ - primary成功時にfallbackが呼ばれない
215
+ - rate limit / timeout / overloaded / 一時的な5xx でfallbackする
216
+ - 認証エラーでfallbackしない
217
+ - 課金枠不足や支払い上限でfallbackしない
218
+ - AI出力のschema検証失敗は、同一candidateでの修復1回後に次candidateへ進む
219
+ - schemaName不正などの設定ミスではfallbackしない
220
+ - 全候補失敗時に最後のエラー情報を含む例外を返す
221
+
222
+ ### Phase 4: スキーマ検証とJSON処理
223
+
224
+ 目的: 中間成果物のJSONをZodで検証し、失敗時の扱いを明確にする。
225
+
226
+ 作業:
227
+
228
+ - `ArticleBriefSchema` を実装する
229
+ - `ArticleOutlineSchema` を実装する
230
+ - `ReviewResultSchema` を実装する
231
+ - schemaNameからZod schemaを解決するregistryを作る
232
+ - JSON parse処理を `src/utils/json.ts` に集約する
233
+ - JSON検証失敗時の修復依頼用フローを `ModelRouter.run()` から呼べる形で実装する
234
+ - 修復依頼は同一candidateにつき最大1回に制限する
235
+ - Providerが構造化出力に対応する場合に備えて `responseFormat` を渡せる型にする
236
+ - AI出力の修復失敗時は `schema_validation` としてfallback候補へ進める
237
+ - `schemaName` 未定義・不正などの設定ミスは `config` として即終了する
238
+
239
+ 受け入れ条件:
240
+
241
+ - schemaName未指定のタスクは通常テキストとして処理できる
242
+ - schemaName指定時はparseとZod検証を通過した成果物だけ次工程へ進む
243
+ - AI出力のスキーマ不正を無制限に別モデルへ投げ続けない
244
+ - schemaName不正はfallbackせず設定エラーとして終了する
245
+ - parse失敗・Zod失敗・修復失敗をログへ全文出力せずに追跡できる
246
+
247
+ ### Phase 5: RunStoreとRunLogger
248
+
249
+ 目的: 途中成果物、メタ情報、最小ログを安全に保存する。
250
+
251
+ 作業:
252
+
253
+ - `RunStore` で `runs/<runId>/` を作成する
254
+ - `brief.json`、`outline.json`、`draft.md`、`review.json`、`final.md` を保存する
255
+ - `meta.json` に工程状態を保存する
256
+ - `RunLogger` でJSON Lines形式のメタログを保存する
257
+ - input本文は保存せず、`sha256` hashのみ保存する
258
+ - elapsed、provider、model、status、usage、cost概算を保存する
259
+ - errorは正規化済みの `kind`、status code、短い要約だけ保存する
260
+
261
+ 受け入れ条件:
262
+
263
+ - 途中停止後も `meta.json` から完了済み工程を判定できる
264
+ - ログにAPIキー、`.env` 内容、全文プロンプトが含まれない
265
+ - `runs/<runId>/` 以外へ成果物を書き込まない
266
+
267
+ ### Phase 6: Qiita記事作成ワークフロー
268
+
269
+ 目的: 設計書のQiita記事作成フローをCLIから実行できるようにする。
270
+
271
+ 作業:
272
+
273
+ - `createQiitaArticle(topic, options)` を実装する
274
+ - 記事作成ステップを宣言的な配列で定義する
275
+ - 共通ランナーで `article_brief`、`outline`、`draft_markdown`、`technical_review`、`rewrite` を実行する
276
+ - 共通ランナーが `meta.json` を見て完了済み工程をスキップする
277
+ - `brief.json`、`outline.json`、`draft.md`、`review.json`、`final.md` を保存する
278
+ - `article:create` コマンドを実装する(`--topic` インライン、または `--topic-file` でテキストファイル指定)
279
+ - `--topic` / `--topic-file` のどちらか必須とし、両方指定時はエラーにする
280
+ - `--topic-file` 指定時の `runId` はファイル名ベースで生成する
281
+ - `--profile <name>` で `config/profiles/<name>.yaml`(platform/style/language)を読み込み、本文生成プロンプトに作法を注入する(既定 `qiita`、`--platform` はラベル上書き)
282
+ - 解決した platform/style を `meta.json` に保存し、resume/review/revise/evaluate が継承する
283
+ - `article:resume` コマンドを実装する
284
+ - `article:review` コマンドを実装する
285
+ - `article:revise` コマンドを実装する(`final.md` に `--instruction` / `--instruction-file` の修正指示を反映)
286
+ - `article:revise` は上書き前の `final.md` を `final.bak.md` に退避する
287
+ - `article:export` コマンドを実装する(`final.md` を `--out <path>` へ書き出し。秘密名拒否・`--force` 上書き・ワークスペース外警告)
288
+ - `article:evaluate` コマンドを実装する(`final.md` を別系統モデルで評価し `final-review.json` を保存)
289
+ - 評価結果から `revise-instruction.md`(フィルタ済み修正指示)と `final-review.md`(全指摘の人向けサマリ)をローカル整形で生成する(追加APIコール無し、自動rewriteしない)
290
+ - `--min-severity` で指示に含める指摘を絞り、`--criteria` / `--criteria-file` で評価観点を指定できる
291
+ - 評価用の `final_review` タスクを `models.yaml` に追加し、既定で本文と別providerに向ける
292
+ - 工程の進捗(開始/完了/スキップ・使用provider/model・所要時間・概算コスト)を stderr に出力する
293
+ - 進捗は `WorkflowReporter` コールバックで渡し、ワークフロー関数は省略可能(テストではno-op)にする
294
+ - コストは `usage` × `prices` のローカル概算とし、表示のための追加APIコールを行わない。run合計も表示する
295
+ - 本文工程の保存前ガードを設ける(truncation検知の警告、全体コードフェンス除去、ラップ文=前置き/後置きの検知警告)。スキーマ工程は対象外
296
+ - ラップ文は自然文のため自動削除せず警告のみとする(正当な導入/結論の誤削除を避ける)
297
+
298
+ 受け入れ条件:
299
+
300
+ - `npm run article:create -- --topic "..."` で新規runを作れる
301
+ - `npm run article:create -- --topic-file <path>` で長文指示ファイルから新規runを作れる
302
+ - `--topic` も `--topic-file` も無い場合はわかりやすいエラーになる
303
+ - `npm run article:resume -- --run <runId>` で未完了工程から再開できる
304
+ - `npm run article:review -- --run <runId>` でレビュー工程以降を再実行できる
305
+ - `npm run article:revise -- --run <runId> --instruction "..."` で final.md に修正指示を反映できる
306
+ - 各工程の成果物が期待ファイル名で保存される
307
+ - create / resume / review が同じステップ定義を共有している
308
+ - 実行中に工程の進捗が stderr に表示され、stdout には `runId` / `final` のみ出力される
309
+
310
+ ### Phase 7: テスト
311
+
312
+ 目的: 課金や情報送信に関わる分岐を重点的に保護する。
313
+
314
+ 作業:
315
+
316
+ - `ModelRouter` のfallback判定テストを追加する
317
+ - `ModelRouter` のprovider未登録テストを追加する
318
+ - timeout時のfallbackテストを追加する
319
+ - 認証エラーでfallbackしないテストを追加する
320
+ - 課金枠不足でfallbackしないテストを追加する
321
+ - AI出力のschema_validationで次candidateへ進むテストを追加する
322
+ - schemaName不正でfallbackしないテストを追加する
323
+ - SDKエラー正規化のテストをProviderごとに追加する
324
+ - AnthropicProviderが未対応パラメータを送らないテストを追加する
325
+ - `RunStore` の保存・再開テストを追加する
326
+ - `RunLogger` が全文inputを保存しないテストを追加する
327
+ - `RunLogger` が生errorやヘッダを保存しないテストを追加する
328
+ - workflowの工程スキップ・再開テストを追加する
329
+
330
+ 受け入れ条件:
331
+
332
+ - `npm test` が成功する
333
+ - 外部APIを呼ばずにテストできる
334
+ - 失敗時にログへ機密情報が混入しないことをテストで確認する
335
+
336
+ ### Phase 8: READMEと利用手順
337
+
338
+ 目的: 最小限の使い方、設定、注意点を利用者が迷わず確認できるようにする。
339
+
340
+ 作業:
341
+
342
+ - READMEに概要を追加する
343
+ - セットアップ手順を追加する
344
+ - `.env` の設定例を追加する
345
+ - `models.yaml` の編集方法を追加する
346
+ - `api_key_env` とモデル別単価設定の扱いを追加する
347
+ - Anthropicなどモデルによって `temperature` が使えない場合があることを明記する
348
+ - `article:create`、`article:resume`、`article:review` の使用例を追加する
349
+ - セキュリティ上やらないことを明記する
350
+
351
+ 受け入れ条件:
352
+
353
+ - READMEだけでローカル実行まで進められる
354
+ - APIキーや秘密情報をログに残さない方針が明記されている
355
+ - MVPで未対応の機能が明記されている
356
+
357
+ ## 6. 実装順序
358
+
359
+ 推奨順序:
360
+
361
+ 1. Phase 0: プロジェクト初期化
362
+ 2. Phase 1: 型定義と設定読み込み
363
+ 3. Phase 5: RunStoreとRunLogger
364
+ 4. Phase 3: ModelRouter中核処理
365
+ 5. Phase 4: スキーマ検証とJSON処理
366
+ 6. Phase 2: Provider実装
367
+ 7. Phase 6: Qiita記事作成ワークフロー
368
+ 8. Phase 7: テスト拡充
369
+ 9. Phase 8: README整備
370
+
371
+ 理由:
372
+
373
+ - 先にProviderを作ると外部API都合に引っ張られるため、mock可能なRouterとStoreを先に固める
374
+ - Router、Store、Loggerは課金や情報保護に直結するため、早い段階でテストを書く
375
+ - Providerは最後寄りに実装し、外部SDK依存を境界に閉じ込める
376
+
377
+ ## 7. テスト計画
378
+
379
+ ### 7.1 単体テスト
380
+
381
+ - config読み込み
382
+ - fallback判定
383
+ - timeout処理
384
+ - schema registry
385
+ - JSON parse / validation
386
+ - RunStoreの保存と読み込み
387
+ - RunLoggerの秘匿情報非保存
388
+
389
+ ### 7.2 結合テスト
390
+
391
+ - mock providerを使った `createQiitaArticle`
392
+ - `meta.json` を使った `resumeQiitaArticle`
393
+ - review工程のみ再実行
394
+
395
+ ### 7.3 手動確認
396
+
397
+ - `.env` 未設定時のエラーメッセージ
398
+ - `models.yaml` 不正時のエラーメッセージ
399
+ - runId指定時の保存先
400
+ - ログに全文プロンプトが含まれないこと
401
+ - 実APIを使った最小1回の疎通確認
402
+
403
+ ## 8. エラー分類
404
+
405
+ ### 8.1 fallbackする
406
+
407
+ - rate limit
408
+ - timeout
409
+ - overloaded
410
+ - temporary unavailable
411
+ - service unavailable
412
+ - provider側の5xx
413
+ - API connection error
414
+ - AI出力のJSON parse / Zod検証失敗後、同一candidateでの修復も失敗した場合
415
+
416
+ ### 8.2 fallbackしない
417
+
418
+ - APIキー未設定
419
+ - APIキー不正
420
+ - 認証エラー
421
+ - 入力が長すぎる
422
+ - schemaName不正
423
+ - 禁止された内容
424
+ - 課金枠不足
425
+ - 料金上限超過
426
+ - `models.yaml` の設定ミス
427
+
428
+ `quota` という文字列では判定しない。
429
+ 一時的なrate limitと、支払い・課金枠・プロジェクト上限などのbilling quota系エラーは別の `RouterErrorKind` として扱う。
430
+
431
+ スキーマ系は `config` と `schema_validation` に分ける。
432
+ `schemaName` 不正やschema registry不整合は設定ミスなのでfallbackしない。AI出力のparse / Zod検証失敗は、同一candidateで最大1回修復を試し、それでも失敗した場合に `schema_validation` として次candidateへ進める。
433
+
434
+ ## 9. セキュリティチェックリスト
435
+
436
+ - `.env` をGit管理しない
437
+ - `.env.example` に実キーを書かない
438
+ - ログにAPIキーを書かない
439
+ - ログに全文プロンプトを書かない
440
+ - エラーメッセージにSDKの生レスポンスを丸ごと保存しない
441
+ - fallback判定をエラーメッセージ文字列の部分一致に依存しない
442
+ - 成果物保存先を `runs/<runId>/` に限定する
443
+ - runIdにパストラバーサル文字列を許可しない
444
+ - CLI引数から任意ファイル書き込み先を受け取らない(例外: `article:export` の `--out` は明示エクスポートとして許可。`.env` 等の秘密名は拒否、`--force` 無しでは上書きしない、ワークスペース外は警告。対象は `final.md` のみ)
445
+ - `--topic-file` / `--instruction-file` で `.env` 等の秘密ファイルを読み込ませない(ワークスペース外は警告)
446
+ - 任意コード実行機能を追加しない
447
+ - 任意URL取得機能を追加しない
448
+
449
+ ## 10. 完了条件
450
+
451
+ MVPは次を満たした時点で完了とする。
452
+
453
+ - `npm run build` が成功する
454
+ - `npm test` が成功する
455
+ - `npm run article:create -- --topic "..."` がmockまたは実APIで動く
456
+ - `runs/<runId>/` に `brief.json`、`outline.json`、`draft.md`、`review.json`、`final.md`、`meta.json` が保存される
457
+ - `npm run article:resume -- --run <runId>` で途中再開できる
458
+ - OpenAI / Anthropic のprimary / fallbackを設定で切り替えられる
459
+ - fallbackすべきでないエラーで別providerへ送信されない
460
+ - fallback判定が正規化済みエラー種別で実装されている
461
+ - schemaName指定時の検証・修復責務がRouterに実装されている
462
+ - ログにAPIキーや全文プロンプトが残らない
463
+ - READMEにセットアップとCLI利用例がある
464
+
465
+ ## 11. MVP後の拡張候補
466
+
467
+ 優先度順:
468
+
469
+ 1. GeminiProvider追加
470
+ 2. LocalProvider / Ollama対応
471
+ 3. 記事テンプレート切り替え
472
+ 4. コスト上限の厳格化
473
+ 5. Qiita API下書き投稿
474
+ 6. GitHubへの成果物保存
475
+ 7. LangGraph連携
476
+ 8. Dify連携
477
+ 9. Web UI
478
+
479
+ MVP後も、外部公開API、任意コード実行、任意URL取得は必要性とリスクを再評価してから追加する。
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@rex0220/llm-task-router",
3
+ "version": "0.1.0",
4
+ "description": "Thin, file-based CLI that routes a multi-step article workflow (brief → outline → draft → review → final) across OpenAI and Anthropic with fallback, schema validation, judge-model evaluation, and platform profiles (Qiita/Zenn/blog/note).",
5
+ "keywords": [
6
+ "cli",
7
+ "llm",
8
+ "openai",
9
+ "anthropic",
10
+ "claude",
11
+ "gpt",
12
+ "article",
13
+ "writing",
14
+ "content-generation",
15
+ "model-router",
16
+ "fallback",
17
+ "qiita",
18
+ "zenn"
19
+ ],
20
+ "license": "MIT",
21
+ "author": "rex0220 <rex0220@gmail.com>",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/rex0220/llm-task-router.git"
25
+ },
26
+ "homepage": "https://github.com/rex0220/llm-task-router#readme",
27
+ "bugs": "https://github.com/rex0220/llm-task-router/issues",
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "type": "module",
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "bin": {
36
+ "llm-task-router": "dist/llm-task-router.js"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "config",
41
+ "docs",
42
+ ".env.example",
43
+ "README.md",
44
+ "README.ja.md"
45
+ ],
46
+ "scripts": {
47
+ "build": "tsc --noEmit -p tsconfig.json && tsup",
48
+ "typecheck": "tsc --noEmit -p tsconfig.json",
49
+ "prepack": "npm run build",
50
+ "test": "npm run build && vitest run",
51
+ "test:unit": "vitest run",
52
+ "article:create": "tsx src/index.ts article:create",
53
+ "article:resume": "tsx src/index.ts article:resume",
54
+ "article:review": "tsx src/index.ts article:review",
55
+ "article:revise": "tsx src/index.ts article:revise",
56
+ "article:evaluate": "tsx src/index.ts article:evaluate",
57
+ "article:export": "tsx src/index.ts article:export"
58
+ },
59
+ "dependencies": {
60
+ "@anthropic-ai/sdk": "^0.56.0",
61
+ "commander": "^14.0.0",
62
+ "dotenv": "^16.4.7",
63
+ "openai": "^5.6.0",
64
+ "yaml": "^2.8.0",
65
+ "zod": "^3.25.67"
66
+ },
67
+ "devDependencies": {
68
+ "@types/node": "^22.15.32",
69
+ "tsup": "^8.5.1",
70
+ "tsx": "^4.20.3",
71
+ "typescript": "^5.8.3",
72
+ "vitest": "^3.2.4"
73
+ }
74
+ }