opencode-studio-server 1.9.5 → 1.9.8
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/index.js +111 -5
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -17,10 +17,24 @@ const atomicWriteFileSync = (filePath, data, options = 'utf8') => {
|
|
|
17
17
|
const tempPath = path.join(dir, `.${path.basename(filePath)}.${crypto.randomBytes(6).toString('hex')}.tmp`);
|
|
18
18
|
try {
|
|
19
19
|
fs.writeFileSync(tempPath, data, options);
|
|
20
|
-
|
|
20
|
+
// Retry rename for Windows file locking issues
|
|
21
|
+
let retries = 5;
|
|
22
|
+
while (retries > 0) {
|
|
23
|
+
try {
|
|
24
|
+
fs.renameSync(tempPath, filePath);
|
|
25
|
+
break;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
if (retries === 1) throw e;
|
|
28
|
+
retries--;
|
|
29
|
+
// Synchronous delay
|
|
30
|
+
const start = Date.now();
|
|
31
|
+
while (Date.now() - start < 50) {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
21
34
|
} catch (err) {
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
if (fs.existsSync(tempPath)) {
|
|
36
|
+
try { fs.unlinkSync(tempPath); } catch (e) {}
|
|
37
|
+
}
|
|
24
38
|
throw err;
|
|
25
39
|
}
|
|
26
40
|
};
|
|
@@ -276,6 +290,10 @@ function loadStudioConfig() {
|
|
|
276
290
|
activeGooglePlugin: 'gemini',
|
|
277
291
|
availableGooglePlugins: [],
|
|
278
292
|
presets: [],
|
|
293
|
+
cooldownRules: [
|
|
294
|
+
{ name: "Opus 4.5 (Antigravity)", duration: 4 * 60 * 60 * 1000 }, // 4 hours
|
|
295
|
+
{ name: "Gemini 3 Pro (Antigravity)", duration: 24 * 60 * 60 * 1000 } // 24 hours
|
|
296
|
+
],
|
|
279
297
|
pluginModels: {
|
|
280
298
|
gemini: {
|
|
281
299
|
"gemini-3-pro-preview": {
|
|
@@ -632,6 +650,36 @@ app.post('/api/restore', (req, res) => {
|
|
|
632
650
|
}
|
|
633
651
|
});
|
|
634
652
|
|
|
653
|
+
app.get('/api/cooldowns', (req, res) => {
|
|
654
|
+
const studio = loadStudioConfig();
|
|
655
|
+
res.json(studio.cooldownRules || []);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
app.post('/api/cooldowns', (req, res) => {
|
|
659
|
+
const { name, duration } = req.body;
|
|
660
|
+
if (!name || typeof duration !== 'number') return res.status(400).json({ error: 'Invalid name or duration' });
|
|
661
|
+
const studio = loadStudioConfig();
|
|
662
|
+
if (!studio.cooldownRules) studio.cooldownRules = [];
|
|
663
|
+
|
|
664
|
+
// Update if exists, else push
|
|
665
|
+
const idx = studio.cooldownRules.findIndex(r => r.name === name);
|
|
666
|
+
if (idx >= 0) studio.cooldownRules[idx] = { name, duration };
|
|
667
|
+
else studio.cooldownRules.push({ name, duration });
|
|
668
|
+
|
|
669
|
+
saveStudioConfig(studio);
|
|
670
|
+
res.json(studio.cooldownRules);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
app.delete('/api/cooldowns/:name', (req, res) => {
|
|
674
|
+
const { name } = req.params;
|
|
675
|
+
const studio = loadStudioConfig();
|
|
676
|
+
if (studio.cooldownRules) {
|
|
677
|
+
studio.cooldownRules = studio.cooldownRules.filter(r => r.name !== name);
|
|
678
|
+
saveStudioConfig(studio);
|
|
679
|
+
}
|
|
680
|
+
res.json(studio.cooldownRules || []);
|
|
681
|
+
});
|
|
682
|
+
|
|
635
683
|
const DROPBOX_CLIENT_ID = 'your-dropbox-app-key';
|
|
636
684
|
const GDRIVE_CLIENT_ID = 'your-google-client-id';
|
|
637
685
|
|
|
@@ -1342,6 +1390,7 @@ app.get('/api/auth/providers', (req, res) => {
|
|
|
1342
1390
|
});
|
|
1343
1391
|
|
|
1344
1392
|
app.get('/api/auth', (req, res) => {
|
|
1393
|
+
importCurrentGoogleAuthToPool();
|
|
1345
1394
|
syncAntigravityPool();
|
|
1346
1395
|
const authCfg = loadAuthConfig() || {};
|
|
1347
1396
|
const studio = loadStudioConfig();
|
|
@@ -1814,6 +1863,55 @@ function listAntigravityAccounts() {
|
|
|
1814
1863
|
}));
|
|
1815
1864
|
}
|
|
1816
1865
|
|
|
1866
|
+
function importCurrentGoogleAuthToPool() {
|
|
1867
|
+
const studio = loadStudioConfig();
|
|
1868
|
+
// Only applies if Antigravity is active
|
|
1869
|
+
if (studio.activeGooglePlugin !== 'antigravity') return;
|
|
1870
|
+
|
|
1871
|
+
const authCfg = loadAuthConfig();
|
|
1872
|
+
if (!authCfg || !authCfg.google || !authCfg.google.email) return;
|
|
1873
|
+
|
|
1874
|
+
const namespace = 'google.antigravity';
|
|
1875
|
+
const profileDir = path.join(AUTH_PROFILES_DIR, namespace);
|
|
1876
|
+
if (!fs.existsSync(profileDir)) fs.mkdirSync(profileDir, { recursive: true });
|
|
1877
|
+
|
|
1878
|
+
const email = authCfg.google.email;
|
|
1879
|
+
const profilePath = path.join(profileDir, `${email}.json`);
|
|
1880
|
+
|
|
1881
|
+
// Check if we need to sync (new account or updated tokens)
|
|
1882
|
+
let shouldSync = true;
|
|
1883
|
+
if (fs.existsSync(profilePath)) {
|
|
1884
|
+
try {
|
|
1885
|
+
const current = JSON.parse(fs.readFileSync(profilePath, 'utf8'));
|
|
1886
|
+
if (current.access_token === authCfg.google.access_token) {
|
|
1887
|
+
shouldSync = false;
|
|
1888
|
+
}
|
|
1889
|
+
} catch {
|
|
1890
|
+
// Corrupt file, overwrite
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
if (shouldSync) {
|
|
1895
|
+
console.log(`[Auth] Syncing Google login for ${email} to Antigravity pool.`);
|
|
1896
|
+
atomicWriteFileSync(profilePath, JSON.stringify(authCfg.google, null, 2));
|
|
1897
|
+
|
|
1898
|
+
const metadata = loadPoolMetadata();
|
|
1899
|
+
if (!metadata[namespace]) metadata[namespace] = {};
|
|
1900
|
+
|
|
1901
|
+
// Only update metadata if it doesn't exist
|
|
1902
|
+
if (!metadata[namespace][email]) {
|
|
1903
|
+
metadata[namespace][email] = {
|
|
1904
|
+
email: email,
|
|
1905
|
+
createdAt: Date.now(),
|
|
1906
|
+
lastUsed: Date.now(),
|
|
1907
|
+
usageCount: 0,
|
|
1908
|
+
imported: true
|
|
1909
|
+
};
|
|
1910
|
+
savePoolMetadata(metadata);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1817
1915
|
function syncAntigravityPool() {
|
|
1818
1916
|
const accounts = listAntigravityAccounts();
|
|
1819
1917
|
const namespace = 'google.antigravity';
|
|
@@ -2159,7 +2257,15 @@ app.post('/api/auth/pool/limit', (req, res) => {
|
|
|
2159
2257
|
// PUT /api/auth/pool/:name/cooldown - Mark account as in cooldown
|
|
2160
2258
|
app.put('/api/auth/pool/:name/cooldown', (req, res) => {
|
|
2161
2259
|
const { name } = req.params;
|
|
2162
|
-
|
|
2260
|
+
let { duration, provider = 'google', rule } = req.body;
|
|
2261
|
+
|
|
2262
|
+
if (rule) {
|
|
2263
|
+
const studio = loadStudioConfig();
|
|
2264
|
+
const r = (studio.cooldownRules || []).find(cr => cr.name === rule);
|
|
2265
|
+
if (r) duration = r.duration;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
if (!duration) duration = 3600000; // default 1 hour
|
|
2163
2269
|
|
|
2164
2270
|
const activePlugin = getActiveGooglePlugin();
|
|
2165
2271
|
const namespace = provider === 'google'
|
|
@@ -2886,7 +2992,7 @@ app.post('/api/presets/:id/apply', (req, res) => {
|
|
|
2886
2992
|
|
|
2887
2993
|
// Start watcher on server start
|
|
2888
2994
|
function startServer() {
|
|
2889
|
-
setupLogWatcher();
|
|
2995
|
+
// setupLogWatcher(); // Disabled as per user request (manual switching only)
|
|
2890
2996
|
importExistingAuth();
|
|
2891
2997
|
app.listen(PORT, () => console.log(`Server running at http://localhost:${PORT}`));
|
|
2892
2998
|
}
|