opencode-studio-server 1.3.5 → 1.3.7
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 +149 -19
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -681,8 +681,25 @@ app.post('/api/auth/profiles/:provider', (req, res) => {
|
|
|
681
681
|
const dir = path.join(AUTH_PROFILES_DIR, namespace);
|
|
682
682
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
683
683
|
|
|
684
|
-
|
|
684
|
+
if (!auth[provider]) {
|
|
685
|
+
return res.status(400).json({ error: 'No current auth for provider' });
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const profileName = name || auth[provider].email || `profile-${Date.now()}`;
|
|
689
|
+
const profilePath = path.join(dir, `${profileName}.json`);
|
|
685
690
|
atomicWriteFileSync(profilePath, JSON.stringify(auth[provider], null, 2));
|
|
691
|
+
|
|
692
|
+
const metadata = loadPoolMetadata();
|
|
693
|
+
if (!metadata[namespace]) metadata[namespace] = {};
|
|
694
|
+
metadata[namespace][profileName] = {
|
|
695
|
+
...(metadata[namespace][profileName] || {}),
|
|
696
|
+
email: auth[provider].email || metadata[namespace][profileName]?.email || null,
|
|
697
|
+
createdAt: metadata[namespace][profileName]?.createdAt || Date.now(),
|
|
698
|
+
lastUsed: Date.now(),
|
|
699
|
+
usageCount: metadata[namespace][profileName]?.usageCount || 0
|
|
700
|
+
};
|
|
701
|
+
savePoolMetadata(metadata);
|
|
702
|
+
|
|
686
703
|
res.json({ success: true, name: path.basename(profilePath, '.json') });
|
|
687
704
|
});
|
|
688
705
|
|
|
@@ -714,6 +731,22 @@ app.post('/api/auth/profiles/:provider/:name/activate', (req, res) => {
|
|
|
714
731
|
const cp = getConfigPath();
|
|
715
732
|
const ap = path.join(path.dirname(cp), 'auth.json');
|
|
716
733
|
atomicWriteFileSync(ap, JSON.stringify(authCfg, null, 2));
|
|
734
|
+
|
|
735
|
+
const metadata = loadPoolMetadata();
|
|
736
|
+
if (!metadata[namespace]) metadata[namespace] = {};
|
|
737
|
+
metadata[namespace][name] = {
|
|
738
|
+
...(metadata[namespace][name] || {}),
|
|
739
|
+
email: profileData.email || metadata[namespace][name]?.email || null,
|
|
740
|
+
createdAt: metadata[namespace][name]?.createdAt || Date.now(),
|
|
741
|
+
lastUsed: Date.now(),
|
|
742
|
+
usageCount: (metadata[namespace][name]?.usageCount || 0) + 1
|
|
743
|
+
};
|
|
744
|
+
if (!metadata._quota) metadata._quota = {};
|
|
745
|
+
if (!metadata._quota[namespace]) metadata._quota[namespace] = {};
|
|
746
|
+
const today = new Date().toISOString().split('T')[0];
|
|
747
|
+
metadata._quota[namespace][today] = (metadata._quota[namespace][today] || 0) + 1;
|
|
748
|
+
savePoolMetadata(metadata);
|
|
749
|
+
|
|
717
750
|
res.json({ success: true });
|
|
718
751
|
});
|
|
719
752
|
|
|
@@ -726,6 +759,30 @@ app.delete('/api/auth/profiles/:provider/:name', (req, res) => {
|
|
|
726
759
|
|
|
727
760
|
const profilePath = path.join(AUTH_PROFILES_DIR, namespace, `${name}.json`);
|
|
728
761
|
if (fs.existsSync(profilePath)) fs.unlinkSync(profilePath);
|
|
762
|
+
|
|
763
|
+
const studio = loadStudioConfig();
|
|
764
|
+
if (studio.activeProfiles && studio.activeProfiles[provider] === name) {
|
|
765
|
+
delete studio.activeProfiles[provider];
|
|
766
|
+
saveStudioConfig(studio);
|
|
767
|
+
|
|
768
|
+
const authCfg = loadAuthConfig() || {};
|
|
769
|
+
delete authCfg[provider];
|
|
770
|
+
if (provider === 'google') {
|
|
771
|
+
const key = activePlugin === 'antigravity' ? 'google.antigravity' : 'google.gemini';
|
|
772
|
+
delete authCfg.google;
|
|
773
|
+
delete authCfg[key];
|
|
774
|
+
}
|
|
775
|
+
const cp = getConfigPath();
|
|
776
|
+
const ap = path.join(path.dirname(cp), 'auth.json');
|
|
777
|
+
atomicWriteFileSync(ap, JSON.stringify(authCfg, null, 2));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const metadata = loadPoolMetadata();
|
|
781
|
+
if (metadata[namespace]?.[name]) {
|
|
782
|
+
delete metadata[namespace][name];
|
|
783
|
+
savePoolMetadata(metadata);
|
|
784
|
+
}
|
|
785
|
+
|
|
729
786
|
res.json({ success: true });
|
|
730
787
|
});
|
|
731
788
|
|
|
@@ -770,10 +827,13 @@ app.post('/api/auth/login', (req, res) => {
|
|
|
770
827
|
let cmd = 'opencode auth login';
|
|
771
828
|
if (provider) cmd += ` ${provider}`;
|
|
772
829
|
|
|
830
|
+
const cp = getConfigPath();
|
|
831
|
+
const configDir = cp ? path.dirname(cp) : process.cwd();
|
|
832
|
+
const safeDir = configDir.replace(/"/g, '\\"');
|
|
773
833
|
const platform = process.platform;
|
|
774
834
|
|
|
775
835
|
if (platform === 'win32') {
|
|
776
|
-
const terminalCmd = `start "" cmd /c "call ${cmd} || pause"`;
|
|
836
|
+
const terminalCmd = `start "" /d "${safeDir}" cmd /c "call ${cmd} || pause"`;
|
|
777
837
|
console.log('Executing terminal command:', terminalCmd);
|
|
778
838
|
exec(terminalCmd, (err) => {
|
|
779
839
|
if (err) {
|
|
@@ -783,7 +843,7 @@ app.post('/api/auth/login', (req, res) => {
|
|
|
783
843
|
res.json({ success: true, message: 'Terminal opened', note: 'Complete login in the terminal window' });
|
|
784
844
|
});
|
|
785
845
|
} else if (platform === 'darwin') {
|
|
786
|
-
const terminalCmd = `osascript -e 'tell application "Terminal" to do script "${cmd}"'`;
|
|
846
|
+
const terminalCmd = `osascript -e 'tell application "Terminal" to do script "cd ${safeDir} && ${cmd}"'`;
|
|
787
847
|
console.log('Executing terminal command:', terminalCmd);
|
|
788
848
|
exec(terminalCmd, (err) => {
|
|
789
849
|
if (err) {
|
|
@@ -794,11 +854,11 @@ app.post('/api/auth/login', (req, res) => {
|
|
|
794
854
|
});
|
|
795
855
|
} else {
|
|
796
856
|
const linuxTerminals = [
|
|
797
|
-
{ name: 'x-terminal-emulator', cmd: `x-terminal-emulator -e "${cmd}"` },
|
|
798
|
-
{ name: 'gnome-terminal', cmd: `gnome-terminal -- bash -c "${cmd}; read -p 'Press Enter to close...'"` },
|
|
799
|
-
{ name: 'konsole', cmd: `konsole -e bash -c "${cmd}; read -p 'Press Enter to close...'"` },
|
|
800
|
-
{ name: 'xfce4-terminal', cmd: `xfce4-terminal -e "bash -c
|
|
801
|
-
{ name: 'xterm', cmd: `xterm -e "bash -c '${cmd}; read -p Press_Enter_to_close...'"` }
|
|
857
|
+
{ name: 'x-terminal-emulator', cmd: `x-terminal-emulator -e "bash -c 'cd ${safeDir} && ${cmd}'"` },
|
|
858
|
+
{ name: 'gnome-terminal', cmd: `gnome-terminal -- bash -c "cd ${safeDir} && ${cmd}; read -p 'Press Enter to close...'"` },
|
|
859
|
+
{ name: 'konsole', cmd: `konsole -e bash -c "cd ${safeDir} && ${cmd}; read -p 'Press Enter to close...'"` },
|
|
860
|
+
{ name: 'xfce4-terminal', cmd: `xfce4-terminal -e "bash -c \"cd ${safeDir} && ${cmd}; read -p 'Press Enter to close...'\"" ` },
|
|
861
|
+
{ name: 'xterm', cmd: `xterm -e "bash -c 'cd ${safeDir} && ${cmd}; read -p Press_Enter_to_close...'"` }
|
|
802
862
|
];
|
|
803
863
|
|
|
804
864
|
const tryTerminal = (index) => {
|
|
@@ -828,18 +888,53 @@ app.post('/api/auth/login', (req, res) => {
|
|
|
828
888
|
}
|
|
829
889
|
});
|
|
830
890
|
|
|
891
|
+
|
|
831
892
|
app.delete('/api/auth/:provider', (req, res) => {
|
|
832
893
|
const { provider } = req.params;
|
|
833
894
|
const authCfg = loadAuthConfig() || {};
|
|
834
|
-
|
|
895
|
+
const studio = loadStudioConfig();
|
|
896
|
+
const activePlugin = studio.activeGooglePlugin;
|
|
897
|
+
|
|
898
|
+
if (provider === 'google') {
|
|
899
|
+
delete authCfg.google;
|
|
900
|
+
delete authCfg['google.gemini'];
|
|
901
|
+
delete authCfg['google.antigravity'];
|
|
902
|
+
|
|
903
|
+
if (studio.activeProfiles) delete studio.activeProfiles.google;
|
|
904
|
+
saveStudioConfig(studio);
|
|
905
|
+
|
|
906
|
+
const geminiDir = path.join(AUTH_PROFILES_DIR, 'google.gemini');
|
|
907
|
+
const antiDir = path.join(AUTH_PROFILES_DIR, 'google.antigravity');
|
|
908
|
+
[geminiDir, antiDir].forEach(dir => {
|
|
909
|
+
if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
const metadata = loadPoolMetadata();
|
|
913
|
+
delete metadata['google.gemini'];
|
|
914
|
+
delete metadata['google.antigravity'];
|
|
915
|
+
savePoolMetadata(metadata);
|
|
916
|
+
} else {
|
|
917
|
+
delete authCfg[provider];
|
|
918
|
+
if (studio.activeProfiles) delete studio.activeProfiles[provider];
|
|
919
|
+
saveStudioConfig(studio);
|
|
920
|
+
|
|
921
|
+
const providerDir = path.join(AUTH_PROFILES_DIR, provider);
|
|
922
|
+
if (fs.existsSync(providerDir)) fs.rmSync(providerDir, { recursive: true, force: true });
|
|
923
|
+
|
|
924
|
+
const metadata = loadPoolMetadata();
|
|
925
|
+
delete metadata[provider];
|
|
926
|
+
savePoolMetadata(metadata);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (provider === 'google' && activePlugin) {
|
|
930
|
+
const key = activePlugin === 'antigravity' ? 'google.antigravity' : 'google.gemini';
|
|
931
|
+
delete authCfg[key];
|
|
932
|
+
}
|
|
933
|
+
|
|
835
934
|
const cp = getConfigPath();
|
|
836
935
|
const ap = path.join(path.dirname(cp), 'auth.json');
|
|
837
936
|
atomicWriteFileSync(ap, JSON.stringify(authCfg, null, 2));
|
|
838
|
-
|
|
839
|
-
const studio = loadStudioConfig();
|
|
840
|
-
if (studio.activeProfiles) delete studio.activeProfiles[provider];
|
|
841
|
-
saveStudioConfig(studio);
|
|
842
|
-
|
|
937
|
+
|
|
843
938
|
res.json({ success: true });
|
|
844
939
|
});
|
|
845
940
|
|
|
@@ -892,11 +987,18 @@ function buildAccountPool(provider) {
|
|
|
892
987
|
files.forEach(file => {
|
|
893
988
|
const name = file.replace('.json', '');
|
|
894
989
|
const meta = providerMeta[name] || {};
|
|
895
|
-
|
|
990
|
+
let profileEmail = null;
|
|
991
|
+
try {
|
|
992
|
+
const raw = fs.readFileSync(path.join(profileDir, file), 'utf8');
|
|
993
|
+
const parsed = JSON.parse(raw);
|
|
994
|
+
profileEmail = parsed?.email || null;
|
|
995
|
+
} catch {}
|
|
996
|
+
let status = getAccountStatus(meta, now);
|
|
997
|
+
if (name === activeProfile && status === 'ready') status = 'active';
|
|
896
998
|
|
|
897
999
|
profiles.push({
|
|
898
1000
|
name,
|
|
899
|
-
email: meta.email || null,
|
|
1001
|
+
email: meta.email || profileEmail || null,
|
|
900
1002
|
status,
|
|
901
1003
|
lastUsed: meta.lastUsed || 0,
|
|
902
1004
|
usageCount: meta.usageCount || 0,
|
|
@@ -1022,8 +1124,15 @@ app.post('/api/auth/pool/rotate', (req, res) => {
|
|
|
1022
1124
|
if (!metadata[namespace]) metadata[namespace] = {};
|
|
1023
1125
|
metadata[namespace][next.name] = {
|
|
1024
1126
|
...metadata[namespace][next.name],
|
|
1025
|
-
lastUsed: now
|
|
1127
|
+
lastUsed: now,
|
|
1128
|
+
usageCount: (metadata[namespace][next.name]?.usageCount || 0) + 1
|
|
1026
1129
|
};
|
|
1130
|
+
|
|
1131
|
+
if (!metadata._quota) metadata._quota = {};
|
|
1132
|
+
if (!metadata._quota[namespace]) metadata._quota[namespace] = {};
|
|
1133
|
+
const today = new Date().toISOString().split('T')[0];
|
|
1134
|
+
metadata._quota[namespace][today] = (metadata._quota[namespace][today] || 0) + 1;
|
|
1135
|
+
|
|
1027
1136
|
savePoolMetadata(metadata);
|
|
1028
1137
|
|
|
1029
1138
|
res.json({
|
|
@@ -1471,8 +1580,8 @@ app.post('/api/auth/google/start', async (req, res) => {
|
|
|
1471
1580
|
const ap = path.join(path.dirname(cp), 'auth.json');
|
|
1472
1581
|
const authCfg = fs.existsSync(ap) ? JSON.parse(fs.readFileSync(ap, 'utf8')) : {};
|
|
1473
1582
|
|
|
1474
|
-
const
|
|
1475
|
-
const activePlugin =
|
|
1583
|
+
const studioConfig = loadStudioConfig();
|
|
1584
|
+
const activePlugin = studioConfig.activeGooglePlugin || 'gemini';
|
|
1476
1585
|
const namespace = activePlugin === 'antigravity' ? 'google.antigravity' : 'google.gemini';
|
|
1477
1586
|
|
|
1478
1587
|
const credentials = {
|
|
@@ -1486,6 +1595,27 @@ app.post('/api/auth/google/start', async (req, res) => {
|
|
|
1486
1595
|
authCfg[namespace] = credentials;
|
|
1487
1596
|
|
|
1488
1597
|
atomicWriteFileSync(ap, JSON.stringify(authCfg, null, 2));
|
|
1598
|
+
|
|
1599
|
+
const profileDir = path.join(AUTH_PROFILES_DIR, namespace);
|
|
1600
|
+
if (!fs.existsSync(profileDir)) fs.mkdirSync(profileDir, { recursive: true });
|
|
1601
|
+
const profileName = email || `google-${Date.now()}`;
|
|
1602
|
+
const profilePath = path.join(profileDir, `${profileName}.json`);
|
|
1603
|
+
atomicWriteFileSync(profilePath, JSON.stringify(credentials, null, 2));
|
|
1604
|
+
|
|
1605
|
+
const metadata = loadPoolMetadata();
|
|
1606
|
+
if (!metadata[namespace]) metadata[namespace] = {};
|
|
1607
|
+
metadata[namespace][profileName] = {
|
|
1608
|
+
...(metadata[namespace][profileName] || {}),
|
|
1609
|
+
email: email || null,
|
|
1610
|
+
createdAt: metadata[namespace][profileName]?.createdAt || Date.now(),
|
|
1611
|
+
lastUsed: Date.now(),
|
|
1612
|
+
usageCount: metadata[namespace][profileName]?.usageCount || 0
|
|
1613
|
+
};
|
|
1614
|
+
savePoolMetadata(metadata);
|
|
1615
|
+
|
|
1616
|
+
if (!studioConfig.activeProfiles) studioConfig.activeProfiles = {};
|
|
1617
|
+
studioConfig.activeProfiles.google = profileName;
|
|
1618
|
+
saveStudioConfig(studioConfig);
|
|
1489
1619
|
|
|
1490
1620
|
pendingOAuthState = { ...pendingOAuthState, status: 'success', email };
|
|
1491
1621
|
|