bingocode 1.0.25 → 1.0.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bingocode",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude": "bin/claude-win.cjs",
@@ -263,6 +263,103 @@ export class ProviderService {
263
263
  await this.writeSettings(settings)
264
264
  }
265
265
 
266
+ /**
267
+ * Sync settings.json based on the current slot table.
268
+ *
269
+ * Examines all configured slots to determine whether the CLI should connect
270
+ * through the local proxy or directly. If ANY slot uses a non-anthropic format
271
+ * (openai_chat, openai_responses), the proxy is required and settings.json is
272
+ * written with:
273
+ * - ANTHROPIC_BASE_URL → http://127.0.0.1:{port}/proxy
274
+ * - ANTHROPIC_AUTH_TOKEN → "proxy-managed"
275
+ *
276
+ * Model env vars (ANTHROPIC_MODEL, ANTHROPIC_DEFAULT_*_MODEL) are populated
277
+ * from the slot table so the CLI requests the correct model names, which the
278
+ * proxy's identifySlot() then routes to the right provider.
279
+ *
280
+ * If ALL configured slots use native anthropic format, we write the main
281
+ * slot's provider info directly (no proxy needed).
282
+ *
283
+ * If no slots are configured at all, settings.json is left unchanged.
284
+ */
285
+ private async syncSettingsForSlots(slots: SlotTable): Promise<void> {
286
+ const index = await this.readIndex()
287
+
288
+ // Collect resolved slot info
289
+ type ResolvedSlot = { slot: SlotName; provider: SavedProvider; modelId: string; label?: string | null }
290
+ const resolved: ResolvedSlot[] = []
291
+ for (const slotName of ['main', 'haiku', 'sonnet', 'opus'] as const) {
292
+ const entry = slots[slotName]
293
+ if (!entry) continue
294
+ const provider = index.providers.find((p) => p.id === entry.providerId)
295
+ if (!provider) continue
296
+ resolved.push({ slot: slotName, provider, modelId: entry.modelId, label: entry.label })
297
+ }
298
+
299
+ // No slots configured at all — don't touch settings.json
300
+ if (resolved.length === 0) return
301
+
302
+ const needsProxy = resolved.some(
303
+ (r) => r.provider.apiFormat != null && r.provider.apiFormat !== 'anthropic',
304
+ )
305
+
306
+ const settings = await this.readSettings()
307
+ const existingEnv = (settings.env as Record<string, string>) || {}
308
+
309
+ // Build model env vars from slot table.
310
+ //
311
+ // The proxy's identifySlot() routes requests by looking for keywords
312
+ // (haiku/sonnet/opus) in the model name the CLI sends. If the actual
313
+ // model ID (e.g., "deepseek-chat") doesn't contain the keyword, the
314
+ // proxy would misroute to "main". To fix this, we ensure the env var
315
+ // value always contains the slot keyword so identifySlot() can match.
316
+ const modelEnv: Record<string, string> = {}
317
+ for (const r of resolved) {
318
+ const rawName = r.label || r.modelId
319
+ switch (r.slot) {
320
+ case 'main':
321
+ modelEnv.ANTHROPIC_MODEL = rawName
322
+ break
323
+ case 'haiku': {
324
+ // Ensure the value contains "haiku" for identifySlot() routing
325
+ const name = /haiku/i.test(rawName) ? rawName : `${rawName}-haiku`
326
+ modelEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL = name
327
+ break
328
+ }
329
+ case 'sonnet': {
330
+ const name = /sonnet/i.test(rawName) ? rawName : `${rawName}-sonnet`
331
+ modelEnv.ANTHROPIC_DEFAULT_SONNET_MODEL = name
332
+ break
333
+ }
334
+ case 'opus': {
335
+ const name = /opus/i.test(rawName) ? rawName : `${rawName}-opus`
336
+ modelEnv.ANTHROPIC_DEFAULT_OPUS_MODEL = name
337
+ break
338
+ }
339
+ }
340
+ }
341
+
342
+ if (needsProxy) {
343
+ settings.env = {
344
+ ...existingEnv,
345
+ ANTHROPIC_BASE_URL: `http://127.0.0.1:${ProviderService.serverPort}/proxy`,
346
+ ANTHROPIC_AUTH_TOKEN: 'proxy-managed',
347
+ ...modelEnv,
348
+ }
349
+ } else {
350
+ // All slots are native anthropic — use main slot's provider directly
351
+ const mainSlot = resolved.find((r) => r.slot === 'main') || resolved[0]
352
+ settings.env = {
353
+ ...existingEnv,
354
+ ANTHROPIC_BASE_URL: mainSlot.provider.baseUrl,
355
+ ANTHROPIC_AUTH_TOKEN: mainSlot.provider.apiKey,
356
+ ...modelEnv,
357
+ }
358
+ }
359
+
360
+ await this.writeSettings(settings)
361
+ }
362
+
266
363
  // --- Auth status ---
267
364
 
268
365
  /**
@@ -356,6 +453,13 @@ export class ProviderService {
356
453
  const slots = await this.readSlots()
357
454
  slots[slot] = entry
358
455
  await this.writeSlots(slots)
456
+
457
+ // Auto-sync settings.json so the CLI knows where to connect.
458
+ // When any slot uses a non-anthropic provider, the CLI must go through
459
+ // the local proxy; when all slots are anthropic (or empty), we can
460
+ // write direct provider info instead.
461
+ await this.syncSettingsForSlots(slots)
462
+
359
463
  return slots
360
464
  }
361
465