opencode-studio-server 1.0.6 → 1.0.9
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 +92 -98
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -56,9 +56,34 @@ const HOME_DIR = os.homedir();
|
|
|
56
56
|
const STUDIO_CONFIG_PATH = path.join(HOME_DIR, '.config', 'opencode-studio', 'studio.json');
|
|
57
57
|
const PENDING_ACTION_PATH = path.join(HOME_DIR, '.config', 'opencode-studio', 'pending-action.json');
|
|
58
58
|
|
|
59
|
-
let pendingActionMemory = null;
|
|
60
|
-
|
|
61
|
-
function
|
|
59
|
+
let pendingActionMemory = null;
|
|
60
|
+
|
|
61
|
+
function loadStudioConfig() {
|
|
62
|
+
if (!fs.existsSync(STUDIO_CONFIG_PATH)) {
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(fs.readFileSync(STUDIO_CONFIG_PATH, 'utf8'));
|
|
67
|
+
} catch {
|
|
68
|
+
return {};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function saveStudioConfig(config) {
|
|
73
|
+
try {
|
|
74
|
+
const dir = path.dirname(STUDIO_CONFIG_PATH);
|
|
75
|
+
if (!fs.existsSync(dir)) {
|
|
76
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
fs.writeFileSync(STUDIO_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
79
|
+
return true;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
console.error('Failed to save studio config:', err);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function loadPendingAction() {
|
|
62
87
|
if (pendingActionMemory) return pendingActionMemory;
|
|
63
88
|
|
|
64
89
|
if (fs.existsSync(PENDING_ACTION_PATH)) {
|
|
@@ -94,53 +119,38 @@ const AUTH_CANDIDATE_PATHS = [
|
|
|
94
119
|
path.join(process.env.APPDATA || '', 'opencode', 'auth.json'),
|
|
95
120
|
];
|
|
96
121
|
|
|
97
|
-
const CANDIDATE_PATHS = [
|
|
98
|
-
path.join(HOME_DIR, '.config', 'opencode'),
|
|
99
|
-
path.join(HOME_DIR, '.opencode'),
|
|
100
|
-
path.join(process.env.APPDATA || '', 'opencode'),
|
|
101
|
-
path.join(process.env.LOCALAPPDATA || '', 'opencode'),
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (!fs.existsSync(dir)) {
|
|
130
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
131
|
-
}
|
|
132
|
-
fs.writeFileSync(STUDIO_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function getConfigDir() {
|
|
136
|
-
const studioConfig = loadStudioConfig();
|
|
137
|
-
if (studioConfig.configPath && fs.existsSync(studioConfig.configPath)) {
|
|
138
|
-
return studioConfig.configPath;
|
|
139
|
-
}
|
|
140
|
-
return detectConfigDir();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function getPaths() {
|
|
122
|
+
const CANDIDATE_PATHS = [
|
|
123
|
+
path.join(HOME_DIR, '.config', 'opencode'),
|
|
124
|
+
path.join(HOME_DIR, '.opencode'),
|
|
125
|
+
path.join(process.env.APPDATA || '', 'opencode'),
|
|
126
|
+
path.join(process.env.LOCALAPPDATA || '', 'opencode'),
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
function getConfigDir() {
|
|
130
|
+
for (const candidate of CANDIDATE_PATHS) {
|
|
131
|
+
if (fs.existsSync(candidate)) {
|
|
132
|
+
return candidate;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const PROVIDER_DISPLAY_NAMES = {
|
|
139
|
+
'github-copilot': 'GitHub Copilot',
|
|
140
|
+
'google': 'Google AI',
|
|
141
|
+
'anthropic': 'Anthropic',
|
|
142
|
+
'openai': 'OpenAI',
|
|
143
|
+
'xai': 'xAI',
|
|
144
|
+
'groq': 'Groq',
|
|
145
|
+
'together': 'Together AI',
|
|
146
|
+
'mistral': 'Mistral',
|
|
147
|
+
'deepseek': 'DeepSeek',
|
|
148
|
+
'openrouter': 'OpenRouter',
|
|
149
|
+
'amazon-bedrock': 'Amazon Bedrock',
|
|
150
|
+
'azure': 'Azure OpenAI',
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
function getPaths() {
|
|
144
154
|
const configDir = getConfigDir();
|
|
145
155
|
if (!configDir) return null;
|
|
146
156
|
return {
|
|
@@ -761,14 +771,17 @@ app.post('/api/restore', (req, res) => {
|
|
|
761
771
|
});
|
|
762
772
|
|
|
763
773
|
// Auth endpoints
|
|
764
|
-
function getAuthFile() {
|
|
765
|
-
for
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
}
|
|
774
|
+
function getAuthFile() {
|
|
775
|
+
console.log('Searching for auth file in:', AUTH_CANDIDATE_PATHS);
|
|
776
|
+
for (const candidate of AUTH_CANDIDATE_PATHS) {
|
|
777
|
+
if (fs.existsSync(candidate)) {
|
|
778
|
+
console.log('Found auth file at:', candidate);
|
|
779
|
+
return candidate;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
console.log('No auth file found');
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
772
785
|
|
|
773
786
|
function loadAuthConfig() {
|
|
774
787
|
const authFile = getAuthFile();
|
|
@@ -793,22 +806,7 @@ function saveAuthConfig(config) {
|
|
|
793
806
|
}
|
|
794
807
|
}
|
|
795
808
|
|
|
796
|
-
|
|
797
|
-
'github-copilot': 'GitHub Copilot',
|
|
798
|
-
'google': 'Google',
|
|
799
|
-
'google-gemini-oauth': 'Google Gemini (OAuth)',
|
|
800
|
-
'anthropic': 'Anthropic',
|
|
801
|
-
'openai': 'OpenAI',
|
|
802
|
-
'zai': 'Z.AI',
|
|
803
|
-
'xai': 'xAI',
|
|
804
|
-
'groq': 'Groq',
|
|
805
|
-
'together': 'Together AI',
|
|
806
|
-
'mistral': 'Mistral',
|
|
807
|
-
'deepseek': 'DeepSeek',
|
|
808
|
-
'openrouter': 'OpenRouter',
|
|
809
|
-
'amazon-bedrock': 'Amazon Bedrock',
|
|
810
|
-
'azure': 'Azure OpenAI',
|
|
811
|
-
};
|
|
809
|
+
|
|
812
810
|
|
|
813
811
|
app.get('/api/auth', (req, res) => {
|
|
814
812
|
const authConfig = loadAuthConfig();
|
|
@@ -850,34 +848,30 @@ app.get('/api/auth', (req, res) => {
|
|
|
850
848
|
res.json({ credentials, authFile, hasGeminiAuthPlugin });
|
|
851
849
|
});
|
|
852
850
|
|
|
853
|
-
app.post('/api/auth/login', (req, res) => {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
if (!provider) {
|
|
857
|
-
return res.status(400).json({ error: 'Provider is required' });
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
if (!PROVIDER_DISPLAY_NAMES[provider]) {
|
|
861
|
-
return res.status(400).json({ error: 'Invalid provider' });
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
// Run opencode auth login - this opens browser
|
|
851
|
+
app.post('/api/auth/login', (req, res) => {
|
|
852
|
+
// opencode auth login is interactive and requires a terminal
|
|
865
853
|
const isWindows = process.platform === 'win32';
|
|
866
|
-
const
|
|
867
|
-
|
|
868
|
-
|
|
854
|
+
const isMac = process.platform === 'darwin';
|
|
855
|
+
|
|
856
|
+
let command;
|
|
857
|
+
if (isWindows) {
|
|
858
|
+
command = 'start cmd /k "opencode auth login"';
|
|
859
|
+
} else if (isMac) {
|
|
860
|
+
command = 'osascript -e \'tell app "Terminal" to do script "opencode auth login"\'';
|
|
861
|
+
} else {
|
|
862
|
+
command = 'x-terminal-emulator -e "opencode auth login" || gnome-terminal -- opencode auth login || xterm -e "opencode auth login"';
|
|
863
|
+
}
|
|
869
864
|
|
|
870
|
-
exec(command, (err) => {
|
|
871
|
-
if (err) console.error('Failed to
|
|
865
|
+
exec(command, { shell: true }, (err) => {
|
|
866
|
+
if (err) console.error('Failed to open terminal:', err);
|
|
872
867
|
});
|
|
873
868
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
});
|
|
869
|
+
res.json({
|
|
870
|
+
success: true,
|
|
871
|
+
message: 'Opening terminal for authentication...',
|
|
872
|
+
note: 'Complete authentication in the terminal window, then refresh this page.'
|
|
873
|
+
});
|
|
874
|
+
});
|
|
881
875
|
|
|
882
876
|
app.delete('/api/auth/:provider', (req, res) => {
|
|
883
877
|
const provider = req.params.provider;
|