@drocketxx/pm2me 1.1.0 → 1.1.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/README.md CHANGED
@@ -10,6 +10,48 @@ PM2Me lets you **deploy apps directly from a GitHub repository**, manage PM2 pro
10
10
 
11
11
  ---
12
12
 
13
+ ## 🚀 Recommended Installation
14
+
15
+ The standard way to use PM2Me is to install it globally via npm:
16
+
17
+ ```bash
18
+ # Install globally
19
+ npm install -g @drocketxx/pm2me
20
+ ```
21
+
22
+ ---
23
+
24
+ ## 📋 Commands
25
+
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:
37
+
38
+ ```bash
39
+ # Install & start as a background service (using PM2)
40
+ pm2me service install
41
+
42
+ # Uninstall/Remove the service
43
+ pm2me service uninstall
44
+
45
+ # Control the service
46
+ pm2me service start
47
+ pm2me service stop
48
+ pm2me service restart
49
+ ```
50
+
51
+ > **Note:** The `service install` command will register PM2Me as `pm2me-server` in PM2 and attempt to set up system startup.
52
+
53
+ ---
54
+
13
55
  ## ✨ Features
14
56
 
15
57
  | Feature | Details |
@@ -45,188 +87,49 @@ PM2Me lets you **deploy apps directly from a GitHub repository**, manage PM2 pro
45
87
 
46
88
  ---
47
89
 
