@cloudcli-ai/cloudcli 1.33.2 → 1.33.3
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/dist/assets/index-73Xw3i9v.css +32 -0
- package/dist/assets/{index-B0mnqBF-.js → index-9n7A21AT.js} +256 -246
- package/dist/index.html +2 -2
- package/dist-server/server/cli.js +2 -2
- package/dist-server/server/cli.js.map +1 -1
- package/dist-server/server/index.js +16 -7
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/database/repositories/notification-preferences.js +2 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -1
- package/dist-server/server/utils/plugin-loader.js +1 -1
- package/dist-server/server/utils/plugin-loader.js.map +1 -1
- package/dist-server/server/utils/plugin-process-manager.js +33 -7
- package/dist-server/server/utils/plugin-process-manager.js.map +1 -1
- package/package.json +1 -1
- package/server/cli.js +2 -2
- package/server/index.js +17 -7
- package/server/modules/database/repositories/notification-preferences.ts +3 -0
- package/server/utils/plugin-loader.js +2 -1
- package/server/utils/plugin-process-manager.js +36 -7
- package/dist/assets/index-FSP9Hz7V.css +0 -32
|
@@ -5,6 +5,38 @@ import { scanPlugins, getPluginsConfig, getPluginDir } from './plugin-loader.js'
|
|
|
5
5
|
const runningPlugins = new Map();
|
|
6
6
|
// Map<pluginName, Promise<port>> — in-flight start operations
|
|
7
7
|
const startingPlugins = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* Build the environment handed to a plugin server subprocess.
|
|
10
|
+
*
|
|
11
|
+
* Intentionally minimal: only non-secret essentials, never the host's full
|
|
12
|
+
* environment. On Windows a handful of system variables are required for any
|
|
13
|
+
* child to bootstrap (Node itself, and any Python or CLI a plugin shells out
|
|
14
|
+
* to). Without APPDATA a `pip install --user` tool cannot locate its
|
|
15
|
+
* site-packages and fails to import; SystemRoot, PATHEXT and TEMP are needed to
|
|
16
|
+
* resolve system DLLs, executable extensions and a temp directory. None of
|
|
17
|
+
* these carry secrets, so the ones that are set get passed straight through.
|
|
18
|
+
*/
|
|
19
|
+
function buildPluginEnv(name) {
|
|
20
|
+
const env = {
|
|
21
|
+
PATH: process.env.PATH,
|
|
22
|
+
HOME: process.env.HOME,
|
|
23
|
+
NODE_ENV: process.env.NODE_ENV || 'production',
|
|
24
|
+
PLUGIN_NAME: name,
|
|
25
|
+
};
|
|
26
|
+
if (process.platform === 'win32') {
|
|
27
|
+
const WINDOWS_ESSENTIALS = [
|
|
28
|
+
'SystemRoot', 'windir', 'SystemDrive',
|
|
29
|
+
'USERPROFILE', 'APPDATA', 'LOCALAPPDATA',
|
|
30
|
+
'TEMP', 'TMP', 'PATHEXT',
|
|
31
|
+
];
|
|
32
|
+
for (const key of WINDOWS_ESSENTIALS) {
|
|
33
|
+
if (process.env[key] !== undefined) {
|
|
34
|
+
env[key] = process.env[key];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return env;
|
|
39
|
+
}
|
|
8
40
|
/**
|
|
9
41
|
* Start a plugin's server subprocess.
|
|
10
42
|
* The plugin's server entry must print a JSON line with { ready: true, port: <number> }
|
|
@@ -20,15 +52,9 @@ export function startPluginServer(name, pluginDir, serverEntry) {
|
|
|
20
52
|
}
|
|
21
53
|
const startPromise = new Promise((resolve, reject) => {
|
|
22
54
|
const serverPath = path.join(pluginDir, serverEntry);
|
|
23
|
-
// Restricted env — only essentials, no host secrets
|
|
24
55
|
const pluginProcess = spawn('node', [serverPath], {
|
|
25
56
|
cwd: pluginDir,
|
|
26
|
-
env:
|
|
27
|
-
PATH: process.env.PATH,
|
|
28
|
-
HOME: process.env.HOME,
|
|
29
|
-
NODE_ENV: process.env.NODE_ENV || 'production',
|
|
30
|
-
PLUGIN_NAME: name,
|
|
31
|
-
},
|
|
57
|
+
env: buildPluginEnv(name),
|
|
32
58
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
33
59
|
});
|
|
34
60
|
let resolved = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-process-manager.js","sourceRoot":"","sources":["../../../server/utils/plugin-process-manager.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjF,qCAAqC;AACrC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAE,CAAC;AACjC,8DAA8D;AAC9D,MAAM,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;AAElC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW;IAC5D,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,iDAAiD;IACjD,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAEnD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAErD,
|
|
1
|
+
{"version":3,"file":"plugin-process-manager.js","sourceRoot":"","sources":["../../../server/utils/plugin-process-manager.js"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/server/cli.js
CHANGED
|
@@ -455,7 +455,7 @@ async function sandboxCommand(args) {
|
|
|
455
455
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
456
456
|
|
|
457
457
|
console.log(`${c.info('▶')} Launching CloudCLI web server...`);
|
|
458
|
-
sbx(['exec', opts.name, 'bash', '-c', 'cloudcli start --port 3001 &']);
|
|
458
|
+
sbx(['exec', opts.name, 'bash', '-c', 'nohup cloudcli start --port 3001 > /tmp/cloudcli-ui.log 2>&1 & disown']);
|
|
459
459
|
|
|
460
460
|
console.log(`${c.info('▶')} Forwarding port ${opts.port} → 3001...`);
|
|
461
461
|
try {
|
|
@@ -554,7 +554,7 @@ async function sandboxCommand(args) {
|
|
|
554
554
|
|
|
555
555
|
// Step 3: Start CloudCLI inside the sandbox
|
|
556
556
|
console.log(`${c.info('▶')} Launching CloudCLI web server...`);
|
|
557
|
-
sbx(['exec', opts.name, 'bash', '-c', 'cloudcli start --port 3001 &']);
|
|
557
|
+
sbx(['exec', opts.name, 'bash', '-c', 'nohup cloudcli start --port 3001 > /tmp/cloudcli-ui.log 2>&1 & disown']);
|
|
558
558
|
|
|
559
559
|
// Step 4: Forward port
|
|
560
560
|
console.log(`${c.info('▶')} Forwarding port ${opts.port} → 3001...`);
|
package/server/index.js
CHANGED
|
@@ -84,6 +84,9 @@ const __dirname = getModuleDir(import.meta.url);
|
|
|
84
84
|
// Resolving the app root once keeps every repo-level lookup below aligned across both layouts.
|
|
85
85
|
const APP_ROOT = findAppRoot(__dirname);
|
|
86
86
|
const installMode = fs.existsSync(path.join(APP_ROOT, '.git')) ? 'git' : 'npm';
|
|
87
|
+
const MAX_FILE_UPLOAD_SIZE_MB = 200;
|
|
88
|
+
const MAX_FILE_UPLOAD_SIZE_BYTES = MAX_FILE_UPLOAD_SIZE_MB * 1024 * 1024;
|
|
89
|
+
const MAX_FILE_UPLOAD_COUNT = 20;
|
|
87
90
|
|
|
88
91
|
console.log('SERVER_PORT from env:', process.env.SERVER_PORT);
|
|
89
92
|
|
|
@@ -897,27 +900,27 @@ const uploadFilesHandler = async (req, res) => {
|
|
|
897
900
|
}
|
|
898
901
|
}),
|
|
899
902
|
limits: {
|
|
900
|
-
fileSize:
|
|
901
|
-
files:
|
|
903
|
+
fileSize: MAX_FILE_UPLOAD_SIZE_BYTES,
|
|
904
|
+
files: MAX_FILE_UPLOAD_COUNT
|
|
902
905
|
}
|
|
903
906
|
});
|
|
904
907
|
|
|
905
908
|
// Use multer middleware
|
|
906
|
-
uploadMiddleware.array('files',
|
|
909
|
+
uploadMiddleware.array('files', MAX_FILE_UPLOAD_COUNT)(req, res, async (err) => {
|
|
907
910
|
if (err) {
|
|
908
911
|
console.error('Multer error:', err);
|
|
909
912
|
if (err.code === 'LIMIT_FILE_SIZE') {
|
|
910
|
-
return res.status(400).json({ error:
|
|
913
|
+
return res.status(400).json({ error: `File too large. Maximum size is ${MAX_FILE_UPLOAD_SIZE_MB}MB.` });
|
|
911
914
|
}
|
|
912
915
|
if (err.code === 'LIMIT_FILE_COUNT') {
|
|
913
|
-
return res.status(400).json({ error:
|
|
916
|
+
return res.status(400).json({ error: `Too many files. Maximum is ${MAX_FILE_UPLOAD_COUNT} files.` });
|
|
914
917
|
}
|
|
915
918
|
return res.status(500).json({ error: err.message });
|
|
916
919
|
}
|
|
917
920
|
|
|
918
921
|
try {
|
|
919
922
|
const { projectId } = req.params;
|
|
920
|
-
const { targetPath, relativePaths } = req.body;
|
|
923
|
+
const { targetPath, relativePaths, requestedFileCount: requestedFileCountRaw } = req.body;
|
|
921
924
|
|
|
922
925
|
// Parse relative paths if provided (for folder uploads)
|
|
923
926
|
let filePaths = [];
|
|
@@ -941,6 +944,11 @@ const uploadFilesHandler = async (req, res) => {
|
|
|
941
944
|
return res.status(400).json({ error: 'No files provided' });
|
|
942
945
|
}
|
|
943
946
|
|
|
947
|
+
const parsedRequestedFileCount = Number.parseInt(requestedFileCountRaw, 10);
|
|
948
|
+
const requestedFileCount = Number.isFinite(parsedRequestedFileCount) && parsedRequestedFileCount > 0
|
|
949
|
+
? parsedRequestedFileCount
|
|
950
|
+
: req.files.length;
|
|
951
|
+
|
|
944
952
|
// Resolve the project directory through the DB using the new projectId.
|
|
945
953
|
const projectRoot = await projectsDb.getProjectPathById(projectId);
|
|
946
954
|
if (!projectRoot) {
|
|
@@ -1019,8 +1027,10 @@ const uploadFilesHandler = async (req, res) => {
|
|
|
1019
1027
|
res.json({
|
|
1020
1028
|
success: true,
|
|
1021
1029
|
files: uploadedFiles,
|
|
1030
|
+
uploadedCount: uploadedFiles.length,
|
|
1031
|
+
requestedFileCount,
|
|
1022
1032
|
targetPath: resolvedTargetDir,
|
|
1023
|
-
message: `Uploaded ${uploadedFiles.length} file
|
|
1033
|
+
message: `Uploaded ${uploadedFiles.length} ${uploadedFiles.length === 1 ? 'file' : 'files'} successfully`
|
|
1024
1034
|
});
|
|
1025
1035
|
} catch (error) {
|
|
1026
1036
|
console.error('Error uploading files:', error);
|
|
@@ -10,6 +10,7 @@ type NotificationPreferences = {
|
|
|
10
10
|
channels: {
|
|
11
11
|
inApp: boolean;
|
|
12
12
|
webPush: boolean;
|
|
13
|
+
sound: boolean;
|
|
13
14
|
};
|
|
14
15
|
events: {
|
|
15
16
|
actionRequired: boolean;
|
|
@@ -22,6 +23,7 @@ const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences = {
|
|
|
22
23
|
channels: {
|
|
23
24
|
inApp: false,
|
|
24
25
|
webPush: false,
|
|
26
|
+
sound: true,
|
|
25
27
|
},
|
|
26
28
|
events: {
|
|
27
29
|
actionRequired: true,
|
|
@@ -37,6 +39,7 @@ function normalizeNotificationPreferences(value: unknown): NotificationPreferenc
|
|
|
37
39
|
channels: {
|
|
38
40
|
inApp: source.channels?.inApp === true,
|
|
39
41
|
webPush: source.channels?.webPush === true,
|
|
42
|
+
sound: source.channels?.sound !== false,
|
|
40
43
|
},
|
|
41
44
|
events: {
|
|
42
45
|
actionRequired: source.events?.actionRequired !== false,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import { spawn } from 'cross-spawn';
|
|
5
6
|
|
|
6
7
|
const PLUGINS_DIR = path.join(os.homedir(), '.claude-code-ui', 'plugins');
|
|
7
8
|
const PLUGINS_CONFIG_PATH = path.join(os.homedir(), '.claude-code-ui', 'plugins.json');
|
|
@@ -7,6 +7,41 @@ const runningPlugins = new Map();
|
|
|
7
7
|
// Map<pluginName, Promise<port>> — in-flight start operations
|
|
8
8
|
const startingPlugins = new Map();
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Build the environment handed to a plugin server subprocess.
|
|
12
|
+
*
|
|
13
|
+
* Intentionally minimal: only non-secret essentials, never the host's full
|
|
14
|
+
* environment. On Windows a handful of system variables are required for any
|
|
15
|
+
* child to bootstrap (Node itself, and any Python or CLI a plugin shells out
|
|
16
|
+
* to). Without APPDATA a `pip install --user` tool cannot locate its
|
|
17
|
+
* site-packages and fails to import; SystemRoot, PATHEXT and TEMP are needed to
|
|
18
|
+
* resolve system DLLs, executable extensions and a temp directory. None of
|
|
19
|
+
* these carry secrets, so the ones that are set get passed straight through.
|
|
20
|
+
*/
|
|
21
|
+
function buildPluginEnv(name) {
|
|
22
|
+
const env = {
|
|
23
|
+
PATH: process.env.PATH,
|
|
24
|
+
HOME: process.env.HOME,
|
|
25
|
+
NODE_ENV: process.env.NODE_ENV || 'production',
|
|
26
|
+
PLUGIN_NAME: name,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (process.platform === 'win32') {
|
|
30
|
+
const WINDOWS_ESSENTIALS = [
|
|
31
|
+
'SystemRoot', 'windir', 'SystemDrive',
|
|
32
|
+
'USERPROFILE', 'APPDATA', 'LOCALAPPDATA',
|
|
33
|
+
'TEMP', 'TMP', 'PATHEXT',
|
|
34
|
+
];
|
|
35
|
+
for (const key of WINDOWS_ESSENTIALS) {
|
|
36
|
+
if (process.env[key] !== undefined) {
|
|
37
|
+
env[key] = process.env[key];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return env;
|
|
43
|
+
}
|
|
44
|
+
|
|
10
45
|
/**
|
|
11
46
|
* Start a plugin's server subprocess.
|
|
12
47
|
* The plugin's server entry must print a JSON line with { ready: true, port: <number> }
|
|
@@ -26,15 +61,9 @@ export function startPluginServer(name, pluginDir, serverEntry) {
|
|
|
26
61
|
|
|
27
62
|
const serverPath = path.join(pluginDir, serverEntry);
|
|
28
63
|
|
|
29
|
-
// Restricted env — only essentials, no host secrets
|
|
30
64
|
const pluginProcess = spawn('node', [serverPath], {
|
|
31
65
|
cwd: pluginDir,
|
|
32
|
-
env:
|
|
33
|
-
PATH: process.env.PATH,
|
|
34
|
-
HOME: process.env.HOME,
|
|
35
|
-
NODE_ENV: process.env.NODE_ENV || 'production',
|
|
36
|
-
PLUGIN_NAME: name,
|
|
37
|
-
},
|
|
66
|
+
env: buildPluginEnv(name),
|
|
38
67
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
39
68
|
});
|
|
40
69
|
|