opencode-antigravity-config 1.0.0
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 +111 -0
- package/app.png +0 -0
- package/cli.js +17 -0
- package/config-data.js +23 -0
- package/i18n.js +198 -0
- package/index.html +432 -0
- package/main.js +307 -0
- package/package.json +27 -0
- package/preload.js +22 -0
- package/renderer.js +316 -0
- package/styles.css +1086 -0
- package/templates/dcp.jsonc +81 -0
- package/templates/oh-my-opencode.jsonc +173 -0
- package/templates/opencode-sync.jsonc +12 -0
- package/templates/opencode.json +236 -0
- package/templates/package.json +6 -0
- package/templates/supermemory.jsonc +15 -0
package/main.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const { exec, spawn } = require('child_process');
|
|
7
|
+
const configData = require('./config-data.js');
|
|
8
|
+
|
|
9
|
+
let mainWindow;
|
|
10
|
+
const configDir = path.join(os.homedir(), '.config', 'opencode');
|
|
11
|
+
|
|
12
|
+
const CONFIG_VERSION = '1.0.0';
|
|
13
|
+
const CONFIG_DATE = '2026-02-20';
|
|
14
|
+
const VERSION_CHECK_URL = '';
|
|
15
|
+
|
|
16
|
+
const BUNDLED_CONFIGS = [
|
|
17
|
+
{ name: "opencode.json", key: "opencode_json", sensitive: false },
|
|
18
|
+
{ name: "oh-my-opencode.jsonc", key: "oh_my_opencode_jsonc", sensitive: false },
|
|
19
|
+
{ name: "dcp.jsonc", key: "dcp_jsonc", sensitive: false },
|
|
20
|
+
{ name: "supermemory.jsonc", key: "supermemory_jsonc", sensitive: true },
|
|
21
|
+
{ name: "opencode-sync.jsonc", key: "opencode_sync_jsonc", sensitive: true },
|
|
22
|
+
{ name: "package.json", key: "package_json", sensitive: false }
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function createWindow() {
|
|
26
|
+
mainWindow = new BrowserWindow({
|
|
27
|
+
width: 860,
|
|
28
|
+
height: 680,
|
|
29
|
+
frame: false,
|
|
30
|
+
transparent: true,
|
|
31
|
+
resizable: false,
|
|
32
|
+
webPreferences: {
|
|
33
|
+
nodeIntegration: false,
|
|
34
|
+
contextIsolation: true,
|
|
35
|
+
preload: path.join(__dirname, 'preload.js')
|
|
36
|
+
},
|
|
37
|
+
icon: fs.existsSync(path.join(__dirname, 'app.ico'))
|
|
38
|
+
? path.join(__dirname, 'app.ico')
|
|
39
|
+
: fs.existsSync(path.join(__dirname, 'app.png'))
|
|
40
|
+
? path.join(__dirname, 'app.png')
|
|
41
|
+
: undefined
|
|
42
|
+
});
|
|
43
|
+
mainWindow.loadFile('index.html');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
app.whenReady().then(() => {
|
|
47
|
+
createWindow();
|
|
48
|
+
app.on('activate', () => {
|
|
49
|
+
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
app.on('window-all-closed', () => {
|
|
54
|
+
if (process.platform !== 'darwin') app.quit();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Window Controls
|
|
58
|
+
ipcMain.on('window-minimize', () => { if (mainWindow) mainWindow.minimize(); });
|
|
59
|
+
ipcMain.on('window-close', () => { if (mainWindow) mainWindow.close(); });
|
|
60
|
+
ipcMain.on('open-config-folder', () => { if (fs.existsSync(configDir)) shell.openPath(configDir); });
|
|
61
|
+
ipcMain.on('run-auth-login', () => {
|
|
62
|
+
if (process.platform === 'win32') {
|
|
63
|
+
spawn('cmd.exe', ['/c', 'start', 'cmd', '/k', 'opencode auth login'], { detached: true, stdio: 'ignore' });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
function runCommand(cmd) {
|
|
68
|
+
return new Promise(resolve => {
|
|
69
|
+
exec(cmd, { timeout: 10000 }, (err, stdout) => resolve(err ? null : stdout.trim()));
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Config Metadata
|
|
74
|
+
ipcMain.handle('get-config-meta', async () => ({
|
|
75
|
+
version: CONFIG_VERSION, date: CONFIG_DATE, fileCount: Object.keys(configData).length
|
|
76
|
+
}));
|
|
77
|
+
|
|
78
|
+
// System Check
|
|
79
|
+
ipcMain.handle('check-system', async () => {
|
|
80
|
+
const items = [];
|
|
81
|
+
const nodeVer = await runCommand('node -v');
|
|
82
|
+
items.push(nodeVer ? { label: 'Node.js', value: nodeVer, status: 'ok' } : { label: 'Node.js', value: 'Not found', status: 'fail' });
|
|
83
|
+
const npmVer = await runCommand('npm -v');
|
|
84
|
+
items.push(npmVer ? { label: 'npm', value: 'v' + npmVer, status: 'ok' } : { label: 'npm', value: 'Not found', status: 'fail' });
|
|
85
|
+
const ocVer = await runCommand('opencode --version');
|
|
86
|
+
items.push(ocVer ? { label: 'OpenCode', value: ocVer, status: 'ok' } : { label: 'OpenCode', value: 'Not found — npm i -g opencode@latest', status: 'warn' });
|
|
87
|
+
const bk = Object.keys(configData).length;
|
|
88
|
+
items.push({ label: 'Embedded Configs', value: `${bk}/6 files`, status: bk === 6 ? 'ok' : 'fail' });
|
|
89
|
+
if (fs.existsSync(configDir)) {
|
|
90
|
+
const f = fs.readdirSync(configDir).filter(x => x.endsWith('.json') || x.endsWith('.jsonc'));
|
|
91
|
+
items.push(f.length > 0 ? { label: 'Existing Config', value: `${f.length} files (will backup)`, status: 'warn' } : { label: 'Config Dir', value: 'Exists, empty', status: 'ok' });
|
|
92
|
+
} else {
|
|
93
|
+
items.push({ label: 'Config Dir', value: 'Will be created', status: 'ok' });
|
|
94
|
+
}
|
|
95
|
+
items.push({ label: 'System', value: `${os.type()} ${os.release()} | ${os.userInfo().username}`, status: 'ok' });
|
|
96
|
+
return { items };
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Get Existing Keys
|
|
100
|
+
ipcMain.handle('get-existing-keys', async () => {
|
|
101
|
+
const keys = { supermemoryKey: '', openSyncKey: '', openSyncUrl: '' };
|
|
102
|
+
try {
|
|
103
|
+
if (!fs.existsSync(configDir)) return keys;
|
|
104
|
+
const smPath = path.join(configDir, 'supermemory.jsonc');
|
|
105
|
+
if (fs.existsSync(smPath)) { const c = fs.readFileSync(smPath, 'utf8'); const m = c.match(/"apiKey"\s*:\s*"([^"]+)"/); if (m && m[1] && m[1] !== "__SUPERMEMORY_API_KEY__") keys.supermemoryKey = m[1]; }
|
|
106
|
+
const osPath = path.join(configDir, 'opencode-sync.jsonc');
|
|
107
|
+
if (fs.existsSync(osPath)) { const c = fs.readFileSync(osPath, 'utf8'); const mk = c.match(/"apiKey"\s*:\s*"([^"]+)"/); if (mk && mk[1] && mk[1] !== "__OPENSYNC_API_KEY__") keys.openSyncKey = mk[1]; const mu = c.match(/"convexUrl"\s*:\s*"([^"]+)"/); if (mu && mu[1] && mu[1] !== "__OPENSYNC_CONVEX_URL__") keys.openSyncUrl = mu[1]; }
|
|
108
|
+
} catch (e) { }
|
|
109
|
+
return keys;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Preview Config
|
|
113
|
+
ipcMain.handle('preview-config', async (ev, fileName) => {
|
|
114
|
+
const cfg = BUNDLED_CONFIGS.find(c => c.name === fileName);
|
|
115
|
+
if (!cfg || !configData[cfg.key]) return { error: 'Not found' };
|
|
116
|
+
return { content: Buffer.from(configData[cfg.key], 'base64').toString('utf8'), fileName: cfg.name };
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Diff Config
|
|
120
|
+
ipcMain.handle('preview-final-opencode', async (ev, plugins) => {
|
|
121
|
+
const b64 = configData['opencode_json'];
|
|
122
|
+
let content = Buffer.from(b64, 'base64').toString('utf8');
|
|
123
|
+
if (plugins) {
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(content);
|
|
126
|
+
if (Array.isArray(parsed.plugin)) {
|
|
127
|
+
parsed.plugin = parsed.plugin.filter(p => plugins.includes(p));
|
|
128
|
+
content = JSON.stringify(parsed, null, 4);
|
|
129
|
+
}
|
|
130
|
+
} catch (e) { }
|
|
131
|
+
}
|
|
132
|
+
return { fileName: 'opencode.json', content };
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
ipcMain.handle('diff-config', async (ev, fileName) => {
|
|
136
|
+
const cfg = BUNDLED_CONFIGS.find(c => c.name === fileName);
|
|
137
|
+
if (!cfg || !configData[cfg.key]) return { error: 'Not found' };
|
|
138
|
+
const newContent = Buffer.from(configData[cfg.key], 'base64').toString('utf8');
|
|
139
|
+
const ep = path.join(configDir, fileName);
|
|
140
|
+
if (!fs.existsSync(ep)) return { isNew: true, newContent, fileName };
|
|
141
|
+
const oldContent = fs.readFileSync(ep, 'utf8');
|
|
142
|
+
const oL = oldContent.split('\n'), nL = newContent.split('\n');
|
|
143
|
+
const max = Math.max(oL.length, nL.length);
|
|
144
|
+
const diffLines = [];
|
|
145
|
+
for (let i = 0; i < max; i++) {
|
|
146
|
+
const o = i < oL.length ? oL[i] : undefined, n = i < nL.length ? nL[i] : undefined;
|
|
147
|
+
if (o === undefined) diffLines.push({ type: 'add', content: n });
|
|
148
|
+
else if (n === undefined) diffLines.push({ type: 'del', content: o });
|
|
149
|
+
else if (o.trimEnd() !== n.trimEnd()) { diffLines.push({ type: 'del', content: o }); diffLines.push({ type: 'add', content: n }); }
|
|
150
|
+
else diffLines.push({ type: 'same', content: o });
|
|
151
|
+
}
|
|
152
|
+
return { isNew: false, hasChanges: diffLines.some(d => d.type !== 'same'), diffLines, fileName };
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Export / Import
|
|
156
|
+
ipcMain.handle('export-settings', async (ev, settings) => {
|
|
157
|
+
const r = await dialog.showSaveDialog(mainWindow, { title: 'Export Settings', defaultPath: path.join(os.homedir(), 'Desktop', 'antigravity-settings.json'), filters: [{ name: 'JSON', extensions: ['json'] }] });
|
|
158
|
+
if (r.canceled) return { saved: false };
|
|
159
|
+
fs.writeFileSync(r.filePath, JSON.stringify(settings, null, 2), 'utf8');
|
|
160
|
+
return { saved: true, path: r.filePath };
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
ipcMain.handle('import-settings', async () => {
|
|
164
|
+
const r = await dialog.showOpenDialog(mainWindow, { title: 'Import Settings', filters: [{ name: 'JSON', extensions: ['json'] }], properties: ['openFile'] });
|
|
165
|
+
if (r.canceled || !r.filePaths.length) return { loaded: false };
|
|
166
|
+
try { return { loaded: true, settings: JSON.parse(fs.readFileSync(r.filePaths[0], 'utf8')) }; }
|
|
167
|
+
catch (e) { return { loaded: false, error: e.message }; }
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Version Check
|
|
171
|
+
ipcMain.handle('check-version', async () => {
|
|
172
|
+
if (!VERSION_CHECK_URL) return { current: CONFIG_VERSION, latest: CONFIG_VERSION, upToDate: true, noEndpoint: true };
|
|
173
|
+
return new Promise(resolve => {
|
|
174
|
+
const req = https.get(VERSION_CHECK_URL, { timeout: 5000 }, res => {
|
|
175
|
+
let d = ''; res.on('data', c => d += c);
|
|
176
|
+
res.on('end', () => { try { const j = JSON.parse(d); resolve({ current: CONFIG_VERSION, latest: j.version || CONFIG_VERSION, upToDate: (j.version || CONFIG_VERSION) === CONFIG_VERSION }); } catch (e) { resolve({ current: CONFIG_VERSION, latest: CONFIG_VERSION, upToDate: true, error: 'Parse error' }); } });
|
|
177
|
+
});
|
|
178
|
+
req.on('error', () => resolve({ current: CONFIG_VERSION, latest: CONFIG_VERSION, upToDate: true, error: 'Network error' }));
|
|
179
|
+
req.on('timeout', () => { req.destroy(); resolve({ current: CONFIG_VERSION, latest: CONFIG_VERSION, upToDate: true, error: 'Timeout' }); });
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Uninstall
|
|
184
|
+
ipcMain.handle('uninstall-config', async () => {
|
|
185
|
+
if (!fs.existsSync(configDir)) return { success: false, message: 'Config directory not found' };
|
|
186
|
+
const files = fs.readdirSync(configDir).filter(f => f.endsWith('.json') || f.endsWith('.jsonc'));
|
|
187
|
+
if (!files.length) return { success: false, message: 'No config files found' };
|
|
188
|
+
try {
|
|
189
|
+
const ds = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
190
|
+
const bd = path.join(configDir, `.uninstall-backup-${ds}`);
|
|
191
|
+
fs.mkdirSync(bd, { recursive: true });
|
|
192
|
+
for (const f of files) { fs.copyFileSync(path.join(configDir, f), path.join(bd, f)); fs.unlinkSync(path.join(configDir, f)); }
|
|
193
|
+
return { success: true, removed: files, backupDir: path.basename(bd) };
|
|
194
|
+
} catch (e) { return { success: false, message: e.message }; }
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Install Flow
|
|
198
|
+
function sendLog(type, message) { if (mainWindow) mainWindow.webContents.send('install-log', { type, message }); }
|
|
199
|
+
function sendProgress(pct) { if (mainWindow) mainWindow.webContents.send('install-progress', pct); }
|
|
200
|
+
|
|
201
|
+
ipcMain.on('start-install', async (ev, config) => {
|
|
202
|
+
try {
|
|
203
|
+
sendLog('info', 'Creating config directory...'); await new Promise(r => setTimeout(r, 100));
|
|
204
|
+
if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); sendLog('success', `Created: ${configDir}`); }
|
|
205
|
+
else sendLog('info', `Directory exists: ${configDir}`);
|
|
206
|
+
sendProgress(10);
|
|
207
|
+
|
|
208
|
+
if (config.backup && fs.existsSync(configDir)) {
|
|
209
|
+
const ds = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
210
|
+
const bd = path.join(configDir, `.backup-${ds}`);
|
|
211
|
+
const ef = fs.readdirSync(configDir).filter(f => f.endsWith('.json') || f.endsWith('.jsonc'));
|
|
212
|
+
if (ef.length) { sendLog('info', 'Backing up...'); fs.mkdirSync(bd); for (const f of ef) { fs.copyFileSync(path.join(configDir, f), path.join(bd, f)); sendLog('info', `Backed up: ${f}`); await new Promise(r => setTimeout(r, 60)); } sendLog('success', `Backup: ${path.basename(bd)}`); }
|
|
213
|
+
}
|
|
214
|
+
sendProgress(25); await new Promise(r => setTimeout(r, 100));
|
|
215
|
+
|
|
216
|
+
const toInstall = BUNDLED_CONFIGS;
|
|
217
|
+
let step = 25; const inc = toInstall.length > 0 ? 40 / toInstall.length : 40;
|
|
218
|
+
|
|
219
|
+
for (const cfg of toInstall) {
|
|
220
|
+
const b64 = configData[cfg.key]; if (!b64) { sendLog('warn', `Skip: ${cfg.name}`); step += inc; continue; }
|
|
221
|
+
let content = Buffer.from(b64, 'base64').toString('utf8');
|
|
222
|
+
if (cfg.sensitive) {
|
|
223
|
+
if (cfg.name === 'supermemory.jsonc' && config.supermemoryKey) { content = content.replace('__SUPERMEMORY_API_KEY__', config.supermemoryKey); sendLog('info', 'Supermemory key injected'); }
|
|
224
|
+
if (cfg.name === 'opencode-sync.jsonc') { if (config.openSyncKey) { content = content.replace('__OPENSYNC_API_KEY__', config.openSyncKey); sendLog('info', 'OpenSync key injected'); } if (config.openSyncUrl) { content = content.replace('__OPENSYNC_CONVEX_URL__', config.openSyncUrl); sendLog('info', 'OpenSync URL injected'); } }
|
|
225
|
+
}
|
|
226
|
+
// Filter plugins in opencode.json based on user selection
|
|
227
|
+
if (cfg.name === 'opencode.json' && config.selectedPlugins) {
|
|
228
|
+
try {
|
|
229
|
+
const parsed = JSON.parse(content);
|
|
230
|
+
if (Array.isArray(parsed.plugin)) {
|
|
231
|
+
const original = parsed.plugin.length;
|
|
232
|
+
parsed.plugin = parsed.plugin.filter(p => config.selectedPlugins.includes(p));
|
|
233
|
+
sendLog('info', `Plugins: ${parsed.plugin.length}/${original} selected`);
|
|
234
|
+
parsed.plugin.forEach(p => sendLog('info', ` ✓ ${p}`));
|
|
235
|
+
content = JSON.stringify(parsed, null, 4);
|
|
236
|
+
}
|
|
237
|
+
} catch (e) { sendLog('warn', `Plugin filter skipped: ${e.message}`); }
|
|
238
|
+
}
|
|
239
|
+
// Inject custom agent models into oh-my-opencode.jsonc
|
|
240
|
+
if (cfg.name === 'oh-my-opencode.jsonc' && config.agentModels) {
|
|
241
|
+
try {
|
|
242
|
+
const agentKeyMap = { multimodal_looker: 'multimodal-looker' };
|
|
243
|
+
let changed = 0;
|
|
244
|
+
|
|
245
|
+
Object.entries(config.agentModels).forEach(([key, model]) => {
|
|
246
|
+
const jsonKey = agentKeyMap[key] || key;
|
|
247
|
+
const re = new RegExp(`("${jsonKey}"\\s*:\\s*\\{[^}]*?"model"\\s*:\\s*)"([^"]*)"`, 's');
|
|
248
|
+
const match = content.match(re);
|
|
249
|
+
if (match && match[2] !== model) {
|
|
250
|
+
content = content.replace(re, `$1"${model}"`);
|
|
251
|
+
sendLog('info', `Agent ${jsonKey}: ${match[2].split('/').pop()} → ${model.split('/').pop()}`);
|
|
252
|
+
changed++;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Also update categories based on agent groups
|
|
257
|
+
const heavyModel = config.agentModels.sisyphus || 'google/antigravity-gemini-3-1-pro';
|
|
258
|
+
const lightModel = config.agentModels.librarian || 'google/antigravity-gemini-3-flash';
|
|
259
|
+
const catMap = {
|
|
260
|
+
'visual-engineering': heavyModel, 'ultrabrain': heavyModel, 'deep': heavyModel,
|
|
261
|
+
'artistry': heavyModel, 'unspecified-high': heavyModel, 'unspecified-low': heavyModel,
|
|
262
|
+
'quick': lightModel, 'writing': lightModel
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
Object.entries(catMap).forEach(([cat, model]) => {
|
|
266
|
+
const re = new RegExp(`("${cat}"\\s*:\\s*\\{[^}]*?"model"\\s*:\\s*)"([^"]*)"`, 's');
|
|
267
|
+
const match = content.match(re);
|
|
268
|
+
if (match && match[2] !== model) {
|
|
269
|
+
content = content.replace(re, `$1"${model}"`);
|
|
270
|
+
changed++;
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
if (changed > 0) sendLog('success', `Agent models: ${changed} updated`);
|
|
275
|
+
else sendLog('info', 'Agent models: no changes (using defaults)');
|
|
276
|
+
} catch (e) { sendLog('warn', `Agent model injection skipped: ${e.message}`); }
|
|
277
|
+
}
|
|
278
|
+
fs.writeFileSync(path.join(configDir, cfg.name), content, 'utf8');
|
|
279
|
+
sendLog('success', `Installed: ${cfg.name}`); step += inc; sendProgress(Math.min(Math.floor(step), 65));
|
|
280
|
+
await new Promise(r => setTimeout(r, 120));
|
|
281
|
+
}
|
|
282
|
+
sendProgress(65);
|
|
283
|
+
|
|
284
|
+
if (config.npmInstall) {
|
|
285
|
+
sendLog('info', ''); sendLog('info', 'Running npm install...');
|
|
286
|
+
const ok = await new Promise(resolve => {
|
|
287
|
+
const p = spawn('npm', ['install'], { cwd: configDir, shell: true, env: { ...process.env } });
|
|
288
|
+
let prog = 65;
|
|
289
|
+
p.stdout.on('data', d => { for (const l of d.toString().trim().split('\n')) { if (l.trim()) { sendLog('info', ` npm: ${l.trim()}`); prog = Math.min(prog + 2, 88); sendProgress(prog); } } });
|
|
290
|
+
p.stderr.on('data', d => { for (const l of d.toString().trim().split('\n')) { if (l.trim() && !l.includes('npm warn')) sendLog('warn', ` npm: ${l.trim()}`); } });
|
|
291
|
+
p.on('close', c => resolve(c === 0)); p.on('error', () => resolve(false));
|
|
292
|
+
});
|
|
293
|
+
sendLog(ok ? 'success' : 'warn', ok ? 'npm dependencies installed' : 'npm install had warnings');
|
|
294
|
+
} else sendLog('info', 'Skipped npm install');
|
|
295
|
+
|
|
296
|
+
sendProgress(90); await new Promise(r => setTimeout(r, 100));
|
|
297
|
+
sendLog('info', ''); sendLog('info', '─── Verification ───');
|
|
298
|
+
const cnt = fs.existsSync(configDir) ? fs.readdirSync(configDir).filter(f => f.endsWith('.json') || f.endsWith('.jsonc')).length : 0;
|
|
299
|
+
sendLog('success', `${cnt} config files installed`);
|
|
300
|
+
sendProgress(100); await new Promise(r => setTimeout(r, 200));
|
|
301
|
+
sendLog('info', ''); sendLog('success', '🎉 Installation complete!');
|
|
302
|
+
mainWindow.webContents.send('install-complete', { success: true, configPath: configDir });
|
|
303
|
+
} catch (e) {
|
|
304
|
+
sendLog('error', `ERROR: ${e.message}`);
|
|
305
|
+
mainWindow.webContents.send('install-complete', { success: false, error: e.message });
|
|
306
|
+
}
|
|
307
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-antigravity-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "GUI installer for Antigravity OpenCode configuration",
|
|
5
|
+
"main": "main.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"opencode-agc": "cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "electron ."
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"opencode",
|
|
14
|
+
"antigravity",
|
|
15
|
+
"config",
|
|
16
|
+
"installer",
|
|
17
|
+
"electron"
|
|
18
|
+
],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@fontsource/fira-code": "^5.2.7",
|
|
23
|
+
"electron": "^40.6.0",
|
|
24
|
+
"jimp": "^1.6.0",
|
|
25
|
+
"png-to-ico": "^3.0.1"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/preload.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { contextBridge, ipcRenderer } = require('electron');
|
|
2
|
+
|
|
3
|
+
contextBridge.exposeInMainWorld('api', {
|
|
4
|
+
minimize: () => ipcRenderer.send('window-minimize'),
|
|
5
|
+
close: () => ipcRenderer.send('window-close'),
|
|
6
|
+
checkSystem: () => ipcRenderer.invoke('check-system'),
|
|
7
|
+
getExistingKeys: () => ipcRenderer.invoke('get-existing-keys'),
|
|
8
|
+
getConfigMeta: () => ipcRenderer.invoke('get-config-meta'),
|
|
9
|
+
previewConfig: (fileName) => ipcRenderer.invoke('preview-config', fileName),
|
|
10
|
+
diffConfig: (fileName) => ipcRenderer.invoke('diff-config', fileName),
|
|
11
|
+
exportSettings: (settings) => ipcRenderer.invoke('export-settings', settings),
|
|
12
|
+
importSettings: () => ipcRenderer.invoke('import-settings'),
|
|
13
|
+
checkVersion: () => ipcRenderer.invoke('check-version'),
|
|
14
|
+
uninstallConfig: () => ipcRenderer.invoke('uninstall-config'),
|
|
15
|
+
previewFinalOpencode: (p) => ipcRenderer.invoke('preview-final-opencode', p),
|
|
16
|
+
startInstall: (config) => ipcRenderer.send('start-install', config),
|
|
17
|
+
onInstallProgress: (cb) => { ipcRenderer.removeAllListeners('install-progress'); ipcRenderer.on('install-progress', (e, d) => cb(d)); },
|
|
18
|
+
onInstallLog: (cb) => { ipcRenderer.removeAllListeners('install-log'); ipcRenderer.on('install-log', (e, d) => cb(d)); },
|
|
19
|
+
onInstallComplete: (cb) => { ipcRenderer.removeAllListeners('install-complete'); ipcRenderer.on('install-complete', (e, d) => cb(d)); },
|
|
20
|
+
openConfigFolder: () => ipcRenderer.send('open-config-folder'),
|
|
21
|
+
runAuthLogin: () => ipcRenderer.send('run-auth-login')
|
|
22
|
+
});
|