Compare commits

..

1 Commits

Author SHA1 Message Date
Haileyesus
6d2be8e03e fix: remove /exit command from claude login flow during onboarding 2026-03-17 10:39:16 +03:00
4 changed files with 4 additions and 53 deletions

View File

@@ -153,7 +153,6 @@ CloudCLI has a plugin system that lets you add custom tabs with their own fronte
| Plugin | Description |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | Shows file counts, lines of code, file-type breakdown, largest files, and recently modified files for your current project |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | Full xterm.js terminal with multi-tab support|
### Build Your Own

2
package-lock.json generated
View File

@@ -1910,6 +1910,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -1926,6 +1927,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [

View File

@@ -65,7 +65,7 @@ import userRoutes from './routes/user.js';
import codexRoutes from './routes/codex.js';
import geminiRoutes from './routes/gemini.js';
import pluginsRoutes from './routes/plugins.js';
import { startEnabledPluginServers, stopAllPlugins, getPluginPort } from './utils/plugin-process-manager.js';
import { startEnabledPluginServers, stopAllPlugins } from './utils/plugin-process-manager.js';
import { initializeDatabase, sessionNamesDb, applyCustomSessionNames } from './database/db.js';
import { configureWebPush } from './services/vapid-keys.js';
import { validateApiKey, authenticateToken, authenticateWebSocket } from './middleware/auth.js';
@@ -1396,50 +1396,6 @@ const uploadFilesHandler = async (req, res) => {
app.post('/api/projects/:projectName/files/upload', authenticateToken, uploadFilesHandler);
/**
* Proxy an authenticated client WebSocket to a plugin's internal WS server.
* Auth is enforced by verifyClient before this function is reached.
*/
function handlePluginWsProxy(clientWs, pathname) {
const pluginName = pathname.replace('/plugin-ws/', '');
if (!pluginName || /[^a-zA-Z0-9_-]/.test(pluginName)) {
clientWs.close(4400, 'Invalid plugin name');
return;
}
const port = getPluginPort(pluginName);
if (!port) {
clientWs.close(4404, 'Plugin not running');
return;
}
const upstream = new WebSocket(`ws://127.0.0.1:${port}/ws`);
upstream.on('open', () => {
console.log(`[Plugins] WS proxy connected to "${pluginName}" on port ${port}`);
});
// Relay messages bidirectionally
upstream.on('message', (data) => {
if (clientWs.readyState === WebSocket.OPEN) clientWs.send(data);
});
clientWs.on('message', (data) => {
if (upstream.readyState === WebSocket.OPEN) upstream.send(data);
});
// Propagate close in both directions
upstream.on('close', () => { if (clientWs.readyState === WebSocket.OPEN) clientWs.close(); });
clientWs.on('close', () => { if (upstream.readyState === WebSocket.OPEN) upstream.close(); });
upstream.on('error', (err) => {
console.error(`[Plugins] WS proxy error for "${pluginName}":`, err.message);
if (clientWs.readyState === WebSocket.OPEN) clientWs.close(4502, 'Upstream error');
});
clientWs.on('error', () => {
if (upstream.readyState === WebSocket.OPEN) upstream.close();
});
}
// WebSocket connection handler that routes based on URL path
wss.on('connection', (ws, request) => {
const url = request.url;
@@ -1453,8 +1409,6 @@ wss.on('connection', (ws, request) => {
handleShellConnection(ws);
} else if (pathname === '/ws') {
handleChatConnection(ws, request);
} else if (pathname.startsWith('/plugin-ws/')) {
handlePluginWsProxy(ws, pathname);
} else {
console.log('[WARN] Unknown WebSocket path:', pathname);
ws.close();

View File

@@ -81,10 +81,6 @@ router.get('/:name/assets/*', (req, res) => {
const contentType = mime.lookup(resolvedPath) || 'application/octet-stream';
res.setHeader('Content-Type', contentType);
// Prevent CDN/proxy caching of plugin assets so updates take effect immediately
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
const stream = fs.createReadStream(resolvedPath);
stream.on('error', () => {
if (!res.headersSent) {
@@ -240,7 +236,7 @@ router.all('/:name/rpc/*', async (req, res) => {
'content-type': req.headers['content-type'] || 'application/json',
};
// Add per-plugin user-configured secrets as X-Plugin-Secret-* headers
// Add per-plugin secrets as X-Plugin-Secret-* headers
for (const [key, value] of Object.entries(secrets)) {
headers[`x-plugin-secret-${key.toLowerCase()}`] = String(value);
}