@sriinnu/kosha-discovery 0.6.0 → 1.0.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 (123) hide show
  1. package/README.md +53 -221
  2. package/dist/cli-cmd-model.d.ts +48 -0
  3. package/dist/cli-cmd-model.d.ts.map +1 -0
  4. package/dist/cli-cmd-model.js +231 -0
  5. package/dist/cli-cmd-model.js.map +1 -0
  6. package/dist/cli-cmd-query.d.ts +40 -0
  7. package/dist/cli-cmd-query.d.ts.map +1 -0
  8. package/dist/cli-cmd-query.js +303 -0
  9. package/dist/cli-cmd-query.js.map +1 -0
  10. package/dist/cli-commands.d.ts +65 -75
  11. package/dist/cli-commands.d.ts.map +1 -1
  12. package/dist/cli-commands.js +122 -504
  13. package/dist/cli-commands.js.map +1 -1
  14. package/dist/cli-format.d.ts +40 -0
  15. package/dist/cli-format.d.ts.map +1 -1
  16. package/dist/cli-format.js +74 -0
  17. package/dist/cli-format.js.map +1 -1
  18. package/dist/cli-help.d.ts +19 -0
  19. package/dist/cli-help.d.ts.map +1 -0
  20. package/dist/cli-help.js +150 -0
  21. package/dist/cli-help.js.map +1 -0
  22. package/dist/cli.js +5 -1
  23. package/dist/cli.js.map +1 -1
  24. package/dist/discovery/anthropic.d.ts +8 -1
  25. package/dist/discovery/anthropic.d.ts.map +1 -1
  26. package/dist/discovery/anthropic.js +26 -3
  27. package/dist/discovery/anthropic.js.map +1 -1
  28. package/dist/discovery/base.d.ts +26 -0
  29. package/dist/discovery/base.d.ts.map +1 -1
  30. package/dist/discovery/base.js +55 -2
  31. package/dist/discovery/base.js.map +1 -1
  32. package/dist/discovery/free-tier.d.ts +31 -0
  33. package/dist/discovery/free-tier.d.ts.map +1 -0
  34. package/dist/discovery/free-tier.js +47 -0
  35. package/dist/discovery/free-tier.js.map +1 -0
  36. package/dist/discovery/google.d.ts +8 -1
  37. package/dist/discovery/google.d.ts.map +1 -1
  38. package/dist/discovery/google.js +25 -3
  39. package/dist/discovery/google.js.map +1 -1
  40. package/dist/discovery/litellm-seed.d.ts +32 -0
  41. package/dist/discovery/litellm-seed.d.ts.map +1 -0
  42. package/dist/discovery/litellm-seed.js +252 -0
  43. package/dist/discovery/litellm-seed.js.map +1 -0
  44. package/dist/discovery/modelsdev-catalog.d.ts +95 -0
  45. package/dist/discovery/modelsdev-catalog.d.ts.map +1 -0
  46. package/dist/discovery/modelsdev-catalog.js +131 -0
  47. package/dist/discovery/modelsdev-catalog.js.map +1 -0
  48. package/dist/discovery/modelsdev-seed.d.ts +19 -0
  49. package/dist/discovery/modelsdev-seed.d.ts.map +1 -0
  50. package/dist/discovery/modelsdev-seed.js +203 -0
  51. package/dist/discovery/modelsdev-seed.js.map +1 -0
  52. package/dist/discovery/openai-compatible.d.ts.map +1 -1
  53. package/dist/discovery/openai-compatible.js +12 -1
  54. package/dist/discovery/openai-compatible.js.map +1 -1
  55. package/dist/discovery/openai.d.ts +9 -1
  56. package/dist/discovery/openai.d.ts.map +1 -1
  57. package/dist/discovery/openai.js +31 -8
  58. package/dist/discovery/openai.js.map +1 -1
  59. package/dist/discovery/openrouter.d.ts.map +1 -1
  60. package/dist/discovery/openrouter.js +18 -1
  61. package/dist/discovery/openrouter.js.map +1 -1
  62. package/dist/discovery/promo-overrides.d.ts +54 -0
  63. package/dist/discovery/promo-overrides.d.ts.map +1 -0
  64. package/dist/discovery/promo-overrides.js +74 -0
  65. package/dist/discovery/promo-overrides.js.map +1 -0
  66. package/dist/discovery/public-seed.d.ts +30 -0
  67. package/dist/discovery/public-seed.d.ts.map +1 -0
  68. package/dist/discovery/public-seed.js +51 -0
  69. package/dist/discovery/public-seed.js.map +1 -0
  70. package/dist/discovery-contract.d.ts +14 -2
  71. package/dist/discovery-contract.d.ts.map +1 -1
  72. package/dist/discovery-contract.js +28 -0
  73. package/dist/discovery-contract.js.map +1 -1
  74. package/dist/enrichment/litellm-catalog.d.ts +81 -0
  75. package/dist/enrichment/litellm-catalog.d.ts.map +1 -0
  76. package/dist/enrichment/litellm-catalog.js +129 -0
  77. package/dist/enrichment/litellm-catalog.js.map +1 -0
  78. package/dist/enrichment/litellm.d.ts +9 -2
  79. package/dist/enrichment/litellm.d.ts.map +1 -1
  80. package/dist/enrichment/litellm.js +192 -23
  81. package/dist/enrichment/litellm.js.map +1 -1
  82. package/dist/index.d.ts +3 -1
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +2 -0
  85. package/dist/index.js.map +1 -1
  86. package/dist/model-features.d.ts +77 -0
  87. package/dist/model-features.d.ts.map +1 -0
  88. package/dist/model-features.js +245 -0
  89. package/dist/model-features.js.map +1 -0
  90. package/dist/normalize.d.ts +13 -0
  91. package/dist/normalize.d.ts.map +1 -1
  92. package/dist/normalize.js +15 -0
  93. package/dist/normalize.js.map +1 -1
  94. package/dist/provider-catalog.d.ts +7 -0
  95. package/dist/provider-catalog.d.ts.map +1 -1
  96. package/dist/provider-catalog.js +4 -0
  97. package/dist/provider-catalog.js.map +1 -1
  98. package/dist/registry-discovery.d.ts.map +1 -1
  99. package/dist/registry-discovery.js +11 -1
  100. package/dist/registry-discovery.js.map +1 -1
  101. package/dist/registry-query.d.ts.map +1 -1
  102. package/dist/registry-query.js +6 -3
  103. package/dist/registry-query.js.map +1 -1
  104. package/dist/registry-runtime.d.ts +39 -1
  105. package/dist/registry-runtime.d.ts.map +1 -1
  106. package/dist/registry-runtime.js +332 -1
  107. package/dist/registry-runtime.js.map +1 -1
  108. package/dist/registry-selection.js +2 -0
  109. package/dist/registry-selection.js.map +1 -1
  110. package/dist/registry.d.ts +9 -0
  111. package/dist/registry.d.ts.map +1 -1
  112. package/dist/registry.js +11 -1
  113. package/dist/registry.js.map +1 -1
  114. package/dist/security.d.ts.map +1 -1
  115. package/dist/security.js +32 -4
  116. package/dist/security.js.map +1 -1
  117. package/dist/tokenizer-family.d.ts +39 -0
  118. package/dist/tokenizer-family.d.ts.map +1 -0
  119. package/dist/tokenizer-family.js +92 -0
  120. package/dist/tokenizer-family.js.map +1 -0
  121. package/dist/types.d.ts +186 -0
  122. package/dist/types.d.ts.map +1 -1
  123. package/package.json +8 -2
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="logo.svg" alt="Kosha — AI Model Discovery" width="140" />
2
+ <img src="logo-icon.svg" alt="Kosha — AI Model Discovery" width="120" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">kosha-discovery — कोश</h1>
@@ -11,206 +11,73 @@
11
11
  <a href="https://www.npmjs.com/package/@sriinnu/kosha-discovery"><img src="https://img.shields.io/npm/dm/%40sriinnu%2Fkosha-discovery?color=0EA5E9&label=downloads" alt="npm downloads" /></a>
