feat: bump version to 0.14.0

Includes all changes from this release cycle:
- Top header navigation (sidebar removed)
- Accounts screen decomposition and visual redesign
- Dev/prod environment isolation
- Usage Analytics with accurate averages, cost reporting, OpenRouter pricing
- Monitor moved to Usage with per-request token/cost tracking
- Clickable traffic logs with expandable JSON body viewer
- OpenCode IDE config in Quick Setup
- API Proxy reorganization (flattened tabs)
- CI/CD pipeline fixes (release config, Node version, pnpm alignment)
- Repository cleanup (~80MB of binaries removed)
This commit is contained in:
Gemini Nexus Bot committed 2026-05-02 00:32:21 -03:00
1 parent 3752dfda91
commit a905877c76
67 files changed
+9303 -3862

No files matched your search

@@ -25,9 +25,7 @@ export class ProxyReplayService {
private readonly buffer: ReplayEntry[] = [];
private readonly maxSize = 20;
constructor(
@Inject(ProxyService) private readonly proxyService: ProxyService,
) {
constructor(@Inject(ProxyService) private readonly proxyService: ProxyService) {
registerProxyAdvancedService('proxyReplay', this);
}
@@ -349,14 +349,23 @@ export class TokenManagerService implements OnModuleInit {
if (requestedAccountId && !excludedAccountIds.has(requestedAccountId)) {
const requestedToken = this.tokens.get(requestedAccountId);
if (requestedToken) {
const isHealthy = this.isAccountHealthy(requestedAccountId, requestedToken, nowSeconds, model);
const isHealthy = this.isAccountHealthy(
requestedAccountId,
requestedToken,
nowSeconds,
model,
);
if (isHealthy) {
this.logger.log(`Using requested account: ${requestedAccountId}`);
return this.buildCloudAccount(requestedAccountId, requestedToken);
}
this.logger.warn(`Requested account ${requestedAccountId} is not healthy, falling back to selection`);
this.logger.warn(
`Requested account ${requestedAccountId} is not healthy, falling back to selection`,
);
} else {
this.logger.warn(`Requested account ${requestedAccountId} not found, falling back to selection`);
this.logger.warn(
`Requested account ${requestedAccountId} not found, falling back to selection`,
);
}
}
@@ -962,7 +971,12 @@ export class TokenManagerService implements OnModuleInit {
}
}
private isAccountHealthy(accountId: string, tokenData: TokenData, nowSeconds: number, model?: string): boolean {
private isAccountHealthy(
accountId: string,
tokenData: TokenData,
nowSeconds: number,
model?: string,
): boolean {
const entry = this.getOrCreateCircuitBreakerEntry(accountId);
if (entry.state === 'unhealthy') {
return false;
@@ -1089,8 +1103,24 @@ export class TokenManagerService implements OnModuleInit {
}
}
getCircuitBreakerStatus(): Record<string, { state: 'healthy' | 'degraded' | 'unhealthy'; failureCount: number; lastFailureTime: number | null; failureRate: number }> {
const result: Record<string, { state: 'healthy' | 'degraded' | 'unhealthy'; failureCount: number; lastFailureTime: number | null; failureRate: number }> = {};
getCircuitBreakerStatus(): Record<
string,
{
state: 'healthy' | 'degraded' | 'unhealthy';
failureCount: number;
lastFailureTime: number | null;
failureRate: number;
}
> {
const result: Record<
string,
{
state: 'healthy' | 'degraded' | 'unhealthy';
failureCount: number;
lastFailureTime: number | null;
failureRate: number;
}
> = {};
for (const accountId of this.tokens.keys()) {
const entry = this.getOrCreateCircuitBreakerEntry(accountId);
this.computeCircuitBreakerState(entry);
@@ -1104,7 +1134,12 @@ export class TokenManagerService implements OnModuleInit {
return result;
}
getParityCounters(): { totalRequests: number; matchedRequests: number; parityViolations: number; lastUpdated: string } {
getParityCounters(): {
totalRequests: number;
matchedRequests: number;
parityViolations: number;
lastUpdated: string;
} {
return {
totalRequests: this.parityRequestCount,
matchedRequests: this.shadowComparisonCount,