opencode-studio-server 1.16.7 → 1.17.0
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 +0 -206
- package/package.json +1 -1
- package/proxy-manager.js +0 -228
package/index.js
CHANGED
|
@@ -8,7 +8,6 @@ const crypto = require('crypto');
|
|
|
8
8
|
const { spawn, exec } = require('child_process');
|
|
9
9
|
|
|
10
10
|
const pkg = require('./package.json');
|
|
11
|
-
const proxyManager = require('./proxy-manager');
|
|
12
11
|
const profileManager = require('./profile-manager');
|
|
13
12
|
const SERVER_VERSION = pkg.version;
|
|
14
13
|
|
|
@@ -2558,211 +2557,6 @@ app.post('/api/auth/pool/quota/limit', (req, res) => {
|
|
|
2558
2557
|
res.json({ success: true, dailyLimit: limit });
|
|
2559
2558
|
});
|
|
2560
2559
|
|
|
2561
|
-
app.get('/api/proxy/status', async (req, res) => {
|
|
2562
|
-
const status = await proxyManager.getStatus();
|
|
2563
|
-
res.json(status);
|
|
2564
|
-
});
|
|
2565
|
-
|
|
2566
|
-
app.post('/api/proxy/start', async (req, res) => {
|
|
2567
|
-
const result = await proxyManager.startProxy();
|
|
2568
|
-
res.json(result);
|
|
2569
|
-
});
|
|
2570
|
-
|
|
2571
|
-
app.post('/api/proxy/stop', async (req, res) => {
|
|
2572
|
-
const result = proxyManager.stopProxy();
|
|
2573
|
-
res.json(result);
|
|
2574
|
-
});
|
|
2575
|
-
|
|
2576
|
-
app.post('/api/proxy/login', async (req, res) => {
|
|
2577
|
-
const { provider } = req.body;
|
|
2578
|
-
const result = await proxyManager.runLogin(provider);
|
|
2579
|
-
if (!result.success) return res.status(400).json(result);
|
|
2580
|
-
|
|
2581
|
-
const cmd = result.command;
|
|
2582
|
-
const cp = getConfigPath();
|
|
2583
|
-
const configDir = cp ? path.dirname(cp) : process.cwd();
|
|
2584
|
-
const safeDir = configDir.replace(/"/g, '\\"');
|
|
2585
|
-
const platform = process.platform;
|
|
2586
|
-
|
|
2587
|
-
if (platform === 'win32') {
|
|
2588
|
-
const terminalCmd = `start "" /d "${safeDir}" cmd /c "call ${cmd} || pause"`;
|
|
2589
|
-
exec(terminalCmd, (err) => {
|
|
2590
|
-
if (err) return res.status(500).json({ error: 'Failed to open terminal', details: err.message });
|
|
2591
|
-
res.json({ success: true, message: 'Terminal opened' });
|
|
2592
|
-
});
|
|
2593
|
-
} else if (platform === 'darwin') {
|
|
2594
|
-
const terminalCmd = `osascript -e 'tell application "Terminal" to do script "cd ${safeDir} && ${cmd}"'`;
|
|
2595
|
-
exec(terminalCmd, (err) => {
|
|
2596
|
-
if (err) return res.status(500).json({ error: 'Failed to open terminal', details: err.message });
|
|
2597
|
-
res.json({ success: true, message: 'Terminal opened' });
|
|
2598
|
-
});
|
|
2599
|
-
} else {
|
|
2600
|
-
const linuxTerminals = [
|
|
2601
|
-
{ name: 'x-terminal-emulator', cmd: `x-terminal-emulator -e "bash -c 'cd ${safeDir} && ${cmd}'"` },
|
|
2602
|
-
{ name: 'gnome-terminal', cmd: `gnome-terminal -- bash -c "cd ${safeDir} && ${cmd}; read -p 'Press Enter to close...'"` },
|
|
2603
|
-
{ name: 'konsole', cmd: `konsole -e bash -c "cd ${safeDir} && ${cmd}; read -p 'Press Enter to close...'"` },
|
|
2604
|
-
{ name: 'xfce4-terminal', cmd: `xfce4-terminal -e "bash -c \"cd ${safeDir} && ${cmd}; read -p 'Press Enter to close...'\"" ` },
|
|
2605
|
-
{ name: 'xterm', cmd: `xterm -e "bash -c 'cd ${safeDir} && ${cmd}; read -p Press_Enter_to_close...'"` }
|
|
2606
|
-
];
|
|
2607
|
-
|
|
2608
|
-
const tryTerminal = (index) => {
|
|
2609
|
-
if (index >= linuxTerminals.length) {
|
|
2610
|
-
return res.json({
|
|
2611
|
-
success: false,
|
|
2612
|
-
message: 'No terminal emulator found',
|
|
2613
|
-
note: 'Run this command manually:',
|
|
2614
|
-
command: cmd
|
|
2615
|
-
});
|
|
2616
|
-
}
|
|
2617
|
-
const terminal = linuxTerminals[index];
|
|
2618
|
-
exec(terminal.cmd, (err) => {
|
|
2619
|
-
if (err) {
|
|
2620
|
-
tryTerminal(index + 1);
|
|
2621
|
-
} else {
|
|
2622
|
-
res.json({ success: true, message: 'Terminal opened' });
|
|
2623
|
-
}
|
|
2624
|
-
});
|
|
2625
|
-
};
|
|
2626
|
-
tryTerminal(0);
|
|
2627
|
-
}
|
|
2628
|
-
});
|
|
2629
|
-
|
|
2630
|
-
app.get('/api/proxy/accounts', (req, res) => {
|
|
2631
|
-
res.json(proxyManager.listAccounts());
|
|
2632
|
-
});
|
|
2633
|
-
|
|
2634
|
-
app.get('/api/proxy/config', (req, res) => {
|
|
2635
|
-
res.json(proxyManager.loadProxyConfig());
|
|
2636
|
-
});
|
|
2637
|
-
|
|
2638
|
-
app.post('/api/proxy/config', (req, res) => {
|
|
2639
|
-
proxyManager.saveProxyConfig(req.body);
|
|
2640
|
-
res.json({ success: true });
|
|
2641
|
-
});
|
|
2642
|
-
|
|
2643
|
-
const PROXY_CONFIG_PATH = path.join(HOME_DIR, '.config', 'opencode-studio', 'cliproxy.yaml');
|
|
2644
|
-
|
|
2645
|
-
app.get('/api/management/config.yaml', (req, res) => {
|
|
2646
|
-
console.log('GET config.yaml hit');
|
|
2647
|
-
if (!fs.existsSync(PROXY_CONFIG_PATH)) {
|
|
2648
|
-
console.log('Config file not found:', PROXY_CONFIG_PATH);
|
|
2649
|
-
return res.send("");
|
|
2650
|
-
}
|
|
2651
|
-
console.log('Sending config file:', PROXY_CONFIG_PATH);
|
|
2652
|
-
const content = fs.readFileSync(PROXY_CONFIG_PATH, 'utf8');
|
|
2653
|
-
res.send(content);
|
|
2654
|
-
});
|
|
2655
|
-
|
|
2656
|
-
app.put('/api/management/config.yaml', (req, res) => {
|
|
2657
|
-
fs.writeFileSync(PROXY_CONFIG_PATH, req.body);
|
|
2658
|
-
res.json({ ok: true, changed: [] });
|
|
2659
|
-
});
|
|
2660
|
-
|
|
2661
|
-
app.get('/api/management/api-keys', (req, res) => {
|
|
2662
|
-
if (!fs.existsSync(PROXY_CONFIG_PATH)) return res.json({ "api-keys": [] });
|
|
2663
|
-
const content = fs.readFileSync(PROXY_CONFIG_PATH, 'utf8');
|
|
2664
|
-
const yaml = require('js-yaml');
|
|
2665
|
-
try {
|
|
2666
|
-
const doc = yaml.load(content) || {};
|
|
2667
|
-
const keys = [];
|
|
2668
|
-
if (doc['management-key']) keys.push(doc['management-key']);
|
|
2669
|
-
if (Array.isArray(doc['api-keys'])) keys.push(...doc['api-keys']);
|
|
2670
|
-
res.json({ "api-keys": [...new Set(keys)].filter(k => k) });
|
|
2671
|
-
} catch (e) {
|
|
2672
|
-
res.json({ "api-keys": [] });
|
|
2673
|
-
}
|
|
2674
|
-
});
|
|
2675
|
-
|
|
2676
|
-
app.put('/api/management/api-keys', (req, res) => {
|
|
2677
|
-
const keys = req.body;
|
|
2678
|
-
if (!fs.existsSync(PROXY_CONFIG_PATH)) return res.status(404).json({ error: "Config not found" });
|
|
2679
|
-
const content = fs.readFileSync(PROXY_CONFIG_PATH, 'utf8');
|
|
2680
|
-
const yaml = require('js-yaml');
|
|
2681
|
-
try {
|
|
2682
|
-
const doc = yaml.load(content) || {};
|
|
2683
|
-
doc['api-keys'] = keys;
|
|
2684
|
-
if (keys.length > 0) doc['management-key'] = keys[0];
|
|
2685
|
-
|
|
2686
|
-
fs.writeFileSync(PROXY_CONFIG_PATH, yaml.dump(doc));
|
|
2687
|
-
res.json({ status: "ok" });
|
|
2688
|
-
} catch (e) {
|
|
2689
|
-
res.status(500).json({ error: e.message });
|
|
2690
|
-
}
|
|
2691
|
-
});
|
|
2692
|
-
|
|
2693
|
-
app.get('/api/management/logs', (req, res) => {
|
|
2694
|
-
if (!fs.existsSync(LOG_DIR)) return res.json({ lines: [], "line-count": 0, "latest-timestamp": Date.now() });
|
|
2695
|
-
const logFiles = fs.readdirSync(LOG_DIR).filter(f => f.endsWith('.log'));
|
|
2696
|
-
if (logFiles.length === 0) return res.json({ lines: [], "line-count": 0, "latest-timestamp": Date.now() });
|
|
2697
|
-
|
|
2698
|
-
const latest = logFiles.map(f => ({ name: f, time: fs.statSync(path.join(LOG_DIR, f)).mtime.getTime() }))
|
|
2699
|
-
.sort((a, b) => b.time - a.time)[0];
|
|
2700
|
-
|
|
2701
|
-
const content = fs.readFileSync(path.join(LOG_DIR, latest.name), 'utf8');
|
|
2702
|
-
const lines = content.split('\n').slice(-1000);
|
|
2703
|
-
res.json({ lines, "line-count": lines.length, "latest-timestamp": latest.time });
|
|
2704
|
-
});
|
|
2705
|
-
|
|
2706
|
-
app.get('/api/management/usage', (req, res) => {
|
|
2707
|
-
res.json({
|
|
2708
|
-
usage: {
|
|
2709
|
-
total_requests: 0,
|
|
2710
|
-
success_count: 0,
|
|
2711
|
-
failure_count: 0,
|
|
2712
|
-
total_tokens: 0,
|
|
2713
|
-
requests_by_day: {},
|
|
2714
|
-
requests_by_hour: {},
|
|
2715
|
-
tokens_by_day: {},
|
|
2716
|
-
tokens_by_hour: {},
|
|
2717
|
-
apis: {},
|
|
2718
|
-
failed_requests: 0
|
|
2719
|
-
}
|
|
2720
|
-
});
|
|
2721
|
-
});
|
|
2722
|
-
|
|
2723
|
-
app.get('/api/management/logging-to-file', (req, res) => {
|
|
2724
|
-
if (!fs.existsSync(PROXY_CONFIG_PATH)) return res.json({ "logging-to-file": false });
|
|
2725
|
-
try {
|
|
2726
|
-
const content = fs.readFileSync(PROXY_CONFIG_PATH, 'utf8');
|
|
2727
|
-
const yaml = require('js-yaml');
|
|
2728
|
-
const doc = yaml.load(content) || {};
|
|
2729
|
-
res.json({ "logging-to-file": !!doc['logging-to-file'] });
|
|
2730
|
-
} catch (e) {
|
|
2731
|
-
res.json({ "logging-to-file": false });
|
|
2732
|
-
}
|
|
2733
|
-
});
|
|
2734
|
-
|
|
2735
|
-
app.patch('/api/management/logging-to-file', (req, res) => {
|
|
2736
|
-
if (!fs.existsSync(PROXY_CONFIG_PATH)) return res.status(404).json({ error: "Config not found" });
|
|
2737
|
-
const enabled = req.body.value;
|
|
2738
|
-
const content = fs.readFileSync(PROXY_CONFIG_PATH, 'utf8');
|
|
2739
|
-
const yaml = require('js-yaml');
|
|
2740
|
-
try {
|
|
2741
|
-
const doc = yaml.load(content) || {};
|
|
2742
|
-
doc['logging-to-file'] = enabled;
|
|
2743
|
-
fs.writeFileSync(PROXY_CONFIG_PATH, yaml.dump(doc));
|
|
2744
|
-
res.json({ status: "ok" });
|
|
2745
|
-
} catch (e) {
|
|
2746
|
-
res.status(500).json({ error: e.message });
|
|
2747
|
-
}
|
|
2748
|
-
});
|
|
2749
|
-
|
|
2750
|
-
app.delete('/api/management/logs', (req, res) => {
|
|
2751
|
-
if (!fs.existsSync(LOG_DIR)) return res.json({ success: true, removed: 0 });
|
|
2752
|
-
const logFiles = fs.readdirSync(LOG_DIR).filter(f => f.endsWith('.log'));
|
|
2753
|
-
let removed = 0;
|
|
2754
|
-
try {
|
|
2755
|
-
logFiles.forEach(f => {
|
|
2756
|
-
const filePath = path.join(LOG_DIR, f);
|
|
2757
|
-
fs.unlinkSync(filePath);
|
|
2758
|
-
removed++;
|
|
2759
|
-
});
|
|
2760
|
-
res.json({ success: true, removed });
|
|
2761
|
-
} catch (e) {
|
|
2762
|
-
res.status(500).json({ error: e.message });
|
|
2763
|
-
}
|
|
2764
|
-
});
|
|
2765
|
-
|
|
2766
2560
|
app.get('/api/profiles', (req, res) => {
|
|
2767
2561
|
res.json(profileManager.listProfiles());
|
|
2768
2562
|
});
|
package/package.json
CHANGED
package/proxy-manager.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
const { spawn, exec, execSync } = require('child_process');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const os = require('os');
|
|
5
|
-
const yaml = require('js-yaml');
|
|
6
|
-
|
|
7
|
-
const HOME_DIR = os.homedir();
|
|
8
|
-
const CONFIG_DIR = path.join(HOME_DIR, '.config', 'opencode-studio');
|
|
9
|
-
const PROXY_CONFIG_FILE = path.join(CONFIG_DIR, 'cliproxy.yaml');
|
|
10
|
-
const PROXY_AUTH_DIR = path.join(HOME_DIR, '.cli-proxy-api');
|
|
11
|
-
|
|
12
|
-
let proxyProcess = null;
|
|
13
|
-
let isProxyRunning = false;
|
|
14
|
-
|
|
15
|
-
const checkBinary = (cmd) => {
|
|
16
|
-
return new Promise((resolve) => {
|
|
17
|
-
if (path.isAbsolute(cmd)) {
|
|
18
|
-
return resolve(fs.existsSync(cmd));
|
|
19
|
-
}
|
|
20
|
-
const checkCmd = process.platform === 'win32' ? `where ${cmd}` : `which ${cmd}`;
|
|
21
|
-
exec(checkCmd, (err) => {
|
|
22
|
-
resolve(!err);
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const getProxyCommand = async () => {
|
|
28
|
-
if (process.platform === 'win32') {
|
|
29
|
-
const localAppData = process.env.LOCALAPPDATA;
|
|
30
|
-
if (localAppData) {
|
|
31
|
-
const aliases = ['CLIProxyAPI.exe', 'cli-proxy-api.exe', 'cliproxyapi.exe'];
|
|
32
|
-
for (const alias of aliases) {
|
|
33
|
-
const wingetPath = path.join(localAppData, 'Microsoft', 'WinGet', 'Links', alias);
|
|
34
|
-
if (fs.existsSync(wingetPath)) return wingetPath;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const progPath = path.join(localAppData, 'Programs', 'CLIProxyAPI', 'CLIProxyAPI.exe');
|
|
38
|
-
if (fs.existsSync(progPath)) return progPath;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (await checkBinary('cli-proxy-api')) return 'cli-proxy-api';
|
|
43
|
-
if (await checkBinary('cliproxyapi')) return 'cliproxyapi';
|
|
44
|
-
if (await checkBinary('CLIProxyAPI')) return 'CLIProxyAPI';
|
|
45
|
-
if (await checkBinary('cliproxyapi.exe')) return 'cliproxyapi.exe';
|
|
46
|
-
if (await checkBinary('cliproxy')) return 'cliproxy';
|
|
47
|
-
return null;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const loadProxyConfig = () => {
|
|
51
|
-
if (!fs.existsSync(PROXY_CONFIG_FILE)) {
|
|
52
|
-
const defaultConfig = {
|
|
53
|
-
port: 8317,
|
|
54
|
-
cors: true,
|
|
55
|
-
"allow-origin": "*",
|
|
56
|
-
"auth-dir": PROXY_AUTH_DIR,
|
|
57
|
-
"management-key": "",
|
|
58
|
-
routing: { strategy: "round-robin" },
|
|
59
|
-
"quota-exceeded": {
|
|
60
|
-
"switch-project": true,
|
|
61
|
-
"switch-preview-model": true
|
|
62
|
-
},
|
|
63
|
-
"gemini-api-key": []
|
|
64
|
-
};
|
|
65
|
-
saveProxyConfig(defaultConfig);
|
|
66
|
-
return defaultConfig;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
const content = fs.readFileSync(PROXY_CONFIG_FILE, 'utf8');
|
|
71
|
-
const config = yaml.load(content);
|
|
72
|
-
if (config && config['management-key'] === undefined) {
|
|
73
|
-
config['management-key'] = "";
|
|
74
|
-
saveProxyConfig(config);
|
|
75
|
-
}
|
|
76
|
-
if (config && config.cors === undefined) {
|
|
77
|
-
config.cors = true;
|
|
78
|
-
config['allow-origin'] = "*";
|
|
79
|
-
saveProxyConfig(config);
|
|
80
|
-
}
|
|
81
|
-
return config;
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error("Failed to load proxy config:", e);
|
|
84
|
-
return {};
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const saveProxyConfig = (config) => {
|
|
89
|
-
try {
|
|
90
|
-
if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
91
|
-
const content = yaml.dump(config);
|
|
92
|
-
fs.writeFileSync(PROXY_CONFIG_FILE, content);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.error("Failed to save proxy config:", e);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const startProxy = async () => {
|
|
99
|
-
if (isProxyRunning) return { success: true, message: "Already running" };
|
|
100
|
-
|
|
101
|
-
const cmd = await getProxyCommand();
|
|
102
|
-
if (!cmd) return { success: false, error: "CLIProxyAPI binary not found. Please install it." };
|
|
103
|
-
|
|
104
|
-
if (!fs.existsSync(PROXY_CONFIG_FILE)) loadProxyConfig();
|
|
105
|
-
|
|
106
|
-
console.log(`Starting proxy with command: ${cmd} -config "${PROXY_CONFIG_FILE}"`);
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
proxyProcess = spawn(cmd, ['-config', PROXY_CONFIG_FILE], {
|
|
110
|
-
detached: true,
|
|
111
|
-
stdio: 'pipe',
|
|
112
|
-
windowsHide: true
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
proxyProcess.unref();
|
|
116
|
-
|
|
117
|
-
proxyProcess.stdout.on('data', (data) => {
|
|
118
|
-
console.log(`[Proxy] ${data}`);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
proxyProcess.stderr.on('data', (data) => {
|
|
122
|
-
console.error(`[Proxy Err] ${data}`);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
proxyProcess.on('close', (code) => {
|
|
126
|
-
console.log(`[Proxy] Exited with code ${code}`);
|
|
127
|
-
isProxyRunning = false;
|
|
128
|
-
proxyProcess = null;
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
isProxyRunning = true;
|
|
132
|
-
return { success: true, pid: proxyProcess.pid };
|
|
133
|
-
} catch (e) {
|
|
134
|
-
return { success: false, error: e.message };
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const stopProxy = () => {
|
|
139
|
-
if (proxyProcess) {
|
|
140
|
-
proxyProcess.kill();
|
|
141
|
-
proxyProcess = null;
|
|
142
|
-
isProxyRunning = false;
|
|
143
|
-
return { success: true };
|
|
144
|
-
}
|
|
145
|
-
return { success: false, error: "Not running" };
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const getStatus = async () => {
|
|
149
|
-
const cmd = await getProxyCommand();
|
|
150
|
-
|
|
151
|
-
let portBusy = false;
|
|
152
|
-
try {
|
|
153
|
-
if (process.platform === 'win32') {
|
|
154
|
-
const out = execSync('netstat -ano | findstr :8317 | findstr LISTENING', { encoding: 'utf8' });
|
|
155
|
-
portBusy = out.includes('LISTENING');
|
|
156
|
-
} else {
|
|
157
|
-
const out = execSync('lsof -i :8317 | grep LISTEN', { encoding: 'utf8' });
|
|
158
|
-
portBusy = out.length > 0;
|
|
159
|
-
}
|
|
160
|
-
} catch (e) {
|
|
161
|
-
portBusy = false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (portBusy) {
|
|
165
|
-
isProxyRunning = true;
|
|
166
|
-
} else {
|
|
167
|
-
isProxyRunning = false;
|
|
168
|
-
proxyProcess = null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
running: isProxyRunning,
|
|
173
|
-
pid: proxyProcess?.pid,
|
|
174
|
-
configFile: PROXY_CONFIG_FILE,
|
|
175
|
-
port: 8317,
|
|
176
|
-
installed: !!cmd,
|
|
177
|
-
binary: cmd
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const runLogin = async (provider) => {
|
|
182
|
-
const cmd = await getProxyCommand();
|
|
183
|
-
if (!cmd) return { success: false, error: "Binary not found" };
|
|
184
|
-
|
|
185
|
-
let loginFlag = '';
|
|
186
|
-
switch(provider) {
|
|
187
|
-
case 'google':
|
|
188
|
-
case 'antigravity': loginFlag = '-antigravity-login'; break;
|
|
189
|
-
case 'openai':
|
|
190
|
-
case 'codex': loginFlag = '-codex-login'; break;
|
|
191
|
-
case 'anthropic': loginFlag = '-claude-login'; break;
|
|
192
|
-
default: return { success: false, error: "Unknown provider" };
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const fullCmd = `${cmd} ${loginFlag} -config "${PROXY_CONFIG_FILE}"`;
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
success: true,
|
|
199
|
-
command: fullCmd,
|
|
200
|
-
message: "Terminal launching..."
|
|
201
|
-
};
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const listAccounts = () => {
|
|
205
|
-
if (!fs.existsSync(PROXY_AUTH_DIR)) return [];
|
|
206
|
-
try {
|
|
207
|
-
return fs.readdirSync(PROXY_AUTH_DIR)
|
|
208
|
-
.filter(f => f.endsWith('.json'))
|
|
209
|
-
.map(f => {
|
|
210
|
-
const parts = f.replace('.json', '').split('-');
|
|
211
|
-
const provider = parts[0];
|
|
212
|
-
const email = parts.slice(1).join('-').replace(/_/g, '.').replace('.gmail.com', '@gmail.com');
|
|
213
|
-
return { id: f, provider, email: email || f };
|
|
214
|
-
});
|
|
215
|
-
} catch {
|
|
216
|
-
return [];
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
module.exports = {
|
|
221
|
-
startProxy,
|
|
222
|
-
stopProxy,
|
|
223
|
-
getStatus,
|
|
224
|
-
loadProxyConfig,
|
|
225
|
-
saveProxyConfig,
|
|
226
|
-
runLogin,
|
|
227
|
-
listAccounts
|
|
228
|
-
};
|