bridgerapi 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +105 -13
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -86,6 +86,15 @@ var ClaudeBackend = class {
86
86
  available() {
87
87
  return (0, import_fs.existsSync)(this.bin) || Boolean(which("claude"));
88
88
  }
89
+ async models() {
90
+ return [
91
+ "claude-opus-4-6",
92
+ "claude-opus-4-6-fast",
93
+ "claude-sonnet-4-6",
94
+ "claude-sonnet-4-5-20250929",
95
+ "claude-haiku-4-5-20251001"
96
+ ];
97
+ }
89
98
  async runBlocking(prompt, model2) {
90
99
  const bin = which("claude") || this.bin;
91
100
  let out;
@@ -117,6 +126,17 @@ var GeminiBackend = class {
117
126
  available() {
118
127
  return Boolean(which("gemini")) || (0, import_fs.existsSync)(this.bin);
119
128
  }
129
+ async models() {
130
+ return [
131
+ "gemini-3.1-pro-preview",
132
+ "gemini-3-pro-preview",
133
+ "gemini-3-flash-preview",
134
+ "gemini-2.5-pro",
135
+ "gemini-2.5-flash",
136
+ "gemini-2.0-flash",
137
+ "gemini-1.5-pro"
138
+ ];
139
+ }
120
140
  async runBlocking(prompt, model2) {
121
141
  const bin = which("gemini") || this.bin;
122
142
  let out;
@@ -157,6 +177,20 @@ var CodexBackend = class {
157
177
  available() {
158
178
  return Boolean(which("codex"));
159
179
  }
180
+ async models() {
181
+ return [
182
+ "gpt-5-codex",
183
+ "gpt-5.1-codex",
184
+ "gpt-5.1-codex-max",
185
+ "gpt-5.1",
186
+ "gpt-5.2",
187
+ "gpt-5.2-codex",
188
+ "gpt-5.3-codex",
189
+ "gpt-5-2025-08-07",
190
+ "o4-mini",
191
+ "o3"
192
+ ];
193
+ }
160
194
  async runBlocking(prompt, model2) {
161
195
  let out;
162
196
  try {
@@ -190,6 +224,9 @@ var CopilotBackend = class {
190
224
  return false;
191
225
  }
192
226
  }
227
+ async models() {
228
+ return ["copilot"];
229
+ }
193
230
  async runBlocking(prompt, model2) {
194
231
  let out;
195
232
  try {
@@ -206,18 +243,66 @@ var CopilotBackend = class {
206
243
  yield* spawnStream(this.bin, ["copilot", "suggest", "-t", "general", prompt]);
207
244
  }
208
245
  };
209
- var DroidBackend = class {
246
+ var DroidBackend = class _DroidBackend {
210
247
  constructor() {
211
248
  this.name = "droid";
212
- // Route Droid-exclusive model families + explicit "droid" prefix
213
249
  this.prefixes = ["droid", "glm", "kimi", "minimax"];
214
250
  }
251
+ static {
252
+ // Up-to-date as of March 2026 — source: droid exec --help + Factory docs
253
+ this.KNOWN_MODELS = [
254
+ // OpenAI via Droid
255
+ "gpt-5-codex",
256
+ "gpt-5.1-codex",
257
+ "gpt-5.1-codex-max",
258
+ "gpt-5.1",
259
+ "gpt-5.2",
260
+ "gpt-5.2-codex",
261
+ "gpt-5.3-codex",
262
+ "gpt-5-2025-08-07",
263
+ // Anthropic via Droid
264
+ "claude-opus-4-6",
265
+ "claude-opus-4-6-fast",
266
+ "claude-opus-4-1-20250805",
267
+ "claude-sonnet-4-5-20250929",
268
+ "claude-haiku-4-5-20251001",
269
+ // Google via Droid
270
+ "gemini-3.1-pro-preview",
271
+ "gemini-3-pro-preview",
272
+ "gemini-3-flash-preview",
273
+ // Droid-native (GLM / Kimi / MiniMax)
274
+ "glm-4.6",
275
+ "glm-4.7",
276
+ "glm-5",
277
+ "kimi-k2.5",
278
+ "minimax-m2.5"
279
+ ];
280
+ }
215
281
  get bin() {
216
282
  return process.env.DROID_BIN ?? which("droid") ?? `${HOME}/.local/bin/droid`;
217
283
  }
218
284
  available() {
219
285
  return (0, import_fs.existsSync)(this.bin) || Boolean(which("droid"));
220
286
  }
287
+ async models() {
288
+ try {
289
+ const help = (0, import_child_process.execFileSync)(which("droid") || this.bin, ["exec", "--help"], {
290
+ encoding: "utf8",
291
+ timeout: 5e3,
292
+ stdio: ["ignore", "pipe", "pipe"]
293
+ });
294
+ const MODEL_RE = /\b([a-z][a-z0-9]+(?:[.\-][a-z0-9]+){1,})\b/g;
295
+ const found = /* @__PURE__ */ new Set();
296
+ for (const [, id] of help.matchAll(MODEL_RE)) {
297
+ if (id.length >= 5 && !["help", "exec", "droid", "text", "json", "output", "format", "model", "usage"].includes(id)) {
298
+ found.add(id);
299
+ }
300
+ }
301
+ if (found.size > 0) return [...found];
302
+ } catch {
303
+ }
304
+ return _DroidBackend.KNOWN_MODELS;
305
+ }
221
306
  async runBlocking(prompt, model2) {
222
307
  const bin = which("droid") || this.bin;
223
308
  let out;
@@ -306,18 +391,25 @@ async function readBody(req) {
306
391
  req.on("error", reject);
307
392
  });
308
393
  }
309
- function handleModels(res) {
394
+ async function handleModels(res) {
310
395
  const ts = Math.floor(Date.now() / 1e3);
396
+ const override = process.env.BRIDGERAPI_BACKEND?.toLowerCase();
397
+ const pinned = override ? BACKENDS.find((b) => b.name === override && b.available()) : null;
398
+ if (pinned) {
399
+ const ids = await pinned.models();
400
+ sendJson(res, 200, {
401
+ object: "list",
402
+ data: ids.map((id) => ({ id, object: "model", created: ts, owned_by: pinned.name }))
403
+ });
404
+ return;
405
+ }
311
406
  const available = BACKENDS.filter((b) => b.available());
312
- sendJson(res, 200, {
313
- object: "list",
314
- data: available.map((b) => ({
315
- id: b.name,
316
- object: "model",
317
- created: ts,
318
- owned_by: "bridgerapi"
319
- }))
320
- });
407
+ const allModels = [];
408
+ for (const b of available) {
409
+ const ids = await b.models();
410
+ for (const id of ids) allModels.push({ id, object: "model", created: ts, owned_by: b.name });
411
+ }
412
+ sendJson(res, 200, { object: "list", data: allModels });
321
413
  }
322
414
  function handleHealth(res, port2) {
323
415
  const backends = {};
@@ -381,7 +473,7 @@ function createBridgeServer(port2) {
381
473
  return;
382
474
  }
383
475
  if (method === "GET" && (path === "/v1/models" || path === "/models")) {
384
- handleModels(res);
476
+ await handleModels(res);
385
477
  return;
386
478
  }
387
479
  if (method === "GET" && path === "/health") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bridgerapi",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Turn any AI CLI (Claude Code, Gemini, Codex, GitHub Copilot) into an OpenAI-compatible API — no API keys needed",
5
5
  "keywords": [
6
6
  "claude",