opencode-studio-server 1.12.12 → 1.12.14
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 +99 -86
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -291,8 +291,8 @@ function loadStudioConfig() {
|
|
|
291
291
|
availableGooglePlugins: [],
|
|
292
292
|
presets: [],
|
|
293
293
|
cooldownRules: [
|
|
294
|
-
{ name: "Opus
|
|
295
|
-
{ name: "Gemini 3 Pro (
|
|
294
|
+
{ name: "Antigravity Claude Opus (4h)", duration: 4 * 60 * 60 * 1000 },
|
|
295
|
+
{ name: "Antigravity Gemini 3 Pro (24h)", duration: 24 * 60 * 60 * 1000 }
|
|
296
296
|
],
|
|
297
297
|
pluginModels: {
|
|
298
298
|
gemini: {
|
|
@@ -427,7 +427,18 @@ function loadStudioConfig() {
|
|
|
427
427
|
if (!fs.existsSync(STUDIO_CONFIG_PATH)) return defaultConfig;
|
|
428
428
|
try {
|
|
429
429
|
const config = JSON.parse(fs.readFileSync(STUDIO_CONFIG_PATH, 'utf8'));
|
|
430
|
-
|
|
430
|
+
const merged = { ...defaultConfig, ...config };
|
|
431
|
+
|
|
432
|
+
if (config.cooldownRules) {
|
|
433
|
+
defaultConfig.cooldownRules.forEach(defaultRule => {
|
|
434
|
+
const existing = config.cooldownRules.find(r => r.name === defaultRule.name);
|
|
435
|
+
if (!existing) {
|
|
436
|
+
merged.cooldownRules.push(defaultRule);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return merged;
|
|
431
442
|
} catch {
|
|
432
443
|
return defaultConfig;
|
|
433
444
|
}
|
|
@@ -1395,22 +1406,6 @@ app.get('/api/auth/providers', (req, res) => {
|
|
|
1395
1406
|
});
|
|
1396
1407
|
|
|
1397
1408
|
app.get('/api/auth', (req, res) => {
|
|
1398
|
-
importCurrentGoogleAuthToPool();
|
|
1399
|
-
syncAntigravityPool();
|
|
1400
|
-
const authCfg = loadAuthConfig() || {};
|
|
1401
|
-
const studio = loadStudioConfig();
|
|
1402
|
-
const ac = studio.activeProfiles || {};
|
|
1403
|
-
const credentials = [];
|
|
1404
|
-
const activePlugin = studio.activeGooglePlugin;
|
|
1405
|
-
|
|
1406
|
-
// DEBUG LOGGING
|
|
1407
|
-
console.log('--- Auth Debug ---');
|
|
1408
|
-
console.log('Active Google Plugin:', activePlugin);
|
|
1409
|
-
console.log('Found keys in authCfg:', Object.keys(authCfg));
|
|
1410
|
-
if (authCfg.google) console.log('Google Auth found!');
|
|
1411
|
-
if (authCfg['google.antigravity']) console.log('google.antigravity found!');
|
|
1412
|
-
if (authCfg['google.gemini']) console.log('google.gemini found!');
|
|
1413
|
-
|
|
1414
1409
|
const providers = [
|
|
1415
1410
|
{ id: 'google', name: 'Google', type: 'oauth' },
|
|
1416
1411
|
{ id: 'anthropic', name: 'Anthropic', type: 'api' },
|
|
@@ -1425,6 +1420,15 @@ app.get('/api/auth', (req, res) => {
|
|
|
1425
1420
|
{ id: 'azure', name: 'Azure OpenAI', type: 'api' }
|
|
1426
1421
|
];
|
|
1427
1422
|
|
|
1423
|
+
providers.forEach(p => importCurrentAuthToPool(p.id));
|
|
1424
|
+
syncAntigravityPool();
|
|
1425
|
+
|
|
1426
|
+
const authCfg = loadAuthConfig() || {};
|
|
1427
|
+
const studio = loadStudioConfig();
|
|
1428
|
+
const ac = studio.activeProfiles || {};
|
|
1429
|
+
const credentials = [];
|
|
1430
|
+
const activePlugin = studio.activeGooglePlugin;
|
|
1431
|
+
|
|
1428
1432
|
const opencodeCfg = loadConfig();
|
|
1429
1433
|
const currentPlugins = opencodeCfg?.plugin || [];
|
|
1430
1434
|
|
|
@@ -1472,13 +1476,15 @@ app.get('/api/auth', (req, res) => {
|
|
|
1472
1476
|
});
|
|
1473
1477
|
|
|
1474
1478
|
app.get('/api/auth/profiles', (req, res) => {
|
|
1479
|
+
const providers = ['google', 'anthropic', 'openai', 'xai', 'openrouter', 'together', 'mistral', 'deepseek', 'amazon-bedrock', 'azure', 'github-copilot'];
|
|
1480
|
+
providers.forEach(p => importCurrentAuthToPool(p));
|
|
1475
1481
|
syncAntigravityPool();
|
|
1482
|
+
|
|
1476
1483
|
const authCfg = loadAuthConfig() || {};
|
|
1477
1484
|
const studio = loadStudioConfig();
|
|
1478
1485
|
const ac = studio.activeProfiles || {};
|
|
1479
1486
|
const activePlugin = studio.activeGooglePlugin;
|
|
1480
1487
|
const profiles = {};
|
|
1481
|
-
const providers = ['google', 'anthropic', 'openai', 'xai', 'openrouter', 'together', 'mistral', 'deepseek', 'amazon-bedrock', 'azure', 'github-copilot'];
|
|
1482
1488
|
|
|
1483
1489
|
providers.forEach(p => {
|
|
1484
1490
|
const saved = listAuthProfiles(p, activePlugin);
|
|
@@ -1871,6 +1877,78 @@ function listAntigravityAccounts() {
|
|
|
1871
1877
|
}));
|
|
1872
1878
|
}
|
|
1873
1879
|
|
|
1880
|
+
function decodeJWT(token) {
|
|
1881
|
+
try {
|
|
1882
|
+
const parts = token.split('.');
|
|
1883
|
+
if (parts.length !== 3) return null;
|
|
1884
|
+
const payload = Buffer.from(parts[1], 'base64').toString('utf8');
|
|
1885
|
+
return JSON.parse(payload);
|
|
1886
|
+
} catch {
|
|
1887
|
+
return null;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
function importCurrentAuthToPool(provider) {
|
|
1892
|
+
if (provider === 'google') {
|
|
1893
|
+
return importCurrentGoogleAuthToPool();
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
const authCfg = loadAuthConfig();
|
|
1897
|
+
if (!authCfg || !authCfg[provider]) return;
|
|
1898
|
+
|
|
1899
|
+
const creds = authCfg[provider];
|
|
1900
|
+
let email = creds.email;
|
|
1901
|
+
|
|
1902
|
+
if (!email && provider === 'openai' && creds.access) {
|
|
1903
|
+
const decoded = decodeJWT(creds.access);
|
|
1904
|
+
if (decoded && decoded['https://api.openai.com/profile']?.email) {
|
|
1905
|
+
email = decoded['https://api.openai.com/profile'].email;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
const name = email || creds.accountId || creds.id || `profile-${Date.now()}`;
|
|
1910
|
+
const profileDir = path.join(AUTH_PROFILES_DIR, provider);
|
|
1911
|
+
if (!fs.existsSync(profileDir)) fs.mkdirSync(profileDir, { recursive: true });
|
|
1912
|
+
|
|
1913
|
+
const profilePath = path.join(profileDir, `${name}.json`);
|
|
1914
|
+
|
|
1915
|
+
let shouldSync = true;
|
|
1916
|
+
if (fs.existsSync(profilePath)) {
|
|
1917
|
+
try {
|
|
1918
|
+
const current = JSON.parse(fs.readFileSync(profilePath, 'utf8'));
|
|
1919
|
+
if (JSON.stringify(current) === JSON.stringify(creds)) {
|
|
1920
|
+
shouldSync = false;
|
|
1921
|
+
}
|
|
1922
|
+
} catch {
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
if (shouldSync) {
|
|
1927
|
+
console.log(`[Auth] Syncing ${provider} login for ${name} to pool.`);
|
|
1928
|
+
atomicWriteFileSync(profilePath, JSON.stringify(creds, null, 2));
|
|
1929
|
+
|
|
1930
|
+
const metadata = loadPoolMetadata();
|
|
1931
|
+
if (!metadata[provider]) metadata[provider] = {};
|
|
1932
|
+
|
|
1933
|
+
metadata[provider][name] = {
|
|
1934
|
+
...(metadata[provider][name] || {}),
|
|
1935
|
+
email: email || null,
|
|
1936
|
+
createdAt: metadata[provider][name]?.createdAt || Date.now(),
|
|
1937
|
+
lastUsed: Date.now(),
|
|
1938
|
+
usageCount: metadata[provider][name]?.usageCount || 0,
|
|
1939
|
+
imported: true
|
|
1940
|
+
};
|
|
1941
|
+
savePoolMetadata(metadata);
|
|
1942
|
+
|
|
1943
|
+
const studio = loadStudioConfig();
|
|
1944
|
+
if (!studio.activeProfiles) studio.activeProfiles = {};
|
|
1945
|
+
if (studio.activeProfiles[provider] !== name) {
|
|
1946
|
+
studio.activeProfiles[provider] = name;
|
|
1947
|
+
saveStudioConfig(studio);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1874
1952
|
function importCurrentGoogleAuthToPool() {
|
|
1875
1953
|
const studio = loadStudioConfig();
|
|
1876
1954
|
// Only applies if Antigravity is active
|
|
@@ -1971,70 +2049,6 @@ function syncAntigravityPool() {
|
|
|
1971
2049
|
savePoolMetadata(metadata);
|
|
1972
2050
|
}
|
|
1973
2051
|
|
|
1974
|
-
function importExistingAuth() {
|
|
1975
|
-
const authCfg = loadAuthConfig();
|
|
1976
|
-
if (!authCfg) return;
|
|
1977
|
-
|
|
1978
|
-
const studio = loadStudioConfig();
|
|
1979
|
-
const activeProfiles = studio.activeProfiles || {};
|
|
1980
|
-
let changed = false;
|
|
1981
|
-
|
|
1982
|
-
// Standard providers to check
|
|
1983
|
-
const providers = ['google', 'openai', 'anthropic', 'xai', 'openrouter', 'github-copilot', 'mistral', 'deepseek', 'amazon-bedrock', 'azure'];
|
|
1984
|
-
|
|
1985
|
-
providers.forEach(provider => {
|
|
1986
|
-
if (!authCfg[provider]) return; // No creds for this provider
|
|
1987
|
-
|
|
1988
|
-
// Determine namespace
|
|
1989
|
-
// For auto-import, we target the standard 'google' namespace unless antigravity plugin is active?
|
|
1990
|
-
// Actually, auth.json 'google' key usually means Gemini/Vertex standard auth.
|
|
1991
|
-
const namespace = provider === 'google' && studio.activeGooglePlugin === 'antigravity'
|
|
1992
|
-
? 'google.antigravity'
|
|
1993
|
-
: (provider === 'google' ? 'google.gemini' : provider);
|
|
1994
|
-
|
|
1995
|
-
const profileDir = path.join(AUTH_PROFILES_DIR, namespace);
|
|
1996
|
-
|
|
1997
|
-
// If we already have an active profile for this provider, skip import
|
|
1998
|
-
if (activeProfiles[provider]) return;
|
|
1999
|
-
|
|
2000
|
-
// If directory exists and has files, check if empty
|
|
2001
|
-
if (fs.existsSync(profileDir) && fs.readdirSync(profileDir).filter(f => f.endsWith('.json')).length > 0) {
|
|
2002
|
-
return;
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
// Import!
|
|
2006
|
-
if (!fs.existsSync(profileDir)) fs.mkdirSync(profileDir, { recursive: true });
|
|
2007
|
-
|
|
2008
|
-
const email = authCfg[provider].email || null;
|
|
2009
|
-
const name = email || `imported-${Date.now()}`;
|
|
2010
|
-
const profilePath = path.join(profileDir, `${name}.json`);
|
|
2011
|
-
|
|
2012
|
-
console.log(`[AutoImport] Importing existing ${provider} credentials as ${name}`);
|
|
2013
|
-
atomicWriteFileSync(profilePath, JSON.stringify(authCfg[provider], null, 2));
|
|
2014
|
-
|
|
2015
|
-
// Set as active
|
|
2016
|
-
if (!studio.activeProfiles) studio.activeProfiles = {};
|
|
2017
|
-
studio.activeProfiles[provider] = name;
|
|
2018
|
-
changed = true;
|
|
2019
|
-
|
|
2020
|
-
// Update metadata
|
|
2021
|
-
const metadata = loadPoolMetadata();
|
|
2022
|
-
if (!metadata[namespace]) metadata[namespace] = {};
|
|
2023
|
-
metadata[namespace][name] = {
|
|
2024
|
-
email: email,
|
|
2025
|
-
createdAt: Date.now(),
|
|
2026
|
-
lastUsed: Date.now(),
|
|
2027
|
-
usageCount: 0,
|
|
2028
|
-
imported: true
|
|
2029
|
-
};
|
|
2030
|
-
savePoolMetadata(metadata);
|
|
2031
|
-
});
|
|
2032
|
-
|
|
2033
|
-
if (changed) {
|
|
2034
|
-
saveStudioConfig(studio);
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
2052
|
function getAccountStatus(meta, now) {
|
|
2039
2053
|
if (!meta) return 'ready';
|
|
2040
2054
|
if (meta.cooldownUntil && meta.cooldownUntil > now) return 'cooldown';
|
|
@@ -3024,8 +3038,7 @@ app.post('/api/presets/:id/apply', (req, res) => {
|
|
|
3024
3038
|
|
|
3025
3039
|
// Start watcher on server start
|
|
3026
3040
|
function startServer() {
|
|
3027
|
-
|
|
3028
|
-
importExistingAuth();
|
|
3041
|
+
['google', 'anthropic', 'openai', 'xai', 'openrouter', 'together', 'mistral', 'deepseek', 'amazon-bedrock', 'azure', 'github-copilot'].forEach(p => importCurrentAuthToPool(p));
|
|
3029
3042
|
app.listen(PORT, () => console.log(`Server running at http://localhost:${PORT}`));
|
|
3030
3043
|
}
|
|
3031
3044
|
|