proxitor 0.3.0 → 0.4.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 +25 -7
- 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 +192 -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/wizard.mjs
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { n as findConfigFile, r as getXdgConfigDir } from "./cli.mjs";
|
|
2
|
+
import { confirm as le, intro as ye, isCancel as R$1, log as R, note as Ce, outro as fe, select as Ee, text as Re } from "./dist.mjs";
|
|
3
|
+
import { t as require_dist } from "./dist2.mjs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
|
+
//#region src/commands/config/wizard.ts
|
|
8
|
+
var import_dist = require_dist();
|
|
9
|
+
const DEFAULT_PORT = 8828;
|
|
10
|
+
const DEFAULT_HOST = "0.0.0.0";
|
|
11
|
+
function maskKey(key) {
|
|
12
|
+
if (key.length <= 11) return "****";
|
|
13
|
+
return `${key.slice(0, 7)}...${key.slice(-4)}`;
|
|
14
|
+
}
|
|
15
|
+
function resolveSavePath(location) {
|
|
16
|
+
switch (location) {
|
|
17
|
+
case "local": return resolve("proxitor.config.yaml");
|
|
18
|
+
case "user": return join(homedir(), ".config", "proxitor", "config.yaml");
|
|
19
|
+
case "xdg": return join(getXdgConfigDir(), "config.yaml");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getSaveLocationOptions(_existingPath) {
|
|
23
|
+
const opts = [{
|
|
24
|
+
value: "local",
|
|
25
|
+
label: "./proxitor.config.yaml",
|
|
26
|
+
hint: "Project directory"
|
|
27
|
+
}, {
|
|
28
|
+
value: "user",
|
|
29
|
+
label: "~/.config/proxitor/config.yaml",
|
|
30
|
+
hint: "User config"
|
|
31
|
+
}];
|
|
32
|
+
if (process.env.XDG_CONFIG_HOME) opts.push({
|
|
33
|
+
value: "xdg",
|
|
34
|
+
label: "$XDG_CONFIG_HOME/proxitor/config.yaml",
|
|
35
|
+
hint: "XDG config directory"
|
|
36
|
+
});
|
|
37
|
+
return opts;
|
|
38
|
+
}
|
|
39
|
+
function detectLocation(path) {
|
|
40
|
+
const cwd = resolve(".");
|
|
41
|
+
if (path.startsWith(cwd)) return "local";
|
|
42
|
+
const userDir = join(homedir(), ".config", "proxitor");
|
|
43
|
+
if (path.startsWith(userDir)) {
|
|
44
|
+
const xdgDir = process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, "proxitor") : null;
|
|
45
|
+
if (xdgDir && path.startsWith(xdgDir)) return "xdg";
|
|
46
|
+
return "user";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function buildYaml(apiKey, port, host, existingRaw) {
|
|
50
|
+
if (existingRaw) {
|
|
51
|
+
const doc = (0, import_dist.parseDocument)(existingRaw);
|
|
52
|
+
doc.set("openrouterKey", apiKey);
|
|
53
|
+
doc.set("port", port);
|
|
54
|
+
doc.set("host", host);
|
|
55
|
+
return doc.toString();
|
|
56
|
+
}
|
|
57
|
+
return (0, import_dist.stringify)({
|
|
58
|
+
openrouterKey: apiKey,
|
|
59
|
+
port,
|
|
60
|
+
host
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function readExistingConfig(path) {
|
|
64
|
+
const raw = readFileSync(path, "utf-8");
|
|
65
|
+
const parsed = (0, import_dist.parseDocument)(raw).toJSON();
|
|
66
|
+
return {
|
|
67
|
+
raw,
|
|
68
|
+
port: typeof parsed?.port === "number" ? parsed.port : DEFAULT_PORT,
|
|
69
|
+
host: typeof parsed?.host === "string" ? parsed.host : DEFAULT_HOST,
|
|
70
|
+
apiKey: typeof parsed?.openrouterKey === "string" ? parsed.openrouterKey : ""
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async function askApiKey(currentKey) {
|
|
74
|
+
if (currentKey) R.info(`Current key: ${maskKey(currentKey)}`);
|
|
75
|
+
const apiKey = await Re({
|
|
76
|
+
message: "OpenRouter API key",
|
|
77
|
+
placeholder: "sk-or-v1-...",
|
|
78
|
+
initialValue: currentKey,
|
|
79
|
+
validate: (v) => {
|
|
80
|
+
if (!v?.trim()) return "API key is required";
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
if (R$1(apiKey)) return null;
|
|
84
|
+
Ce("You can also set the OPENROUTER_API_KEY environment variable\nto avoid storing the key in the config file.", "Tip");
|
|
85
|
+
return apiKey;
|
|
86
|
+
}
|
|
87
|
+
async function askPort(current) {
|
|
88
|
+
const input = await Re({
|
|
89
|
+
message: "Proxy port",
|
|
90
|
+
initialValue: String(current),
|
|
91
|
+
placeholder: String(DEFAULT_PORT),
|
|
92
|
+
validate: (v) => {
|
|
93
|
+
if (!v?.trim()) return void 0;
|
|
94
|
+
const n = Number.parseInt(v, 10);
|
|
95
|
+
if (Number.isNaN(n) || n < 1 || n > 65535) return "Port must be 1–65535";
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
if (R$1(input)) return null;
|
|
99
|
+
return input.trim() ? Number.parseInt(input, 10) : DEFAULT_PORT;
|
|
100
|
+
}
|
|
101
|
+
async function askHost(current) {
|
|
102
|
+
const host = await Ee({
|
|
103
|
+
message: "Listen address",
|
|
104
|
+
initialValue: current,
|
|
105
|
+
options: [{
|
|
106
|
+
value: "0.0.0.0",
|
|
107
|
+
label: "All interfaces (0.0.0.0)",
|
|
108
|
+
hint: "Default"
|
|
109
|
+
}, {
|
|
110
|
+
value: "127.0.0.1",
|
|
111
|
+
label: "Localhost only (127.0.0.1)",
|
|
112
|
+
hint: "More secure"
|
|
113
|
+
}]
|
|
114
|
+
});
|
|
115
|
+
if (R$1(host)) return null;
|
|
116
|
+
return host;
|
|
117
|
+
}
|
|
118
|
+
async function askSaveLocation(existingPath) {
|
|
119
|
+
const options = getSaveLocationOptions(existingPath);
|
|
120
|
+
const location = await Ee({
|
|
121
|
+
message: "Save config to",
|
|
122
|
+
initialValue: (existingPath ? detectLocation(existingPath) : void 0) ?? "local",
|
|
123
|
+
options
|
|
124
|
+
});
|
|
125
|
+
if (R$1(location)) return null;
|
|
126
|
+
return location;
|
|
127
|
+
}
|
|
128
|
+
async function runWizard() {
|
|
129
|
+
ye("Proxitor Setup Wizard");
|
|
130
|
+
const existingPath = findConfigFile();
|
|
131
|
+
let existingRaw;
|
|
132
|
+
let currentPort = DEFAULT_PORT;
|
|
133
|
+
let currentHost = DEFAULT_HOST;
|
|
134
|
+
let currentKey = "";
|
|
135
|
+
if (existingPath) {
|
|
136
|
+
Ce(existingPath, "Existing config found");
|
|
137
|
+
const reconfigure = await le({
|
|
138
|
+
message: "Reconfigure?",
|
|
139
|
+
initialValue: true
|
|
140
|
+
});
|
|
141
|
+
if (R$1(reconfigure) || !reconfigure) {
|
|
142
|
+
fe("Using existing configuration");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const existing = readExistingConfig(existingPath);
|
|
147
|
+
existingRaw = existing.raw;
|
|
148
|
+
currentPort = existing.port;
|
|
149
|
+
currentHost = existing.host;
|
|
150
|
+
currentKey = existing.apiKey;
|
|
151
|
+
} catch {}
|
|
152
|
+
}
|
|
153
|
+
const apiKey = await askApiKey(currentKey);
|
|
154
|
+
if (apiKey === null) {
|
|
155
|
+
fe("Cancelled");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const port = await askPort(currentPort);
|
|
159
|
+
if (port === null) {
|
|
160
|
+
fe("Cancelled");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const host = await askHost(currentHost);
|
|
164
|
+
if (host === null) {
|
|
165
|
+
fe("Cancelled");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const location = await askSaveLocation(existingPath ?? void 0);
|
|
169
|
+
if (location === null) {
|
|
170
|
+
fe("Cancelled");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const yaml = buildYaml(apiKey, port, host, existingRaw);
|
|
174
|
+
Ce(yaml, "Preview");
|
|
175
|
+
const save = await le({
|
|
176
|
+
message: "Save this configuration?",
|
|
177
|
+
initialValue: true
|
|
178
|
+
});
|
|
179
|
+
if (R$1(save) || !save) {
|
|
180
|
+
fe("Cancelled — no files written");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const savePath = resolveSavePath(location);
|
|
184
|
+
const dir = dirname(savePath);
|
|
185
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
186
|
+
writeFileSync(savePath, yaml, "utf-8");
|
|
187
|
+
fe(`Config saved to ${savePath}`);
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
190
|
+
export { runWizard };
|
|
191
|
+
|
|
192
|
+
//# sourceMappingURL=wizard.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.mjs","names":["clack.text","isCancel","clack.select","clack.confirm"],"sources":["../src/commands/config/wizard.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { isCancel } from '@clack/prompts'\nimport { parseDocument, stringify } from 'yaml'\nimport { findConfigFile, getXdgConfigDir } from '../../config.js'\n\nconst DEFAULT_PORT = 8828\nconst DEFAULT_HOST = '0.0.0.0'\n\ntype SaveLocation = 'local' | 'user' | 'xdg'\n\nfunction maskKey(key: string): string {\n if (key.length <= 11) return '****'\n return `${key.slice(0, 7)}...${key.slice(-4)}`\n}\n\nfunction resolveSavePath(location: SaveLocation): string {\n switch (location) {\n case 'local':\n return resolve('proxitor.config.yaml')\n case 'user':\n return join(homedir(), '.config', 'proxitor', 'config.yaml')\n case 'xdg':\n return join(getXdgConfigDir(), 'config.yaml')\n }\n}\n\nfunction getSaveLocationOptions(_existingPath?: string) {\n const opts: { value: SaveLocation; label: string; hint: string }[] = [\n { value: 'local', label: './proxitor.config.yaml', hint: 'Project directory' },\n { value: 'user', label: '~/.config/proxitor/config.yaml', hint: 'User config' },\n ]\n\n if (process.env.XDG_CONFIG_HOME) {\n opts.push({\n value: 'xdg',\n label: '$XDG_CONFIG_HOME/proxitor/config.yaml',\n hint: 'XDG config directory',\n })\n }\n\n return opts\n}\n\nfunction detectLocation(path: string): SaveLocation | undefined {\n const cwd = resolve('.')\n if (path.startsWith(cwd)) return 'local'\n const userDir = join(homedir(), '.config', 'proxitor')\n if (path.startsWith(userDir)) {\n const xdgDir = process.env.XDG_CONFIG_HOME\n ? join(process.env.XDG_CONFIG_HOME, 'proxitor')\n : null\n if (xdgDir && path.startsWith(xdgDir)) return 'xdg'\n return 'user'\n }\n return undefined\n}\n\nfunction buildYaml(\n apiKey: string,\n port: number,\n host: string,\n existingRaw?: string,\n): string {\n if (existingRaw) {\n const doc = parseDocument(existingRaw)\n doc.set('openrouterKey', apiKey)\n doc.set('port', port)\n doc.set('host', host)\n return doc.toString()\n }\n\n return stringify({ openrouterKey: apiKey, port, host })\n}\n\nfunction readExistingConfig(path: string): {\n raw: string\n port: number\n host: string\n apiKey: string\n} {\n const raw = readFileSync(path, 'utf-8')\n const parsed = parseDocument(raw).toJSON() as Record<string, unknown>\n return {\n raw,\n port: typeof parsed?.port === 'number' ? parsed.port : DEFAULT_PORT,\n host: typeof parsed?.host === 'string' ? parsed.host : DEFAULT_HOST,\n apiKey: typeof parsed?.openrouterKey === 'string' ? parsed.openrouterKey : '',\n }\n}\n\nasync function askApiKey(currentKey: string): Promise<string | null> {\n if (currentKey) {\n clack.log.info(`Current key: ${maskKey(currentKey)}`)\n }\n const apiKey = await clack.text({\n message: 'OpenRouter API key',\n placeholder: 'sk-or-v1-...',\n initialValue: currentKey,\n validate: v => {\n if (!v?.trim()) return 'API key is required'\n return undefined\n },\n })\n if (isCancel(apiKey)) return null\n\n clack.note(\n 'You can also set the OPENROUTER_API_KEY environment variable\\nto avoid storing the key in the config file.',\n 'Tip',\n )\n return apiKey as string\n}\n\nasync function askPort(current: number): Promise<number | null> {\n const input = await clack.text({\n message: 'Proxy port',\n initialValue: String(current),\n placeholder: String(DEFAULT_PORT),\n validate: v => {\n if (!v?.trim()) return undefined\n const n = Number.parseInt(v, 10)\n if (Number.isNaN(n) || n < 1 || n > 65535) return 'Port must be 1–65535'\n return undefined\n },\n })\n if (isCancel(input)) return null\n return (input as string).trim() ? Number.parseInt(input as string, 10) : DEFAULT_PORT\n}\n\nasync function askHost(current: string): Promise<string | null> {\n const host = await clack.select({\n message: 'Listen address',\n initialValue: current as '0.0.0.0' | '127.0.0.1',\n options: [\n { value: '0.0.0.0', label: 'All interfaces (0.0.0.0)', hint: 'Default' },\n { value: '127.0.0.1', label: 'Localhost only (127.0.0.1)', hint: 'More secure' },\n ],\n })\n if (isCancel(host)) return null\n return host as string\n}\n\nasync function askSaveLocation(existingPath?: string): Promise<SaveLocation | null> {\n const options = getSaveLocationOptions(existingPath)\n const detected = existingPath ? detectLocation(existingPath) : undefined\n\n const location = await clack.select({\n message: 'Save config to',\n initialValue: detected ?? 'local',\n options,\n })\n if (isCancel(location)) return null\n return location as SaveLocation\n}\n\nexport async function runWizard(): Promise<void> {\n clack.intro('Proxitor Setup Wizard')\n\n const existingPath = findConfigFile()\n let existingRaw: string | undefined\n let currentPort = DEFAULT_PORT\n let currentHost = DEFAULT_HOST\n let currentKey = ''\n\n if (existingPath) {\n clack.note(existingPath, 'Existing config found')\n\n const reconfigure = await clack.confirm({\n message: 'Reconfigure?',\n initialValue: true,\n })\n if (isCancel(reconfigure) || !reconfigure) {\n clack.outro('Using existing configuration')\n return\n }\n\n try {\n const existing = readExistingConfig(existingPath)\n existingRaw = existing.raw\n currentPort = existing.port\n currentHost = existing.host\n currentKey = existing.apiKey\n } catch {\n // use defaults\n }\n }\n\n const apiKey = await askApiKey(currentKey)\n if (apiKey === null) {\n clack.outro('Cancelled')\n return\n }\n\n const port = await askPort(currentPort)\n if (port === null) {\n clack.outro('Cancelled')\n return\n }\n\n const host = await askHost(currentHost)\n if (host === null) {\n clack.outro('Cancelled')\n return\n }\n\n const location = await askSaveLocation(existingPath ?? undefined)\n if (location === null) {\n clack.outro('Cancelled')\n return\n }\n\n const yaml = buildYaml(apiKey, port, host, existingRaw)\n clack.note(yaml, 'Preview')\n\n const save = await clack.confirm({\n message: 'Save this configuration?',\n initialValue: true,\n })\n if (isCancel(save) || !save) {\n clack.outro('Cancelled — no files written')\n return\n }\n\n const savePath = resolveSavePath(location)\n const dir = dirname(savePath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n writeFileSync(savePath, yaml, 'utf-8')\n\n clack.outro(`Config saved to ${savePath}`)\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proxitor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Lightweight proxy for routing CLI requests (claude-code, codex) to OpenRouter",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
8
8
|
],
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"import": {
|
|
12
|
-
"types": "./dist/index.d.mts",
|
|
13
|
-
"default": "./dist/index.mjs"
|
|
14
|
-
},
|
|
15
|
-
"require": {
|
|
16
|
-
"types": "./dist/index.d.cts",
|
|
17
|
-
"default": "./dist/index.cjs"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"main": "./dist/index.cjs",
|
|
22
|
-
"module": "./dist/index.mjs",
|
|
23
|
-
"types": "./dist/index.d.mts",
|
|
24
9
|
"keywords": [
|
|
25
10
|
"proxy",
|
|
26
11
|
"openrouter",
|
package/dist/add.cjs
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
const require_proxy = require("./proxy.cjs");
|
|
2
|
-
const require_providers = require("./providers.cjs");
|
|
3
|
-
const require_config = require("./config.cjs");
|
|
4
|
-
let _clack_prompts = require("@clack/prompts");
|
|
5
|
-
_clack_prompts = require_proxy.__toESM(_clack_prompts, 1);
|
|
6
|
-
//#region src/commands/config/add.ts
|
|
7
|
-
const CUSTOM_PATTERN = "__custom_pattern__";
|
|
8
|
-
/** Run the interactive "Add model override" flow. */
|
|
9
|
-
async function addOverrideCommand(apiKey) {
|
|
10
|
-
_clack_prompts.intro("Add Model Override");
|
|
11
|
-
const configPath = require_config.requireConfigPath();
|
|
12
|
-
const client = new require_providers.OpenRouterClient(apiKey);
|
|
13
|
-
const models = await loadModelsWithSpinner(client);
|
|
14
|
-
if (!models) return;
|
|
15
|
-
const modelId = await searchModel(models);
|
|
16
|
-
if (!modelId) return;
|
|
17
|
-
if (typeof modelId !== "string") return;
|
|
18
|
-
if (modelId === CUSTOM_PATTERN) {
|
|
19
|
-
const pattern = await enterPattern(models);
|
|
20
|
-
if (!pattern) return;
|
|
21
|
-
if (require_config.getModelOverrides(configPath)[pattern]) {
|
|
22
|
-
_clack_prompts.log.warn(`Override for "${pattern}" already exists. Use Edit instead.`);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
await configureProviderAndSave(configPath, client, pattern, true);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const selected = models.find((m) => m.id === modelId);
|
|
29
|
-
if (selected) displayModelInfo(selected);
|
|
30
|
-
if (require_config.getModelOverrides(configPath)[modelId]) {
|
|
31
|
-
_clack_prompts.log.warn(`Override for "${modelId}" already exists. Use Edit instead.`);
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
await configureProviderAndSave(configPath, client, modelId, false);
|
|
35
|
-
}
|
|
36
|
-
async function loadModelsWithSpinner(client) {
|
|
37
|
-
const s = _clack_prompts.spinner();
|
|
38
|
-
s.start("Loading models from OpenRouter...");
|
|
39
|
-
try {
|
|
40
|
-
const models = await require_providers.fetchModels(client);
|
|
41
|
-
s.stop(`${models.length} models available`);
|
|
42
|
-
return models;
|
|
43
|
-
} catch (error) {
|
|
44
|
-
s.stop("Failed to load models");
|
|
45
|
-
_clack_prompts.log.error(String(error));
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async function searchModel(models) {
|
|
50
|
-
const result = await _clack_prompts.autocomplete({
|
|
51
|
-
message: "Search for a model",
|
|
52
|
-
placeholder: "Type to search (e.g. \"claude\", \"gpt-4o\", \"qwen\")",
|
|
53
|
-
maxItems: 15,
|
|
54
|
-
options() {
|
|
55
|
-
const query = this.userInput.trim().toLowerCase();
|
|
56
|
-
if (!query) return [{
|
|
57
|
-
value: CUSTOM_PATTERN,
|
|
58
|
-
label: "✏️ Enter custom pattern (e.g. \"claude-*\")"
|
|
59
|
-
}];
|
|
60
|
-
return [...models.filter((m) => {
|
|
61
|
-
return `${m.id} ${m.name}`.toLowerCase().includes(query);
|
|
62
|
-
}).slice(0, 14).map((m) => ({
|
|
63
|
-
value: m.id,
|
|
64
|
-
label: require_providers.formatModelLabel(m),
|
|
65
|
-
hint: require_providers.formatModelHint(m)
|
|
66
|
-
})), {
|
|
67
|
-
value: CUSTOM_PATTERN,
|
|
68
|
-
label: "✏️ Enter custom pattern (e.g. \"claude-*\")"
|
|
69
|
-
}];
|
|
70
|
-
},
|
|
71
|
-
filter: (_search, _option) => true
|
|
72
|
-
});
|
|
73
|
-
if ((0, _clack_prompts.isCancel)(result)) return null;
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
async function enterPattern(models) {
|
|
77
|
-
const pattern = await _clack_prompts.text({
|
|
78
|
-
message: "Enter model pattern",
|
|
79
|
-
placeholder: "e.g. claude-*, gpt-4*, anthropic/*",
|
|
80
|
-
validate: (v) => {
|
|
81
|
-
if (!v?.trim()) return "Pattern cannot be empty";
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
if ((0, _clack_prompts.isCancel)(pattern)) return null;
|
|
85
|
-
const pat = pattern.trim();
|
|
86
|
-
const matches = countPatternMatches(pat, models);
|
|
87
|
-
if (matches > 0) _clack_prompts.log.info(`Pattern "${pat}" matches ${matches} model(s)`);
|
|
88
|
-
else _clack_prompts.log.warn(`Pattern "${pat}" does not match any current models — it will still be saved`);
|
|
89
|
-
return pat;
|
|
90
|
-
}
|
|
91
|
-
async function configureProviderAndSave(configPath, client, modelKey, isPattern) {
|
|
92
|
-
const mode = await require_providers.selectRoutingMode("Configure provider routing");
|
|
93
|
-
if ((0, _clack_prompts.isCancel)(mode)) return;
|
|
94
|
-
if (mode === "skip") {
|
|
95
|
-
require_config.setModelOverride(configPath, modelKey, {});
|
|
96
|
-
_clack_prompts.outro("Done — override saved without provider routing");
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const providerOptions = await require_providers.fetchProvidersForModel(client, modelKey, isPattern);
|
|
100
|
-
if (!providerOptions) return;
|
|
101
|
-
const override = await require_providers.selectProvidersByMode(mode, providerOptions);
|
|
102
|
-
if (!override) return;
|
|
103
|
-
_clack_prompts.log.info(`Proposed override:\n ${modelKey}:\n ${formatOverrideYaml(override)}`);
|
|
104
|
-
const save = await _clack_prompts.confirm({ message: "Save to config?" });
|
|
105
|
-
if ((0, _clack_prompts.isCancel)(save) || !save) {
|
|
106
|
-
_clack_prompts.outro("Cancelled");
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
require_config.setModelOverride(configPath, modelKey, override);
|
|
110
|
-
_clack_prompts.outro("✓ Model override saved");
|
|
111
|
-
}
|
|
112
|
-
function displayModelInfo(model) {
|
|
113
|
-
_clack_prompts.log.info(`${model.name || model.id}`);
|
|
114
|
-
_clack_prompts.log.info(` Context: ${require_providers.formatContextLength(model.context_length)} tokens`);
|
|
115
|
-
_clack_prompts.log.info(` Pricing: ${require_providers.formatPricing(model.pricing.prompt, model.pricing.completion)}`);
|
|
116
|
-
if (model.pricing.input_cache_read && model.pricing.input_cache_read !== "0") _clack_prompts.log.info(` Cache read: ${require_providers.formatPrice(model.pricing.input_cache_read)}`);
|
|
117
|
-
if (model.pricing.input_cache_write && model.pricing.input_cache_write !== "0") _clack_prompts.log.info(` Cache write: ${require_providers.formatPrice(model.pricing.input_cache_write)}`);
|
|
118
|
-
if (model.top_provider?.max_completion_tokens) _clack_prompts.log.info(` Max output: ${require_providers.formatContextLength(model.top_provider.max_completion_tokens)} tokens`);
|
|
119
|
-
if (model.architecture?.modality) _clack_prompts.log.info(` Modality: ${model.architecture.modality}`);
|
|
120
|
-
}
|
|
121
|
-
function countPatternMatches(pattern, models) {
|
|
122
|
-
if (pattern.endsWith("*")) {
|
|
123
|
-
const prefix = pattern.slice(0, -1);
|
|
124
|
-
return models.filter((m) => m.id.startsWith(prefix)).length;
|
|
125
|
-
}
|
|
126
|
-
return models.filter((m) => m.id === pattern).length;
|
|
127
|
-
}
|
|
128
|
-
function formatOverrideYaml(override) {
|
|
129
|
-
const parts = [];
|
|
130
|
-
if (override.provider && typeof override.provider === "object") {
|
|
131
|
-
const p = override.provider;
|
|
132
|
-
for (const [key, value] of Object.entries(p)) parts.push(`provider.${key}: ${JSON.stringify(value)}`);
|
|
133
|
-
}
|
|
134
|
-
return parts.join("\n ") || "(empty)";
|
|
135
|
-
}
|
|
136
|
-
//#endregion
|
|
137
|
-
exports.addOverrideCommand = addOverrideCommand;
|
|
138
|
-
|
|
139
|
-
//# sourceMappingURL=add.cjs.map
|
package/dist/add.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"add.cjs","names":["requireConfigPath","OpenRouterClient","getModelOverrides","clack","fetchModels","formatModelLabel","formatModelHint","selectRoutingMode","fetchProvidersForModel","selectProvidersByMode","formatContextLength","formatPricing","formatPrice"],"sources":["../src/commands/config/add.ts"],"sourcesContent":["import * as clack from '@clack/prompts'\nimport { isCancel } from '@clack/prompts'\nimport { OpenRouterClient } from '../../openrouter/client.js'\nimport { fetchModels, formatPrice } from '../../openrouter/models.js'\nimport type { OpenRouterModel } from '../../openrouter/types.js'\nimport { getModelOverrides, requireConfigPath, setModelOverride } from './config.js'\nimport {\n formatContextLength,\n formatModelHint,\n formatModelLabel,\n formatPricing,\n} from './format.js'\nimport {\n fetchProvidersForModel,\n selectProvidersByMode,\n selectRoutingMode,\n} from './providers.js'\n\nconst CUSTOM_PATTERN = '__custom_pattern__'\n\n/** Run the interactive \"Add model override\" flow. */\nexport async function addOverrideCommand(apiKey: string): Promise<void> {\n clack.intro('Add Model Override')\n\n const configPath = requireConfigPath()\n const client = new OpenRouterClient(apiKey)\n\n const models = await loadModelsWithSpinner(client)\n if (!models) return\n\n const modelId = await searchModel(models)\n if (!modelId) return\n\n if (typeof modelId !== 'string') return\n\n if (modelId === CUSTOM_PATTERN) {\n const pattern = await enterPattern(models)\n if (!pattern) return\n\n const existing = getModelOverrides(configPath)\n if (existing[pattern]) {\n clack.log.warn(`Override for \"${pattern}\" already exists. Use Edit instead.`)\n return\n }\n\n await configureProviderAndSave(configPath, client, pattern, true)\n return\n }\n\n const selected = models.find(m => m.id === modelId)\n if (selected) displayModelInfo(selected)\n\n const existing = getModelOverrides(configPath)\n if (existing[modelId]) {\n clack.log.warn(`Override for \"${modelId}\" already exists. Use Edit instead.`)\n return\n }\n\n await configureProviderAndSave(configPath, client, modelId, false)\n}\n\nasync function loadModelsWithSpinner(\n client: OpenRouterClient,\n): Promise<OpenRouterModel[] | null> {\n const s = clack.spinner()\n s.start('Loading models from OpenRouter...')\n try {\n const models = await fetchModels(client)\n s.stop(`${models.length} models available`)\n return models\n } catch (error) {\n s.stop('Failed to load models')\n clack.log.error(String(error))\n return null\n }\n}\n\nasync function searchModel(models: OpenRouterModel[]): Promise<string | symbol | null> {\n const result = await clack.autocomplete({\n message: 'Search for a model',\n placeholder: 'Type to search (e.g. \"claude\", \"gpt-4o\", \"qwen\")',\n maxItems: 15,\n options(this: { userInput: string }) {\n const query = this.userInput.trim().toLowerCase()\n\n if (!query) {\n return [\n {\n value: CUSTOM_PATTERN,\n label: '✏️ Enter custom pattern (e.g. \"claude-*\")',\n },\n ]\n }\n\n const filtered = models\n .filter(m => {\n const text = `${m.id} ${m.name}`.toLowerCase()\n return text.includes(query)\n })\n .slice(0, 14)\n .map(m => ({\n value: m.id,\n label: formatModelLabel(m),\n hint: formatModelHint(m),\n }))\n\n return [\n ...filtered,\n { value: CUSTOM_PATTERN, label: '✏️ Enter custom pattern (e.g. \"claude-*\")' },\n ]\n },\n filter: (_search: string, _option: { value: string }) => true,\n })\n\n if (isCancel(result)) return null\n return result as string\n}\n\nasync function enterPattern(models: OpenRouterModel[]): Promise<string | null> {\n const pattern = await clack.text({\n message: 'Enter model pattern',\n placeholder: 'e.g. claude-*, gpt-4*, anthropic/*',\n validate: v => {\n if (!v?.trim()) return 'Pattern cannot be empty'\n return undefined\n },\n })\n\n if (isCancel(pattern)) return null\n\n const pat = (pattern as string).trim()\n const matches = countPatternMatches(pat, models)\n if (matches > 0) {\n clack.log.info(`Pattern \"${pat}\" matches ${matches} model(s)`)\n } else {\n clack.log.warn(\n `Pattern \"${pat}\" does not match any current models — it will still be saved`,\n )\n }\n\n return pat\n}\n\nasync function configureProviderAndSave(\n configPath: string,\n client: OpenRouterClient,\n modelKey: string,\n isPattern: boolean,\n): Promise<void> {\n const mode = await selectRoutingMode('Configure provider routing')\n if (isCancel(mode)) return\n\n if (mode === 'skip') {\n setModelOverride(configPath, modelKey, {})\n clack.outro('Done — override saved without provider routing')\n return\n }\n\n const providerOptions = await fetchProvidersForModel(client, modelKey, isPattern)\n if (!providerOptions) return\n\n const override = await selectProvidersByMode(mode as string, providerOptions)\n if (!override) return\n\n clack.log.info(\n `Proposed override:\\n ${modelKey}:\\n ${formatOverrideYaml(override)}`,\n )\n\n const save = await clack.confirm({ message: 'Save to config?' })\n if (isCancel(save) || !save) {\n clack.outro('Cancelled')\n return\n }\n\n setModelOverride(configPath, modelKey, override)\n clack.outro('✓ Model override saved')\n}\n\nfunction displayModelInfo(model: OpenRouterModel): void {\n clack.log.info(`${model.name || model.id}`)\n clack.log.info(` Context: ${formatContextLength(model.context_length)} tokens`)\n clack.log.info(\n ` Pricing: ${formatPricing(model.pricing.prompt, model.pricing.completion)}`,\n )\n if (model.pricing.input_cache_read && model.pricing.input_cache_read !== '0') {\n clack.log.info(` Cache read: ${formatPrice(model.pricing.input_cache_read)}`)\n }\n if (model.pricing.input_cache_write && model.pricing.input_cache_write !== '0') {\n clack.log.info(` Cache write: ${formatPrice(model.pricing.input_cache_write)}`)\n }\n if (model.top_provider?.max_completion_tokens) {\n clack.log.info(\n ` Max output: ${formatContextLength(model.top_provider.max_completion_tokens)} tokens`,\n )\n }\n if (model.architecture?.modality) {\n clack.log.info(` Modality: ${model.architecture.modality}`)\n }\n}\n\nfunction countPatternMatches(pattern: string, models: OpenRouterModel[]): number {\n if (pattern.endsWith('*')) {\n const prefix = pattern.slice(0, -1)\n return models.filter(m => m.id.startsWith(prefix)).length\n }\n return models.filter(m => m.id === pattern).length\n}\n\nfunction formatOverrideYaml(override: Record<string, unknown>): string {\n const parts: string[] = []\n if (override.provider && typeof override.provider === 'object') {\n const p = override.provider as Record<string, unknown>\n for (const [key, value] of Object.entries(p)) {\n parts.push(`provider.${key}: ${JSON.stringify(value)}`)\n }\n }\n return parts.join('\\n ') || '(empty)'\n}\n"],"mappings":";;;;;;AAkBA,MAAM,iBAAiB;;AAGvB,eAAsB,mBAAmB,QAA+B;CACtE,eAAM,MAAM,oBAAoB;CAEhC,MAAM,aAAaA,eAAAA,kBAAkB;CACrC,MAAM,SAAS,IAAIC,kBAAAA,iBAAiB,MAAM;CAE1C,MAAM,SAAS,MAAM,sBAAsB,MAAM;CACjD,IAAI,CAAC,QAAQ;CAEb,MAAM,UAAU,MAAM,YAAY,MAAM;CACxC,IAAI,CAAC,SAAS;CAEd,IAAI,OAAO,YAAY,UAAU;CAEjC,IAAI,YAAY,gBAAgB;EAC9B,MAAM,UAAU,MAAM,aAAa,MAAM;EACzC,IAAI,CAAC,SAAS;EAGd,IADiBC,eAAAA,kBAAkB,UACxB,EAAE,UAAU;GACrB,eAAM,IAAI,KAAK,iBAAiB,QAAQ,oCAAoC;GAC5E;EACF;EAEA,MAAM,yBAAyB,YAAY,QAAQ,SAAS,IAAI;EAChE;CACF;CAEA,MAAM,WAAW,OAAO,MAAK,MAAK,EAAE,OAAO,OAAO;CAClD,IAAI,UAAU,iBAAiB,QAAQ;CAGvC,IADiBA,eAAAA,kBAAkB,UACxB,EAAE,UAAU;EACrB,eAAM,IAAI,KAAK,iBAAiB,QAAQ,oCAAoC;EAC5E;CACF;CAEA,MAAM,yBAAyB,YAAY,QAAQ,SAAS,KAAK;AACnE;AAEA,eAAe,sBACb,QACmC;CACnC,MAAM,IAAIC,eAAM,QAAQ;CACxB,EAAE,MAAM,mCAAmC;CAC3C,IAAI;EACF,MAAM,SAAS,MAAMC,kBAAAA,YAAY,MAAM;EACvC,EAAE,KAAK,GAAG,OAAO,OAAO,kBAAkB;EAC1C,OAAO;CACT,SAAS,OAAO;EACd,EAAE,KAAK,uBAAuB;EAC9B,eAAM,IAAI,MAAM,OAAO,KAAK,CAAC;EAC7B,OAAO;CACT;AACF;AAEA,eAAe,YAAY,QAA4D;CACrF,MAAM,SAAS,MAAMD,eAAM,aAAa;EACtC,SAAS;EACT,aAAa;EACb,UAAU;EACV,UAAqC;GACnC,MAAM,QAAQ,KAAK,UAAU,KAAK,EAAE,YAAY;GAEhD,IAAI,CAAC,OACH,OAAO,CACL;IACE,OAAO;IACP,OAAO;GACT,CACF;GAeF,OAAO,CACL,GAbe,OACd,QAAO,MAAK;IAEX,OADa,GAAG,EAAE,GAAG,GAAG,EAAE,OAAO,YACvB,EAAE,SAAS,KAAK;GAC5B,CAAC,EACA,MAAM,GAAG,EAAE,EACX,KAAI,OAAM;IACT,OAAO,EAAE;IACT,OAAOE,kBAAAA,iBAAiB,CAAC;IACzB,MAAMC,kBAAAA,gBAAgB,CAAC;GACzB,EAGU,GACV;IAAE,OAAO;IAAgB,OAAO;GAA6C,CAC/E;EACF;EACA,SAAS,SAAiB,YAA+B;CAC3D,CAAC;CAED,KAAA,GAAA,eAAA,UAAa,MAAM,GAAG,OAAO;CAC7B,OAAO;AACT;AAEA,eAAe,aAAa,QAAmD;CAC7E,MAAM,UAAU,MAAMH,eAAM,KAAK;EAC/B,SAAS;EACT,aAAa;EACb,WAAU,MAAK;GACb,IAAI,CAAC,GAAG,KAAK,GAAG,OAAO;EAEzB;CACF,CAAC;CAED,KAAA,GAAA,eAAA,UAAa,OAAO,GAAG,OAAO;CAE9B,MAAM,MAAO,QAAmB,KAAK;CACrC,MAAM,UAAU,oBAAoB,KAAK,MAAM;CAC/C,IAAI,UAAU,GACZ,eAAM,IAAI,KAAK,YAAY,IAAI,YAAY,QAAQ,UAAU;MAE7D,eAAM,IAAI,KACR,YAAY,IAAI,6DAClB;CAGF,OAAO;AACT;AAEA,eAAe,yBACb,YACA,QACA,UACA,WACe;CACf,MAAM,OAAO,MAAMI,kBAAAA,kBAAkB,4BAA4B;CACjE,KAAA,GAAA,eAAA,UAAa,IAAI,GAAG;CAEpB,IAAI,SAAS,QAAQ;EACnB,eAAA,iBAAiB,YAAY,UAAU,CAAC,CAAC;EACzC,eAAM,MAAM,gDAAgD;EAC5D;CACF;CAEA,MAAM,kBAAkB,MAAMC,kBAAAA,uBAAuB,QAAQ,UAAU,SAAS;CAChF,IAAI,CAAC,iBAAiB;CAEtB,MAAM,WAAW,MAAMC,kBAAAA,sBAAsB,MAAgB,eAAe;CAC5E,IAAI,CAAC,UAAU;CAEf,eAAM,IAAI,KACR,yBAAyB,SAAS,SAAS,mBAAmB,QAAQ,GACxE;CAEA,MAAM,OAAO,MAAMN,eAAM,QAAQ,EAAE,SAAS,kBAAkB,CAAC;CAC/D,KAAA,GAAA,eAAA,UAAa,IAAI,KAAK,CAAC,MAAM;EAC3B,eAAM,MAAM,WAAW;EACvB;CACF;CAEA,eAAA,iBAAiB,YAAY,UAAU,QAAQ;CAC/C,eAAM,MAAM,wBAAwB;AACtC;AAEA,SAAS,iBAAiB,OAA8B;CACtD,eAAM,IAAI,KAAK,GAAG,MAAM,QAAQ,MAAM,IAAI;CAC1C,eAAM,IAAI,KAAK,cAAcO,kBAAAA,oBAAoB,MAAM,cAAc,EAAE,QAAQ;CAC/E,eAAM,IAAI,KACR,cAAcC,kBAAAA,cAAc,MAAM,QAAQ,QAAQ,MAAM,QAAQ,UAAU,GAC5E;CACA,IAAI,MAAM,QAAQ,oBAAoB,MAAM,QAAQ,qBAAqB,KACvE,eAAM,IAAI,KAAK,iBAAiBC,kBAAAA,YAAY,MAAM,QAAQ,gBAAgB,GAAG;CAE/E,IAAI,MAAM,QAAQ,qBAAqB,MAAM,QAAQ,sBAAsB,KACzE,eAAM,IAAI,KAAK,kBAAkBA,kBAAAA,YAAY,MAAM,QAAQ,iBAAiB,GAAG;CAEjF,IAAI,MAAM,cAAc,uBACtB,eAAM,IAAI,KACR,iBAAiBF,kBAAAA,oBAAoB,MAAM,aAAa,qBAAqB,EAAE,QACjF;CAEF,IAAI,MAAM,cAAc,UACtB,eAAM,IAAI,KAAK,eAAe,MAAM,aAAa,UAAU;AAE/D;AAEA,SAAS,oBAAoB,SAAiB,QAAmC;CAC/E,IAAI,QAAQ,SAAS,GAAG,GAAG;EACzB,MAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;EAClC,OAAO,OAAO,QAAO,MAAK,EAAE,GAAG,WAAW,MAAM,CAAC,EAAE;CACrD;CACA,OAAO,OAAO,QAAO,MAAK,EAAE,OAAO,OAAO,EAAE;AAC9C;AAEA,SAAS,mBAAmB,UAA2C;CACrE,MAAM,QAAkB,CAAC;CACzB,IAAI,SAAS,YAAY,OAAO,SAAS,aAAa,UAAU;EAC9D,MAAM,IAAI,SAAS;EACnB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,CAAC,GACzC,MAAM,KAAK,YAAY,IAAI,IAAI,KAAK,UAAU,KAAK,GAAG;CAE1D;CACA,OAAO,MAAM,KAAK,QAAQ,KAAK;AACjC"}
|
package/dist/browse.cjs
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
const require_proxy = require("./proxy.cjs");
|
|
2
|
-
const require_providers = require("./providers.cjs");
|
|
3
|
-
const require_add = require("./add.cjs");
|
|
4
|
-
let _clack_prompts = require("@clack/prompts");
|
|
5
|
-
_clack_prompts = require_proxy.__toESM(_clack_prompts, 1);
|
|
6
|
-
//#region src/commands/config/browse.ts
|
|
7
|
-
function toOption(m) {
|
|
8
|
-
return {
|
|
9
|
-
value: m.id,
|
|
10
|
-
label: require_providers.formatModelLabel(m),
|
|
11
|
-
hint: require_providers.formatModelHint(m)
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
function displayModelDetails(model) {
|
|
15
|
-
_clack_prompts.log.success(`${model.name || model.id}`);
|
|
16
|
-
if (model.description) {
|
|
17
|
-
const desc = model.description.length > 200 ? `${model.description.slice(0, 200)}...` : model.description;
|
|
18
|
-
_clack_prompts.log.info(` ${desc}`);
|
|
19
|
-
}
|
|
20
|
-
_clack_prompts.log.info(` Context: ${require_providers.formatContextLength(model.context_length)} tokens`);
|
|
21
|
-
if (model.top_provider?.max_completion_tokens) _clack_prompts.log.info(` Max output: ${require_providers.formatContextLength(model.top_provider.max_completion_tokens)} tokens`);
|
|
22
|
-
_clack_prompts.log.info(` Pricing: ${require_providers.formatPricing(model.pricing.prompt, model.pricing.completion)}`);
|
|
23
|
-
if (model.pricing.input_cache_read && model.pricing.input_cache_read !== "0") _clack_prompts.log.info(` Cache read: ${require_providers.formatPrice(model.pricing.input_cache_read)}`);
|
|
24
|
-
if (model.pricing.input_cache_write && model.pricing.input_cache_write !== "0") _clack_prompts.log.info(` Cache write: ${require_providers.formatPrice(model.pricing.input_cache_write)}`);
|
|
25
|
-
if (model.architecture?.modality) _clack_prompts.log.info(` Modality: ${model.architecture.modality}`);
|
|
26
|
-
if (model.supported_parameters?.length) _clack_prompts.log.info(` Parameters: ${model.supported_parameters.join(", ")}`);
|
|
27
|
-
}
|
|
28
|
-
async function displayProviders(client, model) {
|
|
29
|
-
const author = require_providers.parseModelAuthor(model.id);
|
|
30
|
-
const slug = require_providers.parseModelSlug(model.id);
|
|
31
|
-
const s = _clack_prompts.spinner();
|
|
32
|
-
s.start("Checking providers...");
|
|
33
|
-
try {
|
|
34
|
-
const endpoints = await require_providers.fetchModelEndpoints(client, author, slug);
|
|
35
|
-
const unique = require_providers.getUniqueProviders(endpoints);
|
|
36
|
-
s.stop(`${unique.length} providers available`);
|
|
37
|
-
for (const p of unique) {
|
|
38
|
-
const ep = endpoints.find((e) => e.tag === p.tag);
|
|
39
|
-
const latency = require_providers.formatLatency(ep?.latency_last_30m?.p50 ?? null);
|
|
40
|
-
const throughput = require_providers.formatThroughput(ep?.throughput_last_30m?.p50 ?? null);
|
|
41
|
-
_clack_prompts.log.info(` ${p.providerName} (${p.tag}) — ${latency} · ${throughput}`);
|
|
42
|
-
}
|
|
43
|
-
} catch {
|
|
44
|
-
s.stop("Could not fetch providers");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/** Run the interactive "Browse models" flow. */
|
|
48
|
-
async function browseModelsCommand(apiKey) {
|
|
49
|
-
_clack_prompts.intro("Browse Models");
|
|
50
|
-
const client = new require_providers.OpenRouterClient(apiKey);
|
|
51
|
-
const s = _clack_prompts.spinner();
|
|
52
|
-
s.start("Loading models...");
|
|
53
|
-
let models;
|
|
54
|
-
try {
|
|
55
|
-
models = await require_providers.fetchModels(client);
|
|
56
|
-
s.stop(`${models.length} models available`);
|
|
57
|
-
} catch (error) {
|
|
58
|
-
s.stop("Failed to load models");
|
|
59
|
-
_clack_prompts.log.error(String(error));
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const modelId = await _clack_prompts.autocomplete({
|
|
63
|
-
message: "Search for a model",
|
|
64
|
-
placeholder: "Type to search...",
|
|
65
|
-
maxItems: 15,
|
|
66
|
-
options() {
|
|
67
|
-
const query = this.userInput.trim().toLowerCase();
|
|
68
|
-
if (!query) return models.slice(0, 15).map(toOption);
|
|
69
|
-
return models.filter((m) => `${m.id} ${m.name}`.toLowerCase().includes(query)).slice(0, 15).map(toOption);
|
|
70
|
-
},
|
|
71
|
-
filter: (_search, _option) => true
|
|
72
|
-
});
|
|
73
|
-
if ((0, _clack_prompts.isCancel)(modelId)) return;
|
|
74
|
-
const model = models.find((m) => m.id === modelId);
|
|
75
|
-
if (!model) return;
|
|
76
|
-
displayModelDetails(model);
|
|
77
|
-
await displayProviders(client, model);
|
|
78
|
-
const configure = await _clack_prompts.confirm({ message: `Configure routing for ${model.id}?` });
|
|
79
|
-
if ((0, _clack_prompts.isCancel)(configure) || !configure) {
|
|
80
|
-
_clack_prompts.outro("Bye!");
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
await require_add.addOverrideCommand(apiKey);
|
|
84
|
-
}
|
|
85
|
-
//#endregion
|
|
86
|
-
exports.browseModelsCommand = browseModelsCommand;
|
|
87
|
-
|
|
88
|
-
//# sourceMappingURL=browse.cjs.map
|
package/dist/browse.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browse.cjs","names":["formatModelLabel","formatModelHint","formatContextLength","formatPricing","formatPrice","parseModelAuthor","parseModelSlug","clack","fetchModelEndpoints","getUniqueProviders","formatLatency","formatThroughput","OpenRouterClient","fetchModels","addOverrideCommand"],"sources":["../src/commands/config/browse.ts"],"sourcesContent":["import * as clack from '@clack/prompts'\nimport { isCancel } from '@clack/prompts'\nimport { OpenRouterClient } from '../../openrouter/client.js'\nimport { fetchModelEndpoints, getUniqueProviders } from '../../openrouter/endpoints.js'\nimport {\n fetchModels,\n formatPrice,\n parseModelAuthor,\n parseModelSlug,\n} from '../../openrouter/models.js'\nimport type { OpenRouterModel } from '../../openrouter/types.js'\nimport { addOverrideCommand } from './add.js'\nimport {\n formatContextLength,\n formatLatency,\n formatModelHint,\n formatModelLabel,\n formatPricing,\n formatThroughput,\n} from './format.js'\n\nfunction toOption(m: OpenRouterModel) {\n return { value: m.id, label: formatModelLabel(m), hint: formatModelHint(m) }\n}\n\nfunction displayModelDetails(model: OpenRouterModel): void {\n clack.log.success(`${model.name || model.id}`)\n if (model.description) {\n const desc =\n model.description.length > 200\n ? `${model.description.slice(0, 200)}...`\n : model.description\n clack.log.info(` ${desc}`)\n }\n clack.log.info(` Context: ${formatContextLength(model.context_length)} tokens`)\n if (model.top_provider?.max_completion_tokens) {\n clack.log.info(\n ` Max output: ${formatContextLength(model.top_provider.max_completion_tokens)} tokens`,\n )\n }\n clack.log.info(\n ` Pricing: ${formatPricing(model.pricing.prompt, model.pricing.completion)}`,\n )\n if (model.pricing.input_cache_read && model.pricing.input_cache_read !== '0') {\n clack.log.info(` Cache read: ${formatPrice(model.pricing.input_cache_read)}`)\n }\n if (model.pricing.input_cache_write && model.pricing.input_cache_write !== '0') {\n clack.log.info(` Cache write: ${formatPrice(model.pricing.input_cache_write)}`)\n }\n if (model.architecture?.modality) {\n clack.log.info(` Modality: ${model.architecture.modality}`)\n }\n if (model.supported_parameters?.length) {\n clack.log.info(` Parameters: ${model.supported_parameters.join(', ')}`)\n }\n}\n\nasync function displayProviders(\n client: OpenRouterClient,\n model: OpenRouterModel,\n): Promise<void> {\n const author = parseModelAuthor(model.id)\n const slug = parseModelSlug(model.id)\n const s = clack.spinner()\n s.start('Checking providers...')\n try {\n const endpoints = await fetchModelEndpoints(client, author, slug)\n const unique = getUniqueProviders(endpoints)\n s.stop(`${unique.length} providers available`)\n\n for (const p of unique) {\n const ep = endpoints.find(e => e.tag === p.tag)\n const latency = formatLatency(ep?.latency_last_30m?.p50 ?? null)\n const throughput = formatThroughput(ep?.throughput_last_30m?.p50 ?? null)\n clack.log.info(` ${p.providerName} (${p.tag}) — ${latency} · ${throughput}`)\n }\n } catch {\n s.stop('Could not fetch providers')\n }\n}\n\n/** Run the interactive \"Browse models\" flow. */\nexport async function browseModelsCommand(apiKey: string): Promise<void> {\n clack.intro('Browse Models')\n\n const client = new OpenRouterClient(apiKey)\n\n const s = clack.spinner()\n s.start('Loading models...')\n let models: OpenRouterModel[]\n try {\n models = await fetchModels(client)\n s.stop(`${models.length} models available`)\n } catch (error) {\n s.stop('Failed to load models')\n clack.log.error(String(error))\n return\n }\n\n const modelId = await clack.autocomplete({\n message: 'Search for a model',\n placeholder: 'Type to search...',\n maxItems: 15,\n options(this: { userInput: string }) {\n const query = this.userInput.trim().toLowerCase()\n if (!query) return models.slice(0, 15).map(toOption)\n\n return models\n .filter(m => `${m.id} ${m.name}`.toLowerCase().includes(query))\n .slice(0, 15)\n .map(toOption)\n },\n filter: (_search: string, _option: { value: string }) => true,\n })\n\n if (isCancel(modelId)) return\n\n const model = models.find(m => m.id === modelId)\n if (!model) return\n\n displayModelDetails(model)\n await displayProviders(client, model)\n\n const configure = await clack.confirm({\n message: `Configure routing for ${model.id}?`,\n })\n\n if (isCancel(configure) || !configure) {\n clack.outro('Bye!')\n return\n }\n\n await addOverrideCommand(apiKey)\n}\n"],"mappings":"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"}
|