process-killer-cli 1.0.0
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/LICENSE +21 -0
- package/README.md +260 -0
- package/bin/port-killer.js +554 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MD Milon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Port Killer CLI ⚡
|
|
2
|
+
|
|
3
|
+
> A fast, cross-platform utility to safely kill processes using specific ports on Windows, macOS, and Linux.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## 🎯 Features
|
|
10
|
+
|
|
11
|
+
✨ **Cross-Platform** - Works on Windows, macOS, and Linux
|
|
12
|
+
🎯 **Interactive Menu** - Easy OS selection (no need to memorize commands)
|
|
13
|
+
🛡️ **Safe** - Always asks for confirmation before killing processes
|
|
14
|
+
⚙️ **Zero Dependencies** - Uses only Node.js built-in modules
|
|
15
|
+
🚀 **Fast** - Kills ports instantly
|
|
16
|
+
🎨 **Beautiful UI** - Colorized output with Unicode borders
|
|
17
|
+
📊 **Developer Info** - Shows package info on success
|
|
18
|
+
|
|
19
|
+
## 📦 Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g port-killer-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
port-killer
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then follow the prompts:
|
|
32
|
+
|
|
33
|
+
1. **Select OS** - Choose your operating system (1=Windows, 2=macOS, 3=Linux)
|
|
34
|
+
2. **Enter Port** - Type the port number (e.g., 3001, 8080, 5000)
|
|
35
|
+
3. **Confirm** - Review the process info and confirm
|
|
36
|
+
4. **Done!** - Port is freed and ready to use
|
|
37
|
+
|
|
38
|
+
## 💡 Common Use Cases
|
|
39
|
+
|
|
40
|
+
### Kill Node.js Server
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
$ port-killer
|
|
44
|
+
|
|
45
|
+
Select your Operating System:
|
|
46
|
+
1) Windows
|
|
47
|
+
2) macOS
|
|
48
|
+
3) Linux
|
|
49
|
+
|
|
50
|
+
Enter your choice (1, 2, or 3): 2
|
|
51
|
+
✓ macOS selected
|
|
52
|
+
|
|
53
|
+
Enter the port number you want to stop (e.g., 8087): 3000
|
|
54
|
+
|
|
55
|
+
➜ Searching for processes using port 3000...
|
|
56
|
+
|
|
57
|
+
Found process with PID: 12345 using port 3000
|
|
58
|
+
Process Name: node
|
|
59
|
+
Port: 3000
|
|
60
|
+
PID: 12345
|
|
61
|
+
|
|
62
|
+
Do you want to kill this process? (y/n): y
|
|
63
|
+
|
|
64
|
+
✓ Port 3000 has been killed!
|
|
65
|
+
|
|
66
|
+
You can now start your backend server on this port.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Kill Java Application (Port 8080)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
$ port-killer
|
|
74
|
+
...
|
|
75
|
+
Enter the port number you want to stop: 8080
|
|
76
|
+
✓ Port 8080 has been killed!
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Kill Python Flask (Port 5000)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
$ port-killer
|
|
83
|
+
...
|
|
84
|
+
Enter the port number you want to stop: 5000
|
|
85
|
+
✓ Port 5000 has been killed!
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 🖥️ Supported Operating Systems
|
|
89
|
+
|
|
90
|
+
| OS | Status | Notes |
|
|
91
|
+
| ----------- | ------------------ | -------------------------------------- |
|
|
92
|
+
| **Windows** | ✅ Fully Supported | Uses `netstat`, `tasklist`, `taskkill` |
|
|
93
|
+
| **macOS** | ✅ Fully Supported | Uses `lsof`, `ps`, `fuser` |
|
|
94
|
+
| **Linux** | ✅ Fully Supported | Uses `lsof`, `ps`, `fuser` |
|
|
95
|
+
|
|
96
|
+
## 📋 Requirements
|
|
97
|
+
|
|
98
|
+
- **Node.js** >= 12.0.0
|
|
99
|
+
- **npm** or **yarn**
|
|
100
|
+
|
|
101
|
+
## 🔧 How It Works
|
|
102
|
+
|
|
103
|
+
### Windows
|
|
104
|
+
|
|
105
|
+
- Uses `netstat -ano` to find process by port
|
|
106
|
+
- Uses `tasklist` to get process name
|
|
107
|
+
- Uses `taskkill /PID X /F` to terminate process
|
|
108
|
+
|
|
109
|
+
### macOS & Linux
|
|
110
|
+
|
|
111
|
+
- Uses `lsof -ti:PORT` to find process by port
|
|
112
|
+
- Uses `ps` to get process name
|
|
113
|
+
- Uses `fuser -k PORT/tcp` to terminate process
|
|
114
|
+
|
|
115
|
+
## ⚠️ Troubleshooting
|
|
116
|
+
|
|
117
|
+
### Port Still Shows as In Use
|
|
118
|
+
|
|
119
|
+
Some ports enter TIME_WAIT state. Wait 30-60 seconds and try again.
|
|
120
|
+
|
|
121
|
+
### Permission Denied (macOS/Linux)
|
|
122
|
+
|
|
123
|
+
The tool may need elevated privileges:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
sudo port-killer
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Process Not Found
|
|
130
|
+
|
|
131
|
+
Verify the port number is correct using:
|
|
132
|
+
|
|
133
|
+
**Windows:**
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
netstat -ano | findstr :3000
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**macOS/Linux:**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
lsof -i :3000
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Port Command Not Found
|
|
146
|
+
|
|
147
|
+
Make sure you installed it globally:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm install -g port-killer-cli
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 🗑️ Uninstall
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
npm uninstall -g port-killer-cli
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 📚 Advanced Usage
|
|
160
|
+
|
|
161
|
+
### Manual Port Killing (Without Tool)
|
|
162
|
+
|
|
163
|
+
**Windows:**
|
|
164
|
+
|
|
165
|
+
```powershell
|
|
166
|
+
netstat -ano | findstr :3000
|
|
167
|
+
taskkill /PID 12345 /F
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**macOS/Linux:**
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
lsof -i :3000
|
|
174
|
+
sudo kill -9 12345
|
|
175
|
+
# OR
|
|
176
|
+
sudo fuser -k 3000/tcp
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## 🔄 Update to Latest Version
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm install -g port-killer-cli@latest
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 📝 What's New in v1.0.0
|
|
186
|
+
|
|
187
|
+
- ✨ Initial release
|
|
188
|
+
- 🎨 Beautiful colorized UI with Unicode borders
|
|
189
|
+
- 🌍 Cross-platform support (Windows, macOS, Linux)
|
|
190
|
+
- 📋 Interactive OS selection menu
|
|
191
|
+
- 🎯 Safe operation with confirmation
|
|
192
|
+
- 📊 Developer information display
|
|
193
|
+
- ⚡ Zero external dependencies
|
|
194
|
+
|
|
195
|
+
## 🤝 Contributing
|
|
196
|
+
|
|
197
|
+
Contributions are welcome! Feel free to:
|
|
198
|
+
|
|
199
|
+
- Report bugs
|
|
200
|
+
- Suggest features
|
|
201
|
+
- Submit pull requests
|
|
202
|
+
|
|
203
|
+
[Visit GitHub Repository](https://github.com/devmilon923/port-killer-cli)
|
|
204
|
+
|
|
205
|
+
## 📄 License
|
|
206
|
+
|
|
207
|
+
MIT © Milon
|
|
208
|
+
|
|
209
|
+
This project is open source and available under the MIT License.
|
|
210
|
+
|
|
211
|
+
## 👨💻 Author
|
|
212
|
+
|
|
213
|
+
**Milon Mia**
|
|
214
|
+
|
|
215
|
+
- GitHub: [@devmilon923](https://github.com/devmilon923)
|
|
216
|
+
- npm: [port-killer-cli](https://www.npmjs.com/package/port-killer-cli)
|
|
217
|
+
- Email: dev.milon923@gmail.com
|
|
218
|
+
|
|
219
|
+
## 🙏 Support
|
|
220
|
+
|
|
221
|
+
If you found this tool helpful, please:
|
|
222
|
+
|
|
223
|
+
- ⭐ Star on GitHub
|
|
224
|
+
- 📢 Share with friends
|
|
225
|
+
- 🐛 Report issues
|
|
226
|
+
- 💡 Suggest improvements
|
|
227
|
+
|
|
228
|
+
## FAQ
|
|
229
|
+
|
|
230
|
+
**Q: Is it safe to use?**
|
|
231
|
+
A: Yes! The tool always asks for confirmation before killing any process.
|
|
232
|
+
|
|
233
|
+
**Q: Can I use this on Windows?**
|
|
234
|
+
A: Yes! Full native Windows support without WSL.
|
|
235
|
+
|
|
236
|
+
**Q: Do I need to remember commands?**
|
|
237
|
+
A: No! Interactive menu guides you through every step.
|
|
238
|
+
|
|
239
|
+
**Q: What if I kill the wrong process?**
|
|
240
|
+
A: The tool shows process details before killing, so you can verify.
|
|
241
|
+
|
|
242
|
+
**Q: Can I use this in scripts?**
|
|
243
|
+
A: This tool is interactive. For automation, use OS-specific commands directly.
|
|
244
|
+
|
|
245
|
+
## 🎓 Learn More
|
|
246
|
+
|
|
247
|
+
- [Node.js Documentation](https://nodejs.org/en/docs/)
|
|
248
|
+
- [npm Documentation](https://docs.npmjs.com/)
|
|
249
|
+
- [Port Management Guide](https://www.howtouselinux.com/linux/lsof-command)
|
|
250
|
+
|
|
251
|
+
## 📞 Feedback
|
|
252
|
+
|
|
253
|
+
Have questions or suggestions? Open an issue on GitHub:
|
|
254
|
+
[GitHub Issues](https://github.com/devmilon923/port-killer-cli/issues)
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
**Made with ❤️ for Backend Developers**
|
|
259
|
+
|
|
260
|
+
Happy coding! 🚀
|
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import readline from "readline";
|
|
5
|
+
import process from "process";
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Colors & Styling
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
const colors = {
|
|
12
|
+
reset: "\x1b[0m",
|
|
13
|
+
bold: "\x1b[1m",
|
|
14
|
+
red: "\x1b[31m",
|
|
15
|
+
green: "\x1b[32m",
|
|
16
|
+
yellow: "\x1b[33m",
|
|
17
|
+
blue: "\x1b[34m",
|
|
18
|
+
magenta: "\x1b[35m",
|
|
19
|
+
cyan: "\x1b[36m",
|
|
20
|
+
white: "\x1b[37m",
|
|
21
|
+
bgRed: "\x1b[41m",
|
|
22
|
+
bgGreen: "\x1b[42m",
|
|
23
|
+
bgYellow: "\x1b[43m",
|
|
24
|
+
bgBlue: "\x1b[44m",
|
|
25
|
+
bgCyan: "\x1b[46m",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function c(text, color) {
|
|
29
|
+
return `${color}${text}${colors.reset}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function box(text, color = colors.cyan, width = 50) {
|
|
33
|
+
const padding = Math.max(0, width - text.length - 2);
|
|
34
|
+
const leftPad = Math.floor(padding / 2);
|
|
35
|
+
const rightPad = padding - leftPad;
|
|
36
|
+
return (
|
|
37
|
+
c(`┌${"─".repeat(width)}┐`, color) +
|
|
38
|
+
"\n" +
|
|
39
|
+
c(`│`, color) +
|
|
40
|
+
" ".repeat(leftPad) +
|
|
41
|
+
text +
|
|
42
|
+
" ".repeat(rightPad) +
|
|
43
|
+
c(`│`, color) +
|
|
44
|
+
"\n" +
|
|
45
|
+
c(`└${"─".repeat(width)}┘`, color)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function section(title, color = colors.cyan) {
|
|
50
|
+
return (
|
|
51
|
+
c(`╔${"═".repeat(title.length + 2)}╗`, color) +
|
|
52
|
+
"\n" +
|
|
53
|
+
c(`║ ${title} ║`, color) +
|
|
54
|
+
"\n" +
|
|
55
|
+
c(`╚${"═".repeat(title.length + 2)}╝`, color)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function line(color = colors.cyan, width = 54) {
|
|
60
|
+
return c(`${"─".repeat(width)}`, color);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function header() {
|
|
64
|
+
console.clear();
|
|
65
|
+
console.log("");
|
|
66
|
+
console.log(
|
|
67
|
+
c("╔═══════════════════════════════════════════════════════╗", colors.cyan),
|
|
68
|
+
);
|
|
69
|
+
console.log(
|
|
70
|
+
c(" PORT KILLER UTILITY v1.0.0", colors.bold + colors.cyan),
|
|
71
|
+
);
|
|
72
|
+
// console.log(c(" Tool By Milon", colors.yellow));
|
|
73
|
+
console.log(
|
|
74
|
+
c("╚═══════════════════════════════════════════════════════╝", colors.cyan),
|
|
75
|
+
);
|
|
76
|
+
console.log("");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function info(text, icon = "➜") {
|
|
80
|
+
console.log(c(icon, colors.blue) + " " + text);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function success(text, icon = "✓") {
|
|
84
|
+
console.log(c(icon, colors.green) + " " + c(text, colors.green));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function error(text, icon = "✗") {
|
|
88
|
+
console.log(c(icon, colors.red) + " " + c(text, colors.red));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function warning(text, icon = "⚠") {
|
|
92
|
+
console.log(c(icon, colors.yellow) + " " + c(text, colors.yellow));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ============================================================================
|
|
96
|
+
// Display Functions
|
|
97
|
+
// ============================================================================
|
|
98
|
+
|
|
99
|
+
function showIntro() {
|
|
100
|
+
console.log(
|
|
101
|
+
c(
|
|
102
|
+
"┌─ INFORMATION ─────────────────────────────────────────┐",
|
|
103
|
+
colors.magenta,
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
console.log(
|
|
107
|
+
c("│", colors.magenta) + " Common scenarios when you need this tool:",
|
|
108
|
+
);
|
|
109
|
+
console.log(
|
|
110
|
+
c("│", colors.magenta) +
|
|
111
|
+
" 1. Port 8087 already in use error during development",
|
|
112
|
+
);
|
|
113
|
+
console.log(
|
|
114
|
+
c("│", colors.magenta) +
|
|
115
|
+
" 2. Spring Boot application didn't shutdown properly",
|
|
116
|
+
);
|
|
117
|
+
console.log(
|
|
118
|
+
c("│", colors.magenta) + " 3. Multiple instances running on same port",
|
|
119
|
+
);
|
|
120
|
+
console.log(
|
|
121
|
+
c("│", colors.magenta) +
|
|
122
|
+
" 4. Clean up ports before starting new server instances",
|
|
123
|
+
);
|
|
124
|
+
console.log(
|
|
125
|
+
c(
|
|
126
|
+
"└───────────────────────────────────────────────────────┘",
|
|
127
|
+
colors.magenta,
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
console.log("");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function showDevInfo() {
|
|
134
|
+
console.log("");
|
|
135
|
+
console.log(
|
|
136
|
+
c("╔═══════════════════════════════════════════════════════╗", colors.cyan),
|
|
137
|
+
);
|
|
138
|
+
console.log(
|
|
139
|
+
c("║", colors.cyan) +
|
|
140
|
+
c(
|
|
141
|
+
" ✨ DEVELOPER INFORMATION ✨",
|
|
142
|
+
colors.bold + colors.green,
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
console.log(
|
|
146
|
+
c("╠═══════════════════════════════════════════════════════║", colors.cyan),
|
|
147
|
+
);
|
|
148
|
+
console.log(
|
|
149
|
+
c("║", colors.cyan) +
|
|
150
|
+
c(" Developer Milon Mia", colors.yellow).padEnd(54),
|
|
151
|
+
);
|
|
152
|
+
console.log(
|
|
153
|
+
c("║", colors.cyan) +
|
|
154
|
+
c(" Tool Port Killer CLI", colors.yellow).padEnd(54),
|
|
155
|
+
);
|
|
156
|
+
console.log(
|
|
157
|
+
c("║", colors.cyan) +
|
|
158
|
+
c(" Version 1.0.0", colors.yellow).padEnd(54),
|
|
159
|
+
);
|
|
160
|
+
console.log(
|
|
161
|
+
c("║", colors.cyan) + c(" License MIT", colors.yellow).padEnd(54),
|
|
162
|
+
);
|
|
163
|
+
console.log(
|
|
164
|
+
c("║", colors.cyan) +
|
|
165
|
+
c(" GitHub github.com/devmilon923", colors.green).padEnd(54),
|
|
166
|
+
);
|
|
167
|
+
console.log(
|
|
168
|
+
c("║", colors.cyan) +
|
|
169
|
+
c(" LinkedIn linkedin.com/in/devmilon", colors.green).padEnd(54),
|
|
170
|
+
);
|
|
171
|
+
console.log(
|
|
172
|
+
c("╚═══════════════════════════════════════════════════════╝", colors.cyan),
|
|
173
|
+
);
|
|
174
|
+
console.log("");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function showNotFound(port) {
|
|
178
|
+
console.log("");
|
|
179
|
+
warning(`No process found listening on port ${port}`);
|
|
180
|
+
console.log("");
|
|
181
|
+
console.log(
|
|
182
|
+
c(
|
|
183
|
+
"┌─ TROUBLESHOOTING ─────────────────────────────────────┐",
|
|
184
|
+
colors.yellow,
|
|
185
|
+
),
|
|
186
|
+
);
|
|
187
|
+
console.log(c("│", colors.yellow) + " Try manually:");
|
|
188
|
+
console.log(c("│", colors.yellow));
|
|
189
|
+
console.log(c("│", colors.yellow) + c(" Windows:", colors.white));
|
|
190
|
+
console.log(c("│", colors.yellow) + " netstat -ano | findstr :" + port);
|
|
191
|
+
console.log(c("│", colors.yellow) + " taskkill /PID <PID> /F");
|
|
192
|
+
console.log(c("│", colors.yellow));
|
|
193
|
+
console.log(c("│", colors.yellow) + c(" Linux/macOS:", colors.white));
|
|
194
|
+
console.log(c("│", colors.yellow) + " lsof -i :" + port);
|
|
195
|
+
console.log(c("│", colors.yellow) + " sudo fuser -k " + port + "/tcp");
|
|
196
|
+
console.log(
|
|
197
|
+
c(
|
|
198
|
+
"└───────────────────────────────────────────────────────┘",
|
|
199
|
+
colors.yellow,
|
|
200
|
+
),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function showOSMenu() {
|
|
205
|
+
console.log("");
|
|
206
|
+
console.log(
|
|
207
|
+
c("┌─ SELECT YOUR OPERATING SYSTEM ────────────────────────┐", colors.cyan),
|
|
208
|
+
);
|
|
209
|
+
console.log(c("│", colors.blue));
|
|
210
|
+
console.log(c("│", colors.blue) + c(" 1) Windows", colors.yellow));
|
|
211
|
+
console.log(c("│", colors.blue) + c(" 2) macOS", colors.yellow));
|
|
212
|
+
console.log(c("│", colors.blue) + c(" 3) Linux", colors.yellow));
|
|
213
|
+
console.log(c("│", colors.blue));
|
|
214
|
+
console.log(
|
|
215
|
+
c("└───────────────────────────────────────────────────────┘", colors.cyan),
|
|
216
|
+
);
|
|
217
|
+
console.log("");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function showProcessInfo(pid, port, name) {
|
|
221
|
+
console.log("");
|
|
222
|
+
console.log(
|
|
223
|
+
c(
|
|
224
|
+
"╔─ PROCESS FOUND ───────────────────────────────────────╗",
|
|
225
|
+
colors.green,
|
|
226
|
+
),
|
|
227
|
+
);
|
|
228
|
+
console.log(
|
|
229
|
+
c("║", colors.green) + ` PID: ${String(pid).padEnd(45)}`,
|
|
230
|
+
);
|
|
231
|
+
console.log(
|
|
232
|
+
c("║", colors.green) + ` Port: ${String(port).padEnd(45)}`,
|
|
233
|
+
);
|
|
234
|
+
console.log(
|
|
235
|
+
c("║", colors.green) + ` Process Name: ${String(name).padEnd(45)}`,
|
|
236
|
+
);
|
|
237
|
+
console.log(
|
|
238
|
+
c(
|
|
239
|
+
"╚───────────────────────────────────────────────────────╝",
|
|
240
|
+
colors.green,
|
|
241
|
+
),
|
|
242
|
+
);
|
|
243
|
+
console.log("");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ============================================================================
|
|
247
|
+
// Windows Functions
|
|
248
|
+
// ============================================================================
|
|
249
|
+
|
|
250
|
+
function findProcessWindows(port) {
|
|
251
|
+
try {
|
|
252
|
+
const output = execSync("netstat -ano", { encoding: "utf-8" });
|
|
253
|
+
const lines = output.split("\n");
|
|
254
|
+
|
|
255
|
+
for (const line of lines) {
|
|
256
|
+
if (line.includes(`:${port}`) && line.includes("LISTENING")) {
|
|
257
|
+
const parts = line.trim().split(/\s+/);
|
|
258
|
+
return parts[parts.length - 1];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
} catch (e) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function getProcessNameWindows(pid) {
|
|
268
|
+
try {
|
|
269
|
+
const output = execSync(`tasklist /FI "PID eq ${pid}" /FO table /NH`, {
|
|
270
|
+
encoding: "utf-8",
|
|
271
|
+
}).trim();
|
|
272
|
+
|
|
273
|
+
if (output && output.length > 0) {
|
|
274
|
+
return output.split(/\s+/)[0] || "Unknown";
|
|
275
|
+
}
|
|
276
|
+
return "Unknown";
|
|
277
|
+
} catch (e) {
|
|
278
|
+
return "Unknown";
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function killPortWindows(pid) {
|
|
283
|
+
try {
|
|
284
|
+
execSync(`taskkill /PID ${pid} /F`, { stdio: "pipe" });
|
|
285
|
+
return true;
|
|
286
|
+
} catch (e) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ============================================================================
|
|
292
|
+
// Unix (Linux/macOS) Functions
|
|
293
|
+
// ============================================================================
|
|
294
|
+
|
|
295
|
+
function findProcessUnix(port) {
|
|
296
|
+
try {
|
|
297
|
+
const result = execSync(`lsof -ti:${port}`, { encoding: "utf-8" }).trim();
|
|
298
|
+
return result.split("\n")[0];
|
|
299
|
+
} catch (e) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function getProcessNameUnix(pid) {
|
|
305
|
+
try {
|
|
306
|
+
return (
|
|
307
|
+
execSync(`ps -p ${pid} -o comm=`, { encoding: "utf-8" }).trim() ||
|
|
308
|
+
"Unknown"
|
|
309
|
+
);
|
|
310
|
+
} catch (e) {
|
|
311
|
+
return "Unknown";
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function killPortUnix(port) {
|
|
316
|
+
try {
|
|
317
|
+
execSync(`fuser -k ${port}/tcp`, { stdio: "pipe" });
|
|
318
|
+
return true;
|
|
319
|
+
} catch (e1) {
|
|
320
|
+
try {
|
|
321
|
+
execSync(`sudo fuser -k ${port}/tcp`, { stdio: "pipe" });
|
|
322
|
+
return true;
|
|
323
|
+
} catch (e2) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ============================================================================
|
|
330
|
+
// User Input
|
|
331
|
+
// ============================================================================
|
|
332
|
+
|
|
333
|
+
function getInput(prompt) {
|
|
334
|
+
return new Promise((resolve) => {
|
|
335
|
+
const rl = readline.createInterface({
|
|
336
|
+
input: process.stdin,
|
|
337
|
+
output: process.stdout,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
rl.question(prompt, (answer) => {
|
|
341
|
+
rl.close();
|
|
342
|
+
resolve(answer);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function askConfirm(prompt) {
|
|
348
|
+
return new Promise((resolve) => {
|
|
349
|
+
const rl = readline.createInterface({
|
|
350
|
+
input: process.stdin,
|
|
351
|
+
output: process.stdout,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
rl.question(prompt, (answer) => {
|
|
355
|
+
rl.close();
|
|
356
|
+
resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ============================================================================
|
|
362
|
+
// OS Selection
|
|
363
|
+
// ============================================================================
|
|
364
|
+
|
|
365
|
+
async function selectOS() {
|
|
366
|
+
let osChoice;
|
|
367
|
+
|
|
368
|
+
while (true) {
|
|
369
|
+
showOSMenu();
|
|
370
|
+
osChoice = await getInput(c("Select option (e,g. 1,2,3): ", colors.cyan));
|
|
371
|
+
|
|
372
|
+
if (osChoice === "1") {
|
|
373
|
+
success("Windows selected");
|
|
374
|
+
console.log("");
|
|
375
|
+
return "windows";
|
|
376
|
+
} else if (osChoice === "2") {
|
|
377
|
+
success("macOS selected");
|
|
378
|
+
console.log("");
|
|
379
|
+
return "macos";
|
|
380
|
+
} else if (osChoice === "3") {
|
|
381
|
+
success("Linux selected");
|
|
382
|
+
console.log("");
|
|
383
|
+
return "linux";
|
|
384
|
+
} else {
|
|
385
|
+
error("Invalid choice! Please enter 1, 2, or 3.");
|
|
386
|
+
console.log("");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ============================================================================
|
|
392
|
+
// Main Logic by OS
|
|
393
|
+
// ============================================================================
|
|
394
|
+
|
|
395
|
+
async function runWindows(port) {
|
|
396
|
+
info(`Searching for processes using port ${port}...`);
|
|
397
|
+
console.log("");
|
|
398
|
+
|
|
399
|
+
const pid = findProcessWindows(port);
|
|
400
|
+
|
|
401
|
+
if (!pid) {
|
|
402
|
+
showNotFound(port);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const name = getProcessNameWindows(pid);
|
|
407
|
+
showProcessInfo(pid, port, name);
|
|
408
|
+
|
|
409
|
+
const confirmed = await askConfirm(
|
|
410
|
+
c("Do you want to kill this process? (y/n): ", colors.cyan),
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
if (!confirmed) {
|
|
414
|
+
warning("Operation cancelled by user.");
|
|
415
|
+
console.log("");
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
console.log("");
|
|
420
|
+
info("Terminating process...");
|
|
421
|
+
console.log("");
|
|
422
|
+
|
|
423
|
+
if (killPortWindows(pid)) {
|
|
424
|
+
success(`Port ${port} has been killed!`);
|
|
425
|
+
console.log("");
|
|
426
|
+
info("You can now start your backend server on this port.");
|
|
427
|
+
showDevInfo();
|
|
428
|
+
} else {
|
|
429
|
+
error(`Failed to kill the port! (PID: ${pid})`);
|
|
430
|
+
console.log("");
|
|
431
|
+
console.log(
|
|
432
|
+
c(
|
|
433
|
+
"┌─ SOLUTION ─────────────────────────────────────────────┐",
|
|
434
|
+
colors.red,
|
|
435
|
+
),
|
|
436
|
+
);
|
|
437
|
+
console.log(c("│", colors.red) + " Try manually:");
|
|
438
|
+
console.log(c("│", colors.red));
|
|
439
|
+
console.log(
|
|
440
|
+
c("│", colors.red) + c(` taskkill /PID ${pid} /F`, colors.white),
|
|
441
|
+
);
|
|
442
|
+
console.log(c("│", colors.red));
|
|
443
|
+
console.log(
|
|
444
|
+
c(
|
|
445
|
+
"└────────────────────────────────────────────────────────┘",
|
|
446
|
+
colors.red,
|
|
447
|
+
),
|
|
448
|
+
);
|
|
449
|
+
console.log("");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async function runUnix(port) {
|
|
454
|
+
info(`Searching for processes using port ${port}...`);
|
|
455
|
+
console.log("");
|
|
456
|
+
|
|
457
|
+
const pid = findProcessUnix(port);
|
|
458
|
+
|
|
459
|
+
if (!pid) {
|
|
460
|
+
showNotFound(port);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const name = getProcessNameUnix(pid);
|
|
465
|
+
showProcessInfo(pid, port, name);
|
|
466
|
+
|
|
467
|
+
const confirmed = await askConfirm(
|
|
468
|
+
c("Do you want to kill this process? (y/n): ", colors.cyan),
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
if (!confirmed) {
|
|
472
|
+
warning("Operation cancelled by user.");
|
|
473
|
+
console.log("");
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
console.log("");
|
|
478
|
+
info("Terminating process...");
|
|
479
|
+
console.log("");
|
|
480
|
+
|
|
481
|
+
if (killPortUnix(port)) {
|
|
482
|
+
success(`Port ${port} has been killed!`);
|
|
483
|
+
console.log("");
|
|
484
|
+
info("You can now start your backend server on this port.");
|
|
485
|
+
showDevInfo();
|
|
486
|
+
} else {
|
|
487
|
+
error(`Failed to kill the port! (PID: ${pid})`);
|
|
488
|
+
console.log("");
|
|
489
|
+
console.log(
|
|
490
|
+
c(
|
|
491
|
+
"┌─ SOLUTION ─────────────────────────────────────────────┐",
|
|
492
|
+
colors.red,
|
|
493
|
+
),
|
|
494
|
+
);
|
|
495
|
+
console.log(c("│", colors.red) + " Try manually:");
|
|
496
|
+
console.log(c("│", colors.red));
|
|
497
|
+
console.log(c("│", colors.red) + c(` sudo kill -9 ${pid}`, colors.white));
|
|
498
|
+
console.log(
|
|
499
|
+
c("│", colors.red) + c(` sudo fuser -k ${port}/tcp`, colors.white),
|
|
500
|
+
);
|
|
501
|
+
console.log(c("│", colors.red));
|
|
502
|
+
console.log(
|
|
503
|
+
c(
|
|
504
|
+
"└────────────────────────────────────────────────────────┘",
|
|
505
|
+
colors.red,
|
|
506
|
+
),
|
|
507
|
+
);
|
|
508
|
+
console.log("");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ============================================================================
|
|
513
|
+
// Main
|
|
514
|
+
// ============================================================================
|
|
515
|
+
|
|
516
|
+
async function main() {
|
|
517
|
+
header();
|
|
518
|
+
showIntro();
|
|
519
|
+
|
|
520
|
+
// Step 1: Select OS
|
|
521
|
+
const selectedOS = await selectOS();
|
|
522
|
+
|
|
523
|
+
// Step 2: Get port
|
|
524
|
+
let portInput = await getInput(
|
|
525
|
+
c("Enter the port number (e.g., 8087): ", colors.cyan),
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
if (!portInput.trim()) {
|
|
529
|
+
error("Please enter a port number!");
|
|
530
|
+
console.log("");
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const port = parseInt(portInput);
|
|
535
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
536
|
+
error("Invalid port number! Port must be between 1 and 65535.");
|
|
537
|
+
console.log("");
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
console.log("");
|
|
542
|
+
|
|
543
|
+
// Step 3: Run based on selected OS
|
|
544
|
+
if (selectedOS === "windows") {
|
|
545
|
+
await runWindows(port);
|
|
546
|
+
} else if (selectedOS === "macos" || selectedOS === "linux") {
|
|
547
|
+
await runUnix(port);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
main().catch((err) => {
|
|
552
|
+
error("Error: " + err.message);
|
|
553
|
+
process.exit(1);
|
|
554
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "process-killer-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A utility to safely find and kill processes using specific ports on Linux/macOS. Perfect for backend developers dealing with port conflicts.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"port-killer": "./bin/port-killer.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"port",
|
|
15
|
+
"kill",
|
|
16
|
+
"process",
|
|
17
|
+
"backend",
|
|
18
|
+
"development",
|
|
19
|
+
"utility",
|
|
20
|
+
"nodejs",
|
|
21
|
+
"spring-boot",
|
|
22
|
+
"port-conflict"
|
|
23
|
+
],
|
|
24
|
+
"author": "Milon",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/yourusername/port-killer-cli.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/yourusername/port-killer-cli/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/yourusername/port-killer-cli#readme",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=12.0.0"
|
|
36
|
+
},
|
|
37
|
+
"preferGlobal": true,
|
|
38
|
+
"files": [
|
|
39
|
+
"bin",
|
|
40
|
+
"lib",
|
|
41
|
+
"README.md"
|
|
42
|
+
]
|
|
43
|
+
}
|