@drocketxx/pm2me 1.1.1 → 1.1.4

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/README.md CHANGED
@@ -10,32 +10,42 @@ PM2Me lets you **deploy apps directly from a GitHub repository**, manage PM2 pro
10
10
 
11
11
  ---
12
12
 
13
- ## 🚀 Quick Start (Global Install)
13
+ ## 🚀 Recommended Installation
14
14
 
15
- The easiest way to use PM2Me is to install it globally via npm:
15
+ The standard way to use PM2Me is to install it globally via npm:
16
16
 
17
17
  ```bash
18
- # 1. Install globally
18
+ # Install globally
19
19
  npm install -g @drocketxx/pm2me
20
-
21
- # 2. Run the server
22
- pm2me
23
20
  ```
24
21
 
25
- Open your browser at: **http://localhost:12345**
26
-
27
22
  ---
28
23
 
29
- ## 🛠️ Running as a Background Service
24
+ ## 📋 Commands
30
25
 
31
- If you want PM2Me to run in the background and start automatically on system boot, use the built-in `service` command:
26
+ ### Standard Execution
27
+ ```bash
28
+ # Run the server in foreground
29
+ pm2me
30
+
31
+ # Run on a custom port
32
+ pm2me --port 8080
33
+ ```
34
+
35
+ ### Background Service (Recommended)
36
+ Manage PM2Me as a system service using these commands:
32
37
 
33
38
  ```bash
34
- # Install as a background service (using PM2)
39
+ # Install & start as a background service (using PM2)
35
40
  pm2me service install
36
41
 
37
- # To remove the background service
42
+ # Uninstall/Remove the service
38
43
  pm2me service uninstall
44
+
45
+ # Control the service
46
+ pm2me service start
47
+ pm2me service stop
48
+ pm2me service restart
39
49
  ```
40
50
 
41
51
  > **Note:** The `service install` command will register PM2Me as `pm2me-server` in PM2 and attempt to set up system startup.
