antigravity-claude-proxy 2.9.3 → 3.0.1
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/README.md +1 -1
- package/bin/cli.js +4 -11
- package/package.json +5 -5
- package/public/app.js +7 -4
- package/public/css/src/input.css +0 -7
- package/public/css/style.css +1 -1
- package/public/js/components/claude-config.js +0 -8
- package/public/js/components/dashboard/charts.js +8 -8
- package/public/js/components/dashboard/stats.js +1 -1
- package/public/js/components/logs-viewer.js +1 -1
- package/public/js/components/models.js +2 -3
- package/public/js/components/server-config.js +1 -9
- package/public/js/data-store.js +2 -2
- package/public/js/store.js +1 -1
- package/public/js/translations/en.js +0 -2
- package/public/js/translations/id.js +0 -1
- package/public/js/translations/pt.js +0 -1
- package/public/js/translations/tr.js +0 -2
- package/public/js/translations/zh.js +0 -2
- package/public/js/utils/error-handler.js +0 -2
- package/public/js/utils/ui-logger.js +4 -3
- package/src/account-manager/index.js +0 -4
- package/src/account-manager/rate-limits.js +0 -5
- package/src/account-manager/strategies/base-strategy.js +4 -4
- package/src/account-manager/strategies/hybrid-strategy.js +3 -3
- package/src/auth/database.js +1 -0
- package/src/auth/oauth.js +43 -41
- package/src/auth/token-extractor.js +1 -1
- package/src/cli/accounts.js +2 -1
- package/src/cloudcode/model-registry.js +0 -3
- package/src/cloudcode/rate-limit-state.js +1 -7
- package/src/config.js +1 -1
- package/src/constants.js +0 -2
- package/src/format/content-converter.js +0 -4
- package/src/format/request-converter.js +1 -6
- package/src/format/response-converter.js +0 -3
- package/src/format/schema-sanitizer.js +3 -22
- package/src/format/thinking-utils.js +1 -13
- package/src/index.js +1 -6
- package/src/modules/usage-stats.js +1 -1
- package/src/server.js +8 -29
- package/src/utils/claude-config.js +2 -6
- package/src/utils/native-module-helper.js +0 -4
- package/src/utils/proxy.js +1 -10
- package/src/utils/version-detector.js +14 -5
- package/src/webui/index.js +1 -37
|
@@ -203,10 +203,6 @@ window.Components.claudeConfig = () => ({
|
|
|
203
203
|
}
|
|
204
204
|
},
|
|
205
205
|
|
|
206
|
-
// ==========================================
|
|
207
|
-
// Presets Management
|
|
208
|
-
// ==========================================
|
|
209
|
-
|
|
210
206
|
/**
|
|
211
207
|
* Fetch all saved presets from the server
|
|
212
208
|
*/
|
|
@@ -438,10 +434,6 @@ window.Components.claudeConfig = () => ({
|
|
|
438
434
|
}
|
|
439
435
|
},
|
|
440
436
|
|
|
441
|
-
// ==========================================
|
|
442
|
-
// Mode Toggle (Proxy/Paid)
|
|
443
|
-
// ==========================================
|
|
444
|
-
|
|
445
437
|
/**
|
|
446
438
|
* Fetch current mode from server
|
|
447
439
|
*/
|
|
@@ -75,7 +75,7 @@ function isCanvasReady(canvas) {
|
|
|
75
75
|
try {
|
|
76
76
|
const ctx = canvas.getContext("2d");
|
|
77
77
|
return !!ctx;
|
|
78
|
-
} catch
|
|
78
|
+
} catch {
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -139,14 +139,14 @@ window.DashboardCharts.updateCharts = function (component) {
|
|
|
139
139
|
|
|
140
140
|
// Safety checks
|
|
141
141
|
if (!canvas) {
|
|
142
|
-
|
|
142
|
+
window.UILogger?.debug("quotaChart canvas not found");
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// FORCE DESTROY: Check for existing chart on the canvas element property
|
|
147
147
|
// This handles cases where Component state is lost but DOM persists
|
|
148
148
|
if (canvas._chartInstance) {
|
|
149
|
-
|
|
149
|
+
window.UILogger?.debug("Destroying existing quota chart from canvas property");
|
|
150
150
|
try {
|
|
151
151
|
canvas._chartInstance.destroy();
|
|
152
152
|
} catch(e) { if (window.UILogger) window.UILogger.debug(e); }
|
|
@@ -157,7 +157,7 @@ window.DashboardCharts.updateCharts = function (component) {
|
|
|
157
157
|
if (component.charts.quotaDistribution) {
|
|
158
158
|
try {
|
|
159
159
|
component.charts.quotaDistribution.destroy();
|
|
160
|
-
} catch(e) { }
|
|
160
|
+
} catch (e) { window.UILogger?.debug("quotaDistribution destroy failed", e); }
|
|
161
161
|
component.charts.quotaDistribution = null;
|
|
162
162
|
}
|
|
163
163
|
|
|
@@ -165,7 +165,7 @@ window.DashboardCharts.updateCharts = function (component) {
|
|
|
165
165
|
if (typeof Chart !== "undefined" && Chart.getChart) {
|
|
166
166
|
const regChart = Chart.getChart(canvas);
|
|
167
167
|
if (regChart) {
|
|
168
|
-
try { regChart.destroy(); } catch(e) {}
|
|
168
|
+
try { regChart.destroy(); } catch (e) { window.UILogger?.debug("Registry chart destroy failed", e); }
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -332,7 +332,7 @@ window.DashboardCharts.updateTrendChart = function (component) {
|
|
|
332
332
|
// FORCE DESTROY: Check for existing chart on the canvas element property
|
|
333
333
|
if (canvas) {
|
|
334
334
|
if (canvas._chartInstance) {
|
|
335
|
-
|
|
335
|
+
window.UILogger?.debug("Destroying existing trend chart from canvas property");
|
|
336
336
|
try {
|
|
337
337
|
canvas._chartInstance.stop();
|
|
338
338
|
canvas._chartInstance.destroy();
|
|
@@ -344,7 +344,7 @@ window.DashboardCharts.updateTrendChart = function (component) {
|
|
|
344
344
|
if (typeof Chart !== "undefined" && Chart.getChart) {
|
|
345
345
|
const regChart = Chart.getChart(canvas);
|
|
346
346
|
if (regChart) {
|
|
347
|
-
try { regChart.stop(); regChart.destroy(); } catch(e) {}
|
|
347
|
+
try { regChart.stop(); regChart.destroy(); } catch (e) { window.UILogger?.debug("Registry chart destroy failed", e); }
|
|
348
348
|
}
|
|
349
349
|
}
|
|
350
350
|
}
|
|
@@ -354,7 +354,7 @@ window.DashboardCharts.updateTrendChart = function (component) {
|
|
|
354
354
|
try {
|
|
355
355
|
component.charts.usageTrend.stop();
|
|
356
356
|
component.charts.usageTrend.destroy();
|
|
357
|
-
} catch (e) { }
|
|
357
|
+
} catch (e) { window.UILogger?.debug("usageTrend destroy failed", e); }
|
|
358
358
|
component.charts.usageTrend = null;
|
|
359
359
|
}
|
|
360
360
|
|
|
@@ -81,7 +81,7 @@ window.DashboardStats.updateStats = function(component) {
|
|
|
81
81
|
|
|
82
82
|
enabledAccounts.forEach(acc => {
|
|
83
83
|
const limits = Object.entries(acc.limits || {});
|
|
84
|
-
limits.forEach(([
|
|
84
|
+
limits.forEach(([_id, l]) => {
|
|
85
85
|
totalTrackedModels++;
|
|
86
86
|
if (!l || l.remainingFraction == null || l.remainingFraction <= 0.05) {
|
|
87
87
|
totalLimitedModels++;
|
|
@@ -28,7 +28,7 @@ window.Components.logsViewer = () => ({
|
|
|
28
28
|
try {
|
|
29
29
|
const regex = new RegExp(query, 'i');
|
|
30
30
|
matcher = (msg) => regex.test(msg);
|
|
31
|
-
} catch
|
|
31
|
+
} catch {
|
|
32
32
|
// Invalid regex, fallback to case-insensitive string search
|
|
33
33
|
const lowerQuery = query.toLowerCase();
|
|
34
34
|
matcher = (msg) => msg.toLowerCase().includes(lowerQuery);
|
|
@@ -32,7 +32,6 @@ window.Components.models = () => ({
|
|
|
32
32
|
originalPct: 0
|
|
33
33
|
},
|
|
34
34
|
|
|
35
|
-
// Tracks which model rows have their per-account breakdown expanded beyond the cap
|
|
36
35
|
expandedModels: new Set(),
|
|
37
36
|
|
|
38
37
|
isExpanded(modelId) {
|
|
@@ -197,7 +196,7 @@ window.Components.models = () => ({
|
|
|
197
196
|
const previousModelThresholds = account.modelQuotaThresholds ? { ...account.modelQuotaThresholds } : {};
|
|
198
197
|
|
|
199
198
|
// Build full modelQuotaThresholds for API (full replacement, not merge)
|
|
200
|
-
const existingModelThresholds = { ...
|
|
199
|
+
const existingModelThresholds = { ...account.modelQuotaThresholds };
|
|
201
200
|
|
|
202
201
|
// Preserve the account-level quotaThreshold
|
|
203
202
|
const quotaThreshold = account.quotaThreshold !== undefined ? account.quotaThreshold : null;
|
|
@@ -251,7 +250,7 @@ window.Components.models = () => ({
|
|
|
251
250
|
* Markers within 2% of each other are considered overlapping.
|
|
252
251
|
* Returns a CSS pixel offset string (e.g., '6px' or '-6px').
|
|
253
252
|
*/
|
|
254
|
-
getMarkerOffset(q, row,
|
|
253
|
+
getMarkerOffset(q, row, _qIdx) {
|
|
255
254
|
const pct = this.getMarkerPct(q, row);
|
|
256
255
|
const visible = row.quotaInfo.filter(item => item.thresholdPct > 0 || this.isDragging(item, row));
|
|
257
256
|
// Find all markers within 2% of this one
|
|
@@ -452,10 +452,6 @@ window.Components.serverConfig = () => ({
|
|
|
452
452
|
return descriptions[strategy] || '';
|
|
453
453
|
},
|
|
454
454
|
|
|
455
|
-
// ==========================================
|
|
456
|
-
// Server Configuration Presets
|
|
457
|
-
// ==========================================
|
|
458
|
-
|
|
459
455
|
async fetchServerPresets() {
|
|
460
456
|
const password = Alpine.store('global').webuiPassword;
|
|
461
457
|
try {
|
|
@@ -847,10 +843,6 @@ window.Components.serverConfig = () => ({
|
|
|
847
843
|
};
|
|
848
844
|
},
|
|
849
845
|
|
|
850
|
-
// ==========================================
|
|
851
|
-
// Inline Preset Config Editing
|
|
852
|
-
// ==========================================
|
|
853
|
-
|
|
854
846
|
/**
|
|
855
847
|
* Flatten a nested config object into a flat draft for UI editing.
|
|
856
848
|
* Converts fractions to percentages where needed.
|
|
@@ -1040,7 +1032,7 @@ window.Components.serverConfig = () => ({
|
|
|
1040
1032
|
// Validate capacityBackoffTiersMs text
|
|
1041
1033
|
this.validatePresetConfigField('capacityBackoffTiersMs', this.editingConfigDraft.capacityBackoffTiersMs);
|
|
1042
1034
|
this.configEditMode = 'ui';
|
|
1043
|
-
} catch
|
|
1035
|
+
} catch {
|
|
1044
1036
|
this.jsonParseError = Alpine.store('global').t('invalidJson') || 'Invalid JSON';
|
|
1045
1037
|
}
|
|
1046
1038
|
}
|
package/public/js/data-store.js
CHANGED
|
@@ -51,7 +51,7 @@ document.addEventListener('alpine:init', () => {
|
|
|
51
51
|
if (saved.placeholderMode) {
|
|
52
52
|
this.setPlaceholderMode(true, saved.placeholderIncludeReal !== false);
|
|
53
53
|
}
|
|
54
|
-
} catch
|
|
54
|
+
} catch { /* ignore parse errors */ }
|
|
55
55
|
|
|
56
56
|
// Watch filters to recompute
|
|
57
57
|
// Alpine stores don't have $watch automatically unless inside a component?
|
|
@@ -187,7 +187,7 @@ document.addEventListener('alpine:init', () => {
|
|
|
187
187
|
if (data.config) {
|
|
188
188
|
this.devMode = !!data.config.devMode;
|
|
189
189
|
}
|
|
190
|
-
} catch
|
|
190
|
+
} catch { /* ignore parse errors */ }
|
|
191
191
|
} else {
|
|
192
192
|
this.connectionStatus = 'disconnected';
|
|
193
193
|
}
|
package/public/js/store.js
CHANGED
|
@@ -88,7 +88,6 @@ window.translations.en = {
|
|
|
88
88
|
toggleVisibility: "Toggle Visibility",
|
|
89
89
|
noModels: "NO MODELS DETECTED",
|
|
90
90
|
modelMappingHint: "Server-side model routing. Claude Code users: see 'Claude CLI' tab for client-side setup.",
|
|
91
|
-
modelMapping: "Mapping (Target Model ID)",
|
|
92
91
|
// Settings - Claude
|
|
93
92
|
proxyConnection: "Proxy Connection",
|
|
94
93
|
modelSelection: "Model Selection",
|
|
@@ -179,7 +178,6 @@ window.translations.en = {
|
|
|
179
178
|
requestVolume: "Request Volume",
|
|
180
179
|
filter: "Filter",
|
|
181
180
|
all: "All",
|
|
182
|
-
none: "None",
|
|
183
181
|
noDataTracked: "No data tracked yet",
|
|
184
182
|
selectFamilies: "Select families to display",
|
|
185
183
|
selectModels: "Select models to display",
|
|
@@ -228,7 +228,6 @@ window.translations.id = {
|
|
|
228
228
|
reauthenticating: "Autentikasi ulang {email}...",
|
|
229
229
|
authUrlFailed: "Gagal mendapatkan URL autentikasi",
|
|
230
230
|
deletedAccount: "{email} berhasil dihapus",
|
|
231
|
-
deleteFailed: "Gagal menghapus",
|
|
232
231
|
accountsReloaded: "Akun berhasil dimuat ulang",
|
|
233
232
|
reloadFailed: "Gagal memuat ulang",
|
|
234
233
|
|
|
@@ -155,7 +155,6 @@ window.translations.pt = {
|
|
|
155
155
|
requestVolume: "Volume de Requisições",
|
|
156
156
|
filter: "Filtrar",
|
|
157
157
|
all: "Todos",
|
|
158
|
-
none: "Nenhum",
|
|
159
158
|
noDataTracked: "Nenhum dado rastreado ainda",
|
|
160
159
|
selectFamilies: "Selecione famílias para exibir",
|
|
161
160
|
selectModels: "Selecione modelos para exibir",
|
|
@@ -88,7 +88,6 @@ window.translations.tr = {
|
|
|
88
88
|
toggleVisibility: "Görünürlüğü Değiştir",
|
|
89
89
|
noModels: "MODEL ALGILANMADI",
|
|
90
90
|
modelMappingHint: "Sunucu tarafı model yönlendirme. Claude Code kullanıcıları: istemci tarafı kurulumu için 'Claude CLI' sekmesine bakın.",
|
|
91
|
-
modelMapping: "Eşleştirme (Hedef Model ID)",
|
|
92
91
|
// Settings - Claude
|
|
93
92
|
proxyConnection: "Proxy Bağlantısı",
|
|
94
93
|
modelSelection: "Model Seçimi",
|
|
@@ -158,7 +157,6 @@ window.translations.tr = {
|
|
|
158
157
|
requestVolume: "İstek Hacmi",
|
|
159
158
|
filter: "Filtrele",
|
|
160
159
|
all: "Tümü",
|
|
161
|
-
none: "Hiçbiri",
|
|
162
160
|
noDataTracked: "Henüz veri izlenmedi",
|
|
163
161
|
selectFamilies: "Görüntülenecek aileleri seçin",
|
|
164
162
|
selectModels: "Görüntülenecek modelleri seçin",
|
|
@@ -88,7 +88,6 @@ window.translations.zh = {
|
|
|
88
88
|
toggleVisibility: "切换可见性",
|
|
89
89
|
noModels: "未检测到模型",
|
|
90
90
|
modelMappingHint: "服务端模型路由功能。Claude Code 用户请使用 'Claude CLI' 标签页以便捷配置。",
|
|
91
|
-
modelMapping: "映射 (目标模型 ID)",
|
|
92
91
|
// Settings - Claude
|
|
93
92
|
proxyConnection: "代理连接",
|
|
94
93
|
modelSelection: "模型选择",
|
|
@@ -179,7 +178,6 @@ window.translations.zh = {
|
|
|
179
178
|
requestVolume: "请求量",
|
|
180
179
|
filter: "筛选",
|
|
181
180
|
all: "全选",
|
|
182
|
-
none: "清空",
|
|
183
181
|
noDataTracked: "暂无追踪数据",
|
|
184
182
|
selectFamilies: "选择要显示的系列",
|
|
185
183
|
selectModels: "选择要显示的模型",
|
|
@@ -21,7 +21,6 @@ window.ErrorHandler.safeAsync = async function(fn, errorMessage = null, options
|
|
|
21
21
|
try {
|
|
22
22
|
return await fn();
|
|
23
23
|
} catch (error) {
|
|
24
|
-
// Log error for debugging
|
|
25
24
|
console.error(`[ErrorHandler] ${defaultErrorMessage}:`, error);
|
|
26
25
|
|
|
27
26
|
// Show toast notification
|
|
@@ -86,7 +85,6 @@ window.ErrorHandler.withLoading = async function(asyncFn, context, loadingKey =
|
|
|
86
85
|
context[loadingKey] = true;
|
|
87
86
|
|
|
88
87
|
try {
|
|
89
|
-
// Execute the async function with error handling
|
|
90
88
|
const result = await window.ErrorHandler.safeAsync(asyncFn, options.errorMessage, options);
|
|
91
89
|
return result;
|
|
92
90
|
} finally {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
// Check localStorage
|
|
29
29
|
try {
|
|
30
30
|
return localStorage.getItem('ag_debug') === 'true';
|
|
31
|
-
} catch
|
|
31
|
+
} catch {
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
debugEnabled = true;
|
|
54
54
|
console.info('[UILogger] Debug mode enabled. Refresh page to see all logs.');
|
|
55
55
|
} catch (e) {
|
|
56
|
-
console.warn('[UILogger] Could not save debug preference');
|
|
56
|
+
console.warn('[UILogger] Could not save debug preference', e);
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
debugEnabled = false;
|
|
67
67
|
console.info('[UILogger] Debug mode disabled.');
|
|
68
68
|
} catch (e) {
|
|
69
|
-
|
|
69
|
+
console.warn('[UILogger] Could not clear debug preference', e);
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
|
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
*/
|
|
104
104
|
log(...args) {
|
|
105
105
|
if (debugEnabled) {
|
|
106
|
+
// aislop-ignore-next-line console-leftover -- UILogger's own output sink
|
|
106
107
|
console.log(...args);
|
|
107
108
|
}
|
|
108
109
|
},
|
|
@@ -328,10 +328,6 @@ export class AccountManager {
|
|
|
328
328
|
return getLimitInfo(this.#accounts, email, modelId);
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
// ============================================================================
|
|
332
|
-
// Cooldown Methods (matches opencode-antigravity-auth)
|
|
333
|
-
// ============================================================================
|
|
334
|
-
|
|
335
331
|
/**
|
|
336
332
|
* Mark an account as cooling down for a specified duration
|
|
337
333
|
* Used for temporary backoff separate from rate limits
|
|
@@ -309,11 +309,6 @@ export function incrementConsecutiveFailures(accounts, email) {
|
|
|
309
309
|
return account.consecutiveFailures;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
// ============================================================================
|
|
313
|
-
// Cooldown Mechanism (matches opencode-antigravity-auth)
|
|
314
|
-
// Separate from rate limits - used for temporary backoff after failures
|
|
315
|
-
// ============================================================================
|
|
316
|
-
|
|
317
312
|
/**
|
|
318
313
|
* Cooldown reasons for debugging/logging
|
|
319
314
|
*/
|
|
@@ -36,7 +36,7 @@ export class BaseStrategy {
|
|
|
36
36
|
* @param {Function} [options.onSave] - Callback to save changes
|
|
37
37
|
* @returns {SelectionResult} The selected account and index
|
|
38
38
|
*/
|
|
39
|
-
selectAccount(
|
|
39
|
+
selectAccount(_accounts, _modelId, _options = {}) {
|
|
40
40
|
throw new Error('selectAccount must be implemented by subclass');
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -45,7 +45,7 @@ export class BaseStrategy {
|
|
|
45
45
|
* @param {Object} account - The account that was used
|
|
46
46
|
* @param {string} modelId - The model ID that was used
|
|
47
47
|
*/
|
|
48
|
-
onSuccess(
|
|
48
|
+
onSuccess(_account, _modelId) {
|
|
49
49
|
// Default: no-op, override in subclass if needed
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -54,7 +54,7 @@ export class BaseStrategy {
|
|
|
54
54
|
* @param {Object} account - The account that was rate-limited
|
|
55
55
|
* @param {string} modelId - The model ID that was rate-limited
|
|
56
56
|
*/
|
|
57
|
-
onRateLimit(
|
|
57
|
+
onRateLimit(_account, _modelId) {
|
|
58
58
|
// Default: no-op, override in subclass if needed
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -63,7 +63,7 @@ export class BaseStrategy {
|
|
|
63
63
|
* @param {Object} account - The account that failed
|
|
64
64
|
* @param {string} modelId - The model ID that failed
|
|
65
65
|
*/
|
|
66
|
-
onFailure(
|
|
66
|
+
onFailure(_account, _modelId) {
|
|
67
67
|
// Default: no-op, override in subclass if needed
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -117,7 +117,7 @@ export class HybridStrategy extends BaseStrategy {
|
|
|
117
117
|
/**
|
|
118
118
|
* Called after a successful request
|
|
119
119
|
*/
|
|
120
|
-
onSuccess(account,
|
|
120
|
+
onSuccess(account, _modelId) {
|
|
121
121
|
if (account && account.email) {
|
|
122
122
|
this.#healthTracker.recordSuccess(account.email);
|
|
123
123
|
}
|
|
@@ -126,7 +126,7 @@ export class HybridStrategy extends BaseStrategy {
|
|
|
126
126
|
/**
|
|
127
127
|
* Called when a request is rate-limited
|
|
128
128
|
*/
|
|
129
|
-
onRateLimit(account,
|
|
129
|
+
onRateLimit(account, _modelId) {
|
|
130
130
|
if (account && account.email) {
|
|
131
131
|
this.#healthTracker.recordRateLimit(account.email);
|
|
132
132
|
}
|
|
@@ -135,7 +135,7 @@ export class HybridStrategy extends BaseStrategy {
|
|
|
135
135
|
/**
|
|
136
136
|
* Called when a request fails
|
|
137
137
|
*/
|
|
138
|
-
onFailure(account,
|
|
138
|
+
onFailure(account, _modelId) {
|
|
139
139
|
if (account && account.email) {
|
|
140
140
|
this.#healthTracker.recordFailure(account.email);
|
|
141
141
|
// Refund the token since the request didn't complete
|
package/src/auth/database.js
CHANGED
|
@@ -55,6 +55,7 @@ function loadDatabaseModule() {
|
|
|
55
55
|
return Database;
|
|
56
56
|
} catch (retryError) {
|
|
57
57
|
// Rebuild succeeded but reload failed - user needs to restart
|
|
58
|
+
logger.debug(`[Database] Reload after rebuild failed: ${retryError.message}`);
|
|
58
59
|
moduleLoadError = new NativeModuleError(
|
|
59
60
|
'Native module rebuild completed. Please restart the server to apply the fix.',
|
|
60
61
|
true, // rebuildSucceeded
|
package/src/auth/oauth.js
CHANGED
|
@@ -178,7 +178,7 @@ export function startCallbackServer(expectedState, timeoutMs = 120000) {
|
|
|
178
178
|
let actualPort = OAUTH_CONFIG.callbackPort;
|
|
179
179
|
const host = process.env.HOST || '0.0.0.0';
|
|
180
180
|
|
|
181
|
-
const promise = new Promise(
|
|
181
|
+
const promise = new Promise((resolve, reject) => {
|
|
182
182
|
// Build list of ports to try: primary + fallbacks
|
|
183
183
|
const portsToTry = [OAUTH_CONFIG.callbackPort, ...(OAUTH_CONFIG.callbackFallbackPorts || [])];
|
|
184
184
|
const errors = [];
|
|
@@ -265,37 +265,38 @@ export function startCallbackServer(expectedState, timeoutMs = 120000) {
|
|
|
265
265
|
});
|
|
266
266
|
|
|
267
267
|
// Try ports with fallback logic (issue #176 - Windows EACCES fix)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
268
|
+
(async () => {
|
|
269
|
+
let boundSuccessfully = false;
|
|
270
|
+
for (const port of portsToTry) {
|
|
271
|
+
try {
|
|
272
|
+
await tryBindPort(server, port, host);
|
|
273
|
+
actualPort = port;
|
|
274
|
+
boundSuccessfully = true;
|
|
275
|
+
|
|
276
|
+
if (port !== OAUTH_CONFIG.callbackPort) {
|
|
277
|
+
logger.warn(`[OAuth] Primary port ${OAUTH_CONFIG.callbackPort} unavailable, using fallback port ${port}`);
|
|
278
|
+
} else {
|
|
279
|
+
logger.info(`[OAuth] Callback server listening on ${host}:${port}`);
|
|
280
|
+
}
|
|
281
|
+
break;
|
|
282
|
+
} catch (err) {
|
|
283
|
+
const errMsg = err.code === 'EACCES'
|
|
284
|
+
? `Permission denied on port ${port}`
|
|
285
|
+
: err.code === 'EADDRINUSE'
|
|
286
|
+
? `Port ${port} already in use`
|
|
287
|
+
: `Failed to bind port ${port}: ${err.message}`;
|
|
288
|
+
errors.push(errMsg);
|
|
289
|
+
logger.warn(`[OAuth] ${errMsg}`);
|
|
279
290
|
}
|
|
280
|
-
break;
|
|
281
|
-
} catch (err) {
|
|
282
|
-
const errMsg = err.code === 'EACCES'
|
|
283
|
-
? `Permission denied on port ${port}`
|
|
284
|
-
: err.code === 'EADDRINUSE'
|
|
285
|
-
? `Port ${port} already in use`
|
|
286
|
-
: `Failed to bind port ${port}: ${err.message}`;
|
|
287
|
-
errors.push(errMsg);
|
|
288
|
-
logger.warn(`[OAuth] ${errMsg}`);
|
|
289
291
|
}
|
|
290
|
-
}
|
|
291
292
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
if (!boundSuccessfully) {
|
|
294
|
+
// All ports failed - provide helpful error message
|
|
295
|
+
const isWindows = process.platform === 'win32';
|
|
296
|
+
let errorMsg = `Failed to start OAuth callback server.\nTried ports: ${portsToTry.join(', ')}\n\nErrors:\n${errors.join('\n')}`;
|
|
296
297
|
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
if (isWindows) {
|
|
299
|
+
errorMsg += `\n
|
|
299
300
|
================== WINDOWS TROUBLESHOOTING ==================
|
|
300
301
|
The default port range may be reserved by Hyper-V/WSL2/Docker.
|
|
301
302
|
|
|
@@ -311,21 +312,22 @@ Option 3: Check reserved port ranges
|
|
|
311
312
|
Option 4: Exclude port from reservation (run as Administrator)
|
|
312
313
|
netsh int ipv4 add excludedportrange protocol=tcp startport=51121 numberofports=1
|
|
313
314
|
==============================================================`;
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
reject(new Error(errorMsg));
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
315
|
+
} else {
|
|
316
|
+
errorMsg += `\n\nTry setting a custom port: OAUTH_CALLBACK_PORT=3456`;
|
|
317
|
+
}
|
|
321
318
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (!isAborted) {
|
|
325
|
-
server.close();
|
|
326
|
-
reject(new Error('OAuth callback timeout - no response received'));
|
|
319
|
+
reject(new Error(errorMsg));
|
|
320
|
+
return;
|
|
327
321
|
}
|
|
328
|
-
|
|
322
|
+
|
|
323
|
+
// Timeout after specified duration
|
|
324
|
+
timeoutId = setTimeout(() => {
|
|
325
|
+
if (!isAborted) {
|
|
326
|
+
server.close();
|
|
327
|
+
reject(new Error('OAuth callback timeout - no response received'));
|
|
328
|
+
}
|
|
329
|
+
}, timeoutMs);
|
|
330
|
+
})().catch(reject);
|
|
329
331
|
});
|
|
330
332
|
|
|
331
333
|
// Abort function to clean up server when manual completion happens
|
|
@@ -60,7 +60,7 @@ async function getTokenData() {
|
|
|
60
60
|
return dbData;
|
|
61
61
|
}
|
|
62
62
|
} catch (err) {
|
|
63
|
-
logger.warn(
|
|
63
|
+
logger.warn(`[Token] DB extraction failed (${err.message}), trying HTML page...`);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// Fallback to HTML page
|
package/src/cli/accounts.js
CHANGED
|
@@ -50,7 +50,7 @@ function isServerRunning() {
|
|
|
50
50
|
resolve(false);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
socket.on('error', (
|
|
53
|
+
socket.on('error', () => {
|
|
54
54
|
socket.destroy();
|
|
55
55
|
resolve(false); // Port free
|
|
56
56
|
});
|
|
@@ -447,6 +447,7 @@ async function verifyAccounts() {
|
|
|
447
447
|
console.log(` ✓ ${email} - OK`);
|
|
448
448
|
} catch (error) {
|
|
449
449
|
console.log(` ✗ ${account.email} - ${error.message}`);
|
|
450
|
+
process.exitCode = 1;
|
|
450
451
|
}
|
|
451
452
|
}
|
|
452
453
|
}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Rate Limit State Management
|
|
3
|
-
*
|
|
4
|
-
* Shared utilities for rate limit tracking, backoff calculation,
|
|
5
|
-
* and error classification. Used by both streaming and non-streaming handlers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
1
|
+
// Rate limit tracking, backoff and error classification shared by streaming and non-streaming handlers.
|
|
8
2
|
import {
|
|
9
3
|
RATE_LIMIT_DEDUP_WINDOW_MS,
|
|
10
4
|
RATE_LIMIT_STATE_RESET_MS,
|
package/src/config.js
CHANGED
package/src/constants.js
CHANGED
|
@@ -301,13 +301,11 @@ export const BUILTIN_MODEL_MAPPINGS = {
|
|
|
301
301
|
'claude-sonnet-5': 'claude-sonnet-4-6'
|
|
302
302
|
};
|
|
303
303
|
|
|
304
|
-
// Default test models for each family (used by test suite)
|
|
305
304
|
export const TEST_MODELS = {
|
|
306
305
|
claude: 'claude-sonnet-4-6',
|
|
307
306
|
gemini: 'gemini-3.8-flash-tiered'
|
|
308
307
|
};
|
|
309
308
|
|
|
310
|
-
// Default Claude CLI presets (used by WebUI settings)
|
|
311
309
|
export const DEFAULT_PRESETS = [
|
|
312
310
|
{
|
|
313
311
|
name: 'Claude Thinking',
|
|
@@ -46,7 +46,6 @@ export function convertContentToParts(content, isClaudeModel = false, isGeminiMo
|
|
|
46
46
|
parts.push({ text: block.text });
|
|
47
47
|
}
|
|
48
48
|
} else if (block.type === 'image') {
|
|
49
|
-
// Handle image content
|
|
50
49
|
if (block.source?.type === 'base64') {
|
|
51
50
|
// Base64-encoded image
|
|
52
51
|
parts.push({
|
|
@@ -93,7 +92,6 @@ export function convertContentToParts(content, isClaudeModel = false, isGeminiMo
|
|
|
93
92
|
functionCall.id = block.id;
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
// Build the part with functionCall
|
|
97
95
|
const part = { functionCall };
|
|
98
96
|
|
|
99
97
|
// For Gemini models, include thoughtSignature at the part level
|
|
@@ -133,7 +131,6 @@ export function convertContentToParts(content, isClaudeModel = false, isGeminiMo
|
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
133
|
|
|
136
|
-
// Extract text content
|
|
137
134
|
const texts = responseContent
|
|
138
135
|
.filter(c => c.type === 'text')
|
|
139
136
|
.map(c => c.text)
|
|
@@ -157,7 +154,6 @@ export function convertContentToParts(content, isClaudeModel = false, isGeminiMo
|
|
|
157
154
|
// This ensures all functionResponse parts are consecutive
|
|
158
155
|
deferredInlineData.push(...imageParts);
|
|
159
156
|
} else if (block.type === 'thinking') {
|
|
160
|
-
// Handle thinking blocks with signature compatibility check
|
|
161
157
|
if (block.signature && block.signature.length >= MIN_SIGNATURE_LENGTH) {
|
|
162
158
|
const signatureFamily = getCachedSignatureFamily(block.signature);
|
|
163
159
|
const targetFamily = isClaudeModel ? 'claude' : isGeminiModel ? 'gemini' : null;
|