cloud-ide-cide 2.0.41 → 2.0.43

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 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 = resolveEndpoint(server.server_url, `app/status`) + `?appCode=${encodeURIComponent(appCode)}`;
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 = resolveEndpoint(server.server_url, 'app/stop');
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 = resolveEndpoint(server.server_url, 'app/start');
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
- // Stop
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
- // Start
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,87 @@ function handleBranch(ws, repoName) {
676
676
  else runGitAll(ws, 'branch -vv', true);
677
677
  }
678
678
 
679
- function killBgServer() {
680
- if (!bgServerPid) {
681
- console.log('No background server PID tracked (start with: server dev)');
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 loadPids(ws) {
691
+ const file = getPidFilePath(ws);
692
+ if (fs.existsSync(file)) {
693
+ try {
694
+ const data = JSON.parse(fs.readFileSync(file, 'utf8'));
695
+ return Array.isArray(data) ? data : [data];
696
+ } catch {}
697
+ }
698
+ return [];
699
+ }
700
+
701
+ function savePid(ws, pid, command, args) {
702
+ const file = getPidFilePath(ws);
703
+ const pids = loadPids(ws);
704
+ pids.push({ pid, command, args, timestamp: Date.now() });
705
+ fs.writeFileSync(file, JSON.stringify(pids, null, 2));
706
+ }
707
+
708
+ function clearPid(ws, pidToRemove) {
709
+ const file = getPidFilePath(ws);
710
+ let pids = loadPids(ws);
711
+ if (pidToRemove) {
712
+ pids = pids.filter(p => p.pid !== pidToRemove);
713
+ if (pids.length > 0) {
714
+ fs.writeFileSync(file, JSON.stringify(pids, null, 2));
715
+ return;
716
+ }
717
+ }
718
+ if (fs.existsSync(file)) fs.unlinkSync(file);
719
+ }
720
+
721
+ function killBgServer(ws, specificPid) {
722
+ const pids = loadPids(ws);
723
+ if (pids.length === 0) {
724
+ let fallbackPid = bgServerPid;
725
+ if (specificPid) fallbackPid = parseInt(specificPid, 10);
726
+ if (!fallbackPid) {
727
+ console.log('No background server PIDs tracked.');
728
+ return;
729
+ }
730
+ pids.push({ pid: fallbackPid, command: 'unknown', args: [] });
731
+ }
732
+
733
+ const targets = specificPid
734
+ ? pids.filter(p => p.pid === parseInt(specificPid, 10))
735
+ : pids;
736
+
737
+ if (targets.length === 0) {
738
+ console.log(`PID ${specificPid} not found in tracked background processes.`);
682
739
  return;
683
740
  }
684
- try {
685
- if (process.platform === 'win32') {
686
- execSync(`taskkill /PID ${bgServerPid} /T /F`, { stdio: 'inherit', shell: true });
687
- } else {
688
- process.kill(-bgServerPid, 'SIGTERM');
741
+
742
+ for (const processInfo of targets) {
743
+ const targetPid = processInfo.pid;
744
+ try {
745
+ if (process.platform === 'win32') {
746
+ execSync(`taskkill /PID ${targetPid} /T /F`, { stdio: 'ignore', shell: true });
747
+ } else {
748
+ process.kill(-targetPid, 'SIGTERM');
749
+ }
750
+ console.log(`Stopped process tree ${targetPid} (${processInfo.command} ${processInfo.args.join(' ')})`);
751
+ } catch (e) {
752
+ console.error(`Stop failed or process ${targetPid} already killed: ${e.message}`);
689
753
  }
690
- console.log(`Stopped process tree ${bgServerPid}`);
691
- } catch (e) {
692
- console.error('Stop failed:', e.message);
754
+ clearPid(ws, targetPid);
693
755
  }
694
- bgServerPid = null;
756
+ if (!specificPid) bgServerPid = null;
695
757
  }
696
758
 
697
- function spawnBg(cwd, command, args) {
759
+ function spawnBg(ws, cwd, command, args) {
698
760
  const child = spawn(command, args, {
699
761
  cwd,
700
762
  shell: true,
@@ -703,6 +765,7 @@ function spawnBg(cwd, command, args) {
703
765
  });
704
766
  child.unref();
705
767
  bgServerPid = child.pid;
768
+ savePid(ws, child.pid, command, args);
706
769
  console.log(`Started background PID ${child.pid} (${command} ${args.join(' ')})`);
707
770
  console.log('(Output not shown here; use server stop to end, or run npm in another terminal for logs.)');
708
771
  }
@@ -743,18 +806,48 @@ async function handleServer(ws, sub, rest, rl) {
743
806
  return;
744
807
  }
745
808
  if (sub === 'start') {
746
- spawnBg(cwd, 'npm', ['run', 'start']);
809
+ spawnBg(ws, cwd, 'npm', ['run', 'start']);
747
810
  return;
748
811
  }
749
812
  if (sub === 'dev') {
750
- spawnBg(cwd, 'npm', ['run', 'dev']);
813
+ spawnBg(ws, cwd, 'npm', ['run', 'dev']);
814
+ return;
815
+ }
816
+ if (sub === 'status') {
817
+ const pids = loadPids(ws);
818
+ if (pids.length === 0) {
819
+ console.log('No services are currently tracked as running in the background.');
820
+ return;
821
+ }
822
+ console.log(`Found ${pids.length} tracked background service(s):\n`);
823
+
824
+ for (const processInfo of pids) {
825
+ let isRunning = false;
826
+ try {
827
+ if (process.platform === 'win32') {
828
+ const out = execSync(`tasklist /FI "PID eq ${processInfo.pid}"`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
829
+ isRunning = out.includes(processInfo.pid.toString());
830
+ } else {
831
+ process.kill(processInfo.pid, 0);
832
+ isRunning = true;
833
+ }
834
+ } catch {
835
+ isRunning = false;
836
+ }
837
+ if (isRunning) {
838
+ console.log(`[🏃 RUNNING] PID: ${processInfo.pid} | Command: ${processInfo.command} ${processInfo.args.join(' ')}`);
839
+ } else {
840
+ console.log(`[❌ STALE] PID: ${processInfo.pid} | Command: ${processInfo.command} ${processInfo.args.join(' ')} (No longer running)`);
841
+ clearPid(ws, processInfo.pid);
842
+ }
843
+ }
751
844
  return;
752
845
  }
753
846
  if (sub === 'stop') {
754
- killBgServer();
847
+ killBgServer(ws, rest[0]);
755
848
  return;
756
849
  }
757
- console.error('Usage: server build | start | dev | stop | init | listener start|stop|status|restart');
850
+ console.error('Usage: server build | start | dev | stop | status | init | listener start|stop|status|restart');
758
851
  }
759
852
 
760
853
  function handleSeed(ws, name) {
@@ -796,7 +889,7 @@ function handleServe(ws) {
796
889
  console.error(`No "start" script in ${path.basename(ws.angularRoot)}/package.json`);
797
890
  return;
798
891
  }
799
- spawnBg(ws.angularRoot, 'npm', ['run', 'start']);
892
+ spawnBg(ws, ws.angularRoot, 'npm', ['run', 'start']);
800
893
  }
801
894
 
802
895
  function handleTailwind(ws) {
@@ -805,7 +898,7 @@ function handleTailwind(ws) {
805
898
  console.error(`No "tailwindcss" script in ${path.basename(ws.angularRoot)}/package.json`);
806
899
  return;
807
900
  }
808
- spawnBg(ws.angularRoot, 'npm', ['run', 'tailwindcss']);
901
+ spawnBg(ws, ws.angularRoot, 'npm', ['run', 'tailwindcss']);
809
902
  }
810
903
 
811
904
  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') handleHistory();
63
- elseif ($action === 'rollback') handleRollback();
64
- else handleUpload();
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.41",
3
+ "version": "2.0.43",
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
- }
54
- }
52
+ "repository": {}
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 isGithubPackagesPublishable(pkg) {
45
- const r = pkg && pkg.publishConfig && pkg.publishConfig.registry;
46
- return typeof r === 'string' && r.includes(GPR_HOST);
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 (!isGithubPackagesPublishable(pkg)) return;
141
+ if (!isPublishable(pkg)) return;
139
142
  seen.add(resolved);
140
143
  const folderName = path.basename(absDir);
141
144
  list.push({
@@ -831,7 +834,9 @@ async function publishPackage(options = {}) {
831
834
  const originalCwd = process.cwd();
832
835
 
833
836
  try {
834
- if (entry.kind === 'angular-lib') {
837
+ if (rl) rl.pause();
838
+ try {
839
+ if (entry.kind === 'angular-lib') {
835
840
  if (cide.templete !== 'angular') {
836
841
  console.warn(' Warning: cide.templete is not "angular"; still running ng build.');
837
842
  }
@@ -899,6 +904,9 @@ async function publishPackage(options = {}) {
899
904
  }
900
905
  publishOk++;
901
906
  stepComplete = true;
907
+ } finally {
908
+ if (rl) rl.resume();
909
+ }
902
910
  } catch (err) {
903
911
  console.error(` ❌ Failed: ${err.message}`);
904
912
  process.chdir(originalCwd);