@sriinnu/kosha-discovery 0.6.1 → 1.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.
- package/README.md +95 -263
- package/dist/cli-cmd-model.d.ts +48 -0
- package/dist/cli-cmd-model.d.ts.map +1 -0
- package/dist/cli-cmd-model.js +231 -0
- package/dist/cli-cmd-model.js.map +1 -0
- package/dist/cli-cmd-query.d.ts +40 -0
- package/dist/cli-cmd-query.d.ts.map +1 -0
- package/dist/cli-cmd-query.js +303 -0
- package/dist/cli-cmd-query.js.map +1 -0
- package/dist/cli-commands.d.ts +65 -75
- package/dist/cli-commands.d.ts.map +1 -1
- package/dist/cli-commands.js +93 -543
- package/dist/cli-commands.js.map +1 -1
- package/dist/cli-format.d.ts +32 -0
- package/dist/cli-format.d.ts.map +1 -1
- package/dist/cli-format.js +51 -0
- package/dist/cli-format.js.map +1 -1
- package/dist/cli-help.d.ts +19 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +150 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/discovery/anthropic.d.ts +8 -1
- package/dist/discovery/anthropic.d.ts.map +1 -1
- package/dist/discovery/anthropic.js +26 -3
- package/dist/discovery/anthropic.js.map +1 -1
- package/dist/discovery/base.d.ts +26 -0
- package/dist/discovery/base.d.ts.map +1 -1
- package/dist/discovery/base.js +55 -2
- package/dist/discovery/base.js.map +1 -1
- package/dist/discovery/free-tier.d.ts +31 -0
- package/dist/discovery/free-tier.d.ts.map +1 -0
- package/dist/discovery/free-tier.js +47 -0
- package/dist/discovery/free-tier.js.map +1 -0
- package/dist/discovery/google.d.ts +8 -1
- package/dist/discovery/google.d.ts.map +1 -1
- package/dist/discovery/google.js +25 -3
- package/dist/discovery/google.js.map +1 -1
- package/dist/discovery/index.d.ts +3 -6
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +36 -55
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/litellm-seed.d.ts +32 -0
- package/dist/discovery/litellm-seed.d.ts.map +1 -0
- package/dist/discovery/litellm-seed.js +252 -0
- package/dist/discovery/litellm-seed.js.map +1 -0
- package/dist/discovery/modelsdev-catalog.d.ts +95 -0
- package/dist/discovery/modelsdev-catalog.d.ts.map +1 -0
- package/dist/discovery/modelsdev-catalog.js +131 -0
- package/dist/discovery/modelsdev-catalog.js.map +1 -0
- package/dist/discovery/modelsdev-seed.d.ts +19 -0
- package/dist/discovery/modelsdev-seed.d.ts.map +1 -0
- package/dist/discovery/modelsdev-seed.js +203 -0
- package/dist/discovery/modelsdev-seed.js.map +1 -0
- package/dist/discovery/openai-compatible.d.ts.map +1 -1
- package/dist/discovery/openai-compatible.js +12 -1
- package/dist/discovery/openai-compatible.js.map +1 -1
- package/dist/discovery/openai.d.ts +9 -1
- package/dist/discovery/openai.d.ts.map +1 -1
- package/dist/discovery/openai.js +31 -8
- package/dist/discovery/openai.js.map +1 -1
- package/dist/discovery/promo-overrides.d.ts +54 -0
- package/dist/discovery/promo-overrides.d.ts.map +1 -0
- package/dist/discovery/promo-overrides.js +74 -0
- package/dist/discovery/promo-overrides.js.map +1 -0
- package/dist/discovery/public-seed.d.ts +30 -0
- package/dist/discovery/public-seed.d.ts.map +1 -0
- package/dist/discovery/public-seed.js +51 -0
- package/dist/discovery/public-seed.js.map +1 -0
- package/dist/discovery-contract.d.ts +14 -2
- package/dist/discovery-contract.d.ts.map +1 -1
- package/dist/discovery-contract.js +28 -0
- package/dist/discovery-contract.js.map +1 -1
- package/dist/enrichment/litellm-catalog.d.ts +81 -0
- package/dist/enrichment/litellm-catalog.d.ts.map +1 -0
- package/dist/enrichment/litellm-catalog.js +129 -0
- package/dist/enrichment/litellm-catalog.js.map +1 -0
- package/dist/enrichment/litellm.d.ts +9 -2
- package/dist/enrichment/litellm.d.ts.map +1 -1
- package/dist/enrichment/litellm.js +168 -20
- package/dist/enrichment/litellm.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.d.ts +18 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +293 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/model-features.d.ts +77 -0
- package/dist/model-features.d.ts.map +1 -0
- package/dist/model-features.js +245 -0
- package/dist/model-features.js.map +1 -0
- package/dist/provider-catalog.d.ts +9 -0
- package/dist/provider-catalog.d.ts.map +1 -1
- package/dist/provider-catalog.js +22 -0
- package/dist/provider-catalog.js.map +1 -1
- package/dist/proxy.d.ts +31 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +193 -0
- package/dist/proxy.js.map +1 -0
- package/dist/registry-discovery.d.ts.map +1 -1
- package/dist/registry-discovery.js +12 -2
- package/dist/registry-discovery.js.map +1 -1
- package/dist/registry-runtime.d.ts +40 -1
- package/dist/registry-runtime.d.ts.map +1 -1
- package/dist/registry-runtime.js +502 -30
- package/dist/registry-runtime.js.map +1 -1
- package/dist/registry-selection.js +2 -0
- package/dist/registry-selection.js.map +1 -1
- package/dist/registry.d.ts +9 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +11 -1
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +6 -0
- package/dist/server.js.map +1 -1
- package/dist/tokenizer-family.d.ts +39 -0
- package/dist/tokenizer-family.d.ts.map +1 -0
- package/dist/tokenizer-family.js +92 -0
- package/dist/tokenizer-family.js.map +1 -0
- package/dist/types.d.ts +186 -0
- package/dist/types.d.ts.map +1 -1
- package/logo.png +0 -0
- package/package.json +15 -3
package/dist/cli-commands.js
CHANGED
|
@@ -5,17 +5,21 @@
|
|
|
5
5
|
* Formatting utilities are imported from `./cli-format.js` to keep
|
|
6
6
|
* presentation logic separate from command orchestration.
|
|
7
7
|
*
|
|
8
|
+
* This module also serves as the barrel re-export for commands that were
|
|
9
|
+
* split into dedicated files (`cli-cmd-model.ts`, `cli-cmd-query.ts`,
|
|
10
|
+
* `cli-help.ts`) to keep each file under 450 LOC.
|
|
11
|
+
*
|
|
8
12
|
* @module cli-commands
|
|
9
13
|
*/
|
|
10
|
-
import { BOLD, CYAN, DIM, GREEN,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
import { BOLD, CYAN, DIM, GREEN, RED, YELLOW, c, formatContextWindow, formatPrice, formatPricingTier, formatRelativeTime, formatTimestamp, line, renderTable, } from "./cli-format.js";
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Shared helpers — exported so split modules can import them
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
14
18
|
/**
|
|
15
19
|
* Standard column layout reused by both `cmdList` and `cmdSearch`.
|
|
16
20
|
* Extracted to avoid duplicating the same six-column definition.
|
|
17
21
|
*/
|
|
18
|
-
const MODEL_TABLE_COLUMNS = [
|
|
22
|
+
export const MODEL_TABLE_COLUMNS = [
|
|
19
23
|
{ header: "Provider", width: 12 },
|
|
20
24
|
{ header: "Model", width: 38 },
|
|
21
25
|
{ header: "Mode", width: 10 },
|
|
@@ -23,6 +27,22 @@ const MODEL_TABLE_COLUMNS = [
|
|
|
23
27
|
{ header: "$/M in", width: 8, align: "right" },
|
|
24
28
|
{ header: "$/M out", width: 8, align: "right" },
|
|
25
29
|
];
|
|
30
|
+
/**
|
|
31
|
+
* Extended pricing column layout used when `--pricing` flag is passed.
|
|
32
|
+
* Replaces context-window with tier, cache, and batch columns.
|
|
33
|
+
*/
|
|
34
|
+
const PRICING_TABLE_COLUMNS = [
|
|
35
|
+
{ header: "Provider", width: 12 },
|
|
36
|
+
{ header: "Model", width: 34 },
|
|
37
|
+
{ header: "Mode", width: 10 },
|
|
38
|
+
{ header: "Tier", width: 6 },
|
|
39
|
+
{ header: "$/M in", width: 8, align: "right" },
|
|
40
|
+
{ header: "$/M out", width: 8, align: "right" },
|
|
41
|
+
{ header: "Cache R", width: 8, align: "right" },
|
|
42
|
+
{ header: "Cache W", width: 8, align: "right" },
|
|
43
|
+
{ header: "Batch in", width: 8, align: "right" },
|
|
44
|
+
{ header: "Batch out", width: 9, align: "right" },
|
|
45
|
+
];
|
|
26
46
|
/**
|
|
27
47
|
* Return a human-readable label for a provider's credential source.
|
|
28
48
|
* Providers that need no remote auth (e.g. local Ollama) show `"none (local)"`.
|
|
@@ -30,7 +50,7 @@ const MODEL_TABLE_COLUMNS = [
|
|
|
30
50
|
* @param provider The provider info object.
|
|
31
51
|
* @returns A short label suitable for table display.
|
|
32
52
|
*/
|
|
33
|
-
function formatCredentialSource(provider) {
|
|
53
|
+
export function formatCredentialSource(provider) {
|
|
34
54
|
if (!provider.credentialSource || provider.credentialSource === "none") {
|
|
35
55
|
return c(DIM, "none (local)");
|
|
36
56
|
}
|
|
@@ -51,7 +71,7 @@ function formatCredentialSource(provider) {
|
|
|
51
71
|
*
|
|
52
72
|
* @param registry The shared model registry instance.
|
|
53
73
|
*/
|
|
54
|
-
async function ensureDiscovered(registry) {
|
|
74
|
+
export async function ensureDiscovered(registry) {
|
|
55
75
|
if (registry.providers_list().length > 0)
|
|
56
76
|
return;
|
|
57
77
|
const beforeMs = Date.now();
|
|
@@ -76,7 +96,7 @@ async function ensureDiscovered(registry) {
|
|
|
76
96
|
* @param m A model card object.
|
|
77
97
|
* @returns An array of formatted cell strings.
|
|
78
98
|
*/
|
|
79
|
-
function modelRow(m) {
|
|
99
|
+
export function modelRow(m) {
|
|
80
100
|
return [
|
|
81
101
|
c(CYAN, m.provider), m.id, m.mode,
|
|
82
102
|
formatContextWindow(m.contextWindow),
|
|
@@ -84,13 +104,23 @@ function modelRow(m) {
|
|
|
84
104
|
formatPrice(m.pricing?.outputPerMillion),
|
|
85
105
|
];
|
|
86
106
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Build an extended pricing-table row from a model card.
|
|
109
|
+
* Includes tier label, cache read/write, and batch pricing columns.
|
|
110
|
+
* @param m A model card with full pricing detail.
|
|
111
|
+
* @returns An array of formatted cell strings for the pricing column layout.
|
|
112
|
+
*/
|
|
113
|
+
function pricingRow(m) {
|
|
114
|
+
return [
|
|
115
|
+
c(CYAN, m.provider), m.id, m.mode,
|
|
116
|
+
formatPricingTier(m.pricing),
|
|
117
|
+
formatPrice(m.pricing?.inputPerMillion),
|
|
118
|
+
formatPrice(m.pricing?.outputPerMillion),
|
|
119
|
+
formatPrice(m.pricing?.cacheReadPerMillion),
|
|
120
|
+
formatPrice(m.pricing?.cacheWritePerMillion),
|
|
121
|
+
formatPrice(m.pricing?.batchInputPerMillion),
|
|
122
|
+
formatPrice(m.pricing?.batchOutputPerMillion),
|
|
123
|
+
];
|
|
94
124
|
}
|
|
95
125
|
/** Print a provider summary line (used by discover & refresh). */
|
|
96
126
|
function printProviderSummary(providers) {
|
|
@@ -157,225 +187,72 @@ export async function cmdLatest(registry, flags) {
|
|
|
157
187
|
printProviderSummary(result.providers);
|
|
158
188
|
console.log(c(DIM, `\nFetched at: ${formatTimestamp(result.discoveredAt)}`));
|
|
159
189
|
}
|
|
160
|
-
// ──
|
|
190
|
+
// ── enrich ───────────────────────────────────────────────────────────────
|
|
161
191
|
/**
|
|
162
|
-
*
|
|
163
|
-
* Supports filtering by `--provider`, `--origin`, `--mode`, and `--capability`.
|
|
192
|
+
* Re-run LiteLLM enrichment on cached models without re-discovering providers.
|
|
164
193
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
|
|
168
|
-
export async function cmdList(registry, flags) {
|
|
169
|
-
const provider = typeof flags.provider === "string" ? flags.provider : undefined;
|
|
170
|
-
const originProvider = typeof flags.origin === "string" ? flags.origin : undefined;
|
|
171
|
-
const mode = typeof flags.mode === "string" ? flags.mode : undefined;
|
|
172
|
-
const capability = typeof flags.capability === "string" ? flags.capability : undefined;
|
|
173
|
-
await ensureDiscovered(registry);
|
|
174
|
-
const models = registry.models({ provider, originProvider, mode, capability });
|
|
175
|
-
if (flags.json) {
|
|
176
|
-
console.log(JSON.stringify(models, null, 2));
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
if (models.length === 0) {
|
|
180
|
-
console.log(c(YELLOW, "No models found matching the given filters."));
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
console.log(renderTable(MODEL_TABLE_COLUMNS, models.map(modelRow)));
|
|
184
|
-
const providerCount = new Set(models.map((m) => m.provider)).size;
|
|
185
|
-
console.log(c(DIM, line("\u2500", 90)));
|
|
186
|
-
console.log(`${c(BOLD, String(models.length))} models from ${c(BOLD, String(providerCount))} providers`);
|
|
187
|
-
}
|
|
188
|
-
// ── roles ────────────────────────────────────────────────────────────────
|
|
189
|
-
/**
|
|
190
|
-
* Show a provider -> model -> roles matrix.
|
|
194
|
+
* This is the lightweight alternative to `kosha refresh` when you only need
|
|
195
|
+
* updated pricing data — no provider API calls, just a single fetch from the
|
|
196
|
+
* litellm community catalogue plus a cache + manifest update.
|
|
191
197
|
*
|
|
192
|
-
*
|
|
198
|
+
* @param registry The model registry with cached data.
|
|
199
|
+
* @param flags CLI flags (supports `--json`).
|
|
193
200
|
*/
|
|
194
|
-
export async function
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
await ensureDiscovered(registry);
|
|
201
|
-
const providers = registry.providerRoles({ provider, originProvider, mode, capability, role });
|
|
202
|
-
if (flags.json) {
|
|
203
|
-
console.log(JSON.stringify({
|
|
204
|
-
providers,
|
|
205
|
-
count: providers.length,
|
|
206
|
-
modelCount: providers.reduce((sum, p) => sum + p.models.length, 0),
|
|
207
|
-
missingCredentials: registry.missingCredentialPrompts(providers.map((p) => p.id)),
|
|
208
|
-
}, null, 2));
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
if (providers.length === 0) {
|
|
212
|
-
console.log(c(YELLOW, "No provider/model roles found for the given filters."));
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const columns = [
|
|
216
|
-
{ header: "Provider", width: 12 },
|
|
217
|
-
{ header: "Model", width: 40 },
|
|
218
|
-
{ header: "Mode", width: 10 },
|
|
219
|
-
{ header: "Roles", width: 56 },
|
|
220
|
-
];
|
|
221
|
-
const rows = providers.flatMap((providerInfo) => providerInfo.models.map((model) => [
|
|
222
|
-
c(CYAN, providerInfo.id),
|
|
223
|
-
model.id,
|
|
224
|
-
model.mode,
|
|
225
|
-
model.roles.join(", "),
|
|
226
|
-
]));
|
|
227
|
-
console.log(renderTable(columns, rows));
|
|
228
|
-
const missing = registry.missingCredentialPrompts(providers.map((p) => p.id));
|
|
229
|
-
if (missing.length > 0) {
|
|
230
|
-
console.log(c(DIM, "\nMissing provider credentials:"));
|
|
231
|
-
for (const prompt of missing) {
|
|
232
|
-
console.log(` ${c(YELLOW, prompt.providerId)}: ${prompt.message}`);
|
|
233
|
-
}
|
|
201
|
+
export async function cmdEnrich(registry, flags) {
|
|
202
|
+
console.log(c(DIM, "Re-enriching cached models with LiteLLM pricing data..."));
|
|
203
|
+
const result = await registry.enrichOnly();
|
|
204
|
+
if (result === null) {
|
|
205
|
+
console.error(c(YELLOW, "No cached data found. Run `kosha discover` first."));
|
|
206
|
+
process.exit(1);
|
|
234
207
|
}
|
|
235
|
-
}
|
|
236
|
-
// ── cheapest ─────────────────────────────────────────────────────────────
|
|
237
|
-
/**
|
|
238
|
-
* Return cheapest model candidates for a requested role/capability.
|
|
239
|
-
*/
|
|
240
|
-
export async function cmdCheapest(registry, flags) {
|
|
241
|
-
const provider = typeof flags.provider === "string" ? flags.provider : undefined;
|
|
242
|
-
const originProvider = typeof flags.origin === "string" ? flags.origin : undefined;
|
|
243
|
-
const mode = typeof flags.mode === "string" ? flags.mode : undefined;
|
|
244
|
-
const capability = typeof flags.capability === "string" ? flags.capability : undefined;
|
|
245
|
-
const role = typeof flags.role === "string" ? flags.role : undefined;
|
|
246
|
-
await ensureDiscovered(registry);
|
|
247
|
-
const result = registry.cheapestModels({
|
|
248
|
-
provider,
|
|
249
|
-
originProvider,
|
|
250
|
-
mode,
|
|
251
|
-
capability,
|
|
252
|
-
role,
|
|
253
|
-
limit: parseNumberFlag(flags.limit),
|
|
254
|
-
priceMetric: typeof flags["price-metric"] === "string"
|
|
255
|
-
? flags["price-metric"]
|
|
256
|
-
: undefined,
|
|
257
|
-
inputWeight: parseNumberFlag(flags["input-weight"]),
|
|
258
|
-
outputWeight: parseNumberFlag(flags["output-weight"]),
|
|
259
|
-
includeUnpriced: flags["include-unpriced"] === true,
|
|
260
|
-
});
|
|
261
208
|
if (flags.json) {
|
|
262
209
|
console.log(JSON.stringify(result, null, 2));
|
|
263
210
|
return;
|
|
264
211
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
const columns = [
|
|
276
|
-
{ header: "Provider", width: 12 },
|
|
277
|
-
{ header: "Model", width: 38 },
|
|
278
|
-
{ header: "Mode", width: 10 },
|
|
279
|
-
{ header: "Metric", width: 8 },
|
|
280
|
-
{ header: "Score", width: 10, align: "right" },
|
|
281
|
-
{ header: "$/M in", width: 8, align: "right" },
|
|
282
|
-
{ header: "$/M out", width: 8, align: "right" },
|
|
283
|
-
];
|
|
284
|
-
const rows = result.matches.map((match) => [
|
|
285
|
-
c(CYAN, match.model.provider),
|
|
286
|
-
match.model.id,
|
|
287
|
-
match.model.mode,
|
|
288
|
-
match.priceMetric,
|
|
289
|
-
match.score === undefined ? "\u2014" : formatPrice(match.score),
|
|
290
|
-
formatPrice(match.model.pricing?.inputPerMillion),
|
|
291
|
-
formatPrice(match.model.pricing?.outputPerMillion),
|
|
292
|
-
]);
|
|
293
|
-
console.log(renderTable(columns, rows));
|
|
294
|
-
console.log(c(DIM, `\n${result.pricedCandidates}/${result.candidates} candidates had usable pricing.`));
|
|
295
|
-
if (result.missingCredentials.length > 0) {
|
|
296
|
-
console.log(c(DIM, "\nMissing provider credentials:"));
|
|
297
|
-
for (const prompt of result.missingCredentials) {
|
|
298
|
-
console.log(` ${c(YELLOW, prompt.providerId)}: ${prompt.message}`);
|
|
299
|
-
}
|
|
212
|
+
const totalModels = result.modelCount;
|
|
213
|
+
const cacheUpdated = result.cachePricingUpdated;
|
|
214
|
+
const batchUpdated = result.batchPricingUpdated;
|
|
215
|
+
console.log(c(DIM, `\nEnriched ${c(BOLD, String(totalModels))} models:`));
|
|
216
|
+
if (cacheUpdated > 0) {
|
|
217
|
+
console.log(c(DIM, ` Cache pricing updated: ${cacheUpdated} models`));
|
|
300
218
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Show an aggregated capability overview across all discovered models.
|
|
305
|
-
* Each row shows a capability, how many models/providers support it,
|
|
306
|
-
* and an example model ID for quick reference.
|
|
307
|
-
*
|
|
308
|
-
* @param registry The model registry to query.
|
|
309
|
-
* @param flags CLI flags (supports `--provider`, `--json`).
|
|
310
|
-
*/
|
|
311
|
-
export async function cmdCapabilities(registry, flags) {
|
|
312
|
-
const provider = typeof flags.provider === "string" ? flags.provider : undefined;
|
|
313
|
-
await ensureDiscovered(registry);
|
|
314
|
-
const caps = registry.capabilities({ provider });
|
|
315
|
-
if (flags.json) {
|
|
316
|
-
console.log(JSON.stringify(caps, null, 2));
|
|
317
|
-
return;
|
|
219
|
+
if (batchUpdated > 0) {
|
|
220
|
+
console.log(c(DIM, ` Batch pricing updated: ${batchUpdated} models`));
|
|
318
221
|
}
|
|
319
|
-
if (
|
|
320
|
-
console.log(c(
|
|
321
|
-
return;
|
|
222
|
+
if (cacheUpdated === 0 && batchUpdated === 0) {
|
|
223
|
+
console.log(c(DIM, " No new pricing data found."));
|
|
322
224
|
}
|
|
323
|
-
|
|
324
|
-
{ header: "Capability", width: 20 },
|
|
325
|
-
{ header: "Models", width: 8, align: "right" },
|
|
326
|
-
{ header: "Providers", width: 10, align: "right" },
|
|
327
|
-
{ header: "Example Model", width: 38 },
|
|
328
|
-
];
|
|
329
|
-
const rows = caps.map((cap) => [
|
|
330
|
-
c(CYAN, cap.capability),
|
|
331
|
-
String(cap.modelCount),
|
|
332
|
-
String(cap.providerCount),
|
|
333
|
-
cap.exampleModelId ?? c(DIM, "—"),
|
|
334
|
-
]);
|
|
335
|
-
const totalModels = registry.models({ provider }).length;
|
|
336
|
-
console.log(renderTable(columns, rows));
|
|
337
|
-
console.log(c(DIM, `\n${caps.length} capabilities across ${totalModels} models`));
|
|
225
|
+
console.log(c(DIM, `\nCache and manifest updated at ~/.kosha/`));
|
|
338
226
|
}
|
|
339
|
-
// ──
|
|
227
|
+
// ── list ─────────────────────────────────────────────────────────────────
|
|
340
228
|
/**
|
|
341
|
-
*
|
|
342
|
-
*
|
|
229
|
+
* List all known models in a formatted table.
|
|
230
|
+
* Supports filtering by `--provider`, `--origin`, `--mode`, and `--capability`.
|
|
343
231
|
*
|
|
344
232
|
* @param registry The model registry to query.
|
|
345
|
-
* @param
|
|
346
|
-
* @param flags CLI flags (supports `--provider`, `--origin`, `--json`, `--limit`).
|
|
233
|
+
* @param flags CLI flags (supports `--provider`, `--origin`, `--mode`, `--capability`, `--pricing`, `--json`).
|
|
347
234
|
*/
|
|
348
|
-
export async function
|
|
349
|
-
if (!query) {
|
|
350
|
-
console.error(c(RED, "Usage: kosha capable <capability>"));
|
|
351
|
-
process.exit(1);
|
|
352
|
-
}
|
|
235
|
+
export async function cmdList(registry, flags) {
|
|
353
236
|
const provider = typeof flags.provider === "string" ? flags.provider : undefined;
|
|
354
237
|
const originProvider = typeof flags.origin === "string" ? flags.origin : undefined;
|
|
355
238
|
const mode = typeof flags.mode === "string" ? flags.mode : undefined;
|
|
356
|
-
const
|
|
239
|
+
const capability = typeof flags.capability === "string" ? flags.capability : undefined;
|
|
240
|
+
const showPricing = flags.pricing === true;
|
|
357
241
|
await ensureDiscovered(registry);
|
|
358
|
-
const
|
|
359
|
-
const allModels = registry.models({ provider, originProvider, mode });
|
|
360
|
-
let models = allModels.filter((m) => registry.modelSupportsRole(m, normalized));
|
|
361
|
-
if (limit !== undefined && limit > 0) {
|
|
362
|
-
models = models.slice(0, limit);
|
|
363
|
-
}
|
|
242
|
+
const models = registry.models({ provider, originProvider, mode, capability });
|
|
364
243
|
if (flags.json) {
|
|
365
244
|
console.log(JSON.stringify(models, null, 2));
|
|
366
245
|
return;
|
|
367
246
|
}
|
|
368
247
|
if (models.length === 0) {
|
|
369
|
-
console.log(c(YELLOW,
|
|
248
|
+
console.log(c(YELLOW, "No models found matching the given filters."));
|
|
370
249
|
return;
|
|
371
250
|
}
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
console.log(`\n${c(BOLD, header)}\n`);
|
|
376
|
-
console.log(renderTable(MODEL_TABLE_COLUMNS, models.map(modelRow)));
|
|
251
|
+
const listColumns = showPricing ? PRICING_TABLE_COLUMNS : MODEL_TABLE_COLUMNS;
|
|
252
|
+
const listRowFn = showPricing ? pricingRow : modelRow;
|
|
253
|
+
console.log(renderTable(listColumns, models.map(listRowFn)));
|
|
377
254
|
const providerCount = new Set(models.map((m) => m.provider)).size;
|
|
378
|
-
console.log(c(DIM, line("\u2500", 90)));
|
|
255
|
+
console.log(c(DIM, line("\u2500", showPricing ? 110 : 90)));
|
|
379
256
|
console.log(`${c(BOLD, String(models.length))} models from ${c(BOLD, String(providerCount))} providers`);
|
|
380
257
|
}
|
|
381
258
|
// ── search ───────────────────────────────────────────────────────────────
|
|
@@ -385,7 +262,7 @@ export async function cmdCapable(registry, query, flags) {
|
|
|
385
262
|
*
|
|
386
263
|
* @param registry The model registry to search.
|
|
387
264
|
* @param query The search term (substring).
|
|
388
|
-
* @param flags CLI flags (supports `--origin`, `--json`).
|
|
265
|
+
* @param flags CLI flags (supports `--origin`, `--pricing`, `--json`).
|
|
389
266
|
*/
|
|
390
267
|
export async function cmdSearch(registry, query, flags) {
|
|
391
268
|
if (!query) {
|
|
@@ -395,6 +272,7 @@ export async function cmdSearch(registry, query, flags) {
|
|
|
395
272
|
await ensureDiscovered(registry);
|
|
396
273
|
const needle = query.toLowerCase();
|
|
397
274
|
const originProvider = typeof flags.origin === "string" ? flags.origin : undefined;
|
|
275
|
+
const showPricing = flags.pricing === true;
|
|
398
276
|
// Apply optional origin filter first, then substring-match across id, name, and aliases
|
|
399
277
|
const matches = registry.models({ originProvider }).filter((m) => m.id.toLowerCase().includes(needle) ||
|
|
400
278
|
m.name.toLowerCase().includes(needle) ||
|
|
@@ -407,89 +285,11 @@ export async function cmdSearch(registry, query, flags) {
|
|
|
407
285
|
console.log(c(YELLOW, `No models matching "${query}"`));
|
|
408
286
|
return;
|
|
409
287
|
}
|
|
410
|
-
|
|
288
|
+
const searchColumns = showPricing ? PRICING_TABLE_COLUMNS : MODEL_TABLE_COLUMNS;
|
|
289
|
+
const searchRowFn = showPricing ? pricingRow : modelRow;
|
|
290
|
+
console.log(renderTable(searchColumns, matches.map(searchRowFn)));
|
|
411
291
|
console.log(c(DIM, `\n${matches.length} result${matches.length !== 1 ? "s" : ""} for "${query}"`));
|
|
412
292
|
}
|
|
413
|
-
// ── model (detail view) ─────────────────────────────────────────────────
|
|
414
|
-
/**
|
|
415
|
-
* Show detailed information for a single model identified by id or alias.
|
|
416
|
-
*
|
|
417
|
-
* If an exact match is not found, falls back to fuzzy substring search.
|
|
418
|
-
* Single fuzzy match is shown automatically; multiple matches produce a
|
|
419
|
-
* disambiguation list (capped at 5 suggestions).
|
|
420
|
-
*
|
|
421
|
-
* @param registry The model registry to look up.
|
|
422
|
-
* @param idOrAlias A model id, display name, or alias.
|
|
423
|
-
* @param flags CLI flags (supports `--json`).
|
|
424
|
-
*/
|
|
425
|
-
export async function cmdModel(registry, idOrAlias, flags) {
|
|
426
|
-
if (!idOrAlias) {
|
|
427
|
-
console.error(c(RED, "Usage: kosha model <id|alias>"));
|
|
428
|
-
process.exit(1);
|
|
429
|
-
}
|
|
430
|
-
await ensureDiscovered(registry);
|
|
431
|
-
const model = registry.model(idOrAlias);
|
|
432
|
-
if (!model) {
|
|
433
|
-
// Fuzzy fallback — substring match across id, name, and aliases so users
|
|
434
|
-
// can type fragments like "sonnet" without knowing the full canonical ID.
|
|
435
|
-
const needle = idOrAlias.toLowerCase();
|
|
436
|
-
const fuzzy = registry.models().filter((m) => m.id.toLowerCase().includes(needle) ||
|
|
437
|
-
m.name.toLowerCase().includes(needle) ||
|
|
438
|
-
m.aliases.some((a) => a.toLowerCase().includes(needle)));
|
|
439
|
-
if (fuzzy.length === 1)
|
|
440
|
-
return cmdModel(registry, fuzzy[0].id, flags);
|
|
441
|
-
if (fuzzy.length > 1) {
|
|
442
|
-
console.log(c(YELLOW, `No exact match for "${idOrAlias}". Did you mean:`));
|
|
443
|
-
for (const m of fuzzy.slice(0, 5))
|
|
444
|
-
console.log(` ${c(CYAN, m.id)} (${m.provider})`);
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
console.error(c(RED, `Model not found: "${idOrAlias}"`));
|
|
448
|
-
process.exit(1);
|
|
449
|
-
}
|
|
450
|
-
if (flags.json) {
|
|
451
|
-
console.log(JSON.stringify(model, null, 2));
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
const providerName = registry.provider(model.provider)?.name ?? model.provider;
|
|
455
|
-
const pricingStr = model.pricing
|
|
456
|
-
? `${formatPrice(model.pricing.inputPerMillion)} / ${formatPrice(model.pricing.outputPerMillion)} per million tokens (in/out)`
|
|
457
|
-
: c(DIM, "unknown");
|
|
458
|
-
// Cache pricing is optional — only displayed when the model has it
|
|
459
|
-
const cacheStr = model.pricing?.cacheReadPerMillion !== undefined
|
|
460
|
-
? `\nCache Pricing: ${formatPrice(model.pricing.cacheReadPerMillion)} read / ${formatPrice(model.pricing.cacheWritePerMillion)} write per million tokens`
|
|
461
|
-
: "";
|
|
462
|
-
// Reasoning pricing is optional — shown when providers expose it.
|
|
463
|
-
const reasoningStr = model.pricing?.reasoningInputPerMillion !== undefined || model.pricing?.reasoningOutputPerMillion !== undefined
|
|
464
|
-
? `\nReasoning Pricing: ${formatPrice(model.pricing?.reasoningInputPerMillion)} in / ${formatPrice(model.pricing?.reasoningOutputPerMillion)} out per million tokens`
|
|
465
|
-
: "";
|
|
466
|
-
const originPricingStr = model.originPricing
|
|
467
|
-
? `\nOrigin Pricing: ${formatPrice(model.originPricing.inputPerMillion)} / ${formatPrice(model.originPricing.outputPerMillion)} per million tokens (in/out)` +
|
|
468
|
-
((model.originPricing.reasoningInputPerMillion !== undefined || model.originPricing.reasoningOutputPerMillion !== undefined)
|
|
469
|
-
? `\nOrigin Reasoning Pricing: ${formatPrice(model.originPricing.reasoningInputPerMillion)} in / ${formatPrice(model.originPricing.reasoningOutputPerMillion)} out per million tokens`
|
|
470
|
-
: "")
|
|
471
|
-
: "";
|
|
472
|
-
// Origin provider line: only shown when distinct from the serving-layer provider
|
|
473
|
-
const originLine = model.originProvider && model.originProvider !== model.provider
|
|
474
|
-
? `\n${c(BOLD, "Origin Provider:")} ${c(CYAN, model.originProvider)}`
|
|
475
|
-
: "";
|
|
476
|
-
// Region and project ID are only shown when present (Bedrock / Vertex models)
|
|
477
|
-
const regionLine = model.region ? `\n${c(BOLD, "Region:")} ${model.region}` : "";
|
|
478
|
-
const projectLine = model.projectId ? `\n${c(BOLD, "Project ID:")} ${model.projectId}` : "";
|
|
479
|
-
console.log(`
|
|
480
|
-
${c(BOLD, "Model:")} ${model.id}
|
|
481
|
-
${c(BOLD, "Name:")} ${model.name}
|
|
482
|
-
${c(BOLD, "Provider:")} ${providerName}${originLine}${regionLine}${projectLine}
|
|
483
|
-
${c(BOLD, "Mode:")} ${model.mode}
|
|
484
|
-
${c(BOLD, "Aliases:")} ${model.aliases.length > 0 ? model.aliases.join(", ") : c(DIM, "none")}
|
|
485
|
-
${c(BOLD, "Context Window:")} ${model.contextWindow > 0 ? formatNumber(model.contextWindow) + " tokens" : c(DIM, "unknown")}
|
|
486
|
-
${c(BOLD, "Max Output:")} ${model.maxOutputTokens > 0 ? formatNumber(model.maxOutputTokens) + " tokens" : c(DIM, "unknown")}${model.dimensions ? `\n${c(BOLD, "Dimensions:")} ${formatNumber(model.dimensions)}` : ""}
|
|
487
|
-
${c(BOLD, "Capabilities:")} ${model.capabilities.join(", ")}
|
|
488
|
-
${c(BOLD, "Pricing:")} ${pricingStr}${cacheStr}${reasoningStr}${originPricingStr}
|
|
489
|
-
${c(BOLD, "Source:")} ${model.source}
|
|
490
|
-
${c(BOLD, "Discovered:")} ${formatTimestamp(model.discoveredAt)}
|
|
491
|
-
`.trim());
|
|
492
|
-
}
|
|
493
293
|
// ── providers ────────────────────────────────────────────────────────────
|
|
494
294
|
/**
|
|
495
295
|
* List all known providers with their authentication status and model counts.
|
|
@@ -525,126 +325,6 @@ export async function cmdProviders(registry, flags) {
|
|
|
525
325
|
});
|
|
526
326
|
console.log(renderTable(columns, rows));
|
|
527
327
|
}
|
|
528
|
-
// ── resolve ──────────────────────────────────────────────────────────────
|
|
529
|
-
/**
|
|
530
|
-
* Resolve a model alias to its canonical provider ID.
|
|
531
|
-
* Unknown aliases are returned as-is with a yellow warning.
|
|
532
|
-
*
|
|
533
|
-
* @param registry The model registry containing alias mappings.
|
|
534
|
-
* @param alias The alias string to resolve.
|
|
535
|
-
* @param flags CLI flags (supports `--json`).
|
|
536
|
-
*/
|
|
537
|
-
export async function cmdResolve(registry, alias, flags) {
|
|
538
|
-
if (!alias) {
|
|
539
|
-
console.error(c(RED, "Usage: kosha resolve <alias>"));
|
|
540
|
-
process.exit(1);
|
|
541
|
-
}
|
|
542
|
-
await ensureDiscovered(registry);
|
|
543
|
-
const resolved = registry.resolve(alias);
|
|
544
|
-
// I look the model up after resolving so callers get pricing (incl. cache
|
|
545
|
-
// read/write rates), context window, and capabilities — not just an ID.
|
|
546
|
-
// Downstream tools that pipe `kosha resolve --json` were missing all of
|
|
547
|
-
// this and had to follow up with `kosha model`. Now one call is enough.
|
|
548
|
-
//
|
|
549
|
-
// Fallback: aliases like `sonnet → claude-sonnet-4-6` may resolve to
|
|
550
|
-
// canonical IDs that no provider serves directly (e.g. when Anthropic
|
|
551
|
-
// API discovery is unauthenticated and OpenRouter exposes the same
|
|
552
|
-
// model as `anthropic/claude-sonnet-4.6`). In that case I lean on
|
|
553
|
-
// modelRoutes(), which normalizes IDs and returns every provider route
|
|
554
|
-
// — picking the first as the representative for pricing display.
|
|
555
|
-
let model = registry.model(resolved);
|
|
556
|
-
if (!model) {
|
|
557
|
-
const routes = registry.modelRoutes(resolved);
|
|
558
|
-
if (routes.length > 0)
|
|
559
|
-
model = routes[0];
|
|
560
|
-
}
|
|
561
|
-
if (flags.json) {
|
|
562
|
-
console.log(JSON.stringify({ alias, resolved, model: model ?? null }, null, 2));
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
if (resolved === alias && !model) {
|
|
566
|
-
// resolve() returns input unchanged when no alias mapping exists
|
|
567
|
-
console.log(c(YELLOW, `"${alias}" is not a known alias (returned as-is)`));
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
if (resolved !== alias) {
|
|
571
|
-
console.log(`${c(DIM, alias)} ${c(DIM, "\u2192")} ${c(CYAN, resolved)}`);
|
|
572
|
-
}
|
|
573
|
-
else {
|
|
574
|
-
console.log(c(CYAN, resolved));
|
|
575
|
-
}
|
|
576
|
-
if (model?.pricing) {
|
|
577
|
-
const base = `${formatPrice(model.pricing.inputPerMillion)} / ${formatPrice(model.pricing.outputPerMillion)} per M tokens (in/out)`;
|
|
578
|
-
console.log(`${c(DIM, "Pricing:")} ${base}`);
|
|
579
|
-
if (model.pricing.cacheReadPerMillion !== undefined || model.pricing.cacheWritePerMillion !== undefined) {
|
|
580
|
-
const read = model.pricing.cacheReadPerMillion !== undefined
|
|
581
|
-
? formatPrice(model.pricing.cacheReadPerMillion)
|
|
582
|
-
: c(DIM, "—");
|
|
583
|
-
const write = model.pricing.cacheWritePerMillion !== undefined
|
|
584
|
-
? formatPrice(model.pricing.cacheWritePerMillion)
|
|
585
|
-
: c(DIM, "—");
|
|
586
|
-
console.log(`${c(DIM, "Cache: ")} ${read} read / ${write} write per M tokens`);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
// ── routes ───────────────────────────────────────────────────────────────
|
|
591
|
-
/**
|
|
592
|
-
* Show every provider route through which a model can be accessed.
|
|
593
|
-
*
|
|
594
|
-
* A "route" is a serving-layer entry whose normalized model ID matches the
|
|
595
|
-
* given identifier. Output includes direct/preferred markers, origin provider,
|
|
596
|
-
* model version hint, and serving base URL.
|
|
597
|
-
*
|
|
598
|
-
* Pricing columns show `—` when data is unavailable.
|
|
599
|
-
*
|
|
600
|
-
* @param registry The model registry to query.
|
|
601
|
-
* @param modelId Canonical model ID or alias to look up.
|
|
602
|
-
* @param flags CLI flags (supports `--json`).
|
|
603
|
-
*/
|
|
604
|
-
export async function cmdRoutes(registry, modelId, flags) {
|
|
605
|
-
if (!modelId) {
|
|
606
|
-
console.error(c(RED, "Usage: kosha routes <model-id|alias>"));
|
|
607
|
-
process.exit(1);
|
|
608
|
-
}
|
|
609
|
-
await ensureDiscovered(registry);
|
|
610
|
-
const routes = registry.modelRouteInfo(modelId);
|
|
611
|
-
if (flags.json) {
|
|
612
|
-
console.log(JSON.stringify(routes, null, 2));
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
if (routes.length === 0) {
|
|
616
|
-
console.error(c(RED, `No routes found for model: "${modelId}"`));
|
|
617
|
-
process.exit(1);
|
|
618
|
-
}
|
|
619
|
-
const columns = [
|
|
620
|
-
{ header: "Pref", width: 4 },
|
|
621
|
-
{ header: "Provider", width: 14 },
|
|
622
|
-
{ header: "Model ID", width: 42 },
|
|
623
|
-
{ header: "Region", width: 14 },
|
|
624
|
-
{ header: "Origin", width: 12 },
|
|
625
|
-
{ header: "Ver", width: 12 },
|
|
626
|
-
{ header: "Base URL", width: 34 },
|
|
627
|
-
{ header: "$/M in", width: 8, align: "right" },
|
|
628
|
-
{ header: "$/M out", width: 8, align: "right" },
|
|
629
|
-
];
|
|
630
|
-
const rows = routes.map((route) => [
|
|
631
|
-
route.isPreferred ? c(GREEN, "*") : route.isDirect ? c(CYAN, "\u00B7") : " ",
|
|
632
|
-
c(CYAN, route.provider),
|
|
633
|
-
route.model.id,
|
|
634
|
-
route.model.region ?? c(DIM, "—"),
|
|
635
|
-
route.originProvider ?? c(DIM, "—"),
|
|
636
|
-
route.version ?? c(DIM, "—"),
|
|
637
|
-
route.baseUrl ?? c(DIM, "—"),
|
|
638
|
-
formatPrice(route.model.pricing?.inputPerMillion),
|
|
639
|
-
formatPrice(route.model.pricing?.outputPerMillion),
|
|
640
|
-
]);
|
|
641
|
-
console.log(`\n${c(BOLD, routes[0].model.name)} ${c(DIM, `(${routes.length} route${routes.length !== 1 ? "s" : ""})`)}\n`);
|
|
642
|
-
console.log(renderTable(columns, rows));
|
|
643
|
-
const preferred = routes.find((route) => route.isPreferred);
|
|
644
|
-
if (preferred) {
|
|
645
|
-
console.log(c(DIM, `\nPreferred route: ${preferred.provider} (${preferred.baseUrl ?? "base URL unknown"})`));
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
328
|
// ── refresh ──────────────────────────────────────────────────────────────
|
|
649
329
|
/**
|
|
650
330
|
* Force a full re-discovery of all providers, bypassing the cache.
|
|
@@ -685,140 +365,10 @@ export async function cmdServe(flags) {
|
|
|
685
365
|
const { startServer } = await import("./server.js");
|
|
686
366
|
await startServer(port);
|
|
687
367
|
}
|
|
688
|
-
//
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
${c(BOLD, "USAGE")}
|
|
695
|
-
kosha <command> [options]
|
|
696
|
-
|
|
697
|
-
${c(BOLD, "COMMANDS")}
|
|
698
|
-
${c(CYAN, "discover")} Discover all providers and models
|
|
699
|
-
${c(CYAN, "list")} List all known models
|
|
700
|
-
--provider <name> Filter by serving-layer provider
|
|
701
|
-
--origin <name> Filter by origin/creator provider (e.g. anthropic)
|
|
702
|
-
--mode <mode> Filter by mode (chat, embedding, image, audio)
|
|
703
|
-
--capability <cap> Filter by capability (vision, function_calling, etc.)
|
|
704
|
-
${c(CYAN, "search")} <query> Search models by name/ID (fuzzy match)
|
|
705
|
-
--origin <name> Restrict search to a specific origin provider
|
|
706
|
-
${c(CYAN, "model")} <id|alias> Show detailed info for one model
|
|
707
|
-
${c(CYAN, "roles")} Show provider -> model -> roles matrix
|
|
708
|
-
--role <role> Filter by task role (e.g. embeddings, image, tool_use)
|
|
709
|
-
--provider <name> Filter by serving-layer provider
|
|
710
|
-
--origin <name> Filter by model creator provider
|
|
711
|
-
--mode <mode> Filter by mode (chat, embedding, image, audio, moderation)
|
|
712
|
-
--capability <cap> Filter by capability tag
|
|
713
|
-
${c(CYAN, "capabilities")} ${c(DIM, "(caps)")} Show all capabilities across the ecosystem
|
|
714
|
-
--provider <name> Scope to one provider
|
|
715
|
-
${c(CYAN, "capable")} <capability> List models with a given capability
|
|
716
|
-
--provider <name> Filter by serving-layer provider
|
|
717
|
-
--origin <name> Filter by origin/creator provider
|
|
718
|
-
--mode <mode> Filter by mode (chat, embedding, image, audio)
|
|
719
|
-
--limit <n> Maximum models to show
|
|
720
|
-
${c(CYAN, "cheapest")} Find cheapest eligible models
|
|
721
|
-
--role <role> Task role, e.g. embeddings or image
|
|
722
|
-
--capability <cap> Capability filter (vision, embedding, function_calling)
|
|
723
|
-
--mode <mode> Mode filter
|
|
724
|
-
--limit <n> Maximum matches to return (default 5)
|
|
725
|
-
--price-metric <metric> input | output | blended
|
|
726
|
-
--input-weight <n> Weight for blended metric input price
|
|
727
|
-
--output-weight <n> Weight for blended metric output price
|
|
728
|
-
--include-unpriced Include unpriced models after ranked matches
|
|
729
|
-
${c(CYAN, "routes")} <id|alias> Show all provider routes for a model
|
|
730
|
-
${c(CYAN, "providers")} List all providers and their status
|
|
731
|
-
${c(CYAN, "resolve")} <alias> Resolve an alias to canonical model ID
|
|
732
|
-
${c(CYAN, "latest")} Force-fetch latest model/provider details
|
|
733
|
-
--provider <name> Scope latest fetch to one provider
|
|
734
|
-
${c(CYAN, "refresh")} ${c(DIM, "(update)")} Force re-discover all providers (bypass cache)
|
|
735
|
-
--provider <name> Refresh only one provider
|
|
736
|
-
${c(CYAN, "serve")} [--port 3000] Start HTTP API server
|
|
737
|
-
|
|
738
|
-
${c(BOLD, "CACHING & OUTPUT")}
|
|
739
|
-
Results are cached at ${c(CYAN, "~/.kosha/cache")} for 24h by default.
|
|
740
|
-
Subsequent ${c(CYAN, "kosha list")}, ${c(CYAN, "search")}, etc. load instantly from disk.
|
|
741
|
-
Run ${c(CYAN, "kosha update")} to force a fresh pull from all provider APIs.
|
|
742
|
-
|
|
743
|
-
A stable, third-party-readable manifest is also written to
|
|
744
|
-
${c(CYAN, "~/.kosha/registry.json")}
|
|
745
|
-
after every discover / update, containing the full v1 snapshot
|
|
746
|
-
(providers, models, pricing, capabilities, health). Any language or
|
|
747
|
-
tool that can read JSON can consume it directly.
|
|
748
|
-
|
|
749
|
-
${c(BOLD, "OPTIONS")}
|
|
750
|
-
--json Output as JSON (works with any command)
|
|
751
|
-
--help Show this help message
|
|
752
|
-
--version Show version
|
|
753
|
-
|
|
754
|
-
${c(BOLD, "EXAMPLES")}
|
|
755
|
-
${c(DIM, "$")} kosha discover
|
|
756
|
-
${c(DIM, "$")} kosha list --provider anthropic
|
|
757
|
-
${c(DIM, "$")} kosha list --origin anthropic
|
|
758
|
-
${c(DIM, "$")} kosha list --mode embedding --json
|
|
759
|
-
${c(DIM, "$")} kosha search gemini
|
|
760
|
-
${c(DIM, "$")} kosha search claude --origin anthropic
|
|
761
|
-
${c(DIM, "$")} kosha model sonnet
|
|
762
|
-
${c(DIM, "$")} kosha roles --role embeddings
|
|
763
|
-
${c(DIM, "$")} kosha capabilities
|
|
764
|
-
${c(DIM, "$")} kosha capable vision
|
|
765
|
-
${c(DIM, "$")} kosha capable embeddings --limit 5
|
|
766
|
-
${c(DIM, "$")} kosha cheapest --role image --limit 3
|
|
767
|
-
${c(DIM, "$")} kosha routes claude-opus-4-6
|
|
768
|
-
${c(DIM, "$")} kosha routes gpt-4o --json
|
|
769
|
-
${c(DIM, "$")} kosha providers
|
|
770
|
-
${c(DIM, "$")} kosha latest
|
|
771
|
-
${c(DIM, "$")} kosha latest --provider openai --json
|
|
772
|
-
${c(DIM, "$")} kosha resolve haiku
|
|
773
|
-
${c(DIM, "$")} kosha refresh --provider anthropic
|
|
774
|
-
${c(DIM, "$")} kosha serve --port 8080
|
|
775
|
-
`.trim());
|
|
776
|
-
}
|
|
777
|
-
/** Print the CLI version string to stdout. */
|
|
778
|
-
export function showVersion() {
|
|
779
|
-
console.log(`kosha-discovery v${VERSION}`);
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Display a branded splash screen when `kosha` is invoked with no arguments.
|
|
783
|
-
*
|
|
784
|
-
* Shows the Kosha logo, tagline, version, and quick-start commands.
|
|
785
|
-
* Uses MAGENTA branding with a clean, minimal layout.
|
|
786
|
-
*/
|
|
787
|
-
export function showSplash() {
|
|
788
|
-
const brandWord = `${c(CYAN, "k")}${c(GREEN, "o")}${c(YELLOW, "s")}${c(MAGENTA, "h")}${c(RED, "a")}`;
|
|
789
|
-
const mascot1 = `${c(CYAN, " /\\_/\\ ")} ${c(DIM, "assistant mascot")}`;
|
|
790
|
-
const mascot2 = `${c(CYAN, "( o.o )")} ${c(DIM, "ready to route")}`;
|
|
791
|
-
const mascot3 = `${c(CYAN, " > ^ < ")} ${c(DIM, "providers + models")}`;
|
|
792
|
-
console.log(`
|
|
793
|
-
${c(MAGENTA, " ╔═══════════════════════════════════════════════════╗")}
|
|
794
|
-
${c(MAGENTA, " ║")} ${c(MAGENTA, "║")}
|
|
795
|
-
${c(MAGENTA, " ║")} ${c(BOLD, " █▄▀ █▀█ █▀ █ █ ▄▀█")} ${c(MAGENTA, "║")}
|
|
796
|
-
${c(MAGENTA, " ║")} ${c(BOLD, " █ █ █▄█ ▄█ █▀█ █▀█")} ${c(DIM, "कोश — treasury")} ${c(MAGENTA, "║")}
|
|
797
|
-
${c(MAGENTA, " ║")} ${c(MAGENTA, "║")}
|
|
798
|
-
${c(MAGENTA, " ║")} ${brandWord} ${c(DIM, "AI Model & Provider Discovery Registry")} ${c(MAGENTA, "║")}
|
|
799
|
-
${c(MAGENTA, " ║")} ${c(DIM, `v${VERSION}`)} ${c(MAGENTA, "║")}
|
|
800
|
-
${c(MAGENTA, " ║")} ${mascot1} ${c(MAGENTA, "║")}
|
|
801
|
-
${c(MAGENTA, " ║")} ${mascot2} ${c(MAGENTA, "║")}
|
|
802
|
-
${c(MAGENTA, " ║")} ${mascot3} ${c(MAGENTA, "║")}
|
|
803
|
-
${c(MAGENTA, " ║")} ${c(MAGENTA, "║")}
|
|
804
|
-
${c(MAGENTA, " ╚═══════════════════════════════════════════════════╝")}
|
|
805
|
-
|
|
806
|
-
${c(BOLD, "Quick start:")}
|
|
807
|
-
|
|
808
|
-
${c(CYAN, "kosha discover")} Scan all providers for models
|
|
809
|
-
${c(CYAN, "kosha list")} List all discovered models
|
|
810
|
-
${c(CYAN, "kosha search")} ${c(DIM, "<q>")} Search by name or ID
|
|
811
|
-
${c(CYAN, "kosha model")} ${c(DIM, "<id>")} Detailed info for one model
|
|
812
|
-
${c(CYAN, "kosha capabilities")} What capabilities exist?
|
|
813
|
-
${c(CYAN, "kosha capable")} ${c(DIM, "<cap>")} Models with a given capability
|
|
814
|
-
${c(CYAN, "kosha roles")} Provider -> model -> roles matrix
|
|
815
|
-
${c(CYAN, "kosha cheapest")} Cheapest models for a role
|
|
816
|
-
${c(CYAN, "kosha routes")} ${c(DIM, "<id>")} All provider routes for a model
|
|
817
|
-
${c(CYAN, "kosha providers")} Show provider status
|
|
818
|
-
${c(CYAN, "kosha latest")} Force-fetch latest provider/model details
|
|
819
|
-
${c(CYAN, "kosha serve")} Start the HTTP API server
|
|
820
|
-
|
|
821
|
-
${c(DIM, "Run")} ${c(CYAN, "kosha --help")} ${c(DIM, "for full usage.")}
|
|
822
|
-
`);
|
|
823
|
-
}
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
// Re-exports from split modules
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
export { cmdModel, cmdResolve, cmdRoutes } from "./cli-cmd-model.js";
|
|
372
|
+
export { cmdRoles, cmdCheapest, cmdCapabilities, cmdCapable } from "./cli-cmd-query.js";
|
|
373
|
+
export { showHelp, showVersion, showSplash } from "./cli-help.js";
|
|
824
374
|
//# sourceMappingURL=cli-commands.js.map
|