@@ -45,7 +45,7 @@ router.get('/pm2/version-check', async (req, res) => {
45
45
  // Check globally installed PM2 version via npm (avoids local node_modules/.bin/pm2)
46
46
  let installedVersion = null;
47
47
  try {
48
- const { stdout } = await execAsync('npm list -g pm2 --depth=0 --json');
48
+ const { stdout } = await execAsync('npm list -g pm2 --depth=0 --json', { windowsHide: true });
49
49
  const parsed = JSON.parse(stdout);
50
50
  installedVersion = parsed?.dependencies?.pm2?.version || null;
51
51
  } catch {
@@ -404,7 +404,7 @@ export const performDeployment = async (appId, io) => {
404
404
  await setPipelineState('building');
405
405
  logProcess('Executing Build Script', true);
406
406
  await new Promise((resolve, reject) => {
407
- const child = exec(normalizedScript, { cwd: targetPath, maxBuffer: 10 * 1024 * 1024 });
407
+ const child = exec(normalizedScript, { cwd: targetPath, maxBuffer: 10 * 1024 * 1024, windowsHide: true });
408
408
  child.stdout.on('data', data => { io.emit(`deploy-log-${appId}`, data.toString()); fs.appendFileSync(logFilePath, data); });
409
409
  child.stderr.on('data', data => { io.emit(`deploy-log-${appId}`, data.toString()); fs.appendFileSync(logFilePath, data); });
410
410
  child.on('close', code => {
@@ -1023,7 +1023,7 @@ router.post('/system/update', async (req, res) => {
1023
1023
  cmd = 'git pull origin main && npm run build';
1024
1024
  cwd = path.resolve(__dirname, '../..');
1025
1025
  }
1026
- const { stdout, stderr } = await execAsync(cmd, { cwd }).catch(err => ({
1026
+ const { stdout, stderr } = await execAsync(cmd, { cwd, windowsHide: true }).catch(err => ({
1027
1027
  stdout: '', stderr: err.message
1028
1028
  }));
1029
1029
  const output = [stdout, stderr].filter(Boolean).join('\n').trim();
@@ -28,9 +28,9 @@ export const syncRepo = async (repoUrl, targetPath, branchName, token = null) =>
28
28
  fs.rmSync(targetPath, { recursive: true, force: true });
29
29
  }
30
30
  fs.mkdirSync(targetPath, { recursive: true });
31
- const git = simpleGit().env(envOptions);
31
+ const git = simpleGit({ spawnOptions: { windowsHide: true } }).env(envOptions);
32
32
  await git.clone(finalUrl, targetPath, ['--branch', branchName]);
33
- const gitLocal = simpleGit(targetPath);
33
+ const gitLocal = simpleGit(targetPath, { spawnOptions: { windowsHide: true } });
34
34
  const log = await gitLocal.log(['-1']);
35
35
  const commitHash = log.latest.hash;
36
36
  const commitMessage = log.latest.message;
@@ -45,7 +45,7 @@ export const syncRepo = async (repoUrl, targetPath, branchName, token = null) =>
45
45
  }
46
46
  } else {
47
47
  try {
48
- const git = simpleGit(targetPath).env(envOptions);
48
+ const git = simpleGit(targetPath, { spawnOptions: { windowsHide: true } }).env(envOptions);
49
49
  await git.remote(['set-url', 'origin', finalUrl]);
50
50
  await git.fetch('origin', branchName);
51
51
  await git.checkout(branchName);
@@ -68,7 +68,7 @@ export const syncRepo = async (repoUrl, targetPath, branchName, token = null) =>
68
68
 
69
69
  export const getBranches = async (repoUrl, token = null) => {
70
70
  const finalUrl = getFinalUrl(repoUrl, token);
71
- const git = simpleGit().env({ ...process.env, GIT_TERMINAL_PROMPT: '0' });
71
+ const git = simpleGit({ spawnOptions: { windowsHide: true } }).env({ ...process.env, GIT_TERMINAL_PROMPT: '0' });
72
72
  const branches = await git.listRemote(['--heads', finalUrl]);
73
73
  // Parse branch output, simplistic split
74
74
  return branches.split('\n').filter(Boolean).map(line => line.split('refs/heads/')[1]);
@@ -82,7 +82,7 @@ export const getBehindCount = async (repoUrl, targetPath, branchName, token = nu
82
82
  if (!isGitRepo) return 0;
83
83
 
84
84
  const finalUrl = getFinalUrl(repoUrl, token);
85
- const git = simpleGit(targetPath).env({ ...process.env, GIT_TERMINAL_PROMPT: '0' });
85
+ const git = simpleGit(targetPath, { spawnOptions: { windowsHide: true } }).env({ ...process.env, GIT_TERMINAL_PROMPT: '0' });
86
86
 
87
87
  try {
88
88
  await git.remote(['set-url', 'origin', finalUrl]);
@@ -96,7 +96,7 @@ export const getBehindCount = async (repoUrl, targetPath, branchName, token = nu
96
96
  };
97
97
 
98
98
  export const checkout = async (targetPath, ref) => {
99
- const git = simpleGit(targetPath).env({ ...process.env, GIT_TERMINAL_PROMPT: '0' });
99
+ const git = simpleGit(targetPath, { spawnOptions: { windowsHide: true } }).env({ ...process.env, GIT_TERMINAL_PROMPT: '0' });
100
100
  try {
101
101
  await git.checkout(ref);
102
102
  const log = await git.log(['-1']);
@@ -32,7 +32,7 @@ export const getSystemStats = async () => {
32
32
  const promises = [];
33
33
 
34
34
  // 1. CPU Usage (Every time)
35
- const cpuPromise = execPromise('powershell -Command "(Get-Counter \'\\Processor(_Total)\\% Processor Time\' -ErrorAction SilentlyContinue).CounterSamples.CookedValue"')
35
+ const cpuPromise = execPromise('powershell -Command "(Get-Counter \'\\Processor(_Total)\\% Processor Time\' -ErrorAction SilentlyContinue).CounterSamples.CookedValue"', { windowsHide: true })
36
36
  .then(({ stdout }) => {
37
37
  const realCpu = parseFloat(stdout.trim());
38
38
  if (!isNaN(realCpu)) cpuUsage = realCpu;
@@ -41,7 +41,7 @@ export const getSystemStats = async () => {
41
41
  promises.push(cpuPromise);
42
42
 
43
43
  // 2. Network Stats (Every time)
44
- const netPromise = execPromise('powershell -Command "Get-NetAdapterStatistics | Select-Object ReceivedBytes, SentBytes | ConvertTo-Json"')
44
+ const netPromise = execPromise('powershell -Command "Get-NetAdapterStatistics | Select-Object ReceivedBytes, SentBytes | ConvertTo-Json"', { windowsHide: true })
45
45
  .then(({ stdout }) => {
46
46
  const netData = JSON.parse(stdout);
47
47
  let totalRx = 0;
@@ -67,7 +67,7 @@ export const getSystemStats = async () => {
67
67
 
68
68
  // 3. Disk Stats (Cached)
69
69
  if (now - cachedDiskStats.lastFetch > DISK_CACHE_TTL) {
70
- const diskPromise = execPromise('powershell -Command "Get-Volume -DriveLetter C | Select-Object Size, SizeRemaining | ConvertTo-Json"')
70
+ const diskPromise = execPromise('powershell -Command "Get-Volume -DriveLetter C | Select-Object Size, SizeRemaining | ConvertTo-Json"', { windowsHide: true })
71
71
  .then(({ stdout }) => {
72
72
  const data = JSON.parse(stdout);
73
73
  if (data.Size > 0) {
package/bin/pm2me.js CHANGED
@@ -5,6 +5,9 @@
5
5
  * pm2me (Run in foreground)
6
6
  * pm2me service install (Run in background via PM2 + set boot startup)
7
7
  * pm2me service uninstall (Remove from PM2 background)
8
+ * pm2me service start (Start background service)
9
+ * pm2me service stop (Stop background service)
10
+ * pm2me service restart (Restart background service)
8
11
  */
9
12
  import path from 'path';
10
13
  import { fileURLToPath } from 'url';
@@ -22,6 +25,8 @@ const args = process.argv.slice(2);
22
25
  // ── Handle Service Commands ───────────────────────────────────────────────────
23
26
  if (args[0] === 'service') {
24
27
  const action = args[1];
28
+ const SERVICE_NAME = 'pm2me-server';
29
+
25
30
  if (action === 'install') {
26
31
  console.log('[pm2me] Installing background service...');
27
32
  try {
@@ -30,21 +35,21 @@ if (args[0] === 'service') {
30
35
  const homeDir = path.join(os.homedir(), '.pm2me');
31
36
  const dbPath = path.join(homeDir, 'database.json');
32
37
 
33
- console.log(`[pm2me] Starting via PM2 as 'pm2me-server'...`);
34
- execSync(`pm2 start "${appPath}" --name pm2me-server --env PM2ME_DB_PATH="${dbPath}"`, { stdio: 'inherit' });
38
+ console.log(`[pm2me] Starting via PM2 as '${SERVICE_NAME}'...`);
39
+ execSync(`pm2 start "${appPath}" --name ${SERVICE_NAME} --env PM2ME_DB_PATH="${dbPath}"`, { stdio: 'inherit', windowsHide: true });
35
40
 
36
41
  console.log(`[pm2me] Saving PM2 process list...`);
37
- execSync(`pm2 save`, { stdio: 'inherit' });
42
+ execSync(`pm2 save`, { stdio: 'inherit', windowsHide: true });
38
43
 
39
44
  if (isWindows) {
40
- console.log(`\n[pm2me] 💡 Windows Info: 'pm2me-server' is now running in the background.`);
45
+ console.log(`\n[pm2me] 💡 Windows Info: '${SERVICE_NAME}' is now running in the background.`);
41
46
  console.log(`[pm2me] To make it start automatically on Windows restart, we recommend using 'pm2-windows-startup':`);
42
47
  console.log(` npm install -g pm2-windows-startup`);
43
48
  console.log(` pm2-startup install`);
44
49
  } else {
45
50
  console.log(`[pm2me] Setting up boot startup...`);
46
51
  try {
47
- execSync(`pm2 startup`, { stdio: 'inherit' });
52
+ execSync(`pm2 startup`, { stdio: 'inherit', windowsHide: true });
48
53
  console.log(`[pm2me] Done! If you see a command above, please copy and run it to finalize startup.`);
49
54
  } catch (e) {
50
55
  console.log(`[pm2me] 'pm2 startup' might need manual execution. Check instructions above.`);
@@ -60,16 +65,43 @@ if (args[0] === 'service') {
60
65
  } else if (action === 'uninstall') {
61
66
  console.log('[pm2me] Uninstalling background service...');
62
67
  try {
63
- execSync(`pm2 delete pm2me-server`, { stdio: 'inherit' });
64
- execSync(`pm2 save`, { stdio: 'inherit' });
68
+ execSync(`pm2 delete ${SERVICE_NAME}`, { stdio: 'inherit', windowsHide: true });
69
+ execSync(`pm2 save`, { stdio: 'inherit', windowsHide: true });
65
70
  console.log(`[pm2me] Service uninstalled successfully.`);
66
71
  process.exit(0);
67
72
  } catch (err) {
68
73
  console.error(`[pm2me] Failed to uninstall service:`, err.message);
69
74
  process.exit(1);
70
75
  }
76
+ } else if (action === 'start') {
77
+ console.log(`[pm2me] Starting service '${SERVICE_NAME}'...`);
78
+ try {
79
+ execSync(`pm2 start ${SERVICE_NAME}`, { stdio: 'inherit', windowsHide: true });
80
+ process.exit(0);
81
+ } catch (err) {
82
+ console.error(`[pm2me] Failed to start service:`, err.message);
83
+ process.exit(1);
84
+ }
85
+ } else if (action === 'stop') {
86
+ console.log(`[pm2me] Stopping service '${SERVICE_NAME}'...`);
87
+ try {
88
+ execSync(`pm2 stop ${SERVICE_NAME}`, { stdio: 'inherit', windowsHide: true });
89
+ process.exit(0);
90
+ } catch (err) {
91
+ console.error(`[pm2me] Failed to stop service:`, err.message);
92
+ process.exit(1);
93
+ }
94
+ } else if (action === 'restart') {
95
+ console.log(`[pm2me] Restarting service '${SERVICE_NAME}'...`);
96
+ try {
97
+ execSync(`pm2 restart ${SERVICE_NAME}`, { stdio: 'inherit', windowsHide: true });
98
+ process.exit(0);
99
+ } catch (err) {
100
+ console.error(`[pm2me] Failed to restart service:`, err.message);
101
+ process.exit(1);
102
+ }
71
103
  } else {
72
- console.log(`Usage: pm2me service [install|uninstall]`);
104
+ console.log(`Usage: pm2me service [install|uninstall|start|stop|restart]`);
73
105
  process.exit(1);
74
106
  }
75
107
  }
@@ -113,6 +145,7 @@ console.log(`[pm2me] Using database: ${dbPath}`);
113
145
  const server = spawn('node', ['app.js'], {
114
146
  cwd: backendDir,
115
147
  stdio: 'inherit',
148
+ windowsHide: true,
116
149
  env: {
117
150
  ...process.env,
118
151
  PORT: String(PORT),
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "@drocketxx/pm2me",
3
- "version": "1.1.1",
4
- "description": "PM2 Deployment and Management System — Web UI for PM2 process management",
5
- "type": "module",
6
- "main": "backend/app.js",
7
- "bin": {
8
- "pm2me": "./bin/pm2me.js"
9
- },
10
- "files": [
11
- "bin/",
12
- "backend/",
13
- "README.md"
14
- ],
15
- "dependencies": {
16
- "bcrypt": "^6.0.0",
17
- "connect-history-api-fallback": "^2.0.0",
18
- "cors": "^2.8.6",
19
- "dotenv": "^17.3.1",
20
- "express": "^5.2.1",
21
- "jsonwebtoken": "^9.0.3",
22
- "lowdb": "^7.0.1",
23
- "morgan": "^1.10.1",
24
- "pm2": "^6.0.14",
25
- "simple-git": "^3.32.3",
26
- "socket.io": "^4.8.3"
27
- },
28
- "engines": {
29
- "node": ">=18"
30
- },
31
- "repository": {
32
- "type": "git",
33
- "url": "https://github.com/drocketxx/PM2Me.git"
34
- },
35
- "homepage": "https://github.com/drocketxx/PM2Me",
36
- "keywords": [
37
- "pm2",
38
- "deploy",
39
- "management",
40
- "nginx",
41
- "web-ui"
42
- ],
43
- "author": "drocketxx",
44
- "license": "ISC",
45
- "scripts": {
46
- "dev:frontend": "cd frontend && npm run dev",
47
- "dev:backend": "cd backend && npm run dev",
48
- "dev:concurrent": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",
49
- "build": "cd frontend && npm run build",
50
- "dev": "npm run build && cd backend && npm run dev",
51
- "install:all": "npm install && cd frontend && npm install && cd ../backend && npm install",
52
- "pw": "cd backend && node scripts/change-password.js",
53
- "start": "node bin/pm2me.js"
54
- },
55
- "devDependencies": {
56
- "concurrently": "^8.2.2",
57
- "nodemon": "^3.1.14"
58
- }
1
+ {
2
+ "name": "@drocketxx/pm2me",
3
+ "version": "1.1.4",
4
+ "description": "PM2 Deployment and Management System — Web UI for PM2 process management",
5
+ "type": "module",
6
+ "main": "backend/app.js",
7
+ "bin": {
8
+ "pm2me": "./bin/pm2me.js"
9
+ },
10
+ "files": [
11
+ "bin/",
12
+ "backend/",
13
+ "README.md"
14
+ ],
15
+ "dependencies": {
16
+ "bcrypt": "^6.0.0",
17
+ "connect-history-api-fallback": "^2.0.0",
18
+ "cors": "^2.8.6",
19
+ "dotenv": "^17.3.1",
20
+ "express": "^5.2.1",
21
+ "jsonwebtoken": "^9.0.3",
22
+ "lowdb": "^7.0.1",
23
+ "morgan": "^1.10.1",
24
+ "pm2": "^6.0.14",
25
+ "simple-git": "^3.32.3",
26
+ "socket.io": "^4.8.3"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/drocketxx/PM2Me.git"
34
+ },
35
+ "homepage": "https://github.com/drocketxx/PM2Me",
36
+ "keywords": [
37
+ "pm2",
38
+ "deploy",
39
+ "management",
40
+ "nginx",
41
+ "web-ui"
42
+ ],
43
+ "author": "drocketxx",
44
+ "license": "ISC",
45
+ "scripts": {
46
+ "dev:frontend": "cd frontend && npm run dev",
47
+ "dev:backend": "cd backend && npm run dev",
48
+ "dev:concurrent": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",
49
+ "build": "cd frontend && npm run build",
50
+ "dev": "npm run build && cd backend && npm run dev",
51
+ "install:all": "npm install && cd frontend && npm install && cd ../backend && npm install",
52
+ "pw": "cd backend && node scripts/change-password.js",
53
+ "start": "node bin/pm2me.js"
54
+ },
55
+ "devDependencies": {
56
+ "concurrently": "^8.2.2",
57
+ "nodemon": "^3.1.14"
58
+ }
59
59
  }