12
12
  <a href="https://github.com/sriinnu/kosha-discovery/blob/main/LICENSE"><img src="https://img.shields.io/github/license/sriinnu/kosha-discovery?color=F59E0B" alt="license" /></a>
13
13
  <a href="https://www.npmjs.com/package/@sriinnu/kosha-discovery"><img src="https://img.shields.io/node/v/%40sriinnu%2Fkosha-discovery?color=5B21B6" alt="node version" /></a>
14
- <a href="https://github.com/sriinnu/kosha-discovery/actions/workflows/release-npm.yml"><img src="https://img.shields.io/github/actions/workflow/status/sriinnu/kosha-discovery/release-npm.yml?label=release%20workflow" alt="release workflow status" /></a>
15
- <a href="https://github.com/sriinnu/kosha-discovery/actions/workflows/update-kosha-snapshot.yml"><img src="https://img.shields.io/github/actions/workflow/status/sriinnu/kosha-discovery/update-kosha-snapshot.yml?label=snapshot%20workflow" alt="snapshot workflow status" /></a>
16
- <a href="https://github.com/sriinnu/kosha-discovery/actions/workflows/provider-smoke.yml"><img src="https://img.shields.io/github/actions/workflow/status/sriinnu/kosha-discovery/provider-smoke.yml?label=provider%20smoke" alt="provider smoke status" /></a>
17
- <a href="https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json"><img src="https://img.shields.io/badge/pricing%20source-LiteLLM-2563EB" alt="LiteLLM pricing source" /></a>
18
14
  </p>
19
15
 
20
- Kosha (कोश — treasury/repository) automatically discovers AI models across providers, resolves credentials from CLI tools and environment variables, enriches models with pricing data, and exposes the catalog via library, CLI, and HTTP API.
21
-
22
- ## Why
23
-
24
- AI applications hardcode model IDs, pricing, and provider configs. When providers add models or change pricing, every app breaks. Kosha solves this:
25
-
26
- - **Dynamic discovery** — fetches real model lists from provider APIs
27
- - **Offline direct catalogs** — OpenAI, Anthropic, and Google fallback model coverage even without API keys
28
- - **Smart credentials** — finds API keys from env vars, CLI tools (Claude, Copilot, Gemini CLI), and config files
29
- - **Pricing enrichment** — fills in input/output/reasoning/cache costs and context windows from litellm's community-maintained dataset
30
- - **Proxy vs origin pricing** — preserves route pricing and exposes origin-provider reference pricing for proxy-served models
31
- - **Model aliases** — `sonnet` → `claude-sonnet-4-20250514`, updated as models evolve
32
- - **Role matrix** — query provider -> model -> roles (`chat`, `embedding`, `image_generation`, etc.)
33
- - **Cheapest routing** — rank cheapest eligible models for tasks like embeddings or image generation
34
- - **Local LLM scanning** — detects Ollama models alongside cloud providers
35
- - **Three access patterns** — use as a library, CLI tool, or HTTP API
16
+ Kosha (कोश — *treasury*) discovers AI models across providers, resolves credentials, enriches with pricing, and exposes the catalog through a library, CLI, and HTTP API. One source of truth for model identity, pricing, and routing — so your app doesn't break when providers ship new SKUs or change rates.
36
17
 
37
18
  ## Install
38
19
 
