Files
ag-x/dist/preload.js
admin 43e2a2f78f AG X v2.0.3 - Antigravity fork with multi-provider support
Features:
- Welcome screen on first run (provider choice before LS starts)
- 15+ AI providers (Google Gemini, OpenAI, Anthropic, DeepSeek, Ollama, etc.)
- Provider config syncs to endpoints.json for translation proxy
- Built-in Node.js translation proxy for non-native backends
- Auto-update support, tray integration, URI scheme handler
2026-05-22 23:20:10 +04:00

372 lines
14 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Preload script — runs in every BrowserWindow before the page loads.
* Exposes a minimal, secure API via contextBridge so the renderer can
* communicate with the main-process auto-updater without nodeIntegration.
*/
const electron_1 = require("electron");
const updaterAPI = {
onStateChanged: (callback) => {
const handler = (_event, state) => {
callback(state);
};
electron_1.ipcRenderer.on('updater:state-changed', handler);
// Return unsubscribe function
return () => {
electron_1.ipcRenderer.removeListener('updater:state-changed', handler);
};
},
applyUpdate: () => electron_1.ipcRenderer.invoke('updater:apply'),
quitAndInstall: () => electron_1.ipcRenderer.invoke('updater:quit-and-install'),
checkForUpdates: () => electron_1.ipcRenderer.invoke('updater:check-for-updates'),
};
const dialogAPI = {
showOpenDialog: () => electron_1.ipcRenderer.invoke('dialog:open-workspace'),
};
const notificationAPI = {
send: (options) => electron_1.ipcRenderer.invoke('notification:send', options),
openSystemPreferences: () => electron_1.ipcRenderer.invoke('notification:open-system-preferences'),
onClicked: (callback) => {
const handler = (_event, payload) => {
callback(payload);
};
electron_1.ipcRenderer.on('notification:clicked', handler);
return () => {
electron_1.ipcRenderer.removeListener('notification:clicked', handler);
};
},
};
const storageAPI = {
getItems: () => electron_1.ipcRenderer.invoke('storage:get-items'),
updateItems: (changes) => electron_1.ipcRenderer.invoke('storage:update-items', changes),
onChanged: (callback) => {
const handler = (_event, changes) => {
callback(changes);
};
electron_1.ipcRenderer.on('storage:changed', handler);
return () => {
electron_1.ipcRenderer.removeListener('storage:changed', handler);
};
},
};
const logsAPI = {
getElectronLogs: () => electron_1.ipcRenderer.invoke('logs:electron'),
};
const extensionsAPI = {
sendAuthorities: (authoritiesMap) => electron_1.ipcRenderer.invoke('extensions:send-authorities', authoritiesMap),
};
const deepLinkAPI = {
onDeepLink: (callback) => {
const handler = (_event, url) => {
callback(url);
};
electron_1.ipcRenderer.on('deep-link', handler);
return () => {
electron_1.ipcRenderer.removeListener('deep-link', handler);
};
},
getStoredDeepLink: () => electron_1.ipcRenderer.invoke('deep-link:get-stored'),
// Provider API
provider: {
getActive: () => electron_1.ipcRenderer.invoke('provider:get-active'),
getAll: () => electron_1.ipcRenderer.invoke('provider:get-all'),
openSettings: () => electron_1.ipcRenderer.invoke('provider:open-settings'),
onOpenSettings: (handler) => {
electron_1.ipcRenderer.on('provider:open-settings', handler);
return () => electron_1.ipcRenderer.removeListener('provider:open-settings', handler);
},
},
};
const agentAPI = {
updateActiveAgentCount: (count) => electron_1.ipcRenderer.invoke('agent:update-active-count', count),
};
const electronNativeAPI = {
getZoomLevel: () => electron_1.webFrame.getZoomFactor(),
setTitleBarOverlay: (options) => electron_1.ipcRenderer.invoke('window:set-title-bar-overlay', options),
minimize: () => electron_1.ipcRenderer.invoke('window:minimize'),
maximize: () => electron_1.ipcRenderer.invoke('window:maximize'),
unmaximize: () => electron_1.ipcRenderer.invoke('window:unmaximize'),
isMaximized: () => electron_1.ipcRenderer.invoke('window:is-maximized'),
close: () => electron_1.ipcRenderer.invoke('window:close'),
toggleDevTools: () => electron_1.ipcRenderer.invoke('window:toggle-devtools'),
zoomIn: () => {
const current = electron_1.webFrame.getZoomLevel();
electron_1.webFrame.setZoomLevel(current + 0.5);
},
zoomOut: () => {
const current = electron_1.webFrame.getZoomLevel();
electron_1.webFrame.setZoomLevel(current - 0.5);
},
resetZoom: () => {
electron_1.webFrame.setZoomLevel(0);
},
openExternal: (url) => electron_1.ipcRenderer.invoke('shell:open-external', url),
};
electron_1.contextBridge.exposeInMainWorld('electronUpdater', updaterAPI);
electron_1.contextBridge.exposeInMainWorld('dialog', dialogAPI);
electron_1.contextBridge.exposeInMainWorld('nativeNotifications', notificationAPI);
electron_1.contextBridge.exposeInMainWorld('nativeStorage', storageAPI);
electron_1.contextBridge.exposeInMainWorld('logs', logsAPI);
electron_1.contextBridge.exposeInMainWorld('extensions', extensionsAPI);
electron_1.contextBridge.exposeInMainWorld('deepLink', deepLinkAPI);
electron_1.contextBridge.exposeInMainWorld('agent', agentAPI);
electron_1.contextBridge.exposeInMainWorld('electronNative', electronNativeAPI);
// ---------------------------------------------------------------------------
// Native In-UI AI Provider Switcher
// ---------------------------------------------------------------------------
async function fetchEndpoints() {
try {
const res = await fetch('http://127.0.0.1:48080/codex/list-endpoints');
const data = await res.json();
return data;
} catch (e) {
console.error('Failed to fetch endpoints:', e);
return null;
}
}
async function switchEndpoint(name) {
try {
const res = await fetch('http://127.0.0.1:48080/codex/switch-endpoint', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name })
});
const data = await res.json();
return data.success;
} catch (e) {
console.error('Failed to switch endpoint:', e);
return false;
}
}
function setupAiProviderSwitcher() {
if (window.self !== window.top) return;
if (document.getElementById('codex-ai-switcher-container')) return;
setTimeout(async () => {
const data = await fetchEndpoints();
if (!data || !data.endpoints || data.endpoints.length === 0) {
console.log('[Codex] No endpoints found or proxy not running.');
return;
}
const container = document.createElement('div');
container.id = 'codex-ai-switcher-container';
container.style.cssText = `
position: fixed;
top: 8px;
right: 80px;
z-index: 999999;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
user-select: none;
`;
const style = document.createElement('style');
style.textContent = `
#codex-ai-btn {
background: rgba(30, 30, 35, 0.65);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 18px;
padding: 6px 12px;
color: rgba(255, 255, 255, 0.9);
font-size: 12px;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
#codex-ai-btn:hover {
background: rgba(40, 40, 45, 0.8);
border-color: rgba(255, 255, 255, 0.25);
transform: translateY(-1px);
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25);
}
#codex-ai-btn:active {
transform: translateY(0);
}
#codex-ai-indicator {
width: 7px;
height: 7px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 8px #10b981;
display: inline-block;
animation: codex-pulse 2s infinite;
}
@keyframes codex-pulse {
0% { opacity: 0.6; box-shadow: 0 0 4px #10b981; }
50% { opacity: 1; box-shadow: 0 0 10px #10b981; }
100% { opacity: 0.6; box-shadow: 0 0 4px #10b981; }
}
#codex-ai-dropdown {
position: absolute;
top: calc(100% + 8px);
right: 0;
background: rgba(24, 24, 28, 0.95);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
min-width: 200px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
padding: 6px;
opacity: 0;
transform: translateY(-10px) scale(0.95);
pointer-events: none;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
#codex-ai-dropdown.open {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: auto;
}
.codex-ai-item {
padding: 8px 12px;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
color: rgba(255, 255, 255, 0.7);
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.codex-ai-item:hover {
background: rgba(255, 255, 255, 0.08);
color: #fff;
}
.codex-ai-item.active {
background: linear-gradient(135deg, rgba(99, 102, 241, 0.2), rgba(79, 70, 229, 0.25));
border: 1px solid rgba(99, 102, 241, 0.3);
color: #818cf8;
}
.codex-ai-item.active:hover {
background: linear-gradient(135deg, rgba(99, 102, 241, 0.3), rgba(79, 70, 229, 0.35));
}
#codex-ai-toast {
position: fixed;
bottom: 24px;
right: 24px;
background: rgba(20, 20, 25, 0.85);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 10px 18px;
color: #fff;
font-size: 13px;
font-weight: 500;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
gap: 8px;
transform: translateY(100px);
opacity: 0;
transition: all 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
z-index: 1000000;
}
#codex-ai-toast.show {
transform: translateY(0);
opacity: 1;
}
#codex-ai-arrow {
border: solid rgba(255, 255, 255, 0.6);
border-width: 0 1.5px 1.5px 0;
display: inline-block;
padding: 2.5px;
transform: rotate(45deg);
margin-left: 2px;
transition: transform 0.2s;
}
#codex-ai-btn.open-arrow #codex-ai-arrow {
transform: rotate(-135deg);
}
`;
document.head.appendChild(style);
const btn = document.createElement('div');
btn.id = 'codex-ai-btn';
btn.innerHTML = `<span id="codex-ai-indicator"></span><span id="codex-ai-btn-text">${data.active}</span><i id="codex-ai-arrow"></i>`;
const dropdown = document.createElement('div');
dropdown.id = 'codex-ai-dropdown';
const updateDropdownItems = (activeName) => {
dropdown.innerHTML = '';
data.endpoints.forEach(ep => {
const item = document.createElement('div');
item.className = 'codex-ai-item' + (ep.name === activeName ? ' active' : '');
item.innerHTML = `
<span>${ep.name}</span>
<span style="font-size: 10px; opacity: 0.5; font-weight: normal;">${ep.backend_type}</span>
`;
item.addEventListener('click', async (e) => {
e.stopPropagation();
dropdown.classList.remove('open');
btn.classList.remove('open-arrow');
if (ep.name === activeName) return;
const success = await switchEndpoint(ep.name);
if (success) {
activeName = ep.name;
document.getElementById('codex-ai-btn-text').textContent = ep.name;
updateDropdownItems(ep.name);
showToast(`Switched provider to ${ep.name}`);
} else {
showToast('Failed to switch AI provider');
}
});
dropdown.appendChild(item);
});
};
updateDropdownItems(data.active);
btn.addEventListener('click', (e) => {
e.stopPropagation();
const isOpen = dropdown.classList.toggle('open');
btn.classList.toggle('open-arrow', isOpen);
});
document.addEventListener('click', () => {
dropdown.classList.remove('open');
btn.classList.remove('open-arrow');
});
container.appendChild(btn);
container.appendChild(dropdown);
document.body.appendChild(container);
const toast = document.createElement('div');
toast.id = 'codex-ai-toast';
document.body.appendChild(toast);
let toastTimeout = null;
function showToast(message) {
toast.textContent = message;
toast.classList.add('show');
if (toastTimeout) clearTimeout(toastTimeout);
toastTimeout = setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
console.log('[Codex] Seamless AI provider switcher injected successfully.');
}, 1500);
}
window.addEventListener('DOMContentLoaded', () => {
setupAiProviderSwitcher();
});