@@ -19,6 +19,7 @@ import { V2Writer } from './lib/v2/v2-writer.js';
1919import { reportSwallowed } from './lib/error-report.js' ;
2020import { latestMainSessionDir , sessionHasCompletedMainTurn } from './lib/v2/session-select.js' ;
2121import { sanitizePathComponent } from './lib/v2/layout.js' ;
22+ import { setRetryConfigPath , loadRetryConfig , DEFAULT_RETRY_CONFIG } from './lib/proxy-retry.js' ;
2223
2324
2425
@@ -81,6 +82,26 @@ export let _cachedHaikuModel = null;
8182const PROFILE_PATH = join ( LOG_DIR , 'profile.json' ) ;
8283let _activeProfile = null ; // { id, name, baseURL?, apiKey?, effort?, ANTHROPIC_MODEL?, ANTHROPIC_DEFAULT_OPUS_MODEL?, ANTHROPIC_DEFAULT_SONNET_MODEL?, ANTHROPIC_DEFAULT_HAIKU_MODEL?, activeModel?(legacy) }
8384
85+ // ── 代理重试配置(运行时热切换,对齐 profile 模式)──
86+ // retry-config.json 存全局共享的重试配置(mode/interval/maxRetries/maxConcurrent 等)。
87+ // env(CCV_PROXY_RETRY_*)仍是启动默认/兜底,文件字段覆盖 env(文件优先)。
88+ // watchFile 1.5s 跨 ccv 进程同步;proxy.js 经 namespace import 读 _retryConfigState live binding。
89+ const RETRY_CONFIG_PATH = join ( LOG_DIR , 'retry-config.json' ) ;
90+ let _retryConfigState = { ...DEFAULT_RETRY_CONFIG } ; // 可变,由 _loadRetryConfigState 刷新
91+
92+ // 把配置文件路径注入 proxy-retry.js(其 resolveRetryConfig 在 fileOverride=true 时读此路径)。
93+ // 在模块加载阶段同步注入,确保后续 _loadRetryConfigState() 调用时路径已就绪。
94+ setRetryConfigPath ( RETRY_CONFIG_PATH ) ;
95+
96+ /** 重读 retry-config.json + env 合并,刷新 _retryConfigState(live binding 消费方即取到新值)。 */
97+ function _loadRetryConfigState ( ) {
98+ try {
99+ _retryConfigState = loadRetryConfig ( ) ;
100+ } catch ( err ) {
101+ if ( process . env . CCV_DEBUG ) console . error ( '[ccv retry-config] _loadRetryConfigState failed:' , err && err . message ) ;
102+ }
103+ }
104+
84105// 启动时捕获的原始配置(首次 API 请求时记录,不可变)
85106let _defaultConfig = null ; // { origin, authType, model }
86107
@@ -200,7 +221,7 @@ function _replaceProxyAuthHeaders(headers, apiKey) {
200221 return { headers : newHeaders , matchedAuthKey, matchedXApiKey } ;
201222}
202223
203- export { _activeProfile , _defaultConfig , _loadProxyProfile , PROFILE_PATH , setActiveProfileForWorkspace , getActiveProfileId } ;
224+ export { _activeProfile , _defaultConfig , _loadProxyProfile , PROFILE_PATH , setActiveProfileForWorkspace , getActiveProfileId , RETRY_CONFIG_PATH , _retryConfigState , _loadRetryConfigState } ;
204225
205226// 1.7.0: the v1 single-file write path is retired — logs live in per-session
206227// v2 dirs owned by V2Writer. Only the project binding (name + dir) remains
@@ -420,6 +441,11 @@ _syncContinuationMode(); // seed from the CLI env at module load (`ccv -c`)
420441_loadProxyProfile ( ) ;
421442try { watchFile ( PROFILE_PATH , { interval : 1500 } , _loadProxyProfile ) ; } catch { }
422443
444+ // Retry config: initial load + watchFile cross-process sync (UI writes
445+ // retry-config.json → hot-reloaded within 1.5s, mirroring PROFILE_PATH above).
446+ _loadRetryConfigState ( ) ;
447+ try { watchFile ( RETRY_CONFIG_PATH , { interval : 1500 } , _loadRetryConfigState ) ; } catch { }
448+
423449// Kept as an awaited boot barrier for callers; nothing asynchronous remains
424450// since the v1 resume flow retired (v2 sessions key off wire session_ids).
425451const _initPromise = Promise . resolve ( ) ;
0 commit comments