feat: complete rebranding to Gemini Nexus with improved UI, proxies and documentation

This commit is contained in:
Gemini Nexus Bot committed 2026-04-22 00:00:56 -03:00
1 parent e524a340cb
commit 433dccbaa9
108 files changed
+1004 -1139

No files matched your search

+7 -7
View File
@@ -6,7 +6,7 @@ import {
deleteAccount,
} from '../../ipc/account/handler';
import { restoreAccount } from '../../ipc/database/handler';
import { startAntigravity } from '../../ipc/process/handler';
import { startGeminiNexus } from '../../ipc/process/handler';
import fs from 'fs';
import path from 'path';
import { applyDeviceProfile, generateDeviceProfile } from '../../ipc/device/handler';
@@ -20,8 +20,8 @@ vi.mock('../../utils/paths', async () => {
getAgentDir: vi.fn(() => agentDir),
getAccountsFilePath: vi.fn(() => path.join(agentDir, 'accounts.json')),
getBackupsDir: vi.fn(() => path.join(agentDir, 'backups')),
getAntigravityDbPath: vi.fn(() => path.join(agentDir, 'state.vscdb')),
getAntigravityExecutablePath: vi.fn(() => 'mock_exec_path'),
getGeminiNexusDbPath: vi.fn(() => path.join(agentDir, 'state.vscdb')),
getGeminiNexusExecutablePath: vi.fn(() => 'mock_exec_path'),
};
});
@@ -37,8 +37,8 @@ vi.mock('../../ipc/database/handler', () => ({
}));
vi.mock('../../ipc/process/handler', () => ({
closeAntigravity: vi.fn(),
startAntigravity: vi.fn(),
closeGeminiNexus: vi.fn(),
startGeminiNexus: vi.fn(),
_waitForProcessExit: vi.fn(),
isProcessRunning: vi.fn(() => Promise.resolve(false)),
}));
@@ -144,13 +144,13 @@ describe('Account Handler', () => {
devDeviceId: 'dev-device-id',
sqmId: '{SQM-ID}',
});
expect(startAntigravity).not.toHaveBeenCalled();
expect(startGeminiNexus).not.toHaveBeenCalled();
});
it('should queue switch requests instead of rejecting concurrent calls', async () => {
const account = await addAccountSnapshot();
const startMock = vi.mocked(startAntigravity);
const startMock = vi.mocked(startGeminiNexus);
let releaseFirstStart!: () => void;
const firstStartBlocker = new Promise<void>((resolve) => {
releaseFirstStart = resolve;
+21 -21
View File
@@ -58,7 +58,7 @@ vi.mock('../../ipc/database/dbConnection', () => ({
}));
vi.mock('../../utils/paths', () => ({
getAntigravityDbPaths: () => ['mock-db'],
getGeminiNexusDbPaths: () => ['mock-db'],
getCloudAccountsDbPath: () => 'mock-cloud-db',
}));
@@ -152,7 +152,7 @@ describe('CloudAccountRepo.syncFromIDE', () => {
ProtobufUtils.createOAuthTokenInfo('access-old', 'refresh-old', 1700000000),
).toString('base64');
mockData['antigravityUnifiedStateSync.oauthToken'] = unifiedB64;
mockData['geminiNexusUnifiedStateSync.oauthToken'] = unifiedB64;
mockData['jetskiStateSync.agentManagerInitState'] = oldB64;
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
@@ -179,8 +179,8 @@ describe('CloudAccountRepo.syncFromIDE', () => {
projectPayload,
);
mockData['antigravityUnifiedStateSync.oauthToken'] = unifiedB64;
mockData['antigravityUnifiedStateSync.enterprisePreferences'] = enterprisePreferenceB64;
mockData['geminiNexusUnifiedStateSync.oauthToken'] = unifiedB64;
mockData['geminiNexusUnifiedStateSync.enterprisePreferences'] = enterprisePreferenceB64;
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
vi.mocked(GoogleAPIService.getUserInfo).mockResolvedValue(
@@ -302,8 +302,8 @@ describe('CloudAccountRepo.syncFromIDE', () => {
ProtobufUtils.createStringValuePayload('enterprise-project-recovered'),
);
mockData['antigravityUnifiedStateSync.oauthToken'] = unifiedB64;
mockData['antigravityUnifiedStateSync.enterprisePreferences'] = enterprisePreferenceB64;
mockData['geminiNexusUnifiedStateSync.oauthToken'] = unifiedB64;
mockData['geminiNexusUnifiedStateSync.enterprisePreferences'] = enterprisePreferenceB64;
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
vi.mocked(GoogleAPIService.getUserInfo).mockResolvedValue(
@@ -431,8 +431,8 @@ describe('CloudAccountRepo.syncFromIDE', () => {
it('should prefer new format when capability detection finds unified key', async () => {
vi.resetModules();
vi.doMock('../../utils/antigravityVersion', () => ({
getAntigravityVersion: () => {
vi.doMock('../../utils/geminiNexusVersion', () => ({
getGeminiNexusVersion: () => {
throw new Error('version detection failed');
},
isNewVersion: () => false,
@@ -442,7 +442,7 @@ describe('CloudAccountRepo.syncFromIDE', () => {
const accessToken = 'access-new';
const refreshToken = 'refresh-new';
mockData['antigravityUnifiedStateSync.oauthToken'] = 'exists';
mockData['geminiNexusUnifiedStateSync.oauthToken'] = 'exists';
mockData['jetskiStateSync.agentManagerInitState'] = 'exists-old';
RepoWithMock.injectCloudToken({
@@ -474,7 +474,7 @@ describe('CloudAccountRepo.syncFromIDE', () => {
const wroteUnifiedKey = runCalls.some(
(call) =>
call.sql === 'insert' &&
(call.args[0] as { key?: string })?.key === 'antigravityUnifiedStateSync.oauthToken',
(call.args[0] as { key?: string })?.key === 'geminiNexusUnifiedStateSync.oauthToken',
);
expect(wroteUnifiedKey).toBe(true);
@@ -486,13 +486,13 @@ describe('syncLocalAccount ORPC error mapping', () => {
it('preserves re-login guidance as an actionable unauthorized error', () => {
const error = toSyncLocalAccountORPCError(
new Error(
'Failed to validate token with Google API. The token may be expired. Please re-login in Antigravity IDE.',
'Failed to validate token with Google API. The token may be expired. Please re-login in Gemini Nexus IDE.',
),
);
expect(error.code).toBe('UNAUTHORIZED');
expect(error.status).toBe(401);
expect(error.message).toContain('Please re-login in Antigravity IDE');
expect(error.message).toContain('Please re-login in Gemini Nexus IDE');
});
});
@@ -506,7 +506,7 @@ describe('cloud switch fail-fast path', () => {
vi.resetModules();
const applyDeviceProfileMock = vi.fn();
const startAntigravityMock = vi.fn(async () => undefined);
const startGeminiNexusMock = vi.fn(async () => undefined);
const recordSwitchFailureMock = vi.fn();
const recordSwitchSuccessMock = vi.fn();
@@ -561,8 +561,8 @@ describe('cloud switch fail-fast path', () => {
}));
vi.doMock('../../ipc/process/handler', () => ({
closeAntigravity: vi.fn(async () => undefined),
startAntigravity: startAntigravityMock,
closeGeminiNexus: vi.fn(async () => undefined),
startGeminiNexus: startGeminiNexusMock,
_waitForProcessExit: vi.fn(async () => undefined),
}));
@@ -576,7 +576,7 @@ describe('cloud switch fail-fast path', () => {
}));
vi.doMock('../../utils/paths', () => ({
getAntigravityDbPaths: () => [],
getGeminiNexusDbPaths: () => [],
}));
vi.doMock('../../utils/logger', () => ({
@@ -605,7 +605,7 @@ describe('cloud switch fail-fast path', () => {
expect(applyDeviceProfileMock).toHaveBeenCalledTimes(1);
expect(applyDeviceProfileMock).toHaveBeenCalledWith(account.device_profile);
expect(startAntigravityMock).not.toHaveBeenCalled();
expect(startGeminiNexusMock).not.toHaveBeenCalled();
expect(recordSwitchFailureMock).toHaveBeenCalledWith(
'cloud',
'perform_switch_failed',
@@ -686,7 +686,7 @@ describe('cloud oauth client key backfill', () => {
readCurrentDeviceProfile: vi.fn(),
saveGlobalOriginalProfile: vi.fn(),
}));
vi.doMock('../../utils/paths', () => ({ getAntigravityDbPaths: () => [] }));
vi.doMock('../../utils/paths', () => ({ getGeminiNexusDbPaths: () => [] }));
vi.doMock('../../ipc/switchGuard', () => ({
runWithSwitchGuard: async (_owner: string, fn: () => Promise<void>) => fn(),
}));
@@ -736,7 +736,7 @@ describe('cloud oauth client key backfill', () => {
return false;
}
if (key === 'active_oauth_client_key') {
return 'antigravity_enterprise';
return 'geminiNexus_enterprise';
}
return defaultValue;
}),
@@ -747,7 +747,7 @@ describe('cloud oauth client key backfill', () => {
vi.doMock('../../services/GoogleAPIService', () => ({
GoogleAPIService: {
setActiveOAuthClientKey: vi.fn(),
getActiveOAuthClientKey: vi.fn(() => 'antigravity_enterprise'),
getActiveOAuthClientKey: vi.fn(() => 'geminiNexus_enterprise'),
},
}));
@@ -769,7 +769,7 @@ describe('cloud oauth client key backfill', () => {
readCurrentDeviceProfile: vi.fn(),
saveGlobalOriginalProfile: vi.fn(),
}));
vi.doMock('../../utils/paths', () => ({ getAntigravityDbPaths: () => [] }));
vi.doMock('../../utils/paths', () => ({ getGeminiNexusDbPaths: () => [] }));
vi.doMock('../../ipc/switchGuard', () => ({
runWithSwitchGuard: async (_owner: string, fn: () => Promise<void>) => fn(),
}));
+4 -4
View File
@@ -22,7 +22,7 @@ vi.mock('../../ipc/database/dbConnection', () => ({
}));
vi.mock('../../utils/paths', () => ({
getAntigravityDbPaths: () => ['mock-db'],
getGeminiNexusDbPaths: () => ['mock-db'],
}));
vi.mock('../../utils/logger', () => ({
@@ -73,12 +73,12 @@ describe('database backup keys', () => {
last_used: new Date().toISOString(),
},
data: {
antigravityAuthStatus: '{"email":"[email protected]"}',
geminiNexusAuthStatus: '{"email":"[email protected]"}',
'jetskiStateSync.agentManagerInitState': 'old',
'antigravityUnifiedStateSync.oauthToken': 'unified',
'geminiNexusUnifiedStateSync.oauthToken': 'unified',
},
});
expect(writes['antigravityUnifiedStateSync.oauthToken']).toBe('unified');
expect(writes['geminiNexusUnifiedStateSync.oauthToken']).toBe('unified');
});
});
+6 -6
View File
@@ -16,8 +16,8 @@ vi.mock('../../utils/paths', async () => {
const path = await import('path');
const tempDbPath = path.join(process.cwd(), 'temp_test.vscdb');
return {
getAntigravityDbPath: () => tempDbPath,
getAntigravityDbPaths: () => [tempDbPath],
getGeminiNexusDbPath: () => tempDbPath,
getGeminiNexusDbPaths: () => [tempDbPath],
getAgentDir: () => path.join(process.cwd(), 'temp_test_agent'),
};
});
@@ -39,7 +39,7 @@ describe.skip('Database Handler', () => {
const db = new Database(tempDbPath);
db.exec('CREATE TABLE IF NOT EXISTS ItemTable (key TEXT PRIMARY KEY, value TEXT)');
db.prepare('INSERT INTO ItemTable (key, value) VALUES (?, ?)').run(
'antigravityAuthStatus',
'geminiNexusAuthStatus',
JSON.stringify({
user: { email: '[email protected]', name: 'Test User' },
}),
@@ -76,7 +76,7 @@ describe.skip('Database Handler', () => {
};
const backup = backupAccount(account);
expect(backup.account).toEqual(account);
expect(backup.data['antigravityAuthStatus']).toBeDefined();
expect(backup.data['geminiNexusAuthStatus']).toBeDefined();
});
it('should restore account', () => {
@@ -90,7 +90,7 @@ describe.skip('Database Handler', () => {
last_used: new Date().toISOString(),
},
data: {
antigravityAuthStatus: JSON.stringify({
geminiNexusAuthStatus: JSON.stringify({
user: { email: '[email protected]' },
}),
newKey: 'newValue',
@@ -101,7 +101,7 @@ describe.skip('Database Handler', () => {
const db = new Database(tempDbPath);
const row = db
.prepare("SELECT value FROM ItemTable WHERE key = 'antigravityAuthStatus'")
.prepare("SELECT value FROM ItemTable WHERE key = 'geminiNexusAuthStatus'")
.get() as { value: string };
const value = JSON.parse(row.value);
expect(value.user.email).toBe('[email protected]');
@@ -1,7 +1,7 @@
import { describe, it, expect, vi } from 'vitest';
import { compareVersion, isNewVersion } from '../../utils/antigravityVersion';
import { compareVersion, isNewVersion } from '../../utils/geminiNexusVersion';
describe('antigravityVersion', () => {
describe('geminiNexusVersion', () => {
it('should compare versions correctly', () => {
expect(compareVersion('1.16.5', '1.16.4')).toBe(1);
expect(compareVersion('1.16.5', '1.16.5')).toBe(0);
@@ -43,12 +43,12 @@ describe('antigravityVersion', () => {
},
}));
vi.doMock('../../utils/paths', () => ({
getAntigravityExecutablePath: () => 'C:\\Program Files\\Antigravity\\Antigravity.exe',
getGeminiNexusExecutablePath: () => 'C:\\Program Files\\GeminiNexus\\GeminiNexus.exe',
}));
const { getAntigravityVersion } = await import('../../utils/antigravityVersion');
const version = getAntigravityVersion();
const cached = getAntigravityVersion();
const { getGeminiNexusVersion } = await import('../../utils/geminiNexusVersion');
const version = getGeminiNexusVersion();
const cached = getGeminiNexusVersion();
expect(version.shortVersion).toBe('1.16.6');
expect(cached.shortVersion).toBe('1.16.6');
+3 -3
View File
@@ -114,7 +114,7 @@ describe('GoogleAPIService OAuth clients', () => {
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
const clients = GoogleAPIService.listOAuthClients();
expect(clients.find((client) => client.key === 'antigravity_enterprise')).toBeDefined();
expect(clients.find((client) => client.key === 'geminiNexus_enterprise')).toBeDefined();
expect(clients.find((client) => client.key === 'custom_a')?.label).toBe('Custom A');
expect(clients.find((client) => client.key === 'custom_b')?.is_active).toBe(true);
});
@@ -272,7 +272,7 @@ describe('GoogleAPIService fetchQuota fallback policy', () => {
metadata: {
ide_type: 'ANTIGRAVITY',
ide_version: expectedVersion,
ide_name: 'antigravity',
ide_name: 'geminiNexus',
},
}),
);
@@ -410,7 +410,7 @@ describe('QuotaService fallback policy', () => {
isAxiosError: (error: unknown) => Boolean((error as { isAxiosError?: boolean })?.isAxiosError),
}));
const { QuotaService } = await import('../../lib/antigravity/QuotaService');
const { QuotaService } = await import('../../lib/geminiNexus/QuotaService');
await expect(QuotaService.fetchQuota('access-token', '[email protected]')).rejects.toThrow(
'HTTP 400 - {"error":"INVALID_ARGUMENT"}',
+8 -8
View File
@@ -1,9 +1,9 @@
import { describe, it, expect } from 'vitest';
import {
getAppDataDir,
getAntigravityDbPath,
getAntigravityStoragePath,
getAntigravityExecutablePath,
getGeminiNexusDbPath,
getGeminiNexusStoragePath,
getGeminiNexusExecutablePath,
} from '../../utils/paths';
describe('Path Utilities', () => {
@@ -14,21 +14,21 @@ describe('Path Utilities', () => {
});
it('should get correct DB path', () => {
const dbPath = getAntigravityDbPath();
const dbPath = getGeminiNexusDbPath();
expect(dbPath).toContain('state.vscdb');
});
it('should get correct storage path', () => {
const storagePath = getAntigravityStoragePath();
const storagePath = getGeminiNexusStoragePath();
expect(storagePath).toContain('storage.json');
});
it('should get correct executable path', () => {
const execPath = getAntigravityExecutablePath();
const execPath = getGeminiNexusExecutablePath();
if (process.platform === 'linux') {
expect(execPath).toBe('/usr/share/antigravity/antigravity');
expect(execPath).toBe('/usr/share/geminiNexus/geminiNexus');
} else if (process.platform === 'darwin') {
expect(execPath).toBe('/Applications/Antigravity.app/Contents/MacOS/Antigravity');
expect(execPath).toBe('/Applications/GeminiNexus.app/Contents/MacOS/GeminiNexus');
}
// Windows path depends on env vars, harder to test strictly without mocking
});
+24 -24
View File
@@ -17,12 +17,12 @@ vi.mock('../../utils/logger', () => ({
// Mock paths module to avoid child_process issues
vi.mock('../../utils/paths', () => ({
getAntigravityExecutablePath: vi.fn(() => '/path/to/antigravity'),
getGeminiNexusExecutablePath: vi.fn(() => '/path/to/geminiNexus'),
isWsl: vi.fn(() => false),
}));
// Import after mocks are set up
import { isProcessRunning, closeAntigravity, startAntigravity } from '../../ipc/process/handler';
import { isProcessRunning, closeGeminiNexus, startGeminiNexus } from '../../ipc/process/handler';
import findProcess from 'find-process';
describe('Process Handler', () => {
@@ -33,21 +33,21 @@ describe('Process Handler', () => {
});
describe('isProcessRunning', () => {
it('should return true when Antigravity main process is found on macOS', async () => {
it('should return true when Gemini Nexus main process is found on macOS', async () => {
Object.defineProperty(process, 'platform', { value: 'darwin', configurable: true });
Object.defineProperty(process, 'pid', { value: 1000, configurable: true });
mockFindProcess.mockResolvedValue([
{
pid: 12345,
name: 'Antigravity',
cmd: '/Applications/Antigravity.app/Contents/MacOS/Antigravity',
name: 'Gemini Nexus',
cmd: '/Applications/GeminiNexus.app/Contents/MacOS/GeminiNexus',
},
]);
const result = await isProcessRunning();
expect(result).toBe(true);
expect(mockFindProcess).toHaveBeenCalledWith('name', 'Antigravity', true);
expect(mockFindProcess).toHaveBeenCalledWith('name', 'Gemini Nexus', true);
});
it('should return false when only helper processes are found', async () => {
@@ -57,13 +57,13 @@ describe('Process Handler', () => {
mockFindProcess.mockResolvedValue([
{
pid: 12346,
name: 'Antigravity Helper (Renderer)',
cmd: '/Applications/Antigravity.app/Contents/Frameworks/Antigravity Helper (Renderer).app --type=renderer',
name: 'Gemini Nexus Helper (Renderer)',
cmd: '/Applications/GeminiNexus.app/Contents/Frameworks/Gemini Nexus Helper (Renderer).app --type=renderer',
},
{
pid: 12347,
name: 'Antigravity Helper (GPU)',
cmd: '/Applications/Antigravity.app/Contents/Frameworks/Antigravity Helper (GPU).app --type=gpu-process',
name: 'Gemini Nexus Helper (GPU)',
cmd: '/Applications/GeminiNexus.app/Contents/Frameworks/Gemini Nexus Helper (GPU).app --type=gpu-process',
},
]);
@@ -78,8 +78,8 @@ describe('Process Handler', () => {
mockFindProcess.mockResolvedValue([
{
pid: 12348,
name: 'Antigravity Manager',
cmd: '/Applications/Antigravity Manager.app/Contents/MacOS/Antigravity Manager',
name: 'Gemini Nexus',
cmd: '/Applications/Gemini Nexus.app/Contents/MacOS/Gemini Nexus',
},
]);
@@ -104,8 +104,8 @@ describe('Process Handler', () => {
mockFindProcess.mockResolvedValue([
{
pid: 12345, // Same as current PID
name: 'Antigravity',
cmd: '/Applications/Antigravity.app/Contents/MacOS/Antigravity',
name: 'Gemini Nexus',
cmd: '/Applications/GeminiNexus.app/Contents/MacOS/GeminiNexus',
},
]);
@@ -113,15 +113,15 @@ describe('Process Handler', () => {
expect(result).toBe(false);
});
it('should return true when Antigravity.exe is found on Windows', async () => {
it('should return true when Gemini Nexus.exe is found on Windows', async () => {
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
Object.defineProperty(process, 'pid', { value: 1000, configurable: true });
mockFindProcess.mockResolvedValue([
{
pid: 12345,
name: 'Antigravity.exe',
cmd: 'C:\\Program Files\\Antigravity\\Antigravity.exe',
name: 'GeminiNexus.exe',
cmd: 'C:\\Program Files\\GeminiNexus\\GeminiNexus.exe',
},
]);
@@ -129,15 +129,15 @@ describe('Process Handler', () => {
expect(result).toBe(true);
});
it('should return true when antigravity is found on Linux', async () => {
it('should return true when geminiNexus is found on Linux', async () => {
Object.defineProperty(process, 'platform', { value: 'linux', configurable: true });
Object.defineProperty(process, 'pid', { value: 1000, configurable: true });
mockFindProcess.mockResolvedValue([
{
pid: 12345,
name: 'antigravity',
cmd: '/usr/bin/antigravity',
name: 'geminiNexus',
cmd: '/usr/bin/geminiNexus',
},
]);
@@ -162,8 +162,8 @@ describe('Process Handler', () => {
mockFindProcess.mockResolvedValue([
{
pid: 12345,
name: 'Antigravity',
cmd: '/Applications/Antigravity.app/Contents/MacOS/Antigravity --type=utility',
name: 'Gemini Nexus',
cmd: '/Applications/GeminiNexus.app/Contents/MacOS/Gemini Nexus --type=utility',
},
]);
@@ -175,8 +175,8 @@ describe('Process Handler', () => {
describe('Module exports', () => {
it('should export all required functions', () => {
expect(isProcessRunning).toBeDefined();
expect(closeAntigravity).toBeDefined();
expect(startAntigravity).toBeDefined();
expect(closeGeminiNexus).toBeDefined();
expect(startGeminiNexus).toBeDefined();
});
});
});
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { applyJitter, calculateRetryDelay } from '../../lib/antigravity/retry-utils';
import { applyJitter, calculateRetryDelay } from '../../lib/geminiNexus/retry-utils';
describe('applyJitter', () => {
it('should return values within ±20% range', () => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { decodeSignature } from '../../lib/antigravity/signature-utils';
import { decodeSignature } from '../../lib/geminiNexus/signature-utils';
describe('decodeSignature', () => {
describe('Base64 decoding', () => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { classifyStreamError, formatErrorForSSE } from '../../lib/antigravity/stream-error-utils';
import { classifyStreamError, formatErrorForSSE } from '../../lib/geminiNexus/stream-error-utils';
describe('classifyStreamError', () => {
it('should identify timeout errors', () => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { PartProcessor, StreamingState } from '../../lib/antigravity/ClaudeStreamingMapper';
import { PartProcessor, StreamingState } from '../../lib/geminiNexus/ClaudeStreamingMapper';
describe('StreamingState', () => {
let state: StreamingState;
+1 -1
View File
@@ -3,7 +3,7 @@ import {
hasValidSignature,
gracefulDegradeThinking,
processThinkingBlocks,
} from '../../lib/antigravity/thinking-utils';
} from '../../lib/geminiNexus/thinking-utils';
describe('hasValidSignature', () => {
it('should return true for empty thinking + valid signature', () => {
@@ -141,7 +141,7 @@ describe('TokenManagerService parity scheduling replay', () => {
oauth_client_key: undefined,
project_id: undefined,
},
'antigravity_enterprise',
'geminiNexus_enterprise',
);
expect(normalized).toBeUndefined();