39
20
  ```bash
40
- pnpm add kosha-discovery
41
- ```
42
-
43
- ## Development (pnpm)
44
-
45
- ```bash
46
- pnpm install
47
- pnpm run build
48
- pnpm run test
21
+ npm install @sriinnu/kosha-discovery # library / server
22
+ npm install -g @sriinnu/kosha-discovery # global `kosha` CLI
49
23
  ```
50
24
 
51
- ## Quick Start
25
+ ## Quick start
52
26
 
53
27
  ### Library
54
28
 
55
29
  ```typescript
56
- import { createKosha } from "kosha-discovery";
30
+ import { createKosha } from "@sriinnu/kosha-discovery";
57
31
 
58
32
  const kosha = await createKosha();
59
33
 
60
- const models = kosha.models(); // all models
61
- const embeddings = kosha.models({ mode: "embedding" }); // filter by mode
62
- const model = kosha.model("sonnet"); // resolve alias
63
- const cheapest = kosha.cheapestModels({ role: "image", limit: 3 });
64
-
65
- console.log(model.pricing); // { inputPerMillion: 3, outputPerMillion: 15, ... }
34
+ const models = kosha.models(); // all
35
+ const cheapest = kosha.cheapestModels({ role: "image" }); // ranked
36
+ const sonnet = kosha.model("sonnet"); // alias resolves
37
+ console.log(sonnet.pricing); // { inputPerMillion: 3, outputPerMillion: 15, ... }
66
38
  ```
67
39
 
68
40
  ### CLI
69
41
 
70
42
  ```bash
71
- kosha discover # discover all providers
72
- kosha list # list models
73
- kosha list --provider anthropic # filter by provider
74
- kosha search gemini # fuzzy search
75
- kosha model sonnet # model details
76
- kosha cheapest --role embeddings # cheapest for a task
77
- kosha routes gpt-4o # all provider routes
78
- kosha providers # provider status
79
- kosha latest # force-fetch latest provider/model details
80
- kosha latest --provider openai # latest for one provider
81
- kosha serve --port 3000 # start HTTP API
43
+ kosha discover # discover all providers (writes cache + manifest)
44
+ kosha list --provider anthropic # filter from local cache
45
+ kosha model sonnet # details for one model (alias-aware)
46
+ kosha cheapest --role embeddings # rank cheapest for a role
47
+ kosha update # force a fresh fetch
48
+ kosha serve --port 3000 # HTTP API
82
49
  ```
83
50
 
84
- ### Auto-Fetch JSON Snapshot
51
+ After each discovery, a stable v1 manifest lands at `~/.kosha/registry.json` — any tool that reads JSON can consume it:
85
52
 
86
53
  ```bash
87
- # one-shot latest snapshot
88
- pnpm run autofetch:once
89
-
90
- # custom output/provider
91
- pnpm run autofetch:once -- --provider openai --output ./data/openai-latest.json
92
-
93
- # continuous loop (default 3600s)
94
- pnpm run autofetch -- --interval-seconds 900
54
+ jq '.models[] | select(.pricing.inputPerMillion < 0.1) | .modelId' ~/.kosha/registry.json
95
55
  ```
96
56
 
