proxitor 0.3.0 → 0.5.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 +27 -8
- package/dist/add.mjs +26 -27
- package/dist/add.mjs.map +1 -1
- package/dist/browse.mjs +20 -21
- package/dist/browse.mjs.map +1 -1
- package/dist/cli.mjs +14774 -33
- package/dist/cli.mjs.map +1 -1
- package/dist/config.mjs +6 -5
- package/dist/config.mjs.map +1 -1
- package/dist/config2.mjs +5 -6
- package/dist/config2.mjs.map +1 -1
- package/dist/dist.mjs +1325 -0
- package/dist/dist.mjs.map +1 -0
- package/dist/dist2.mjs +6617 -0
- package/dist/dist2.mjs.map +1 -0
- package/dist/edit.mjs +17 -18
- package/dist/edit.mjs.map +1 -1
- package/dist/list.mjs +4 -4
- package/dist/list.mjs.map +1 -1
- package/dist/prompt.mjs +849 -0
- package/dist/prompt.mjs.map +1 -0
- package/dist/providers.mjs +16 -16
- package/dist/providers.mjs.map +1 -1
- package/dist/remove.mjs +10 -11
- package/dist/remove.mjs.map +1 -1
- package/dist/validate.mjs +9 -9
- package/dist/validate.mjs.map +1 -1
- package/dist/wizard.mjs +222 -0
- package/dist/wizard.mjs.map +1 -0
- package/package.json +1 -16
- package/dist/add.cjs +0 -139
- package/dist/add.cjs.map +0 -1
- package/dist/browse.cjs +0 -88
- package/dist/browse.cjs.map +0 -1
- package/dist/cli.cjs +0 -159
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.mts +0 -1
- package/dist/config.cjs +0 -68
- package/dist/config.cjs.map +0 -1
- package/dist/config2.cjs +0 -75
- package/dist/config2.cjs.map +0 -1
- package/dist/edit.cjs +0 -82
- package/dist/edit.cjs.map +0 -1
- package/dist/index.cjs +0 -12
- package/dist/index.d.cts +0 -261
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts +0 -261
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -2
- package/dist/list.cjs +0 -33
- package/dist/list.cjs.map +0 -1
- package/dist/providers.cjs +0 -376
- package/dist/providers.cjs.map +0 -1
- package/dist/proxy.cjs +0 -656
- package/dist/proxy.cjs.map +0 -1
- package/dist/proxy.mjs +0 -544
- package/dist/proxy.mjs.map +0 -1
- package/dist/remove.cjs +0 -38
- package/dist/remove.cjs.map +0 -1
- package/dist/validate.cjs +0 -26
- package/dist/validate.cjs.map +0 -1
package/dist/providers.cjs
DELETED
|
@@ -1,376 +0,0 @@
|
|
|
1
|
-
const require_proxy = require("./proxy.cjs");
|
|
2
|
-
let node_fs = require("node:fs");
|
|
3
|
-
let node_os = require("node:os");
|
|
4
|
-
let node_path = require("node:path");
|
|
5
|
-
let _clack_prompts = require("@clack/prompts");
|
|
6
|
-
_clack_prompts = require_proxy.__toESM(_clack_prompts, 1);
|
|
7
|
-
//#region src/openrouter/client.ts
|
|
8
|
-
const DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
9
|
-
var OpenRouterClientError = class extends Error {
|
|
10
|
-
status;
|
|
11
|
-
constructor(status, message) {
|
|
12
|
-
super(`OpenRouter API error (${status}): ${message}`);
|
|
13
|
-
this.name = "OpenRouterClientError";
|
|
14
|
-
this.status = status;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
/** HTTP client for OpenRouter REST endpoints. Auth header is only sent when apiKey is non-empty. */
|
|
18
|
-
var OpenRouterClient = class {
|
|
19
|
-
apiKey;
|
|
20
|
-
baseUrl;
|
|
21
|
-
constructor(apiKey, baseUrl) {
|
|
22
|
-
this.apiKey = apiKey;
|
|
23
|
-
this.baseUrl = baseUrl ?? DEFAULT_BASE_URL;
|
|
24
|
-
}
|
|
25
|
-
async get(path) {
|
|
26
|
-
const url = `${this.baseUrl}${path}`;
|
|
27
|
-
const res = await fetch(url, { headers: { ...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {} } });
|
|
28
|
-
if (!res.ok) {
|
|
29
|
-
const body = await res.text().catch(() => "");
|
|
30
|
-
throw new OpenRouterClientError(res.status, body || res.statusText);
|
|
31
|
-
}
|
|
32
|
-
return res.json();
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
//#endregion
|
|
36
|
-
//#region src/openrouter/cache.ts
|
|
37
|
-
const CACHE_DIR = (0, node_path.join)((0, node_os.homedir)(), ".proxitor", "cache");
|
|
38
|
-
/** Read a cached value. Returns `null` when missing, expired (older than `ttlMs`), or unparseable. */
|
|
39
|
-
function readCache(key, ttlMs) {
|
|
40
|
-
const path = (0, node_path.join)(CACHE_DIR, `${key}.json`);
|
|
41
|
-
if (!(0, node_fs.existsSync)(path)) return null;
|
|
42
|
-
try {
|
|
43
|
-
const entry = JSON.parse((0, node_fs.readFileSync)(path, "utf-8"));
|
|
44
|
-
if (Date.now() - entry.fetchedAt > ttlMs) return null;
|
|
45
|
-
return entry.data;
|
|
46
|
-
} catch {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function writeCache(key, data) {
|
|
51
|
-
(0, node_fs.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
52
|
-
const entry = {
|
|
53
|
-
fetchedAt: Date.now(),
|
|
54
|
-
data
|
|
55
|
-
};
|
|
56
|
-
(0, node_fs.writeFileSync)((0, node_path.join)(CACHE_DIR, `${key}.json`), JSON.stringify(entry));
|
|
57
|
-
}
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/openrouter/models.ts
|
|
60
|
-
const CACHE_KEY$1 = "models";
|
|
61
|
-
const CACHE_TTL$1 = 3600 * 1e3;
|
|
62
|
-
async function fetchModels(client) {
|
|
63
|
-
const cached = readCache(CACHE_KEY$1, CACHE_TTL$1);
|
|
64
|
-
if (cached) return cached;
|
|
65
|
-
const response = await client.get("/models");
|
|
66
|
-
writeCache(CACHE_KEY$1, response.data);
|
|
67
|
-
return response.data;
|
|
68
|
-
}
|
|
69
|
-
/** `"anthropic/claude-sonnet-4"` → `"anthropic"` */
|
|
70
|
-
function parseModelAuthor(modelId) {
|
|
71
|
-
return modelId.split("/")[0] ?? "";
|
|
72
|
-
}
|
|
73
|
-
/** `"anthropic/claude-sonnet-4"` → `"claude-sonnet-4"` */
|
|
74
|
-
function parseModelSlug(modelId) {
|
|
75
|
-
return modelId.split("/").slice(1).join("/");
|
|
76
|
-
}
|
|
77
|
-
/** `"0.000003"` → `"$3.00"`, `"0"` → `"free"` */
|
|
78
|
-
function formatPrice(pricePerToken) {
|
|
79
|
-
const per1M = Number.parseFloat(pricePerToken) * 1e6;
|
|
80
|
-
if (per1M === 0) return "free";
|
|
81
|
-
if (per1M < .01) return `$${per1M.toFixed(4)}`;
|
|
82
|
-
return `$${per1M.toFixed(2)}`;
|
|
83
|
-
}
|
|
84
|
-
//#endregion
|
|
85
|
-
//#region src/commands/config/format.ts
|
|
86
|
-
function formatPricing(prompt, completion) {
|
|
87
|
-
const fmt = (perToken) => {
|
|
88
|
-
const per1M = Number.parseFloat(perToken) * 1e6;
|
|
89
|
-
if (per1M === 0) return "free";
|
|
90
|
-
if (per1M < .01) return `$${per1M.toFixed(4)}`;
|
|
91
|
-
return `$${per1M.toFixed(2)}`;
|
|
92
|
-
};
|
|
93
|
-
return `${fmt(prompt)} / ${fmt(completion)}`;
|
|
94
|
-
}
|
|
95
|
-
/** `200000` → `"200k"`, `1000000` → `"1.0M"` */
|
|
96
|
-
function formatContextLength(tokens) {
|
|
97
|
-
if (tokens >= 1e6) return `${(tokens / 1e6).toFixed(1)}M`;
|
|
98
|
-
if (tokens >= 1e3) return `${Math.round(tokens / 1e3)}k`;
|
|
99
|
-
return `${tokens}`;
|
|
100
|
-
}
|
|
101
|
-
/** `1137` → `"1.1s"`, `null` → `"N/A"` */
|
|
102
|
-
function formatLatency(ms) {
|
|
103
|
-
if (ms === null) return "N/A";
|
|
104
|
-
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
105
|
-
return `${(ms / 1e3).toFixed(1)}s`;
|
|
106
|
-
}
|
|
107
|
-
function formatThroughput(tokensPerSec) {
|
|
108
|
-
if (tokensPerSec === null) return "N/A";
|
|
109
|
-
return `${tokensPerSec.toFixed(0)} t/s`;
|
|
110
|
-
}
|
|
111
|
-
function formatModelLabel(m) {
|
|
112
|
-
return `${m.name || m.id} — ${formatPrice(m.pricing.prompt)} · ${formatContextLength(m.context_length)}`;
|
|
113
|
-
}
|
|
114
|
-
function formatModelHint(m) {
|
|
115
|
-
const parts = [`out ${formatPrice(m.pricing.completion)}`];
|
|
116
|
-
if (m.pricing.input_cache_read && m.pricing.input_cache_read !== "0") parts.push(`cache ${formatPrice(m.pricing.input_cache_read)}`);
|
|
117
|
-
return parts.join(" · ");
|
|
118
|
-
}
|
|
119
|
-
//#endregion
|
|
120
|
-
//#region src/openrouter/endpoints.ts
|
|
121
|
-
async function fetchModelEndpoints(client, author, slug) {
|
|
122
|
-
return (await client.get(`/models/${author}/${slug}/endpoints`)).data.endpoints ?? [];
|
|
123
|
-
}
|
|
124
|
-
function getUniqueProviders(endpoints) {
|
|
125
|
-
const seen = /* @__PURE__ */ new Set();
|
|
126
|
-
const result = [];
|
|
127
|
-
for (const ep of endpoints) {
|
|
128
|
-
if (seen.has(ep.tag)) continue;
|
|
129
|
-
seen.add(ep.tag);
|
|
130
|
-
result.push({
|
|
131
|
-
tag: ep.tag,
|
|
132
|
-
providerName: ep.provider_name
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
result.sort((a, b) => a.providerName.localeCompare(b.providerName));
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
138
|
-
//#endregion
|
|
139
|
-
//#region src/openrouter/providers.ts
|
|
140
|
-
const CACHE_KEY = "providers";
|
|
141
|
-
const CACHE_TTL = 1440 * 60 * 1e3;
|
|
142
|
-
async function fetchProviders(client) {
|
|
143
|
-
const cached = readCache(CACHE_KEY, CACHE_TTL);
|
|
144
|
-
if (cached) return cached;
|
|
145
|
-
const response = await client.get("/providers");
|
|
146
|
-
writeCache(CACHE_KEY, response.data);
|
|
147
|
-
return response.data;
|
|
148
|
-
}
|
|
149
|
-
//#endregion
|
|
150
|
-
//#region src/commands/config/providers.ts
|
|
151
|
-
async function fetchProvidersForPattern(client) {
|
|
152
|
-
const s = _clack_prompts.spinner();
|
|
153
|
-
s.start("Fetching providers...");
|
|
154
|
-
try {
|
|
155
|
-
const providers = await fetchProviders(client);
|
|
156
|
-
const options = providers.map((p) => ({
|
|
157
|
-
value: p.slug,
|
|
158
|
-
label: p.name
|
|
159
|
-
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
160
|
-
s.stop(`${providers.length} providers available`);
|
|
161
|
-
return options;
|
|
162
|
-
} catch (error) {
|
|
163
|
-
s.stop("Failed to fetch providers");
|
|
164
|
-
_clack_prompts.log.error(String(error));
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
async function fetchEndpointsForModel(client, modelId) {
|
|
169
|
-
const author = parseModelAuthor(modelId);
|
|
170
|
-
const slug = parseModelSlug(modelId);
|
|
171
|
-
const s = _clack_prompts.spinner();
|
|
172
|
-
s.start("Fetching providers for this model...");
|
|
173
|
-
try {
|
|
174
|
-
const endpoints = await fetchModelEndpoints(client, author, slug);
|
|
175
|
-
const unique = getUniqueProviders(endpoints);
|
|
176
|
-
const options = unique.map((p) => {
|
|
177
|
-
const ep = endpoints.find((e) => e.tag === p.tag);
|
|
178
|
-
const latency = ep?.latency_last_30m?.p50 ?? null;
|
|
179
|
-
const throughput = ep?.throughput_last_30m?.p50 ?? null;
|
|
180
|
-
return {
|
|
181
|
-
value: p.tag,
|
|
182
|
-
label: `${p.providerName} (${p.tag})`,
|
|
183
|
-
hint: `${formatLatency(latency)} · ${formatThroughput(throughput)}`
|
|
184
|
-
};
|
|
185
|
-
});
|
|
186
|
-
s.stop(`${unique.length} providers available for this model`);
|
|
187
|
-
return options;
|
|
188
|
-
} catch (error) {
|
|
189
|
-
s.stop("Failed to fetch providers");
|
|
190
|
-
_clack_prompts.log.error(String(error));
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async function fetchProvidersForModel(client, modelKey, isPattern) {
|
|
195
|
-
if (isPattern) return fetchProvidersForPattern(client);
|
|
196
|
-
return fetchEndpointsForModel(client, modelKey);
|
|
197
|
-
}
|
|
198
|
-
const DONE_OPTION = "__done__";
|
|
199
|
-
async function selectRoutingMode(message) {
|
|
200
|
-
return _clack_prompts.select({
|
|
201
|
-
message,
|
|
202
|
-
options: [
|
|
203
|
-
{
|
|
204
|
-
value: "only",
|
|
205
|
-
label: "Use specific providers only"
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
value: "order",
|
|
209
|
-
label: "Set provider priority order"
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
value: "ignore",
|
|
213
|
-
label: "Ignore specific providers"
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
value: "skip",
|
|
217
|
-
label: "Skip provider routing"
|
|
218
|
-
}
|
|
219
|
-
]
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
async function selectProvidersByMode(mode, providerOptions) {
|
|
223
|
-
if (mode === "only") return selectOnlyProviders(providerOptions);
|
|
224
|
-
if (mode === "order") return selectOrderedProviders(providerOptions);
|
|
225
|
-
if (mode === "ignore") return selectIgnoreProviders(providerOptions);
|
|
226
|
-
return null;
|
|
227
|
-
}
|
|
228
|
-
async function selectOnlyProviders(providerOptions) {
|
|
229
|
-
const selected = await _clack_prompts.multiselect({
|
|
230
|
-
message: "Select providers",
|
|
231
|
-
options: providerOptions,
|
|
232
|
-
required: false
|
|
233
|
-
});
|
|
234
|
-
if (_clack_prompts.isCancel(selected)) return null;
|
|
235
|
-
const values = selected;
|
|
236
|
-
if (values.length === 0) return {};
|
|
237
|
-
return { provider: { only: values.length === 1 ? values[0] : values } };
|
|
238
|
-
}
|
|
239
|
-
async function selectOrderedProviders(providerOptions) {
|
|
240
|
-
const order = [];
|
|
241
|
-
for (let i = 1;; i++) {
|
|
242
|
-
const remaining = providerOptions.filter((p) => !order.includes(p.value));
|
|
243
|
-
if (remaining.length === 0) break;
|
|
244
|
-
const pick = await _clack_prompts.select({
|
|
245
|
-
message: `Select provider #${i} (or cancel to finish)`,
|
|
246
|
-
options: [...remaining, {
|
|
247
|
-
value: DONE_OPTION,
|
|
248
|
-
label: "✓ Done"
|
|
249
|
-
}]
|
|
250
|
-
});
|
|
251
|
-
if (_clack_prompts.isCancel(pick) || pick === DONE_OPTION) break;
|
|
252
|
-
order.push(pick);
|
|
253
|
-
}
|
|
254
|
-
if (order.length === 0) {
|
|
255
|
-
_clack_prompts.log.warn("No providers selected");
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
const allowFallbacks = await _clack_prompts.confirm({
|
|
259
|
-
message: "Allow fallbacks to other providers?",
|
|
260
|
-
initialValue: true
|
|
261
|
-
});
|
|
262
|
-
return { provider: {
|
|
263
|
-
order: order.length === 1 ? order[0] : order,
|
|
264
|
-
allowFallbacks: _clack_prompts.isCancel(allowFallbacks) ? true : allowFallbacks
|
|
265
|
-
} };
|
|
266
|
-
}
|
|
267
|
-
async function selectIgnoreProviders(providerOptions) {
|
|
268
|
-
const selected = await _clack_prompts.multiselect({
|
|
269
|
-
message: "Select providers to ignore",
|
|
270
|
-
options: providerOptions,
|
|
271
|
-
required: false
|
|
272
|
-
});
|
|
273
|
-
if (_clack_prompts.isCancel(selected)) return null;
|
|
274
|
-
const values = selected;
|
|
275
|
-
if (values.length === 0) return {};
|
|
276
|
-
return { provider: { ignore: values.length === 1 ? values[0] : values } };
|
|
277
|
-
}
|
|
278
|
-
//#endregion
|
|
279
|
-
Object.defineProperty(exports, "OpenRouterClient", {
|
|
280
|
-
enumerable: true,
|
|
281
|
-
get: function() {
|
|
282
|
-
return OpenRouterClient;
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
Object.defineProperty(exports, "fetchModelEndpoints", {
|
|
286
|
-
enumerable: true,
|
|
287
|
-
get: function() {
|
|
288
|
-
return fetchModelEndpoints;
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
Object.defineProperty(exports, "fetchModels", {
|
|
292
|
-
enumerable: true,
|
|
293
|
-
get: function() {
|
|
294
|
-
return fetchModels;
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
Object.defineProperty(exports, "fetchProvidersForModel", {
|
|
298
|
-
enumerable: true,
|
|
299
|
-
get: function() {
|
|
300
|
-
return fetchProvidersForModel;
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
Object.defineProperty(exports, "formatContextLength", {
|
|
304
|
-
enumerable: true,
|
|
305
|
-
get: function() {
|
|
306
|
-
return formatContextLength;
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
Object.defineProperty(exports, "formatLatency", {
|
|
310
|
-
enumerable: true,
|
|
311
|
-
get: function() {
|
|
312
|
-
return formatLatency;
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
Object.defineProperty(exports, "formatModelHint", {
|
|
316
|
-
enumerable: true,
|
|
317
|
-
get: function() {
|
|
318
|
-
return formatModelHint;
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
Object.defineProperty(exports, "formatModelLabel", {
|
|
322
|
-
enumerable: true,
|
|
323
|
-
get: function() {
|
|
324
|
-
return formatModelLabel;
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
Object.defineProperty(exports, "formatPrice", {
|
|
328
|
-
enumerable: true,
|
|
329
|
-
get: function() {
|
|
330
|
-
return formatPrice;
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
Object.defineProperty(exports, "formatPricing", {
|
|
334
|
-
enumerable: true,
|
|
335
|
-
get: function() {
|
|
336
|
-
return formatPricing;
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
Object.defineProperty(exports, "formatThroughput", {
|
|
340
|
-
enumerable: true,
|
|
341
|
-
get: function() {
|
|
342
|
-
return formatThroughput;
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
Object.defineProperty(exports, "getUniqueProviders", {
|
|
346
|
-
enumerable: true,
|
|
347
|
-
get: function() {
|
|
348
|
-
return getUniqueProviders;
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
Object.defineProperty(exports, "parseModelAuthor", {
|
|
352
|
-
enumerable: true,
|
|
353
|
-
get: function() {
|
|
354
|
-
return parseModelAuthor;
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
Object.defineProperty(exports, "parseModelSlug", {
|
|
358
|
-
enumerable: true,
|
|
359
|
-
get: function() {
|
|
360
|
-
return parseModelSlug;
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
Object.defineProperty(exports, "selectProvidersByMode", {
|
|
364
|
-
enumerable: true,
|
|
365
|
-
get: function() {
|
|
366
|
-
return selectProvidersByMode;
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
Object.defineProperty(exports, "selectRoutingMode", {
|
|
370
|
-
enumerable: true,
|
|
371
|
-
get: function() {
|
|
372
|
-
return selectRoutingMode;
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
//# sourceMappingURL=providers.cjs.map
|
package/dist/providers.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"providers.cjs","names":["CACHE_KEY","CACHE_TTL","clack"],"sources":["../src/openrouter/client.ts","../src/openrouter/cache.ts","../src/openrouter/models.ts","../src/commands/config/format.ts","../src/openrouter/endpoints.ts","../src/openrouter/providers.ts","../src/commands/config/providers.ts"],"sourcesContent":["const DEFAULT_BASE_URL = 'https://openrouter.ai/api/v1'\n\nexport class OpenRouterClientError extends Error {\n readonly status: number\n\n constructor(status: number, message: string) {\n super(`OpenRouter API error (${status}): ${message}`)\n this.name = 'OpenRouterClientError'\n this.status = status\n }\n}\n\n/** HTTP client for OpenRouter REST endpoints. Auth header is only sent when apiKey is non-empty. */\nexport class OpenRouterClient {\n private readonly apiKey: string\n private readonly baseUrl: string\n\n constructor(apiKey: string, baseUrl?: string) {\n this.apiKey = apiKey\n this.baseUrl = baseUrl ?? DEFAULT_BASE_URL\n }\n\n async get<T>(path: string): Promise<T> {\n const url = `${this.baseUrl}${path}`\n\n const res = await fetch(url, {\n headers: {\n ...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),\n },\n })\n\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new OpenRouterClientError(res.status, body || res.statusText)\n }\n\n return res.json() as Promise<T>\n }\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type CacheEntry<T> = {\n data: T\n fetchedAt: number\n}\n\nexport const CACHE_DIR = join(homedir(), '.proxitor', 'cache')\n\n/** Read a cached value. Returns `null` when missing, expired (older than `ttlMs`), or unparseable. */\nexport function readCache<T>(key: string, ttlMs: number): T | null {\n const path = join(CACHE_DIR, `${key}.json`)\n if (!existsSync(path)) return null\n\n try {\n const entry: CacheEntry<T> = JSON.parse(readFileSync(path, 'utf-8'))\n if (Date.now() - entry.fetchedAt > ttlMs) return null\n return entry.data\n } catch {\n return null\n }\n}\n\nexport function writeCache<T>(key: string, data: T): void {\n mkdirSync(CACHE_DIR, { recursive: true })\n const entry: CacheEntry<T> = { fetchedAt: Date.now(), data }\n writeFileSync(join(CACHE_DIR, `${key}.json`), JSON.stringify(entry))\n}\n\nexport function clearCache(key: string): void {\n const path = join(CACHE_DIR, `${key}.json`)\n if (existsSync(path)) unlinkSync(path)\n}\n","import { readCache, writeCache } from './cache.js'\nimport type { OpenRouterClient } from './client.js'\nimport type { OpenRouterModel, OpenRouterModelsResponse } from './types.js'\n\nconst CACHE_KEY = 'models'\nconst CACHE_TTL = 60 * 60 * 1000 // 1 hour\n\nexport async function fetchModels(client: OpenRouterClient): Promise<OpenRouterModel[]> {\n const cached = readCache<OpenRouterModel[]>(CACHE_KEY, CACHE_TTL)\n if (cached) return cached\n\n const response = await client.get<OpenRouterModelsResponse>('/models')\n writeCache(CACHE_KEY, response.data)\n return response.data\n}\n\n/** `\"anthropic/claude-sonnet-4\"` → `\"anthropic\"` */\nexport function parseModelAuthor(modelId: string): string {\n return modelId.split('/')[0] ?? ''\n}\n\n/** `\"anthropic/claude-sonnet-4\"` → `\"claude-sonnet-4\"` */\nexport function parseModelSlug(modelId: string): string {\n return modelId.split('/').slice(1).join('/')\n}\n\n/** `\"0.000003\"` → `\"$3.00\"`, `\"0\"` → `\"free\"` */\nexport function formatPrice(pricePerToken: string): string {\n const per1M = Number.parseFloat(pricePerToken) * 1_000_000\n if (per1M === 0) return 'free'\n if (per1M < 0.01) return `$${per1M.toFixed(4)}`\n return `$${per1M.toFixed(2)}`\n}\n","import { formatPrice } from '../../openrouter/models.js'\nimport type { OpenRouterModel } from '../../openrouter/types.js'\n\nexport function formatPricing(prompt: string, completion: string): string {\n const fmt = (perToken: string) => {\n const per1M = Number.parseFloat(perToken) * 1_000_000\n if (per1M === 0) return 'free'\n if (per1M < 0.01) return `$${per1M.toFixed(4)}`\n return `$${per1M.toFixed(2)}`\n }\n return `${fmt(prompt)} / ${fmt(completion)}`\n}\n\n/** `200000` → `\"200k\"`, `1000000` → `\"1.0M\"` */\nexport function formatContextLength(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`\n if (tokens >= 1_000) return `${Math.round(tokens / 1_000)}k`\n return `${tokens}`\n}\n\n/** `1137` → `\"1.1s\"`, `null` → `\"N/A\"` */\nexport function formatLatency(ms: number | null): string {\n if (ms === null) return 'N/A'\n if (ms < 1000) return `${Math.round(ms)}ms`\n return `${(ms / 1000).toFixed(1)}s`\n}\n\nexport function formatThroughput(tokensPerSec: number | null): string {\n if (tokensPerSec === null) return 'N/A'\n return `${tokensPerSec.toFixed(0)} t/s`\n}\n\nexport function formatModelLabel(m: OpenRouterModel): string {\n return `${m.name || m.id} — ${formatPrice(m.pricing.prompt)} · ${formatContextLength(m.context_length)}`\n}\n\nexport function formatModelHint(m: OpenRouterModel): string {\n const parts = [`out ${formatPrice(m.pricing.completion)}`]\n if (m.pricing.input_cache_read && m.pricing.input_cache_read !== '0') {\n parts.push(`cache ${formatPrice(m.pricing.input_cache_read)}`)\n }\n return parts.join(' · ')\n}\n","import type { OpenRouterClient } from './client.js'\nimport type { ModelEndpoint, ModelEndpointsResponse } from './types.js'\n\nexport async function fetchModelEndpoints(\n client: OpenRouterClient,\n author: string,\n slug: string,\n): Promise<ModelEndpoint[]> {\n const response = await client.get<ModelEndpointsResponse>(\n `/models/${author}/${slug}/endpoints`,\n )\n return response.data.endpoints ?? []\n}\n\nexport type ProviderOption = {\n providerName: string\n /** Routing slug for `provider.only/order/ignore` (e.g. \"anthropic\", \"google-vertex/global\"). */\n tag: string\n}\n\nexport function getUniqueProviders(endpoints: ModelEndpoint[]): ProviderOption[] {\n const seen = new Set<string>()\n const result: ProviderOption[] = []\n\n for (const ep of endpoints) {\n if (seen.has(ep.tag)) continue\n seen.add(ep.tag)\n result.push({ tag: ep.tag, providerName: ep.provider_name })\n }\n\n result.sort((a, b) => a.providerName.localeCompare(b.providerName))\n return result\n}\n","import { readCache, writeCache } from './cache.js'\nimport type { OpenRouterClient } from './client.js'\nimport type { OpenRouterProvider, OpenRouterProvidersResponse } from './types.js'\n\nconst CACHE_KEY = 'providers'\nconst CACHE_TTL = 24 * 60 * 60 * 1000 // 24 hours\n\nexport async function fetchProviders(\n client: OpenRouterClient,\n): Promise<OpenRouterProvider[]> {\n const cached = readCache<OpenRouterProvider[]>(CACHE_KEY, CACHE_TTL)\n if (cached) return cached\n\n const response = await client.get<OpenRouterProvidersResponse>('/providers')\n writeCache(CACHE_KEY, response.data)\n return response.data\n}\n","import * as clack from '@clack/prompts'\nimport type { OpenRouterClient } from '../../openrouter/client.js'\nimport { fetchModelEndpoints, getUniqueProviders } from '../../openrouter/endpoints.js'\nimport { parseModelAuthor, parseModelSlug } from '../../openrouter/models.js'\nimport { fetchProviders } from '../../openrouter/providers.js'\nimport { formatLatency, formatThroughput } from './format.js'\n\nexport async function fetchProvidersForPattern(\n client: OpenRouterClient,\n): Promise<Array<{ value: string; label: string; hint?: string }> | null> {\n const s = clack.spinner()\n s.start('Fetching providers...')\n try {\n const providers = await fetchProviders(client)\n const options = providers\n .map(p => ({ value: p.slug, label: p.name }))\n .sort((a, b) => a.label.localeCompare(b.label))\n s.stop(`${providers.length} providers available`)\n return options\n } catch (error) {\n s.stop('Failed to fetch providers')\n clack.log.error(String(error))\n return null\n }\n}\n\nexport async function fetchEndpointsForModel(\n client: OpenRouterClient,\n modelId: string,\n): Promise<Array<{ value: string; label: string; hint?: string }> | null> {\n const author = parseModelAuthor(modelId)\n const slug = parseModelSlug(modelId)\n\n const s = clack.spinner()\n s.start('Fetching providers for this model...')\n try {\n const endpoints = await fetchModelEndpoints(client, author, slug)\n const unique = getUniqueProviders(endpoints)\n\n const options = unique.map(p => {\n const ep = endpoints.find(e => e.tag === p.tag)\n const latency = ep?.latency_last_30m?.p50 ?? null\n const throughput = ep?.throughput_last_30m?.p50 ?? null\n return {\n value: p.tag,\n label: `${p.providerName} (${p.tag})`,\n hint: `${formatLatency(latency)} · ${formatThroughput(throughput)}`,\n }\n })\n\n s.stop(`${unique.length} providers available for this model`)\n return options\n } catch (error) {\n s.stop('Failed to fetch providers')\n clack.log.error(String(error))\n return null\n }\n}\n\nexport async function fetchProvidersForModel(\n client: OpenRouterClient,\n modelKey: string,\n isPattern: boolean,\n): Promise<Array<{ value: string; label: string; hint?: string }> | null> {\n if (isPattern) return fetchProvidersForPattern(client)\n return fetchEndpointsForModel(client, modelKey)\n}\n\nconst DONE_OPTION = '__done__'\n\nexport async function selectRoutingMode(message: string): Promise<string | symbol> {\n return clack.select({\n message,\n options: [\n { value: 'only', label: 'Use specific providers only' },\n { value: 'order', label: 'Set provider priority order' },\n { value: 'ignore', label: 'Ignore specific providers' },\n { value: 'skip', label: 'Skip provider routing' },\n ],\n })\n}\n\nexport async function selectProvidersByMode(\n mode: string,\n providerOptions: Array<{ value: string; label: string; hint?: string }>,\n): Promise<Record<string, unknown> | null> {\n if (mode === 'only') return selectOnlyProviders(providerOptions)\n if (mode === 'order') return selectOrderedProviders(providerOptions)\n if (mode === 'ignore') return selectIgnoreProviders(providerOptions)\n return null\n}\n\nasync function selectOnlyProviders(\n providerOptions: Array<{ value: string; label: string; hint?: string }>,\n): Promise<Record<string, unknown> | null> {\n const selected = await clack.multiselect({\n message: 'Select providers',\n options: providerOptions,\n required: false,\n })\n\n if (clack.isCancel(selected)) return null\n\n const values = selected as string[]\n if (values.length === 0) return {}\n\n const only = values.length === 1 ? values[0] : values\n return { provider: { only } }\n}\n\nasync function selectOrderedProviders(\n providerOptions: Array<{ value: string; label: string; hint?: string }>,\n): Promise<Record<string, unknown> | null> {\n const order: string[] = []\n\n for (let i = 1; ; i++) {\n const remaining = providerOptions.filter(p => !order.includes(p.value))\n if (remaining.length === 0) break\n\n const pick = await clack.select({\n message: `Select provider #${i} (or cancel to finish)`,\n options: [...remaining, { value: DONE_OPTION, label: '✓ Done' }],\n })\n\n if (clack.isCancel(pick) || pick === DONE_OPTION) break\n order.push(pick as string)\n }\n\n if (order.length === 0) {\n clack.log.warn('No providers selected')\n return null\n }\n\n const allowFallbacks = await clack.confirm({\n message: 'Allow fallbacks to other providers?',\n initialValue: true,\n })\n\n return {\n provider: {\n order: order.length === 1 ? order[0] : order,\n allowFallbacks: clack.isCancel(allowFallbacks) ? true : (allowFallbacks as boolean),\n },\n }\n}\n\nasync function selectIgnoreProviders(\n providerOptions: Array<{ value: string; label: string; hint?: string }>,\n): Promise<Record<string, unknown> | null> {\n const selected = await clack.multiselect({\n message: 'Select providers to ignore',\n options: providerOptions,\n required: false,\n })\n\n if (clack.isCancel(selected)) return null\n\n const values = selected as string[]\n if (values.length === 0) return {}\n\n const ignore = values.length === 1 ? values[0] : values\n return { provider: { ignore } }\n}\n"],"mappings":"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"}
|