bingocode 1.0.17 → 1.0.19

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.
@@ -71,7 +71,7 @@ export class HahaOAuthService {
71
71
  private getOAuthFilePath(): string {
72
72
  const configDir =
73
73
  process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude')
74
- return path.join(configDir, 'cc-haha', 'oauth.json')
74
+ return path.join(configDir, 'bingo', 'oauth.json')
75
75
  }
76
76
 
77
77
  async loadTokens(): Promise<StoredOAuthTokens | null> {
@@ -6,7 +6,7 @@ import { loadPresets, applyPreset } from '../config/providerPresets.ts';
6
6
  import axios from 'axios';
7
7
 
8
8
  const home = process.env.CLAUDE_CONFIG_DIR || os.homedir();
9
- const PROVIDERS_PATH = path.resolve(home, '.claude', 'cc-haha', 'providers.json');
9
+ const PROVIDERS_PATH = path.resolve(home, '.claude', 'bingo', 'providers.json');
10
10
 
11
11
  export class ProviderManager {
12
12
  static async load(): Promise<ProvidersIndex> {
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Provider Service — preset-based provider configuration
3
3
  *
4
- * Storage: ~/.claude/cc-haha/providers.json (lightweight index)
5
- * Active provider env vars written to ~/.claude/cc-haha/settings.json
4
+ * Storage: ~/.claude/bingo/providers.json (lightweight index)
5
+ * Active provider env vars written to ~/.claude/bingo/settings.json
6
6
  * (isolated from the original Claude Code's ~/.claude/settings.json)
7
7
  */
8
8
 
@@ -58,7 +58,7 @@ export class ProviderService {
58
58
  }
59
59
 
60
60
  private getCcHahaDir(): string {
61
- return path.join(this.getConfigDir(), 'cc-haha')
61
+ return path.join(this.getConfigDir(), 'bingo')
62
62
  }
63
63
 
64
64
  private getIndexPath(): string {
@@ -267,22 +267,22 @@ export class ProviderService {
267
267
 
268
268
  /**
269
269
  * Check whether any usable auth exists:
270
- * 1. A cc-haha provider is active → has auth
270
+ * 1. A bingo provider is active → has auth
271
271
  * 2. Original ~/.claude/settings.json has ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY → has auth
272
272
  * 3. process.env already has ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN → has auth
273
273
  * 4. None of the above → needs setup
274
274
  */
275
275
  async checkAuthStatus(): Promise<{
276
276
  hasAuth: boolean
277
- source: 'cc-haha-provider' | 'original-settings' | 'env' | 'none'
277
+ source: 'bingo-provider' | 'original-settings' | 'env' | 'none'
278
278
  activeProvider?: string
279
279
  }> {
280
- // 1. Check cc-haha active provider
280
+ // 1. Check bingo active provider
281
281
  const index = await this.readIndex()
282
282
  if (index.activeId) {
283
283
  const provider = index.providers.find(p => p.id === index.activeId)
284
284
  if (provider?.apiKey) {
285
- return { hasAuth: true, source: 'cc-haha-provider', activeProvider: provider.name }
285
+ return { hasAuth: true, source: 'bingo-provider', activeProvider: provider.name }
286
286
  }
287
287
  }
288
288
 
@@ -364,6 +364,7 @@ export class ProviderService {
364
364
  apiKey: string
365
365
  apiFormat: ApiFormat
366
366
  modelId: string
367
+ label?: string | null
367
368
  } | null> {
368
369
  const slots = await this.readSlots()
369
370
  const entry = slots[slotName]
@@ -376,6 +377,7 @@ export class ProviderService {
376
377
  apiKey: provider.apiKey,
377
378
  apiFormat: provider.apiFormat ?? 'anthropic',
378
379
  modelId: entry.modelId,
380
+ label: entry.label,
379
381
  }
380
382
  }
381
383
 
@@ -384,7 +386,12 @@ export class ProviderService {
384
386
  const preset = PROVIDER_PRESETS.find(p => p.id === provider.presetId)
385
387
 
386
388
  const base = provider.baseUrl.replace(/\/+$/, '')
387
- if (!base) return []
389
+ if (!base && provider.presetId !== 'official') return []
390
+
391
+ // Special case for Official
392
+ if (provider.presetId === 'official') {
393
+ return ['claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', 'claude-3-haiku-20240307']
394
+ }
388
395
 
389
396
  const modelsUrl = preset?.modelsUrl || '/v1/models'
390
397
  const url = `${base}${modelsUrl}`
@@ -402,9 +409,10 @@ export class ProviderService {
402
409
  }
403
410
 
404
411
  try {
405
- const directOpts = getDirectFetchOptions()
406
- const res = await fetch(url, { headers, signal: AbortSignal.timeout(10000), ...directOpts })
412
+ const fetchOpts = getProxyFetchOptions()
413
+ const res = await fetch(url, { headers, signal: AbortSignal.timeout(10000), ...fetchOpts })
407
414
  if (!res.ok) {
415
+ console.error(`[ProviderService] Failed to fetch models from ${url}: ${res.status}`)
408
416
  return []
409
417
  }
410
418
  const data = await res.json() as any
@@ -412,7 +420,8 @@ export class ProviderService {
412
420
  const list = data[dataPath] ?? data.data ?? data.models ?? []
413
421
  if (!Array.isArray(list)) return []
414
422
  return list.map((m: any) => (typeof m === 'string' ? m : m.id)).filter(Boolean)
415
- } catch {
423
+ } catch (err) {
424
+ console.error(`[ProviderService] Error fetching models from ${url}:`, err)
416
425
  return []
417
426
  }
418
427
  }
@@ -425,9 +434,17 @@ export class ProviderService {
425
434
  ): Promise<ProviderTestResult> {
426
435
  const provider = await this.getProvider(id)
427
436
  const baseUrl = overrides?.baseUrl || provider.baseUrl
428
- const modelId = overrides?.modelId || provider.models.main
429
437
  const apiFormat = overrides?.apiFormat ?? provider.apiFormat ?? 'anthropic'
430
438
 
439
+ // If no modelId provided, try to fetch from provider or use preset default
440
+ let modelId = overrides?.modelId || provider.models.main
441
+ if (!modelId || modelId === 'auto' || modelId.startsWith('claude-')) {
442
+ const fetched = await this.fetchProviderModels(id).catch(() => [])
443
+ if (fetched.length > 0) {
444
+ modelId = fetched[0] // Use first available model for testing
445
+ }
446
+ }
447
+
431
448
  if (!baseUrl || !provider.apiKey) {
432
449
  return { connectivity: { success: false, latencyMs: 0, error: 'Missing baseUrl or apiKey' } }
433
450
  }
@@ -474,6 +491,7 @@ export class ProviderService {
474
491
  const start = Date.now()
475
492
  try {
476
493
  const { url, headers, body } = buildDirectTestRequest(base, apiKey, modelId, format)
494
+ // 使用 getDirectFetchOptions 以绕开系统代理,测试直接连接
477
495
  const directOpts = getDirectFetchOptions()
478
496
  const response = await fetch(url, {
479
497
  method: 'POST',
@@ -538,13 +556,13 @@ export class ProviderService {
538
556
  }
539
557
 
540
558
  // Call upstream with transformed request
541
- const directOpts = getDirectFetchOptions()
559
+ const fetchOpts = getProxyFetchOptions()
542
560
  const response = await fetch(upstreamUrl, {
543
561
  method: 'POST',
544
562
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
545
563
  body: JSON.stringify(transformedBody),
546
564
  signal: AbortSignal.timeout(30000),
547
- ...directOpts,
565
+ ...fetchOpts,
548
566
  })
549
567
 
550
568
  if (!response.ok) {
@@ -82,6 +82,7 @@ export type SlotName = z.infer<typeof SlotNameSchema>
82
82
  export const SlotEntrySchema = z.object({
83
83
  providerId: z.string(),
84
84
  modelId: z.string(),
85
+ label: z.string().nullable().optional(), // Display name for UI
85
86
  }).nullable()
86
87
  export type SlotEntry = z.infer<typeof SlotEntrySchema>
87
88
 
@@ -263,7 +263,7 @@ async function runDesktopPermissionDialog(
263
263
  }
264
264
 
265
265
  /**
266
- * Load pre-authorized apps from ~/.claude/cc-haha/computer-use-config.json.
266
+ * Load pre-authorized apps from ~/.claude/bingo/computer-use-config.json.
267
267
  * Called once when the binding is first created. Pre-authorized apps
268
268
  * are injected into appState so `getAllowedApps()` returns them
269
269
  * immediately — no runtime permission dialog needed.
@@ -272,7 +272,7 @@ async function loadPreAuthorizedApps(): Promise<void> {
272
272
  try {
273
273
  const configPath = join(
274
274
  process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), '.claude'),
275
- 'cc-haha',
275
+ 'bingo',
276
276
  'computer-use-config.json',
277
277
  )
278
278
  const raw = await readFile(configPath, 'utf8')
@@ -98,15 +98,23 @@ function filterSettingsEnv(
98
98
  * contains ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, model defaults, etc.
99
99
  * Returns an empty object if the file doesn't exist or is invalid.
100
100
  */
101
- function getCcHahaSettingsEnv(): Record<string, string> {
102
- try {
103
- const bingoSettings = join(getClaudeConfigHomeDir(), 'bingo', 'settings.json')
104
- const raw = readFileSync(bingoSettings, 'utf-8')
105
- const parsed = JSON.parse(raw) as { env?: Record<string, string> }
106
- return parsed.env ?? {}
107
- } catch {
108
- return {}
101
+ function getBingoSettingsEnv(): Record<string, string> {
102
+ const configDir = getClaudeConfigHomeDir()
103
+ const paths = [
104
+ join(configDir, 'bingo', 'settings.json'),
105
+ join(configDir, 'cc-haha', 'settings.json'), // Fallback for migration
106
+ ]
107
+
108
+ for (const settingsPath of paths) {
109
+ try {
110
+ const raw = readFileSync(settingsPath, 'utf-8')
111
+ const parsed = JSON.parse(raw) as { env?: Record<string, string> }
112
+ if (parsed.env) return parsed.env
113
+ } catch {
114
+ continue
115
+ }
109
116
  }
117
+ return {}
110
118
  }
111
119
 
112
120
  /**
@@ -167,11 +175,11 @@ export function applySafeConfigEnvironmentVariables(): void {
167
175
  )
168
176
  }
169
177
 
170
- // cc-haha provider isolation: apply env from ~/.claude/cc-haha/settings.json
171
- // AFTER userSettings so Haha-specific provider config takes priority over
172
- // the original Claude Code's settings. This prevents Haha from polluting
178
+ // bingo provider isolation: apply env from ~/.claude/bingo/settings.json
179
+ // AFTER userSettings so Bingo-specific provider config takes priority over
180
+ // the original Claude Code's settings. This prevents Bingo from polluting
173
181
  // ~/.claude/settings.json while still allowing it to override provider vars.
174
- Object.assign(process.env, filterSettingsEnv(getCcHahaSettingsEnv()))
182
+ Object.assign(process.env, filterSettingsEnv(getBingoSettingsEnv()))
175
183
 
176
184
  // Compute remote-managed-settings eligibility now, with userSettings and
177
185
  // flagSettings env applied. Eligibility reads CLAUDE_CODE_USE_BEDROCK,
@@ -214,9 +222,9 @@ export function applyConfigEnvironmentVariables(): void {
214
222
 
215
223
  Object.assign(process.env, filterSettingsEnv(getSettings_DEPRECATED()?.env))
216
224
 
217
- // cc-haha provider isolation: same as in applySafeConfigEnvironmentVariables,
218
- // apply Haha-specific env last so it overrides the original settings.
219
- Object.assign(process.env, filterSettingsEnv(getCcHahaSettingsEnv()))
225
+ // bingo provider isolation: same as in applySafeConfigEnvironmentVariables,
226
+ // apply Bingo-specific env last so it overrides the original settings.
227
+ Object.assign(process.env, filterSettingsEnv(getBingoSettingsEnv()))
220
228
 
221
229
  // Clear caches so agents are rebuilt with the new env vars
222
230
  clearCACertsCache()
@@ -334,14 +334,26 @@ export function getDirectFetchOptions(): {
334
334
  return { ...base, proxy: undefined, ...getTLSFetchOptions() }
335
335
  }
336
336
 
337
+ // Check if system proxy exists
338
+ const proxyUrl = getProxyUrl()
339
+ if (!proxyUrl) {
340
+ // No proxy configured, just return normal fetch options
341
+ return { ...base, ...getTLSFetchOptions() }
342
+ }
343
+
337
344
  // In Node.js/undici, a fresh Agent with no proxy settings bypasses system defaults
338
345
  // eslint-disable-next-line @typescript-eslint/no-require-imports
339
346
  const undiciMod = require('undici') as typeof undici
340
347
  const tlsOpts = getTLSFetchOptions()
341
348
 
349
+ // Use the global dispatcher's options if possible, or fresh default options
350
+ const agentOptions = tlsOpts.dispatcher && 'options' in (tlsOpts.dispatcher as any)
351
+ ? (tlsOpts.dispatcher as any).options
352
+ : {}
353
+
342
354
  return {
343
355
  ...base,
344
- dispatcher: new undiciMod.Agent(tlsOpts.dispatcher ? (tlsOpts.dispatcher as any).options : {}),
356
+ dispatcher: new undiciMod.Agent(agentOptions),
345
357
  }
346
358
  }
347
359