48
- ## 🚀 Getting Started
49
-
50
- ### Prerequisites
51
- - [Node.js](https://nodejs.org/) >= 18
52
- - [PM2](https://pm2.keymetrics.io/) installed globally: `npm install -g pm2`
53
- - [Git](https://git-scm.com/) installed and accessible in `PATH`
54
-
55
- ### Installation & Running (Recommended with PM2)
90
+ ## 🔐 Setup & Security
56
91
 
57
- ```bash
58
- # 1. Clone the repository
59
- git clone https://github.com/drocketxx/PM2Me.git
60
- cd PM2Me
92
+ ### First Run
93
+ On your first run, PM2Me will guide you through a **Setup Wizard** to configure your apps storage path and set your admin password.
61
94
 
62
- # 2. Install all dependencies (frontend + backend)
63
- npm run install:all
64
-
65
- # 3. Build the frontend
66
- npm run build
67
-
68
- # 4. Start PM2Me with PM2 ✅ Recommended
69
- cd backend
70
- pm2 start app.js --name pm2me
71
-
72
- # 5. Auto-start on system reboot
73
- pm2 save
74
- pm2 startup
75
- ```
76
-
77
- Open your browser at: **http://localhost:12345**
78
-
79
- > 💡 **Useful PM2 commands:**
80
- > ```bash
81
- > pm2 status # Check PM2Me status
82
- > pm2 logs pm2me # View PM2Me logs
83
- > pm2 restart pm2me # Restart PM2Me
84
- > pm2 stop pm2me # Stop PM2Me
85
- > ```
86
-
87
- **Development mode** (nodemon auto-restart):
88
- ```bash
89
- cd /path/to/PM2Me
90
- npm run dev
91
- ```
92
-
93
- ---
94
-
95
- ## 🔐 Default Login & Password Management
96
-
97
- On first run, **no password is set**. Use the CLI to set one:
98
-
99
- ```bash
100
- # Set or change admin password
101
- npm run pw -- <your_password>
102
-
103
- # Example
104
- npm run pw -- mySecretPass123
105
- ```
106
-
107
- > You can also run it directly from the `backend/` folder:
108
- > ```bash
109
- > cd backend && node scripts/change-password.js mySecretPass123
110
- > ```
111
- >
112
- > The password is stored as a **bcrypt hash** (12 rounds) in `backend/db/database.json`.
113
-
114
- ---
115
-
116
- ## 🔗 GitHub Webhook Setup
117
-
118
- PM2Me supports automatic deployments triggered by `git push`. Here's how to enable it:
95
+ ### Data Storage
96
+ - **Database:** Stored in `~/.pm2me/database.json`
97
+ - **Cloned Apps:** Default to `~/.pm2me/apps/` (User configurable)
119
98
 
99
+ ### GitHub Webhooks
120
100
  1. Go to your GitHub repository → **Settings** → **Webhooks** → **Add webhook**
121
101
  2. Set **Payload URL** to: `http://your-server-ip:12345/api/webhook`
122
102
  3. Set **Content type** to: **`application/json`** ⚠️
123
- 4. Set **Secret** from the Settings page in PM2Me (generate one if needed)
103
+ 4. Set **Secret** from the Settings page in PM2Me
124
104
  5. Select **Just the push event**
125
- 6. Click **Add webhook**
126
-
127
- PM2Me will automatically re-deploy any matching app (matched by repo URL + branch) on each push.
128
-
129
- > **Webhook History** (last 50 events) is displayed on the Settings page in real-time.
130
-
131
- ---
132
-
133
- ## 📂 Project Structure
134
-
135
- ```
136
- PM2Me/
137
- ├── backend/
138
- │ ├── app.js # Express server + Socket.IO setup
139
- │ ├── db/
140
- │ │ ├── index.js # LowDB initialization
141
- │ │ └── database.json # App data, settings, webhook logs
142
- │ ├── routes/
143
- │ │ ├── api.js # Main API routes
144
- │ │ └── auth.js # Login / JWT auth
145
- │ ├── services/
146
- │ │ ├── gitService.js # Git clone/pull operations
147
- │ │ ├── pm2Service.js # PM2 process management
148
- │ │ ├── systemService.js# CPU / RAM / Disk / Network stats
149
- │ │ └── notificationService.js # Discord & Telegram alerts
150
- │ ├── scripts/
151
- │ │ └── change-password.js # CLI tool to change admin password
152
- │ └── public/ # Built Vue frontend (served statically)
153
- ├── frontend/
154
- │ ├── src/
155
- │ │ ├── views/
156
- │ │ │ ├── Dashboard.vue # Main app dashboard
157
- │ │ │ ├── Settings.vue # Settings & webhook history
158
- │ │ │ └── Login.vue # Auth page
159
- │ │ ├── components/
160
- │ │ │ ├── DeployModal.vue # New/Edit app deployment modal
161
- │ │ │ ├── LogViewer.vue # Real-time log stream
162
- │ │ │ └── ServerStats.vue # CPU/RAM/Network widget
163
- │ │ ├── router/ # Vue Router config
164
- │ │ └── App.vue # Nav layout
165
- │ └── vite.config.js
166
- ├── apps/ # Cloned app repos live here
167
- └── package.json # Root scripts (dev, build, pw)
168
- ```
169
-
170
- ---
171
-
172
- ## 📝 Available Scripts
173
-
174
- Run these from the **root** `PM2Me/` directory:
175
-
176
- | Command | Description |
177
- |---|---|
178
- | `npm run dev` | Build frontend & start backend dev server |
179
- | `npm run build` | Build frontend only |
180
- | `npm run pw -- <password>` | Change admin password |
181
- | `npm run install:all` | Install all dependencies (root + frontend + backend) |
182
105
 
183
106
  ---
184
107
 
185
- ## 📡 API Overview
186
-
187
- | Method | Endpoint | Description |
188
- |---|---|---|
189
- | `POST` | `/api/auth/login` | Login, returns JWT token |
190
- | `GET` | `/api/pm2/list` | List all PM2 processes |
191
- | `POST` | `/api/pm2/:action` | PM2 action: start/stop/restart/delete |
192
- | `GET` | `/api/apps` | List all deployed apps (DB) |
193
- | `POST` | `/api/apps` | Register a new app |
194
- | `PUT` | `/api/apps/:id` | Update app config |
195
- | `DELETE` | `/api/apps/:id` | Delete app from DB |
196
- | `POST` | `/api/apps/:id/deploy` | Trigger deployment |
197
- | `GET` | `/api/apps/:id/sync-status` | Check if branch is behind remote |
198
- | `GET` | `/api/settings` | Get current settings |
199
- | `POST` | `/api/settings` | Save settings |
200
- | `GET` | `/api/settings/webhook-logs` | Get last 50 webhook events |
201
- | `POST` | `/api/webhook` | GitHub Webhook receiver |
202
- | `GET` | `/api/system/stats` | Server system stats |
108
+ ## 🛠️ Manual Installation (For Developers)
203
109
 
204
- ---
110
+ If you want to contribute or run from source:
205
111
 
206
- ## 📦 Deployment (Production)
112
+ ```bash
113
+ # 1. Clone the repository
114
+ git clone https://github.com/drocketxx/PM2Me.git
115
+ cd PM2Me
207
116
 
208
- For production, it's recommended to run the PM2Me backend itself with PM2:
117
+ # 2. Install all dependencies
118
+ npm run install:all
209
119
 
210
- ```bash
211
- # Build the frontend
120
+ # 3. Build the frontend
212
121
  npm run build
213
122
 
214
- # Start with PM2
215
- cd backend
216
- pm2 start app.js --name pm2me
217
-
218
- # Save and set to auto-restart on reboot
219
- pm2 save
220
- pm2 startup
123
+ # 4. Start in development mode
124
+ npm run dev
221
125
  ```
222
126
 
223
127
  ---
224
128
 
225
129
  ## 🛡 Security Notes
226
130
 
227
- - Change the default admin password immediately on first run using `npm run pw`.
228
- - Set a strong `JWT_SECRET` in your `.env` file.
229
- - Always set a **Webhook Secret** to prevent unauthorized deploys.
131
+ - Set a strong admin password during the setup wizard.
132
+ - Always use a **Webhook Secret** to prevent unauthorized deployment triggers.
230
133
  - Consider putting PM2Me behind a reverse proxy (e.g., Nginx) with HTTPS in production.
231
134
 
232
135
  ---
@@ -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']);
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,32 +25,38 @@ 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 {
28
- // 1. Start pm2me via PM2
29
- // We use the full path to the backend app.js
33
+ const isWindows = os.platform() === 'win32';
30
34
  const appPath = path.join(backendDir, 'app.js');
31
35
  const homeDir = path.join(os.homedir(), '.pm2me');
32
36
  const dbPath = path.join(homeDir, 'database.json');
33
37
 
34
- console.log(`[pm2me] Starting via PM2 as 'pm2me-server'...`);
35
- 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 });
36
40
 
37
- // 2. Save PM2 list
38
41
  console.log(`[pm2me] Saving PM2 process list...`);
39
- execSync(`pm2 save`, { stdio: 'inherit' });
40
-
41
- // 3. Optional: Startup (User needs to run this with sudo/admin usually, but we try)
42
- console.log(`[pm2me] Setting up boot startup...`);
43
- try {
44
- execSync(`pm2 startup`, { stdio: 'inherit' });
45
- console.log(`[pm2me] Done! If you see a command above, please copy and run it to finalize startup.`);
46
- } catch (e) {
47
- console.log(`[pm2me] 'pm2 startup' might need manual execution. Check instructions above.`);
42
+ execSync(`pm2 save`, { stdio: 'inherit', windowsHide: true });
43
+
44
+ if (isWindows) {
45
+ console.log(`\n[pm2me] 💡 Windows Info: '${SERVICE_NAME}' is now running in the background.`);
46
+ console.log(`[pm2me] To make it start automatically on Windows restart, we recommend using 'pm2-windows-startup':`);
47
+ console.log(` npm install -g pm2-windows-startup`);
48
+ console.log(` pm2-startup install`);
49
+ } else {
50
+ console.log(`[pm2me] Setting up boot startup...`);
51
+ try {
52
+ execSync(`pm2 startup`, { stdio: 'inherit', windowsHide: true });
53
+ console.log(`[pm2me] Done! If you see a command above, please copy and run it to finalize startup.`);
54
+ } catch (e) {
55
+ console.log(`[pm2me] 'pm2 startup' might need manual execution. Check instructions above.`);
56
+ }
48
57
  }
49
58
 
50
- console.log(`[pm2me] Service installed successfully. Access your UI at http://localhost:12345`);
59
+ console.log(`\n[pm2me] Service installed successfully. Access your UI at http://localhost:12345`);
51
60
  process.exit(0);
52
61
  } catch (err) {
53
62
  console.error(`[pm2me] Failed to install service:`, err.message);
@@ -56,16 +65,43 @@ if (args[0] === 'service') {
56
65
  } else if (action === 'uninstall') {
57
66
  console.log('[pm2me] Uninstalling background service...');
58
67
  try {
59
- execSync(`pm2 delete pm2me-server`, { stdio: 'inherit' });
60
- execSync(`pm2 save`, { stdio: 'inherit' });
68
+ execSync(`pm2 delete ${SERVICE_NAME}`, { stdio: 'inherit', windowsHide: true });
69
+ execSync(`pm2 save`, { stdio: 'inherit', windowsHide: true });
61
70
  console.log(`[pm2me] Service uninstalled successfully.`);
62
71
  process.exit(0);
63
72
  } catch (err) {
64
73
  console.error(`[pm2me] Failed to uninstall service:`, err.message);
65
74
  process.exit(1);
66
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
+ }
67
103
  } else {
68
- console.log(`Usage: pm2me service [install|uninstall]`);
104
+ console.log(`Usage: pm2me service [install|uninstall|start|stop|restart]`);
69
105
  process.exit(1);
70
106
  }
71
107
  }
@@ -109,6 +145,7 @@ console.log(`[pm2me] Using database: ${dbPath}`);
109
145
  const server = spawn('node', ['app.js'], {
110
146
  cwd: backendDir,
111
147
  stdio: 'inherit',
148
+ windowsHide: true,
112
149
  env: {
113
150
  ...process.env,
114
151
  PORT: String(PORT),
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "@drocketxx/pm2me",
3
- "version": "1.1.0",
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.3",
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
  }