cloud-ide-cide 2.0.41 → 2.0.42
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/appManager.js +76 -49
- package/cideShell.js +77 -13
- package/deployer/php/upload-ui.php +52 -3
- package/package.json +2 -3
- package/publishPackage.js +7 -4
package/appManager.js
CHANGED
|
@@ -15,11 +15,77 @@ const {
|
|
|
15
15
|
printProjectList,
|
|
16
16
|
selectProject,
|
|
17
17
|
selectServer,
|
|
18
|
-
resolveEndpoint,
|
|
19
18
|
getToken,
|
|
20
19
|
getAuthHeaders,
|
|
21
20
|
} = require('./uploadProject');
|
|
22
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Resolve app management endpoint URL.
|
|
24
|
+
* PHP uses ?action=app-status, Node uses /app/status routes.
|
|
25
|
+
*/
|
|
26
|
+
function resolveAppEndpoint(serverUrl, action) {
|
|
27
|
+
const u = new URL(serverUrl);
|
|
28
|
+
if (u.pathname.endsWith('.php')) {
|
|
29
|
+
u.searchParams.set('action', `app-${action}`);
|
|
30
|
+
return u.toString();
|
|
31
|
+
}
|
|
32
|
+
const base = u.pathname.replace(/\/upload\/?$/, '');
|
|
33
|
+
u.pathname = `${base}/app/${action}`;
|
|
34
|
+
return u.toString();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isPhpServer(serverUrl) {
|
|
38
|
+
return new URL(serverUrl).pathname.endsWith('.php');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function printStatus(data) {
|
|
42
|
+
console.log(` App : ${data.appCode}`);
|
|
43
|
+
if (data.type === 'php') {
|
|
44
|
+
console.log(` Type : PHP/UI (served by Apache/Nginx)`);
|
|
45
|
+
console.log(` Deployed : ${data.version ? 'Yes' : 'No'}`);
|
|
46
|
+
if (data.version) console.log(` Version : ${data.version}`);
|
|
47
|
+
if (data.deployedAt) console.log(` Date : ${data.deployedAt}`);
|
|
48
|
+
if (data.appUrl) console.log(` URL : ${data.appUrl}`);
|
|
49
|
+
if (data.releases) console.log(` Releases : ${data.releases}`);
|
|
50
|
+
} else {
|
|
51
|
+
console.log(` Status : ${data.running ? `Running (PID: ${data.pid})` : 'Stopped'}`);
|
|
52
|
+
if (data.appDir) console.log(` Path : ${data.appDir}`);
|
|
53
|
+
if (data.logFile) console.log(` Log : ${data.logFile}`);
|
|
54
|
+
}
|
|
55
|
+
console.log('');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function printAppResult(data, action) {
|
|
59
|
+
if (data.type === 'php') {
|
|
60
|
+
console.log(` ${data.message}`);
|
|
61
|
+
console.log('');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (action === 'stop') {
|
|
66
|
+
if (data.stopped) {
|
|
67
|
+
console.log(` Stopped (was PID: ${data.pid})`);
|
|
68
|
+
} else {
|
|
69
|
+
console.log(` ${data.reason || 'Not running'}`);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
if (data.started) {
|
|
73
|
+
console.log(` ${action === 'start' ? 'Started' : 'Restarted'} (PID: ${data.pid})`);
|
|
74
|
+
if (data.logFile) console.log(` Log : ${data.logFile}`);
|
|
75
|
+
} else {
|
|
76
|
+
console.log(` Failed to start: ${data.reason || 'unknown'}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (data.output) {
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(' ── App Console Output ──────────────────────');
|
|
83
|
+
console.log(data.output.trim().split('\n').map(l => ` ${l}`).join('\n'));
|
|
84
|
+
console.log(' ─────────────────────────────────────────────');
|
|
85
|
+
}
|
|
86
|
+
console.log('');
|
|
87
|
+
}
|
|
88
|
+
|
|
23
89
|
async function appManager(opts = {}) {
|
|
24
90
|
const action = opts.restart ? 'restart'
|
|
25
91
|
: opts.stop ? 'stop'
|
|
@@ -48,66 +114,27 @@ async function appManager(opts = {}) {
|
|
|
48
114
|
|
|
49
115
|
try {
|
|
50
116
|
if (action === 'status') {
|
|
51
|
-
const url =
|
|
117
|
+
const url = resolveAppEndpoint(server.server_url, 'status') + `${isPhpServer(server.server_url) ? '&' : '?'}appCode=${encodeURIComponent(appCode)}`;
|
|
52
118
|
const { data } = await axios.get(url, { headers, timeout: 15000 });
|
|
53
|
-
|
|
54
|
-
console.log(` App : ${data.appCode}`);
|
|
55
|
-
console.log(` Status : ${data.running ? `Running (PID: ${data.pid})` : 'Stopped'}`);
|
|
56
|
-
if (data.appDir) console.log(` Path : ${data.appDir}`);
|
|
57
|
-
if (data.logFile) console.log(` Log : ${data.logFile}`);
|
|
58
|
-
console.log('');
|
|
119
|
+
printStatus(data);
|
|
59
120
|
|
|
60
121
|
} else if (action === 'stop') {
|
|
61
|
-
const url =
|
|
122
|
+
const url = resolveAppEndpoint(server.server_url, 'stop');
|
|
62
123
|
const { data } = await axios.post(url, { appCode }, { headers, timeout: 15000 });
|
|
63
|
-
|
|
64
|
-
if (data.stopped) {
|
|
65
|
-
console.log(` Stopped (was PID: ${data.pid})`);
|
|
66
|
-
} else {
|
|
67
|
-
console.log(` ${data.reason || 'Not running'}`);
|
|
68
|
-
}
|
|
69
|
-
console.log('');
|
|
124
|
+
printAppResult(data, 'stop');
|
|
70
125
|
|
|
71
126
|
} else if (action === 'start') {
|
|
72
|
-
const url =
|
|
127
|
+
const url = resolveAppEndpoint(server.server_url, 'start');
|
|
73
128
|
const { data } = await axios.post(url, { appCode }, { headers, timeout: 30000 });
|
|
74
|
-
|
|
75
|
-
if (data.started) {
|
|
76
|
-
console.log(` Started (PID: ${data.pid})`);
|
|
77
|
-
if (data.logFile) console.log(` Log : ${data.logFile}`);
|
|
78
|
-
} else {
|
|
79
|
-
console.log(` Failed to start: ${data.reason || 'unknown'}`);
|
|
80
|
-
}
|
|
81
|
-
if (data.output) {
|
|
82
|
-
console.log('');
|
|
83
|
-
console.log(' ── App Console Output ──────────────────────');
|
|
84
|
-
console.log(data.output.trim().split('\n').map(l => ` ${l}`).join('\n'));
|
|
85
|
-
console.log(' ─────────────────────────────────────────────');
|
|
86
|
-
}
|
|
87
|
-
console.log('');
|
|
129
|
+
printAppResult(data, 'start');
|
|
88
130
|
|
|
89
131
|
} else if (action === 'restart') {
|
|
90
|
-
|
|
91
|
-
const stopUrl = resolveEndpoint(server.server_url, 'app/stop');
|
|
132
|
+
const stopUrl = resolveAppEndpoint(server.server_url, 'stop');
|
|
92
133
|
await axios.post(stopUrl, { appCode }, { headers, timeout: 15000 }).catch(() => {});
|
|
93
134
|
|
|
94
|
-
|
|
95
|
-
const startUrl = resolveEndpoint(server.server_url, 'app/start');
|
|
135
|
+
const startUrl = resolveAppEndpoint(server.server_url, 'start');
|
|
96
136
|
const { data } = await axios.post(startUrl, { appCode }, { headers, timeout: 30000 });
|
|
97
|
-
|
|
98
|
-
if (data.started) {
|
|
99
|
-
console.log(` Restarted (PID: ${data.pid})`);
|
|
100
|
-
if (data.logFile) console.log(` Log : ${data.logFile}`);
|
|
101
|
-
} else {
|
|
102
|
-
console.log(` Failed to start: ${data.reason || 'unknown'}`);
|
|
103
|
-
}
|
|
104
|
-
if (data.output) {
|
|
105
|
-
console.log('');
|
|
106
|
-
console.log(' ── App Console Output ──────────────────────');
|
|
107
|
-
console.log(data.output.trim().split('\n').map(l => ` ${l}`).join('\n'));
|
|
108
|
-
console.log(' ─────────────────────────────────────────────');
|
|
109
|
-
}
|
|
110
|
-
console.log('');
|
|
137
|
+
printAppResult(data, 'restart');
|
|
111
138
|
}
|
|
112
139
|
} catch (err) {
|
|
113
140
|
const msg = err.response?.data?.message || err.message || err;
|
package/cideShell.js
CHANGED
|
@@ -676,25 +676,62 @@ function handleBranch(ws, repoName) {
|
|
|
676
676
|
else runGitAll(ws, 'branch -vv', true);
|
|
677
677
|
}
|
|
678
678
|
|
|
679
|
-
|
|
680
|
-
|
|
679
|
+
const PID_FILE = '.cide_node_bg_pid.json';
|
|
680
|
+
|
|
681
|
+
function getPidFilePath(ws) {
|
|
682
|
+
if (ws && ws.nodeBackend) {
|
|
683
|
+
const dir = path.join(ws.nodeBackend.absPath, '.cide');
|
|
684
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
685
|
+
return path.join(dir, PID_FILE);
|
|
686
|
+
}
|
|
687
|
+
return path.join(process.cwd(), PID_FILE);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function savePid(ws, pid, command, args) {
|
|
691
|
+
const file = getPidFilePath(ws);
|
|
692
|
+
fs.writeFileSync(file, JSON.stringify({ pid, command, args, timestamp: Date.now() }));
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function loadPid(ws) {
|
|
696
|
+
const file = getPidFilePath(ws);
|
|
697
|
+
if (fs.existsSync(file)) {
|
|
698
|
+
try {
|
|
699
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
700
|
+
} catch {}
|
|
701
|
+
}
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function clearPid(ws) {
|
|
706
|
+
const file = getPidFilePath(ws);
|
|
707
|
+
if (fs.existsSync(file)) fs.unlinkSync(file);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function killBgServer(ws) {
|
|
711
|
+
const processInfo = loadPid(ws);
|
|
712
|
+
let targetPid = bgServerPid;
|
|
713
|
+
if (processInfo && processInfo.pid) {
|
|
714
|
+
targetPid = processInfo.pid;
|
|
715
|
+
}
|
|
716
|
+
if (!targetPid) {
|
|
681
717
|
console.log('No background server PID tracked (start with: server dev)');
|
|
682
718
|
return;
|
|
683
719
|
}
|
|
684
720
|
try {
|
|
685
721
|
if (process.platform === 'win32') {
|
|
686
|
-
execSync(`taskkill /PID ${
|
|
722
|
+
execSync(`taskkill /PID ${targetPid} /T /F`, { stdio: 'inherit', shell: true });
|
|
687
723
|
} else {
|
|
688
|
-
process.kill(-
|
|
724
|
+
process.kill(-targetPid, 'SIGTERM');
|
|
689
725
|
}
|
|
690
|
-
console.log(`Stopped process tree ${
|
|
726
|
+
console.log(`Stopped process tree ${targetPid}`);
|
|
691
727
|
} catch (e) {
|
|
692
|
-
console.error(
|
|
728
|
+
console.error(`Stop failed or process already killed: ${e.message}`);
|
|
693
729
|
}
|
|
694
730
|
bgServerPid = null;
|
|
731
|
+
clearPid(ws);
|
|
695
732
|
}
|
|
696
733
|
|
|
697
|
-
function spawnBg(cwd, command, args) {
|
|
734
|
+
function spawnBg(ws, cwd, command, args) {
|
|
698
735
|
const child = spawn(command, args, {
|
|
699
736
|
cwd,
|
|
700
737
|
shell: true,
|
|
@@ -703,6 +740,7 @@ function spawnBg(cwd, command, args) {
|
|
|
703
740
|
});
|
|
704
741
|
child.unref();
|
|
705
742
|
bgServerPid = child.pid;
|
|
743
|
+
savePid(ws, child.pid, command, args);
|
|
706
744
|
console.log(`Started background PID ${child.pid} (${command} ${args.join(' ')})`);
|
|
707
745
|
console.log('(Output not shown here; use server stop to end, or run npm in another terminal for logs.)');
|
|
708
746
|
}
|
|
@@ -743,18 +781,44 @@ async function handleServer(ws, sub, rest, rl) {
|
|
|
743
781
|
return;
|
|
744
782
|
}
|
|
745
783
|
if (sub === 'start') {
|
|
746
|
-
spawnBg(cwd, 'npm', ['run', 'start']);
|
|
784
|
+
spawnBg(ws, cwd, 'npm', ['run', 'start']);
|
|
747
785
|
return;
|
|
748
786
|
}
|
|
749
787
|
if (sub === 'dev') {
|
|
750
|
-
spawnBg(cwd, 'npm', ['run', 'dev']);
|
|
788
|
+
spawnBg(ws, cwd, 'npm', ['run', 'dev']);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (sub === 'status') {
|
|
792
|
+
const processInfo = loadPid(ws);
|
|
793
|
+
if (!processInfo) {
|
|
794
|
+
console.log('Server is NOT running (no PID tracked).');
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
let isRunning = false;
|
|
798
|
+
try {
|
|
799
|
+
if (process.platform === 'win32') {
|
|
800
|
+
const out = execSync(`tasklist /FI "PID eq ${processInfo.pid}"`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
801
|
+
isRunning = out.includes(processInfo.pid.toString());
|
|
802
|
+
} else {
|
|
803
|
+
process.kill(processInfo.pid, 0);
|
|
804
|
+
isRunning = true;
|
|
805
|
+
}
|
|
806
|
+
} catch {
|
|
807
|
+
isRunning = false;
|
|
808
|
+
}
|
|
809
|
+
if (isRunning) {
|
|
810
|
+
console.log(`Server is RUNNING (PID: ${processInfo.pid}, Command: ${processInfo.command} ${processInfo.args.join(' ')})`);
|
|
811
|
+
} else {
|
|
812
|
+
console.log(`Server was tracked as PID: ${processInfo.pid} but appears to be dead now.`);
|
|
813
|
+
clearPid(ws);
|
|
814
|
+
}
|
|
751
815
|
return;
|
|
752
816
|
}
|
|
753
817
|
if (sub === 'stop') {
|
|
754
|
-
killBgServer();
|
|
818
|
+
killBgServer(ws);
|
|
755
819
|
return;
|
|
756
820
|
}
|
|
757
|
-
console.error('Usage: server build | start | dev | stop | init | listener start|stop|status|restart');
|
|
821
|
+
console.error('Usage: server build | start | dev | stop | status | init | listener start|stop|status|restart');
|
|
758
822
|
}
|
|
759
823
|
|
|
760
824
|
function handleSeed(ws, name) {
|
|
@@ -796,7 +860,7 @@ function handleServe(ws) {
|
|
|
796
860
|
console.error(`No "start" script in ${path.basename(ws.angularRoot)}/package.json`);
|
|
797
861
|
return;
|
|
798
862
|
}
|
|
799
|
-
spawnBg(ws.angularRoot, 'npm', ['run', 'start']);
|
|
863
|
+
spawnBg(ws, ws.angularRoot, 'npm', ['run', 'start']);
|
|
800
864
|
}
|
|
801
865
|
|
|
802
866
|
function handleTailwind(ws) {
|
|
@@ -805,7 +869,7 @@ function handleTailwind(ws) {
|
|
|
805
869
|
console.error(`No "tailwindcss" script in ${path.basename(ws.angularRoot)}/package.json`);
|
|
806
870
|
return;
|
|
807
871
|
}
|
|
808
|
-
spawnBg(ws.angularRoot, 'npm', ['run', 'tailwindcss']);
|
|
872
|
+
spawnBg(ws, ws.angularRoot, 'npm', ['run', 'tailwindcss']);
|
|
809
873
|
}
|
|
810
874
|
|
|
811
875
|
function handleLint(ws) {
|
|
@@ -59,9 +59,12 @@ $deploymentsFile = "{$cideDir}/deployments.json";
|
|
|
59
59
|
// ── Route ────────────────────────────────────────────────────────────────────
|
|
60
60
|
$action = $_GET['action'] ?? $_POST['action'] ?? 'upload';
|
|
61
61
|
|
|
62
|
-
if ($action === 'history')
|
|
63
|
-
elseif ($action === 'rollback')
|
|
64
|
-
|
|
62
|
+
if ($action === 'history') handleHistory();
|
|
63
|
+
elseif ($action === 'rollback') handleRollback();
|
|
64
|
+
elseif ($action === 'app-status') handleAppStatus();
|
|
65
|
+
elseif ($action === 'app-start') handleAppManageNA('start');
|
|
66
|
+
elseif ($action === 'app-stop') handleAppManageNA('stop');
|
|
67
|
+
else handleUpload();
|
|
65
68
|
|
|
66
69
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
67
70
|
// ── Upload ────────────────────────────────────────────────────────────────────
|
|
@@ -238,6 +241,52 @@ function handleRollback() {
|
|
|
238
241
|
]);
|
|
239
242
|
}
|
|
240
243
|
|
|
244
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
245
|
+
// ── App Status ───────────────────────────────────────────────────────────────
|
|
246
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
247
|
+
function handleAppStatus() {
|
|
248
|
+
global $currentDir;
|
|
249
|
+
|
|
250
|
+
$appCode = isset($_GET['appCode']) ? preg_replace('/[^a-zA-Z0-9\-_]/', '', $_GET['appCode']) : '';
|
|
251
|
+
if ($appCode === '') {
|
|
252
|
+
http_response_code(422);
|
|
253
|
+
echo json_encode(['status' => 'FAILED', 'message' => 'Missing appCode']);
|
|
254
|
+
exit;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
$deployments = loadDeployments();
|
|
258
|
+
$current = $deployments['apps'][$appCode]['current'] ?? null;
|
|
259
|
+
$currentPath = "{$currentDir}/{$appCode}";
|
|
260
|
+
$deployed = is_dir($currentPath) || is_link($currentPath);
|
|
261
|
+
|
|
262
|
+
// Build the app URL from server info
|
|
263
|
+
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
|
264
|
+
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
|
|
265
|
+
// Strip port from host if present, UI runs on default 80/443
|
|
266
|
+
$host = preg_replace('/:\d+$/', '', $host);
|
|
267
|
+
$appUrl = "{$protocol}://{$host}";
|
|
268
|
+
|
|
269
|
+
echo json_encode([
|
|
270
|
+
'status' => 'SUCCESS',
|
|
271
|
+
'appCode' => $appCode,
|
|
272
|
+
'running' => $deployed,
|
|
273
|
+
'type' => 'php',
|
|
274
|
+
'appUrl' => $appUrl,
|
|
275
|
+
'appDir' => $currentPath,
|
|
276
|
+
'version' => $current['version'] ?? null,
|
|
277
|
+
'deployedAt' => $current['deployedAt'] ?? null,
|
|
278
|
+
'releases' => count($deployments['apps'][$appCode]['history'] ?? []),
|
|
279
|
+
]);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function handleAppManageNA($action) {
|
|
283
|
+
echo json_encode([
|
|
284
|
+
'status' => 'SUCCESS',
|
|
285
|
+
'message' => "PHP/UI apps are served by Apache/Nginx — no process to {$action}. The app is always running when deployed.",
|
|
286
|
+
'type' => 'php',
|
|
287
|
+
]);
|
|
288
|
+
}
|
|
289
|
+
|
|
241
290
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
242
291
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
243
292
|
// ═══════════════════════════════════════════════════════════════════════════════
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloud-ide-cide",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.42",
|
|
4
4
|
"description": "Cloud IDE CLI — create, build, publish, upload and deploy Cloud IDE projects.",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -49,6 +49,5 @@
|
|
|
49
49
|
],
|
|
50
50
|
"author": "Ankush Shivlal Bhure",
|
|
51
51
|
"license": "ISC",
|
|
52
|
-
"repository": {
|
|
53
|
-
}
|
|
52
|
+
"repository": {}
|
|
54
53
|
}
|
package/publishPackage.js
CHANGED
|
@@ -41,9 +41,12 @@ function writeJson(p, obj) {
|
|
|
41
41
|
fs.writeFileSync(p, JSON.stringify(obj, null, 2) + '\n', 'utf8');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
function isPublishable(pkg) {
|
|
45
|
+
if (!pkg || !pkg.publishConfig) return false;
|
|
46
|
+
const r = pkg.publishConfig.registry;
|
|
47
|
+
if (typeof r === 'string' && (r.includes(GPR_HOST) || r.includes('npmjs.org'))) return true;
|
|
48
|
+
if (pkg.publishConfig.access === 'public') return true;
|
|
49
|
+
return false;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
function bumpSemver(version, kind) {
|
|
@@ -135,7 +138,7 @@ function discoverPublishablePackages({ cide, angularRoot, monorepoRoot }) {
|
|
|
135
138
|
} catch {
|
|
136
139
|
return;
|
|
137
140
|
}
|
|
138
|
-
if (!
|
|
141
|
+
if (!isPublishable(pkg)) return;
|
|
139
142
|
seen.add(resolved);
|
|
140
143
|
const folderName = path.basename(absDir);
|
|
141
144
|
list.push({
|