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 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,62 @@ function handleBranch(ws, repoName) {
676
676
  else runGitAll(ws, 'branch -vv', true);
677
677
  }
678
678
 
679
- function killBgServer() {
680
- if (!bgServerPid) {
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 ${bgServerPid} /T /F`, { stdio: 'inherit', shell: true });
722
+ execSync(`taskkill /PID ${targetPid} /T /F`, { stdio: 'inherit', shell: true });
687
723
  } else {
688
- process.kill(-bgServerPid, 'SIGTERM');
724
+ process.kill(-targetPid, 'SIGTERM');
689
725
  }
690
- console.log(`Stopped process tree ${bgServerPid}`);
726
+ console.log(`Stopped process tree ${targetPid}`);
691
727
  } catch (e) {
692
- console.error('Stop failed:', e.message);
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') 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.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 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({