byterover-cli 2.3.3 → 2.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.
@@ -51,8 +51,6 @@ export declare class ByteRoverLlmHttpService {
51
51
  * Call ByteRover REST LLM service to generate content.
52
52
  *
53
53
  * Simple forward to remote REST API - delegates all formatting to backend.
54
- * Supports both Gemini and Claude formats - the correct format is determined
55
- * automatically based on the model name.
56
54
  *
57
55
  * Parameter structure differs by provider:
58
56
  * - Gemini: contents = Content[], config = GenerateContentConfig
@@ -60,27 +58,22 @@ export declare class ByteRoverLlmHttpService {
60
58
  *
61
59
  * @param contents - For Gemini: Content[]. For Claude: MessageCreateParamsNonStreaming (complete body)
62
60
  * @param config - For Gemini: GenerateContentConfig. For Claude: RequestOptions (optional HTTP options)
63
- * @param model - Model to use (detects provider from model name)
64
61
  * @param executionMetadata - Optional execution metadata (mode, executionContext)
65
62
  * @returns Response in GenerateContentResponse format
66
63
  */
67
- generateContent(contents: Content[] | MessageCreateParamsNonStreaming, config: GenerateContentConfig | RequestOptions, model: string, executionMetadata?: Record<string, unknown>): Promise<GenerateContentResponse>;
64
+ generateContent(contents: Content[] | MessageCreateParamsNonStreaming, config: GenerateContentConfig | RequestOptions, executionMetadata?: Record<string, unknown>): Promise<GenerateContentResponse>;
68
65
  /**
69
66
  * Call ByteRover REST LLM service to generate content with streaming.
70
67
  *
71
- * Currently falls back to non-streaming endpoint since /api/llm/generate/stream
72
- * doesn't exist on the backend yet. Extracts thinking/reasoning from the complete
73
- * response and yields them as separate chunks.
74
- *
75
- * When backend streaming is available, this will use SSE for true streaming.
68
+ * Currently falls back to non-streaming endpoint. Extracts thinking/reasoning
69
+ * from the complete response and yields them as separate chunks.
76
70
  *
77
71
  * @param contents - For Gemini: Content[]. For Claude: MessageCreateParamsNonStreaming (complete body)
78
72
  * @param config - For Gemini: GenerateContentConfig. For Claude: RequestOptions (optional HTTP options)
79
- * @param model - Model to use (detects provider from model name)
80
73
  * @param executionMetadata - Optional execution metadata (mode, executionContext)
81
74
  * @yields GenerateContentChunk objects as they are generated
82
75
  */
83
- generateContentStream(contents: Content[] | MessageCreateParamsNonStreaming, config: GenerateContentConfig | RequestOptions, model: string, executionMetadata?: Record<string, unknown>): AsyncGenerator<GenerateContentChunk>;
76
+ generateContentStream(contents: Content[] | MessageCreateParamsNonStreaming, config: GenerateContentConfig | RequestOptions, executionMetadata?: Record<string, unknown>): AsyncGenerator<GenerateContentChunk>;
84
77
  /**
85
78
  * Call the ByteRover REST Generate endpoint.
86
79
  *
@@ -91,26 +84,6 @@ export declare class ByteRoverLlmHttpService {
91
84
  * @throws Error if the request fails
92
85
  */
93
86
  private callHttpGenerate;
94
- /**
95
- * Detect LLM provider from model identifier.
96
- *
97
- * Determines which provider (Claude or Gemini) to use based on the model name.
98
- * Defaults to Gemini if the model doesn't match Claude patterns.
99
- *
100
- * @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
101
- * @returns Provider name: 'claude' or 'gemini'
102
- */
103
- private detectProviderFromModel;
104
- /**
105
- * Detect appropriate GCP region from model identifier.
106
- *
107
- * Routes Claude models to us-east5 and Gemini models to global.
108
- * This ensures compatibility with the provider's available regions on Vertex AI.
109
- *
110
- * @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
111
- * @returns GCP region identifier ('us-east5' or 'global')
112
- */
113
- private detectRegionFromModel;
114
87
  /**
115
88
  * Extract content chunks from a complete response.
116
89
  *
@@ -33,7 +33,7 @@ export class ByteRoverLlmHttpService {
33
33
  this.config = {
34
34
  apiBaseUrl: config.apiBaseUrl,
35
35
  projectId: config.projectId ?? 'byterover',
36
- region: config.region ?? 'us-east1',
36
+ region: config.region ?? 'global',
37
37
  sessionKey: config.sessionKey,
38
38
  spaceId: config.spaceId,
39
39
  teamId: config.teamId,
@@ -44,8 +44,6 @@ export class ByteRoverLlmHttpService {
44
44
  * Call ByteRover REST LLM service to generate content.
45
45
  *
46
46
  * Simple forward to remote REST API - delegates all formatting to backend.
47
- * Supports both Gemini and Claude formats - the correct format is determined
48
- * automatically based on the model name.
49
47
  *
50
48
  * Parameter structure differs by provider:
51
49
  * - Gemini: contents = Content[], config = GenerateContentConfig
@@ -53,21 +51,18 @@ export class ByteRoverLlmHttpService {
53
51
  *
54
52
  * @param contents - For Gemini: Content[]. For Claude: MessageCreateParamsNonStreaming (complete body)
55
53
  * @param config - For Gemini: GenerateContentConfig. For Claude: RequestOptions (optional HTTP options)
56
- * @param model - Model to use (detects provider from model name)
57
54
  * @param executionMetadata - Optional execution metadata (mode, executionContext)
58
55
  * @returns Response in GenerateContentResponse format
59
56
  */
60
- async generateContent(contents, config, model, executionMetadata) {
57
+ async generateContent(contents, config, executionMetadata) {
61
58
  const request = {
62
59
  executionMetadata: JSON.stringify(executionMetadata ?? {}),
63
60
  params: {
64
61
  config,
65
62
  contents,
66
- model,
67
63
  },
68
64
  project_id: typeof this.config.projectId === 'function' ? this.config.projectId() : this.config.projectId,
69
- provider: this.detectProviderFromModel(model),
70
- region: this.detectRegionFromModel(model),
65
+ region: this.config.region,
71
66
  spaceId: typeof this.config.spaceId === 'function' ? this.config.spaceId() : this.config.spaceId,
72
67
  teamId: typeof this.config.teamId === 'function' ? this.config.teamId() : this.config.teamId,
73
68
  };
@@ -76,22 +71,18 @@ export class ByteRoverLlmHttpService {
76
71
  /**
77
72
  * Call ByteRover REST LLM service to generate content with streaming.
78
73
  *
79
- * Currently falls back to non-streaming endpoint since /api/llm/generate/stream
80
- * doesn't exist on the backend yet. Extracts thinking/reasoning from the complete
81
- * response and yields them as separate chunks.
82
- *
83
- * When backend streaming is available, this will use SSE for true streaming.
74
+ * Currently falls back to non-streaming endpoint. Extracts thinking/reasoning
75
+ * from the complete response and yields them as separate chunks.
84
76
  *
85
77
  * @param contents - For Gemini: Content[]. For Claude: MessageCreateParamsNonStreaming (complete body)
86
78
  * @param config - For Gemini: GenerateContentConfig. For Claude: RequestOptions (optional HTTP options)
87
- * @param model - Model to use (detects provider from model name)
88
79
  * @param executionMetadata - Optional execution metadata (mode, executionContext)
89
80
  * @yields GenerateContentChunk objects as they are generated
90
81
  */
91
- async *generateContentStream(contents, config, model, executionMetadata) {
82
+ async *generateContentStream(contents, config, executionMetadata) {
92
83
  // Fall back to non-streaming endpoint and simulate streaming
93
84
  // by extracting thinking from the complete response
94
- const response = await this.generateContent(contents, config, model, executionMetadata);
85
+ const response = await this.generateContent(contents, config, executionMetadata);
95
86
  // Extract and yield thinking/reasoning chunks first
96
87
  yield* this.extractThinkingFromResponse(response);
97
88
  // Then yield the final content
@@ -115,30 +106,6 @@ export class ByteRoverLlmHttpService {
115
106
  });
116
107
  return httpResponse.data;
117
108
  }
118
- /**
119
- * Detect LLM provider from model identifier.
120
- *
121
- * Determines which provider (Claude or Gemini) to use based on the model name.
122
- * Defaults to Gemini if the model doesn't match Claude patterns.
123
- *
124
- * @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
125
- * @returns Provider name: 'claude' or 'gemini'
126
- */
127
- detectProviderFromModel(model) {
128
- return model.toLowerCase().startsWith('claude') ? 'claude' : 'gemini';
129
- }
130
- /**
131
- * Detect appropriate GCP region from model identifier.
132
- *
133
- * Routes Claude models to us-east5 and Gemini models to global.
134
- * This ensures compatibility with the provider's available regions on Vertex AI.
135
- *
136
- * @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
137
- * @returns GCP region identifier ('us-east5' or 'global')
138
- */
139
- detectRegionFromModel(model) {
140
- return model.toLowerCase().startsWith('claude') ? 'us-east5' : 'global';
141
- }
142
109
  /**
143
110
  * Extract content chunks from a complete response.
144
111
  *
@@ -87,7 +87,7 @@ export class ByteRoverContentGenerator {
87
87
  };
88
88
  // // Debug: Log taskId for tracking
89
89
  // appendFileSync('debug-taskid.log', `[${new Date().toISOString()}] taskId from request: "${request.taskId}"\n`)
90
- const rawResponse = await this.httpService.generateContent(contents, config, this.config.model, executionMetadata);
90
+ const rawResponse = await this.httpService.generateContent(contents, config, executionMetadata);
91
91
  // Parse response to internal format
92
92
  const messages = this.formatter.parseResponse(rawResponse);
93
93
  const lastMessage = messages.at(-1);
@@ -143,7 +143,7 @@ export class ByteRoverContentGenerator {
143
143
  const contents = this.providerType === 'claude' ? genConfig : formattedMessages;
144
144
  const config = this.providerType === 'claude' ? {} : genConfig;
145
145
  // Stream from HTTP service
146
- yield* this.httpService.generateContentStream(contents, config, this.config.model, executionMetadata);
146
+ yield* this.httpService.generateContentStream(contents, config, executionMetadata);
147
147
  }
148
148
  /**
149
149
  * Build Claude-specific generation configuration.
@@ -3,6 +3,7 @@ import axios, { isAxiosError } from 'axios';
3
3
  import crypto from 'node:crypto';
4
4
  import { OAuthTokenData } from '../../core/domain/entities/oauth-token-data.js';
5
5
  import { AuthenticationError } from '../../core/domain/errors/auth-error.js';
6
+ import { ProxyConfig } from '../http/proxy-config.js';
6
7
  export const NETWORK_ERROR_CODE = {
7
8
  EAI_AGAIN: 'EAI_AGAIN',
8
9
  ECONNABORTED: 'ECONNABORTED',
@@ -49,6 +50,8 @@ export class OAuthService {
49
50
  headers: {
50
51
  'Content-Type': 'application/x-www-form-urlencoded',
51
52
  },
53
+ httpAgent: ProxyConfig.getProxyAgent(),
54
+ httpsAgent: ProxyConfig.getProxyAgent(),
52
55
  });
53
56
  return this.parseTokenResponse(response.data);
54
57
  }
@@ -91,6 +94,9 @@ export class OAuthService {
91
94
  client_secret: this.config.clientSecret,
92
95
  grant_type: 'refresh_token',
93
96
  refresh_token: refreshToken,
97
+ }, {
98
+ httpAgent: ProxyConfig.getProxyAgent(),
99
+ httpsAgent: ProxyConfig.getProxyAgent(),
94
100
  });
95
101
  return this.parseTokenResponse(response.data);
96
102
  }
@@ -1,5 +1,6 @@
1
1
  import axios, { isAxiosError } from 'axios';
2
2
  import { DiscoveryError, DiscoveryNetworkError, DiscoveryTimeoutError } from '../../core/domain/errors/discovery-error.js';
3
+ import { ProxyConfig } from '../http/proxy-config.js';
3
4
  /**
4
5
  * OIDC discovery service implementation.
5
6
  * Fetches OIDC configuration from the well-known endpoint with in-memory caching.
@@ -76,6 +77,8 @@ export class OidcDiscoveryService {
76
77
  try {
77
78
  const wellKnownUrl = `${issuerUrl}/.well-known/openid-configuration`;
78
79
  const response = await axios.get(wellKnownUrl, {
80
+ httpAgent: ProxyConfig.getProxyAgent(),
81
+ httpsAgent: ProxyConfig.getProxyAgent(),
79
82
  timeout: this.timeoutMs,
80
83
  });
81
84
  // Validate required fields
@@ -2,6 +2,7 @@
2
2
  import axios from 'axios';
3
3
  import { CogitPushResponse } from '../../core/domain/entities/cogit-push-response.js';
4
4
  import { getErrorMessage } from '../../utils/error-helpers.js';
5
+ import { ProxyConfig } from '../http/proxy-config.js';
5
6
  /**
6
7
  * Extracts the current SHA from an error response details field.
7
8
  * Error format: "...Expected SHA 'xxx' but current SHA is 'yyy'..."
@@ -96,6 +97,8 @@ export class HttpCogitPushService {
96
97
  headers: {
97
98
  'x-byterover-session-id': params.sessionKey,
98
99
  },
100
+ httpAgent: ProxyConfig.getProxyAgent(),
101
+ httpsAgent: ProxyConfig.getProxyAgent(),
99
102
  timeout: this.config.timeout,
100
103
  });
101
104
  return CogitPushResponse.fromJson(response.data);
@@ -1,4 +1,5 @@
1
1
  import axios, { isAxiosError } from 'axios';
2
+ import { ProxyConfig } from './proxy-config.js';
2
3
  /**
3
4
  * HTTP client implementation that automatically adds authentication headers to all requests.
4
5
  *
@@ -27,6 +28,8 @@ export class AuthenticatedHttpClient {
27
28
  try {
28
29
  const axiosConfig = {
29
30
  headers: this.buildHeaders(config?.headers),
31
+ httpAgent: ProxyConfig.getProxyAgent(),
32
+ httpsAgent: ProxyConfig.getProxyAgent(),
30
33
  timeout: config?.timeout,
31
34
  };
32
35
  const response = await axios.get(url, axiosConfig);
@@ -48,6 +51,8 @@ export class AuthenticatedHttpClient {
48
51
  try {
49
52
  const axiosConfig = {
50
53
  headers: this.buildHeaders(config?.headers),
54
+ httpAgent: ProxyConfig.getProxyAgent(),
55
+ httpsAgent: ProxyConfig.getProxyAgent(),
51
56
  timeout: config?.timeout,
52
57
  };
53
58
  const response = await axios.post(url, data, axiosConfig);
@@ -69,6 +74,8 @@ export class AuthenticatedHttpClient {
69
74
  try {
70
75
  const axiosConfig = {
71
76
  headers: this.buildHeaders(config?.headers),
77
+ httpAgent: ProxyConfig.getProxyAgent(),
78
+ httpsAgent: ProxyConfig.getProxyAgent(),
72
79
  timeout: config?.timeout,
73
80
  };
74
81
  const response = await axios.put(url, data, axiosConfig);
@@ -107,13 +114,21 @@ export class AuthenticatedHttpClient {
107
114
  // Server responded with error status
108
115
  return new Error(`HTTP ${error.response.status}: ${error.response.statusText}`);
109
116
  }
110
- if (error.code === 'ECONNABORTED' || error.message.includes('timeout')) {
111
- // Request timeout
112
- return new Error(`Request timeout: ${error.message}`);
117
+ // Enterprise Proxy / SSL Checks
118
+ if (error.code === 'SELF_SIGNED_CERT_IN_CHAIN' || error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' || error.code === 'CERT_HAS_EXPIRED') {
119
+ return new Error(`SSL Certificate Validation Failed (${error.code}). Your company may be using SSL Inspection.\n` +
120
+ `Solution: Set the NODE_EXTRA_CA_CERTS environment variable to your corporate CA certificate path.\n` +
121
+ `Example: export NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem`);
122
+ }
123
+ const isTimeout = error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT' || error.message.includes('timeout');
124
+ const isRefused = error.code === 'ECONNREFUSED';
125
+ if (isTimeout || isRefused) {
126
+ return new Error(`Connection Failed (${error.code || 'TIMEOUT'}). If you are behind a corporate firewall, configure your proxy:\n` +
127
+ ` export HTTPS_PROXY=http://proxy-host:port`);
113
128
  }
114
129
  if (error.request) {
115
130
  // Request was made but no response received
116
- return new Error('Network error: No response received from server');
131
+ return new Error('Network error: No response received from server. Check your proxy or internet connection.');
117
132
  }
118
133
  }
119
134
  // Generic error
@@ -10,6 +10,7 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
10
10
  import { dirname, join } from 'node:path';
11
11
  import { z } from 'zod';
12
12
  import { getGlobalDataDir } from '../../utils/global-data-path.js';
13
+ import { ProxyConfig } from './proxy-config.js';
13
14
  const CacheEnvelopeSchema = z.object({
14
15
  data: z.record(z.unknown()),
15
16
  timestamp: z.number(),
@@ -57,6 +58,8 @@ export class ModelsDevClient {
57
58
  }
58
59
  async fetchAndCache() {
59
60
  const response = await axios.get(MODELS_DEV_URL, {
61
+ httpAgent: ProxyConfig.getProxyAgent(),
62
+ httpsAgent: ProxyConfig.getProxyAgent(),
60
63
  timeout: FETCH_TIMEOUT_MS,
61
64
  });
62
65
  const { data } = response;
@@ -8,6 +8,7 @@
8
8
  * Uses the OpenRouter REST API: https://openrouter.ai/api/v1
9
9
  */
10
10
  import axios, { isAxiosError } from 'axios';
11
+ import { ProxyConfig } from './proxy-config.js';
11
12
  const DEFAULT_BASE_URL = 'https://openrouter.ai/api/v1';
12
13
  const DEFAULT_CACHE_TTL = 60 * 60 * 1000; // 1 hour
13
14
  /**
@@ -100,6 +101,8 @@ export class OpenRouterApiClient {
100
101
  'HTTP-Referer': this.httpReferer,
101
102
  'X-Title': this.xTitle,
102
103
  },
104
+ httpAgent: ProxyConfig.getProxyAgent(),
105
+ httpsAgent: ProxyConfig.getProxyAgent(),
103
106
  timeout: 30_000,
104
107
  });
105
108
  return response.data.data.map((model) => this.normalizeModel(model));
@@ -16,6 +16,7 @@ import { APICallError, generateText } from 'ai';
16
16
  import axios, { isAxiosError } from 'axios';
17
17
  import OpenAI from 'openai';
18
18
  import { getModelsDevClient as getModelsDevClientDefault } from './models-dev-client.js';
19
+ import { ProxyConfig } from './proxy-config.js';
19
20
  const DEFAULT_CACHE_TTL = 60 * 60 * 1000; // 1 hour
20
21
  const ANTHROPIC_KNOWN_MODELS = {
21
22
  'claude-3-5-haiku-20241022': { contextLength: 200_000, inputPerM: 0.8, outputPerM: 4 },
@@ -346,6 +347,8 @@ export class OpenAICompatibleModelFetcher {
346
347
  }
347
348
  const response = await axios.get(`${this.baseUrl}/models`, {
348
349
  headers: { Authorization: `Bearer ${apiKey}` },
350
+ httpAgent: ProxyConfig.getProxyAgent(),
351
+ httpsAgent: ProxyConfig.getProxyAgent(),
349
352
  timeout: 30_000,
350
353
  });
351
354
  // Handle different response formats:
@@ -376,6 +379,8 @@ export class OpenAICompatibleModelFetcher {
376
379
  try {
377
380
  await axios.get(`${this.baseUrl}/models`, {
378
381
  headers: { Authorization: `Bearer ${apiKey}` },
382
+ httpAgent: ProxyConfig.getProxyAgent(),
383
+ httpsAgent: ProxyConfig.getProxyAgent(),
379
384
  timeout: 15_000,
380
385
  });
381
386
  return { isValid: true };
@@ -431,6 +436,8 @@ export class ChatBasedModelFetcher {
431
436
  Authorization: `Bearer ${apiKey}`,
432
437
  'Content-Type': 'application/json',
433
438
  },
439
+ httpAgent: ProxyConfig.getProxyAgent(),
440
+ httpsAgent: ProxyConfig.getProxyAgent(),
434
441
  timeout: 15_000,
435
442
  });
436
443
  return { isValid: true };
@@ -0,0 +1,5 @@
1
+ import { ProxyAgent } from 'proxy-agent';
2
+ export declare class ProxyConfig {
3
+ private static agent;
4
+ static getProxyAgent(): ProxyAgent;
5
+ }
@@ -0,0 +1,10 @@
1
+ import { ProxyAgent } from 'proxy-agent';
2
+ export class ProxyConfig {
3
+ static agent;
4
+ static getProxyAgent() {
5
+ if (!this.agent) {
6
+ this.agent = new ProxyAgent();
7
+ }
8
+ return this.agent;
9
+ }
10
+ }
@@ -1,6 +1,7 @@
1
1
  import axios, { isAxiosError } from 'axios';
2
2
  import { join } from 'node:path';
3
3
  import { BRV_DIR, CONTEXT_TREE_DIR } from '../../constants.js';
4
+ import { ProxyConfig } from '../http/proxy-config.js';
4
5
  import { buildAuthHeaders } from './hub-auth-headers.js';
5
6
  export class HubInstallService {
6
7
  fileService;
@@ -30,6 +31,8 @@ export class HubInstallService {
30
31
  const headers = buildAuthHeaders(auth ?? {});
31
32
  const response = await axios.get(url, {
32
33
  headers,
34
+ httpAgent: ProxyConfig.getProxyAgent(),
35
+ httpsAgent: ProxyConfig.getProxyAgent(),
33
36
  responseType: 'text',
34
37
  timeout: 15_000,
35
38
  });
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable camelcase */
2
2
  import axios, { isAxiosError } from 'axios';
3
3
  import { z } from 'zod';
4
+ import { ProxyConfig } from '../http/proxy-config.js';
4
5
  import { buildAuthHeaders } from './hub-auth-headers.js';
5
6
  const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
6
7
  const HubEntrySchema = z.object({
@@ -69,6 +70,8 @@ export class HubRegistryService {
69
70
  });
70
71
  const response = await axios.get(this.registryUrl, {
71
72
  headers,
73
+ httpAgent: ProxyConfig.getProxyAgent(),
74
+ httpsAgent: ProxyConfig.getProxyAgent(),
72
75
  timeout: this.timeoutMs,
73
76
  });
74
77
  const validated = this.parseRegistryResponse(response.data);
@@ -4,6 +4,7 @@ import { PresignedUrl } from '../../core/domain/entities/presigned-url.js';
4
4
  import { PresignedUrlsResponse } from '../../core/domain/entities/presigned-urls-response.js';
5
5
  import { getErrorMessage } from '../../utils/error-helpers.js';
6
6
  import { AuthenticatedHttpClient } from '../http/authenticated-http-client.js';
7
+ import { ProxyConfig } from '../http/proxy-config.js';
7
8
  /**
8
9
  * HTTP implementation of IMemoryStorageService for ByteRover CoGit service.
9
10
  * Handles uploading playbooks to blob storage.
@@ -55,6 +56,8 @@ export class HttpMemoryStorageService {
55
56
  headers: {
56
57
  'Content-Type': 'application/json',
57
58
  },
59
+ httpAgent: ProxyConfig.getProxyAgent(),
60
+ httpsAgent: ProxyConfig.getProxyAgent(),
58
61
  timeout: this.config.timeout,
59
62
  });
60
63
  }
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable camelcase */
2
2
  import axios, { isAxiosError } from 'axios';
3
+ import { ProxyConfig } from '../http/proxy-config.js';
3
4
  import { extractOAuthErrorFields, ProviderTokenExchangeError } from './errors.js';
4
5
  import { ProviderTokenResponseSchema } from './types.js';
5
6
  /**
@@ -20,6 +21,8 @@ export async function exchangeRefreshToken(params) {
20
21
  headers: {
21
22
  'Content-Type': params.contentType,
22
23
  },
24
+ httpAgent: ProxyConfig.getProxyAgent(),
25
+ httpsAgent: ProxyConfig.getProxyAgent(),
23
26
  timeout: 30_000,
24
27
  });
25
28
  }
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable camelcase */
2
2
  import axios, { isAxiosError } from 'axios';
3
+ import { ProxyConfig } from '../http/proxy-config.js';
3
4
  import { extractOAuthErrorFields, ProviderTokenExchangeError } from './errors.js';
4
5
  import { ProviderTokenResponseSchema } from './types.js';
5
6
  /**
@@ -25,6 +26,8 @@ export async function exchangeCodeForTokens(params) {
25
26
  headers: {
26
27
  'Content-Type': params.contentType,
27
28
  },
29
+ httpAgent: ProxyConfig.getProxyAgent(),
30
+ httpsAgent: ProxyConfig.getProxyAgent(),
28
31
  timeout: 30_000,
29
32
  });
30
33
  }
@@ -1636,5 +1636,5 @@
1636
1636
  ]
1637
1637
  }
1638
1638
  },
1639
- "version": "2.3.3"
1639
+ "version": "2.4.0"
1640
1640
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "byterover-cli",
3
3
  "description": "ByteRover's CLI",
4
- "version": "2.3.3",
4
+ "version": "2.4.0",
5
5
  "author": "ByteRover",
6
6
  "bin": {
7
7
  "brv": "./bin/run.js"
@@ -55,6 +55,7 @@
55
55
  "officeparser": "^6.0.4",
56
56
  "open": "^10.2.0",
57
57
  "openai": "^6.9.1",
58
+ "proxy-agent": "^7.0.0",
58
59
  "react": "^19.2.1",
59
60
  "react-router-dom": "^7.13.0",
60
61
  "remark-parse": "^11.0.0",