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.
Files changed (2) hide show
  1. package/index.js +99 -86
  2. 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 4.5 (Antigravity)", duration: 4 * 60 * 60 * 1000 }, // 4 hours
295
- { name: "Gemini 3 Pro (Antigravity)", duration: 24 * 60 * 60 * 1000 } // 24 hours
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
- return { ...defaultConfig, ...config };
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
- // setupLogWatcher(); // Disabled as per user request (manual switching only)
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-studio-server",
3
- "version": "1.12.12",
3
+ "version": "1.12.14",
4
4
  "description": "Backend server for OpenCode Studio - manages opencode configurations",
5
5
  "main": "index.js",
6
6
  "bin": {