97
- By default this writes JSON to `./data/kosha-latest.json`.
98
-
99
- ### CI / Smoke Checks
100
-
101
- Workflow files:
102
-
103
- - `.github/workflows/update-kosha-snapshot.yml`
104
- - `.github/workflows/provider-smoke.yml`
105
-
106
- Snapshot workflow:
107
-
108
- - Scheduled: weekly (Monday 06:00 UTC)
109
- - Manual: GitHub UI -> Actions -> `Update Kosha Snapshot` -> `Run workflow`
110
- - Optional manual inputs:
111
- - `provider` (empty = all providers)
112
- - `output` (default `data/kosha-latest.json`)
113
- - Disable scheduled runs without removing the workflow by setting `KOSHA_SNAPSHOT_SCHEDULE_ENABLED=false`
114
- - Manual `Run workflow` still works even when schedule is disabled
115
-
116
- Provider smoke workflow:
117
-
118
- - Scheduled: nightly (03:00 UTC)
119
- - Manual: GitHub UI -> Actions -> `Provider Smoke Checks` -> `Run workflow`
120
- - Runs only when repository variable `KOSHA_PROVIDER_SMOKE_ENABLED=true`
121
- - Manual dispatch can override that gate with `force=true`
122
- - Installs with pnpm, builds, then runs a node inline smoke script against real provider endpoints
123
- - Providers without the required secrets are skipped instead of failing the job
124
- - Always uploads `artifacts/provider-smoke-report.json`
125
-
126
- Provider smoke secrets:
127
-
128
- - OpenAI: `OPENAI_API_KEY`
129
- - Google/Gemini: `GOOGLE_API_KEY` or `GEMINI_API_KEY`
130
- - Mistral: `MISTRAL_API_KEY`
131
- - DeepSeek: `DEEPSEEK_API_KEY`
132
- - Moonshot: `MOONSHOT_API_KEY` or `KIMI_API_KEY`
133
- - GLM: `GLM_API_KEY` or `ZHIPUAI_API_KEY`
134
- - Z.AI: `ZAI_API_KEY`
135
- - MiniMax: `MINIMAX_API_KEY`
136
- - OpenRouter: optional `OPENROUTER_API_KEY`
137
- - Bedrock: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION`
138
- - Vertex AI: `GOOGLE_APPLICATION_CREDENTIALS_JSON`, `GOOGLE_CLOUD_PROJECT`
139
-
140
- Security controls in these workflows:
141
-
142
- - Snapshot workflow commits only the configured snapshot file path plus its checksum file, never broad `git add -A`
143
- - Snapshot workflow validates the generated snapshot against a local JSON schema before commit
144
- - Snapshot workflow runs a high-signal secret-pattern scan on snapshot output before commit
145
- - Snapshot workflow writes `data/kosha-latest.sha256` alongside the snapshot
146
- - Snapshot workflow uploads an always-on artifact with run metadata, provider summaries, and failure details
147
- - Provider smoke workflow never echoes secret values and records a machine-readable JSON report
148
-
149
- ### Branch Protection Audit
150
-
151
- Workflow file: `.github/workflows/branch-protection-check.yml`
152
-
153
- - Runs on `main` and via `workflow_dispatch`
154
- - Reads the `main` branch protection rule through the GitHub API
155
- - Expects the required status checks list to include `Branch Protection Check / audit`
156
- - Uploads a warning artifact instead of failing when the token cannot read branch protection settings
157
-
158
- Keep that check name stable when you rename the workflow or job, and update the protection rule whenever you add more required checks.
159
-
160
- ### Where Data Is Stored
161
-
162
- - Git repo: model/provider discovery data is **not** committed by default.
163
- - Runtime cache: `~/.kosha/cache/*.json` (machine-local, TTL-based).
164
- - Exported snapshot: only if you run `autofetch`/`autofetch:once` with an output file and commit it yourself.
165
-
166
57
  ### HTTP API
167
58
 
168
- ```bash
169
- kosha serve --port 3000
170
59
  ```
171
-
172
- ```
173
- GET /api/models — All models (filterable)
174
- GET /api/models/cheapest — Cheapest ranked models
175
- GET /api/models/:idOrAlias — Single model
176
- GET /api/models/:idOrAlias/routes — All provider routes
177
- GET /api/roles — Provider → model → roles matrix
178
- GET /api/providers — All providers
179
- POST /api/refresh — Re-discover
180
- GET /health — Health check
60
+ GET /api/models[?provider=…&role=…] GET /api/models/:idOrAlias
61
+ GET /api/models/:idOrAlias/routes GET /api/models/cheapest?role=…
62
+ GET /api/providers GET /api/roles
63
+ POST /api/refresh GET /health
181
64
  ```
182
65
 
183
- ## Supported Providers
66
+ ## Supported providers
184
67
 
185
- | Provider | Discovery | Credential Sources |
186
- |----------|-----------|-------------------|
187
- | Anthropic | API (`/v1/models`) | `ANTHROPIC_API_KEY`, Claude CLI, Codex CLI |
188
- | OpenAI | API (`/v1/models`) | `OPENAI_API_KEY`, GitHub Copilot tokens |
189
- | Google | API (`/v1beta/models`) | `GOOGLE_API_KEY`, `GEMINI_API_KEY`, Gemini CLI, gcloud |
68
+ | Provider | Discovery | Credential sources |
69
+ |----------|-----------|--------------------|
70
+ | Anthropic | `/v1/models` | `ANTHROPIC_API_KEY`, Claude CLI, Codex CLI |
71
+ | OpenAI | `/v1/models` | `OPENAI_API_KEY`, GitHub Copilot tokens |
72
+ | Google | `/v1beta/models` | `GOOGLE_API_KEY`, `GEMINI_API_KEY`, Gemini CLI, gcloud |
190
73
  | AWS Bedrock | SDK → CLI → static | `AWS_ACCESS_KEY_ID`, `~/.aws/credentials`, SSO, IAM |
191
- | Vertex AI | API + gcloud | `GOOGLE_APPLICATION_CREDENTIALS`, gcloud ADC |
192
- | Ollama | Local API | None needed (local) |
193
- | OpenRouter | API | `OPENROUTER_API_KEY` (optional) |
194
- | NVIDIA | API | `NVIDIA_API_KEY` |
195
- | Together AI | API | `TOGETHER_API_KEY` |
196
- | Fireworks AI | API | `FIREWORKS_API_KEY` |
197
- | Groq | API | `GROQ_API_KEY` |
198
- | Mistral AI | API | `MISTRAL_API_KEY` |
199
- | DeepInfra | API | `DEEPINFRA_API_KEY` |
200
- | Cohere | API | `CO_API_KEY` |
201
- | Cerebras | API | `CEREBRAS_API_KEY` |
202
- | Perplexity | API | `PERPLEXITY_API_KEY` |
203
- | DeepSeek | API | `DEEPSEEK_API_KEY` |
204
- | Moonshot (Kimi) | API | `MOONSHOT_API_KEY` / `KIMI_API_KEY` |
205
- | GLM (Zhipu) | API | `GLM_API_KEY` / `ZHIPUAI_API_KEY` |
206
- | Z.AI | API | `ZAI_API_KEY` |
207
- | MiniMax | API | `MINIMAX_API_KEY` |
208
-
209
- ## Security
210
-
211
- All external data (API responses, CLI output, cache reads) is scanned for 9 threat types before use: credential leaks, base64 payloads, script/shell injection, data URIs, null bytes, prototype pollution, hex blobs, and oversized strings. A pre-commit hook blocks secrets at commit time.
212
-
213
- See [docs/security.md](docs/security.md) for the full threat catalogue and architecture.
74
+ | Vertex AI | API + gcloud | `GOOGLE_APPLICATION_CREDENTIALS`, ADC |
75
+ | Ollama | local API | (local) |
76
+ | OpenRouter | API | `OPENROUTER_API_KEY` *(optional)* |
77
+ | NVIDIA / Together / Fireworks / Groq / Cerebras / Cohere / DeepInfra / Perplexity | API | provider key env var |
78
+ | DeepSeek / Mistral / Moonshot (Kimi) / GLM (Zhipu) / Z.AI / MiniMax | API | provider key env var |
79
+
80
+ Full credential setup: [docs/credentials.md](docs/credentials.md).
214
81
 
215
82
  ## Architecture
216
83
 
@@ -218,70 +85,35 @@ See [docs/security.md](docs/security.md) for the full threat catalogue and archi
218
85
  <img src="architecture.svg" alt="Kosha Architecture" width="720" />
219
86
  </p>
220
87
 
221
- ```
222
- ┌─────────────────────────────────────────────────────┐
223
- │ Your Application │
224
- │ import { createKosha } from "kosha" │
225
- └───────────────────────┬─────────────────────────────┘
226
-
227
- ┌───────────────────────▼─────────────────────────────┐
228
- │ ModelRegistry │
229
- │ models() · providerRoles() · cheapestModels() │
230
- └──┬──────────┬──────────────┬───────────────┬────────┘
231
- │ │ │ │
232
- ┌──▼───┐ ┌───▼────────┐ ┌───▼──────────┐ ┌──▼─────────┐
233
- │Alias │ │ Discovery │ │ Enrichment │ │ Resilience │
234
- │System│ │ Layer │ │ Layer │ │ Layer │
235
- └──────┘ └───┬────────┘ └──────┬───────┘ └────────────┘
236
- │ │ CircuitBreaker
237
- ┌────────┼────────┐ │ HealthTracker
238
- ▼ ▼ ▼ ▼ StaleCachePolicy
239
- Direct OpenAI- Cloud litellm
240
- API Compatible Proxies JSON
241
- ```
88
+ Discovery layer talks to provider APIs and local catalogs. Enrichment layer fills pricing and context windows from the LiteLLM catalog and models.dev. Resilience layer (circuit breaker + stale-cache fallback + health tracker) keeps a flaky provider a degraded read, never a crash. Manifest layer writes a v1-stable JSON snapshot so downstream consumers — `tokmeter`, `chitragupta`, `ayuh` — read prices from one source instead of inventing their own.
242
89
 
243
- ## Documentation
90
+ ## Docs
244
91
 
245
- | Doc | What's in it |
246
- |-----|-------------|
247
- | [Credentials](docs/credentials.md) | Setup for all 21 providers (env vars, CLI tools, config files) |
248
- | [CLI Reference](docs/cli.md) | All commands, flags, and example output |
249
- | [HTTP API](docs/api.md) | All endpoints, parameters, and response schemas |
250
- | [Configuration](docs/configuration.md) | Aliases, routing, pricing enrichment, programmatic config |
251
- | [Architecture](docs/architecture.md) | Discovery flow, module map, data pipeline, adding providers |
252
- | [Resilience](docs/resilience.md) | Circuit breakers, stale cache fallback, health monitoring |
92
+ | | |
93
+ |---|---|
94
+ | [Credentials](docs/credentials.md) | Env vars, CLI tools, and config files for every provider |
95
+ | [CLI](docs/cli.md) | Commands, flags, examples |
96
+ | [HTTP API](docs/api.md) | Endpoints, parameters, response schemas |
97
+ | [Configuration](docs/configuration.md) | Aliases, routing, enrichment, programmatic config |
98
+ | [Architecture](docs/architecture.md) | Discovery flow, module map, adding providers |
99
+ | [Resilience](docs/resilience.md) | Circuit breakers, stale cache, health |
253
100
  | [Security](docs/security.md) | Threat catalogue, runtime scanning, pre-commit hook |
254
101
  | [Discovery Plane v1](docs/discovery-plane-v1.md) | Stable daemon contract (deltas, SSE watch, binding hints) |
255
102
 
256
- ## Release & Tagging
257
-
258
- Package: `@sriinnu/kosha-discovery`
103
+ ## Release
259
104
 
260
- This repo uses a human-in-the-loop release flow:
105
+ Tag-driven via GitHub Actions:
261
106
 
262
- 1. Update version in `package.json` and lockfiles locally.
263
- 2. Create a signed tag and push it:
264
- ```bash
265
- git tag -s v0.6.0 -m "v0.6.0"
266
- git push origin v0.6.0
267
- ```
268
- 3. In GitHub Actions, run `Manual Release (Tag + npm)` and provide `tag=v0.6.0`.
269
- 4. Workflow verifies tag/version match, builds/tests, then publishes to npm (if enabled) and creates a GitHub Release.
107
+ ```bash
108
+ git tag -s vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z
109
+ # → Actions → "Manual Release (Tag + npm)" → run with tag=vX.Y.Z
110
+ ```
270
111
 
271
- Required secret for publish:
272
- - `NPM_TOKEN` (publish rights for `@sriinnu` scope)
112
+ The workflow checks tag ↔ package.json match, builds, tests, publishes to npm, and creates the GitHub Release. Requires the `NPM_TOKEN` secret.
273
113
 
274
114
  ## Credits
275
115
 
276
- - **[litellm](https://github.com/BerriAI/litellm)** -- Community-maintained model pricing database
277
- - **[openrouter](https://openrouter.ai)** -- Model aggregation API
278
- - **[ollama](https://ollama.ai)** -- Local LLM runtime
279
- - **[chitragupta](https://github.com/sriinnu/chitragupta)** -- Autonomous AI Agent Platform whose registry patterns inspired kosha
280
- - **[takumi](https://github.com/sriinnu/takumi)** -- AI coding agent TUI whose routing needs drove kosha's creation
281
-
282
- ## What "Kosha" Means
283
-
284
- `Kosha` comes from Sanskrit -- a container, treasury, or layered sheath of knowledge. A standalone model-discovery utility for any AI system.
116
+ [litellm](https://github.com/BerriAI/litellm) (pricing data) · [openrouter](https://openrouter.ai) · [ollama](https://ollama.ai) · [chitragupta](https://github.com/sriinnu/chitragupta) (registry patterns) · [takumi](https://github.com/sriinnu/takumi) (routing needs that drove kosha's creation).
285
117
 
286
118
  ## License
287
119
 
@@ -0,0 +1,48 @@
1
+ /**
2
+ * cli-cmd-model.ts — Pricing-heavy model detail commands.
3
+ *
4
+ * Contains `cmdModel`, `cmdResolve`, and `cmdRoutes` — the three commands
5
+ * that display detailed per-model information including multi-tier pricing
6
+ * (cache, reasoning, batch, origin).
7
+ *
8
+ * Extracted from `cli-commands.ts` to keep each module under 450 LOC.
9
+ *
10
+ * @module cli-cmd-model
11
+ */
12
+ import type { ModelRegistry } from "./registry.js";
13
+ /**
14
+ * Show detailed information for a single model identified by id or alias.
15
+ *
16
+ * If an exact match is not found, falls back to fuzzy substring search.
17
+ * Single fuzzy match is shown automatically; multiple matches produce a
18
+ * disambiguation list (capped at 5 suggestions).
19
+ *
20
+ * @param registry The model registry to look up.
21
+ * @param idOrAlias A model id, display name, or alias.
22
+ * @param flags CLI flags (supports `--json`).
23
+ */
24
+ export declare function cmdModel(registry: ModelRegistry, idOrAlias: string, flags: Record<string, string | boolean>): Promise<void>;
25
+ /**
26
+ * Resolve a model alias to its canonical provider ID.
27
+ * Unknown aliases are returned as-is with a yellow warning.
28
+ *
29
+ * @param registry The model registry containing alias mappings.
30
+ * @param alias The alias string to resolve.
31
+ * @param flags CLI flags (supports `--json`).
32
+ */
33
+ export declare function cmdResolve(registry: ModelRegistry, alias: string, flags: Record<string, string | boolean>): Promise<void>;
34
+ /**
35
+ * Show every provider route through which a model can be accessed.
36
+ *
37
+ * A "route" is a serving-layer entry whose normalized model ID matches the
38
+ * given identifier. Output includes direct/preferred markers, origin provider,
39
+ * model version hint, and serving base URL.
40
+ *
41
+ * Pricing columns show `—` when data is unavailable.
42
+ *
43
+ * @param registry The model registry to query.
44
+ * @param modelId Canonical model ID or alias to look up.
45
+ * @param flags CLI flags (supports `--json`).
46
+ */
47
+ export declare function cmdRoutes(registry: ModelRegistry, modelId: string, flags: Record<string, string | boolean>): Promise<void>;
48
+ //# sourceMappingURL=cli-cmd-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-cmd-model.d.ts","sourceRoot":"","sources":["../src/cli-cmd-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAWnD;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA6EjI;AAID;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA6D/H;AAID;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ChI"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * cli-cmd-model.ts — Pricing-heavy model detail commands.
3
+ *
4
+ * Contains `cmdModel`, `cmdResolve`, and `cmdRoutes` — the three commands
5
+ * that display detailed per-model information including multi-tier pricing
6
+ * (cache, reasoning, batch, origin).
7
+ *
8
+ * Extracted from `cli-commands.ts` to keep each module under 450 LOC.
9
+ *
10
+ * @module cli-cmd-model
11
+ */
12
+ import { BOLD, CYAN, DIM, GREEN, RED, YELLOW, c, formatBatchDiscount, formatNumber, formatPrice, formatTimestamp, renderTable, } from "./cli-format.js";
13
+ import { ensureDiscovered } from "./cli-commands.js";
14
+ // ── model (detail view) ─────────────────────────────────────────────────
15
+ /**
16
+ * Show detailed information for a single model identified by id or alias.
17
+ *
18
+ * If an exact match is not found, falls back to fuzzy substring search.
19
+ * Single fuzzy match is shown automatically; multiple matches produce a
20
+ * disambiguation list (capped at 5 suggestions).
21
+ *
22
+ * @param registry The model registry to look up.
23
+ * @param idOrAlias A model id, display name, or alias.
24
+ * @param flags CLI flags (supports `--json`).
25
+ */
26
+ export async function cmdModel(registry, idOrAlias, flags) {
27
+ if (!idOrAlias) {
28
+ console.error(c(RED, "Usage: kosha model <id|alias>"));
29
+ process.exit(1);
30
+ }
31
+ await ensureDiscovered(registry);
32
+ const model = registry.model(idOrAlias);
33
+ if (!model) {
34
+ // Fuzzy fallback — substring match across id, name, and aliases so users
35
+ // can type fragments like "sonnet" without knowing the full canonical ID.
36
+ const needle = idOrAlias.toLowerCase();
37
+ const fuzzy = registry.models().filter((m) => m.id.toLowerCase().includes(needle) ||
38
+ m.name.toLowerCase().includes(needle) ||
39
+ m.aliases.some((a) => a.toLowerCase().includes(needle)));
40
+ if (fuzzy.length === 1)
41
+ return cmdModel(registry, fuzzy[0].id, flags);
42
+ if (fuzzy.length > 1) {
43
+ console.log(c(YELLOW, `No exact match for "${idOrAlias}". Did you mean:`));
44
+ for (const m of fuzzy.slice(0, 5))
45
+ console.log(` ${c(CYAN, m.id)} (${m.provider})`);
46
+ return;
47
+ }
48
+ console.error(c(RED, `Model not found: "${idOrAlias}"`));
49
+ process.exit(1);
50
+ }
51
+ if (flags.json) {
52
+ console.log(JSON.stringify(model, null, 2));
53
+ return;
54
+ }
55
+ const providerName = registry.provider(model.provider)?.name ?? model.provider;
56
+ const pricingStr = model.pricing
57
+ ? `${formatPrice(model.pricing.inputPerMillion)} / ${formatPrice(model.pricing.outputPerMillion)} per million tokens (in/out)`
58
+ : c(DIM, "unknown");
59
+ // Cache pricing is optional — only displayed when the model has it
60
+ const cacheStr = model.pricing?.cacheReadPerMillion !== undefined
61
+ ? `\nCache Pricing: ${formatPrice(model.pricing.cacheReadPerMillion)} read / ${formatPrice(model.pricing.cacheWritePerMillion)} write per million tokens`
62
+ : "";
63
+ // Reasoning pricing is optional — shown when providers expose it.
64
+ const reasoningStr = model.pricing?.reasoningInputPerMillion !== undefined || model.pricing?.reasoningOutputPerMillion !== undefined
65
+ ? `\nReasoning Pricing: ${formatPrice(model.pricing?.reasoningInputPerMillion)} in / ${formatPrice(model.pricing?.reasoningOutputPerMillion)} out per million tokens`
66
+ : "";
67
+ // Batch API pricing — shown when providers offer async batch discounts.
68
+ const batchDiscount = formatBatchDiscount(model.pricing);
69
+ const batchStr = model.pricing?.batchInputPerMillion !== undefined || model.pricing?.batchOutputPerMillion !== undefined
70
+ ? `\nBatch Pricing: ${formatPrice(model.pricing?.batchInputPerMillion)} in / ${formatPrice(model.pricing?.batchOutputPerMillion)} out per million tokens${batchDiscount ? ` ${batchDiscount}` : ""}`
71
+ : "";
72
+ const originPricingStr = model.originPricing
73
+ ? `\nOrigin Pricing: ${formatPrice(model.originPricing.inputPerMillion)} / ${formatPrice(model.originPricing.outputPerMillion)} per million tokens (in/out)` +
74
+ ((model.originPricing.reasoningInputPerMillion !== undefined || model.originPricing.reasoningOutputPerMillion !== undefined)
75
+ ? `\nOrigin Reasoning Pricing: ${formatPrice(model.originPricing.reasoningInputPerMillion)} in / ${formatPrice(model.originPricing.reasoningOutputPerMillion)} out per million tokens`
76
+ : "") +
77
+ ((model.originPricing.batchInputPerMillion !== undefined || model.originPricing.batchOutputPerMillion !== undefined)
78
+ ? `\nOrigin Batch Pricing: ${formatPrice(model.originPricing.batchInputPerMillion)} in / ${formatPrice(model.originPricing.batchOutputPerMillion)} out per million tokens`
79
+ : "")
80
+ : "";
81
+ // Origin provider line: only shown when distinct from the serving-layer provider
82
+ const originLine = model.originProvider && model.originProvider !== model.provider
83
+ ? `\n${c(BOLD, "Origin Provider:")} ${c(CYAN, model.originProvider)}`
84
+ : "";
85
+ // Region and project ID are only shown when present (Bedrock / Vertex models)
86
+ const regionLine = model.region ? `\n${c(BOLD, "Region:")} ${model.region}` : "";
87
+ const projectLine = model.projectId ? `\n${c(BOLD, "Project ID:")} ${model.projectId}` : "";
88
+ console.log(`
89
+ ${c(BOLD, "Model:")} ${model.id}
90
+ ${c(BOLD, "Name:")} ${model.name}
91
+ ${c(BOLD, "Provider:")} ${providerName}${originLine}${regionLine}${projectLine}
92
+ ${c(BOLD, "Mode:")} ${model.mode}
93
+ ${c(BOLD, "Aliases:")} ${model.aliases.length > 0 ? model.aliases.join(", ") : c(DIM, "none")}
94
+ ${c(BOLD, "Context Window:")} ${model.contextWindow > 0 ? formatNumber(model.contextWindow) + " tokens" : c(DIM, "unknown")}
95
+ ${c(BOLD, "Max Output:")} ${model.maxOutputTokens > 0 ? formatNumber(model.maxOutputTokens) + " tokens" : c(DIM, "unknown")}${model.dimensions ? `\n${c(BOLD, "Dimensions:")} ${formatNumber(model.dimensions)}` : ""}
96
+ ${c(BOLD, "Capabilities:")} ${model.capabilities.join(", ")}
97
+ ${c(BOLD, "Pricing:")} ${pricingStr}${cacheStr}${reasoningStr}${batchStr}${originPricingStr}
98
+ ${c(BOLD, "Source:")} ${model.source}
99
+ ${c(BOLD, "Discovered:")} ${formatTimestamp(model.discoveredAt)}
100
+ `.trim());
101
+ }
102
+ // ── resolve ──────────────────────────────────────────────────────────────
103
+ /**
104
+ * Resolve a model alias to its canonical provider ID.
105
+ * Unknown aliases are returned as-is with a yellow warning.
106
+ *
107
+ * @param registry The model registry containing alias mappings.
108
+ * @param alias The alias string to resolve.
109
+ * @param flags CLI flags (supports `--json`).
110
+ */
111
+ export async function cmdResolve(registry, alias, flags) {
112
+ if (!alias) {
113
+ console.error(c(RED, "Usage: kosha resolve <alias>"));
114
+ process.exit(1);
115
+ }
116
+ await ensureDiscovered(registry);
117
+ const resolved = registry.resolve(alias);
118
+ // I look the model up after resolving so callers get pricing (incl. cache
119
+ // read/write rates), context window, and capabilities — not just an ID.
120
+ // Downstream tools that pipe `kosha resolve --json` were missing all of
121
+ // this and had to follow up with `kosha model`. Now one call is enough.
122
+ //
123
+ // Fallback: aliases like `sonnet → claude-sonnet-4-6` may resolve to
124
+ // canonical IDs that no provider serves directly (e.g. when Anthropic
125
+ // API discovery is unauthenticated and OpenRouter exposes the same
126
+ // model as `anthropic/claude-sonnet-4.6`). In that case I lean on
127
+ // modelRoutes(), which normalizes IDs and returns every provider route
128
+ // — picking the first as the representative for pricing display.
129
+ let model = registry.model(resolved);
130
+ if (!model) {
131
+ const routes = registry.modelRoutes(resolved);
132
+ if (routes.length > 0)
133
+ model = routes[0];
134
+ }
135
+ if (flags.json) {
136
+ console.log(JSON.stringify({ alias, resolved, model: model ?? null }, null, 2));
137
+ return;
138
+ }
139
+ if (resolved === alias && !model) {
140
+ // resolve() returns input unchanged when no alias mapping exists
141
+ console.log(c(YELLOW, `"${alias}" is not a known alias (returned as-is)`));
142
+ return;
143
+ }
144
+ if (resolved !== alias) {
145
+ console.log(`${c(DIM, alias)} ${c(DIM, "\u2192")} ${c(CYAN, resolved)}`);
146
+ }
147
+ else {
148
+ console.log(c(CYAN, resolved));
149
+ }
150
+ if (model?.pricing) {
151
+ const base = `${formatPrice(model.pricing.inputPerMillion)} / ${formatPrice(model.pricing.outputPerMillion)} per M tokens (in/out)`;
152
+ console.log(`${c(DIM, "Pricing:")} ${base}`);
153
+ if (model.pricing.cacheReadPerMillion !== undefined || model.pricing.cacheWritePerMillion !== undefined) {
154
+ const read = model.pricing.cacheReadPerMillion !== undefined
155
+ ? formatPrice(model.pricing.cacheReadPerMillion)
156
+ : c(DIM, "\u2014");
157
+ const write = model.pricing.cacheWritePerMillion !== undefined
158
+ ? formatPrice(model.pricing.cacheWritePerMillion)
159
+ : c(DIM, "\u2014");
160
+ console.log(`${c(DIM, "Cache: ")} ${read} read / ${write} write per M tokens`);
161
+ }
162
+ if (model.pricing.batchInputPerMillion !== undefined || model.pricing.batchOutputPerMillion !== undefined) {
163
+ const bIn = model.pricing.batchInputPerMillion !== undefined
164
+ ? formatPrice(model.pricing.batchInputPerMillion)
165
+ : c(DIM, "\u2014");
166
+ const bOut = model.pricing.batchOutputPerMillion !== undefined
167
+ ? formatPrice(model.pricing.batchOutputPerMillion)
168
+ : c(DIM, "\u2014");
169
+ console.log(`${c(DIM, "Batch: ")} ${bIn} in / ${bOut} out per M tokens`);
170
+ }
171
+ }
172
+ }
173
+ // ── routes ───────────────────────────────────────────────────────────────
174
+ /**
175
+ * Show every provider route through which a model can be accessed.
176
+ *
177
+ * A "route" is a serving-layer entry whose normalized model ID matches the
178
+ * given identifier. Output includes direct/preferred markers, origin provider,
179
+ * model version hint, and serving base URL.
180
+ *
181
+ * Pricing columns show `—` when data is unavailable.
182
+ *
183
+ * @param registry The model registry to query.
184
+ * @param modelId Canonical model ID or alias to look up.
185
+ * @param flags CLI flags (supports `--json`).
186
+ */
187
+ export async function cmdRoutes(registry, modelId, flags) {
188
+ if (!modelId) {
189
+ console.error(c(RED, "Usage: kosha routes <model-id|alias>"));
190
+ process.exit(1);
191
+ }
192
+ await ensureDiscovered(registry);
193
+ const routes = registry.modelRouteInfo(modelId);
194
+ if (flags.json) {
195
+ console.log(JSON.stringify(routes, null, 2));
196
+ return;
197
+ }
198
+ if (routes.length === 0) {
199
+ console.error(c(RED, `No routes found for model: "${modelId}"`));
200
+ process.exit(1);
201
+ }
202
+ const columns = [
203
+ { header: "Pref", width: 4 },
204
+ { header: "Provider", width: 14 },
205
+ { header: "Model ID", width: 42 },
206
+ { header: "Region", width: 14 },
207
+ { header: "Origin", width: 12 },
208
+ { header: "Ver", width: 12 },
209
+ { header: "Base URL", width: 34 },
210
+ { header: "$/M in", width: 8, align: "right" },
211
+ { header: "$/M out", width: 8, align: "right" },
212
+ ];
213
+ const rows = routes.map((route) => [
214
+ route.isPreferred ? c(GREEN, "*") : route.isDirect ? c(CYAN, "\u00B7") : " ",
215
+ c(CYAN, route.provider),
216
+ route.model.id,
217
+ route.model.region ?? c(DIM, "\u2014"),
218
+ route.originProvider ?? c(DIM, "\u2014"),
219
+ route.version ?? c(DIM, "\u2014"),
220
+ route.baseUrl ?? c(DIM, "\u2014"),
221
+ formatPrice(route.model.pricing?.inputPerMillion),
222
+ formatPrice(route.model.pricing?.outputPerMillion),
223
+ ]);
224
+ console.log(`\n${c(BOLD, routes[0].model.name)} ${c(DIM, `(${routes.length} route${routes.length !== 1 ? "s" : ""})`)}\n`);
225
+ console.log(renderTable(columns, rows));
226
+ const preferred = routes.find((route) => route.isPreferred);
227
+ if (preferred) {
228
+ console.log(c(DIM, `\nPreferred route: ${preferred.provider} (${preferred.baseUrl ?? "base URL unknown"})`));
229
+ }
230
+ }
231
+ //# sourceMappingURL=cli-cmd-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-cmd-model.js","sourceRoot":"","sources":["../src/cli-cmd-model.ts"],"names":[],"mappings":"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"}