portclean 1.0.0 → 1.1.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 +39 -10
- package/cli.js +109 -76
- package/package.json +11 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tejaswan Kalluri
|
|
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
CHANGED
|
@@ -14,7 +14,7 @@ npm install -g portclean
|
|
|
14
14
|
portclean [ports...] [options]
|
|
15
15
|
|
|
16
16
|
Arguments:
|
|
17
|
-
ports Port number(s) to target
|
|
17
|
+
ports Port number(s) or ranges to target (e.g. 3000 or 3000-3010)
|
|
18
18
|
|
|
19
19
|
Options:
|
|
20
20
|
--force, -f Skip confirmation prompt
|
|
@@ -38,7 +38,7 @@ Process 12345 (node) is using port 3000. Kill it? (y/N) y
|
|
|
38
38
|
### Kill multiple ports
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
$ portclean 3000 8080
|
|
41
|
+
$ portclean 3000 8080 9000
|
|
42
42
|
Processes on port 3000:
|
|
43
43
|
1. PID 12345 (node)
|
|
44
44
|
Process 12345 (node) is using port 3000. Kill it? (y/N) y
|
|
@@ -48,6 +48,11 @@ Processes on port 8080:
|
|
|
48
48
|
1. PID 54321 (python)
|
|
49
49
|
Process 54321 (python) is using port 8080. Kill it? (y/N) y
|
|
50
50
|
✓ Killed process 54321 (python)
|
|
51
|
+
|
|
52
|
+
Processes on port 9000:
|
|
53
|
+
1. PID 11111 (go)
|
|
54
|
+
Process 11111 (go) is using port 9000. Kill it? (y/N) y
|
|
55
|
+
✓ Killed process 11111 (go)
|
|
51
56
|
```
|
|
52
57
|
|
|
53
58
|
### Kill without confirmation
|
|
@@ -59,6 +64,21 @@ Processes on port 3000:
|
|
|
59
64
|
✓ Killed process 12345 (node)
|
|
60
65
|
```
|
|
61
66
|
|
|
67
|
+
### Kill a port range
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
$ portclean 3000-3010 --force
|
|
71
|
+
Processes on port 3000:
|
|
72
|
+
1. PID 12345 (node)
|
|
73
|
+
✓ Killed process 12345 (node)
|
|
74
|
+
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
Processes on port 3010:
|
|
78
|
+
1. PID 12399 (go)
|
|
79
|
+
✓ Killed process 12399 (go)
|
|
80
|
+
```
|
|
81
|
+
|
|
62
82
|
### Kill all processes using a port
|
|
63
83
|
|
|
64
84
|
When multiple processes are using the same port:
|
|
@@ -78,7 +98,7 @@ Kill all 3 process(es) on port 3000? (y/N) y
|
|
|
78
98
|
### Kill all processes without confirmation
|
|
79
99
|
|
|
80
100
|
```bash
|
|
81
|
-
$ portclean 3000 8080 --all --force
|
|
101
|
+
$ portclean 3000 8080 9000 --all --force
|
|
82
102
|
Processes on port 3000:
|
|
83
103
|
1. PID 12345 (node)
|
|
84
104
|
2. PID 12346 (node)
|
|
@@ -88,20 +108,28 @@ Processes on port 3000:
|
|
|
88
108
|
Processes on port 8080:
|
|
89
109
|
1. PID 54321 (python)
|
|
90
110
|
✓ Killed process 54321 (python)
|
|
111
|
+
|
|
112
|
+
Processes on port 9000:
|
|
113
|
+
1. PID 11111 (go)
|
|
114
|
+
✓ Killed process 11111 (go)
|
|
91
115
|
```
|
|
92
116
|
|
|
93
117
|
### Kill processes on ports without --all (prompts per process)
|
|
94
118
|
|
|
95
119
|
```bash
|
|
96
|
-
$ portclean 3000
|
|
120
|
+
$ portclean 3000-3002
|
|
97
121
|
Processes on port 3000:
|
|
98
122
|
1. PID 12345 (node)
|
|
99
|
-
2. PID 12346 (node)
|
|
100
|
-
3. PID 12347 (node)
|
|
101
123
|
Process 12345 (node) is using port 3000. Kill it? (y/N) y
|
|
102
124
|
✓ Killed process 12345 (node)
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
|
|
126
|
+
Processes on port 3001:
|
|
127
|
+
1. PID 12346 (node)
|
|
128
|
+
Process 12346 (node) is using port 3001. Kill it? (y/N) n
|
|
129
|
+
|
|
130
|
+
Processes on port 3002:
|
|
131
|
+
1. PID 12347 (node)
|
|
132
|
+
Process 12347 (node) is using port 3002. Kill it? (y/N) y
|
|
105
133
|
✓ Killed process 12347 (node)
|
|
106
134
|
```
|
|
107
135
|
|
|
@@ -110,8 +138,9 @@ Process 12347 (node) is using port 3000. Kill it? (y/N) y
|
|
|
110
138
|
### macOS/Linux
|
|
111
139
|
|
|
112
140
|
1. **Primary method**: Uses `lsof -i :<port>` to find processes
|
|
113
|
-
2. **Fallback**: If `lsof` is not available, uses `netstat -anp` and parses the output
|
|
114
|
-
3. **
|
|
141
|
+
2. **Fallback (Linux only)**: If `lsof` is not available, uses `netstat -anp` and parses the output (stderr suppressed)
|
|
142
|
+
3. **macOS fallback**: macOS `netstat` lacks PID data, so we skip it and return no processes instead of printing errors
|
|
143
|
+
4. **Process names**: Extracted from the command output or via `ps` command
|
|
115
144
|
|
|
116
145
|
### Windows
|
|
117
146
|
|
package/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { execSync
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
4
|
import { kill } from 'process';
|
|
5
|
-
import { stdin, stdout
|
|
5
|
+
import { stdin, stdout } from 'process';
|
|
6
6
|
import parseArgs from 'mri';
|
|
7
7
|
import colors from 'picocolors';
|
|
8
8
|
import * as readline from 'readline';
|
|
@@ -10,26 +10,63 @@ import * as readline from 'readline';
|
|
|
10
10
|
const VERSION = '1.0.0';
|
|
11
11
|
const PLATFORM = process.platform;
|
|
12
12
|
|
|
13
|
-
// Parse
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
13
|
+
// Parse ports (single numbers or inclusive ranges like 3000-3010)
|
|
14
|
+
function parsePorts(inputs) {
|
|
15
|
+
const ports = new Set();
|
|
16
|
+
const errors = [];
|
|
17
|
+
|
|
18
|
+
for (const input of inputs) {
|
|
19
|
+
if (typeof input !== 'string') {
|
|
20
|
+
errors.push(`Invalid port input: ${input}`);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (input.includes('-')) {
|
|
25
|
+
const [startStr, endStr] = input.split('-', 2);
|
|
26
|
+
const start = parseInt(startStr, 10);
|
|
27
|
+
const end = parseInt(endStr, 10);
|
|
28
|
+
|
|
29
|
+
if (Number.isNaN(start) || Number.isNaN(end) || start < 1 || end > 65535 || start > end) {
|
|
30
|
+
errors.push(`Error: Invalid port range ${input}`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (let p = start; p <= end; p++) {
|
|
35
|
+
ports.add(p);
|
|
36
|
+
}
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const port = parseInt(input, 10);
|
|
41
|
+
if (Number.isNaN(port) || port < 1 || port > 65535) {
|
|
42
|
+
errors.push(`Error: Invalid port ${input}`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
ports.add(port);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { ports: Array.from(ports), errors };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function main() {
|
|
52
|
+
const args = parseArgs(process.argv.slice(2), {
|
|
53
|
+
alias: {
|
|
54
|
+
h: 'help',
|
|
55
|
+
v: 'version',
|
|
56
|
+
f: 'force',
|
|
57
|
+
a: 'all',
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (args.help) {
|
|
62
|
+
console.log(`
|
|
26
63
|
${colors.bold('portclean')} - Kill processes using specific ports
|
|
27
64
|
|
|
28
65
|
${colors.bold('Usage:')}
|
|
29
66
|
portclean [ports...] [options]
|
|
30
67
|
|
|
31
68
|
${colors.bold('Arguments:')}
|
|
32
|
-
ports Port number(s) to target
|
|
69
|
+
ports Port number(s) or ranges to target (e.g. 3000 or 3000-3010)
|
|
33
70
|
|
|
34
71
|
${colors.bold('Options:')}
|
|
35
72
|
--force, -f Skip confirmation prompt
|
|
@@ -39,59 +76,50 @@ ${colors.bold('Options:')}
|
|
|
39
76
|
|
|
40
77
|
${colors.bold('Examples:')}
|
|
41
78
|
portclean 3000 Kill process on port 3000
|
|
42
|
-
portclean 3000 8080
|
|
79
|
+
portclean 3000 8080 9000 Kill processes on multiple ports
|
|
80
|
+
portclean 3000-3010 Kill processes on ports 3000 through 3010
|
|
43
81
|
portclean 3000 --force Kill port 3000 without confirmation
|
|
44
82
|
portclean 3000 --all Kill all processes using port 3000
|
|
45
83
|
portclean 3000 8080 --force --all Kill all processes on both ports without confirmation
|
|
46
84
|
`);
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Handle version flag
|
|
51
|
-
if (args.version) {
|
|
52
|
-
console.log(`portkill v${VERSION}`);
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
55
87
|
|
|
56
|
-
|
|
57
|
-
|
|
88
|
+
if (args.version) {
|
|
89
|
+
console.log(`portkill v${VERSION}`);
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
58
92
|
|
|
59
|
-
|
|
60
|
-
if (ports.length === 0) {
|
|
61
|
-
console.error(colors.red('Error: No ports specified'));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
93
|
+
const rawPorts = args._;
|
|
64
94
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
console.error(colors.red(`Error: Invalid port ${p}`));
|
|
69
|
-
return false;
|
|
95
|
+
if (rawPorts.length === 0) {
|
|
96
|
+
console.error(colors.red('Error: No ports specified'));
|
|
97
|
+
process.exit(1);
|
|
70
98
|
}
|
|
71
|
-
return true;
|
|
72
|
-
});
|
|
73
99
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
100
|
+
const { ports, errors: portErrors } = parsePorts(rawPorts);
|
|
101
|
+
portErrors.forEach((msg) => console.error(colors.red(msg)));
|
|
77
102
|
|
|
78
|
-
|
|
79
|
-
(async () => {
|
|
80
|
-
try {
|
|
81
|
-
for (const port of validPorts) {
|
|
82
|
-
await handlePort(parseInt(port, 10));
|
|
83
|
-
}
|
|
84
|
-
process.exit(0);
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.error(colors.red(`Error: ${error.message}`));
|
|
103
|
+
if (ports.length === 0) {
|
|
87
104
|
process.exit(1);
|
|
88
105
|
}
|
|
89
|
-
|
|
106
|
+
|
|
107
|
+
for (const port of ports) {
|
|
108
|
+
await handlePort(port, args);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
process.exit(0);
|
|
112
|
+
}
|
|
90
113
|
|
|
91
114
|
/**
|
|
92
115
|
* Handle killing processes on a specific port
|
|
93
116
|
*/
|
|
94
|
-
async function handlePort(port) {
|
|
117
|
+
async function handlePort(port, args) {
|
|
118
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
119
|
+
console.error(colors.red(`Error: Invalid port ${port}`));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
95
123
|
try {
|
|
96
124
|
const processes = await getProcessesOnPort(port);
|
|
97
125
|
|
|
@@ -108,14 +136,12 @@ async function handlePort(port) {
|
|
|
108
136
|
if (args.force || args.all) {
|
|
109
137
|
// If --force or --all, show single confirmation per port (or none with --force)
|
|
110
138
|
if (args.force) {
|
|
111
|
-
// Kill without confirmation
|
|
112
139
|
for (const proc of processes) {
|
|
113
140
|
await killProcess(proc.pid, proc.command);
|
|
114
141
|
}
|
|
115
142
|
} else if (args.all) {
|
|
116
|
-
// --all without --force: single confirmation
|
|
117
143
|
const confirmed = await prompt(
|
|
118
|
-
`Kill all ${processes.length} process(es) on port ${port}? (
|
|
144
|
+
`Kill all ${processes.length} process(es) on port ${port}? (Y/n) `
|
|
119
145
|
);
|
|
120
146
|
if (confirmed) {
|
|
121
147
|
for (const proc of processes) {
|
|
@@ -124,10 +150,9 @@ async function handlePort(port) {
|
|
|
124
150
|
}
|
|
125
151
|
}
|
|
126
152
|
} else {
|
|
127
|
-
// Without --all: prompt per process
|
|
128
153
|
for (const proc of processes) {
|
|
129
154
|
const confirmed = await prompt(
|
|
130
|
-
`Process ${proc.pid} (${proc.command}) is using port ${port}. Kill it? (
|
|
155
|
+
`Process ${proc.pid} (${proc.command}) is using port ${port}. Kill it? (Y/n) `
|
|
131
156
|
);
|
|
132
157
|
if (confirmed) {
|
|
133
158
|
await killProcess(proc.pid, proc.command);
|
|
@@ -156,18 +181,21 @@ async function getProcessesOnPort(port) {
|
|
|
156
181
|
* Get processes on macOS/Linux using lsof or netstat
|
|
157
182
|
*/
|
|
158
183
|
async function getProcessesPosix(port) {
|
|
184
|
+
// Suppress stderr from system commands to avoid leaking raw tool logs
|
|
185
|
+
const execOpts = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] };
|
|
186
|
+
|
|
159
187
|
try {
|
|
160
|
-
// Try lsof first
|
|
161
188
|
try {
|
|
162
|
-
const output = execSync(`lsof -i :${port} -n -P`,
|
|
189
|
+
const output = execSync(`lsof -i :${port} -n -P`, execOpts);
|
|
163
190
|
return parseLsofOutput(output);
|
|
164
191
|
} catch {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
192
|
+
if (PLATFORM === 'linux') {
|
|
193
|
+
const output = execSync('netstat -anp', execOpts);
|
|
194
|
+
return parseNetstatOutput(output, port);
|
|
195
|
+
}
|
|
196
|
+
return [];
|
|
168
197
|
}
|
|
169
|
-
} catch
|
|
170
|
-
console.error(colors.red(`Failed to get processes on port ${port}: ${error.message}`));
|
|
198
|
+
} catch {
|
|
171
199
|
return [];
|
|
172
200
|
}
|
|
173
201
|
}
|
|
@@ -176,7 +204,7 @@ async function getProcessesPosix(port) {
|
|
|
176
204
|
* Parse lsof output
|
|
177
205
|
*/
|
|
178
206
|
function parseLsofOutput(output) {
|
|
179
|
-
const lines = output.trim().split('\n').slice(1);
|
|
207
|
+
const lines = output.trim().split('\n').slice(1);
|
|
180
208
|
const processes = [];
|
|
181
209
|
|
|
182
210
|
for (const line of lines) {
|
|
@@ -186,7 +214,6 @@ function parseLsofOutput(output) {
|
|
|
186
214
|
const command = parts[0];
|
|
187
215
|
|
|
188
216
|
if (!isNaN(pid) && pid > 0) {
|
|
189
|
-
// Check if already added
|
|
190
217
|
if (!processes.find((p) => p.pid === pid)) {
|
|
191
218
|
processes.push({ pid, command });
|
|
192
219
|
}
|
|
@@ -201,7 +228,7 @@ function parseLsofOutput(output) {
|
|
|
201
228
|
* Parse netstat output for a specific port
|
|
202
229
|
*/
|
|
203
230
|
function parseNetstatOutput(output, port) {
|
|
204
|
-
const lines = output.trim().split('\n').slice(1);
|
|
231
|
+
const lines = output.trim().split('\n').slice(1);
|
|
205
232
|
const processes = [];
|
|
206
233
|
|
|
207
234
|
for (const line of lines) {
|
|
@@ -213,19 +240,17 @@ function parseNetstatOutput(output, port) {
|
|
|
213
240
|
|
|
214
241
|
if (match && state === 'LISTEN') {
|
|
215
242
|
const pid = parseInt(match[1], 10);
|
|
216
|
-
const proto = parts[0];
|
|
217
243
|
const addr = parts[3];
|
|
218
244
|
const addrParts = addr.split(':');
|
|
219
245
|
const addrPort = addrParts[addrParts.length - 1];
|
|
220
246
|
|
|
221
247
|
if (parseInt(addrPort, 10) === port && !isNaN(pid) && pid > 0) {
|
|
222
|
-
// Get command name
|
|
223
248
|
let command = 'unknown';
|
|
224
249
|
try {
|
|
225
250
|
const psOutput = execSync(`ps -p ${pid} -o comm=`, { encoding: 'utf8' });
|
|
226
251
|
command = psOutput.trim();
|
|
227
252
|
} catch {
|
|
228
|
-
//
|
|
253
|
+
// ignore
|
|
229
254
|
}
|
|
230
255
|
|
|
231
256
|
if (!processes.find((p) => p.pid === pid)) {
|
|
@@ -247,7 +272,7 @@ async function getProcessesWindows(port) {
|
|
|
247
272
|
const netstatOutput = execSync('netstat -ano', { encoding: 'utf8' });
|
|
248
273
|
const pids = new Set();
|
|
249
274
|
|
|
250
|
-
const lines = netstatOutput.trim().split('\n').slice(4);
|
|
275
|
+
const lines = netstatOutput.trim().split('\n').slice(4);
|
|
251
276
|
for (const line of lines) {
|
|
252
277
|
const parts = line.trim().split(/\s+/);
|
|
253
278
|
if (parts.length >= 5) {
|
|
@@ -279,7 +304,7 @@ async function getProcessesWindows(port) {
|
|
|
279
304
|
command = taskLine;
|
|
280
305
|
}
|
|
281
306
|
} catch {
|
|
282
|
-
//
|
|
307
|
+
// ignore
|
|
283
308
|
}
|
|
284
309
|
|
|
285
310
|
processes.push({ pid, command });
|
|
@@ -300,11 +325,9 @@ async function killProcess(pid, command) {
|
|
|
300
325
|
if (PLATFORM === 'win32') {
|
|
301
326
|
execSync(`taskkill /PID ${pid} /F`, { encoding: 'utf8' });
|
|
302
327
|
} else {
|
|
303
|
-
// Try using process.kill first
|
|
304
328
|
try {
|
|
305
329
|
kill(pid, 'SIGKILL');
|
|
306
330
|
} catch {
|
|
307
|
-
// Fallback to shell command
|
|
308
331
|
execSync(`kill -9 ${pid}`);
|
|
309
332
|
}
|
|
310
333
|
}
|
|
@@ -326,7 +349,17 @@ function prompt(question) {
|
|
|
326
349
|
|
|
327
350
|
rl.question(question, (answer) => {
|
|
328
351
|
rl.close();
|
|
329
|
-
|
|
352
|
+
const response = answer.trim().toLowerCase();
|
|
353
|
+
resolve(response === '' || response === 'y' || response === 'yes');
|
|
330
354
|
});
|
|
331
355
|
});
|
|
332
356
|
}
|
|
357
|
+
|
|
358
|
+
if (import.meta.url === new URL(process.argv[1], 'file:').href) {
|
|
359
|
+
main().catch((error) => {
|
|
360
|
+
console.error(colors.red(`Error: ${error.message}`));
|
|
361
|
+
process.exit(1);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export { parsePorts };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "portclean",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Kill processes using specific ports on macOS, Linux, and Windows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cli.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"portclean": "cli.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "node --test
|
|
11
|
+
"test": "node --test",
|
|
12
12
|
"smoke": "node cli.js --help"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
@@ -17,8 +17,16 @@
|
|
|
17
17
|
"kill",
|
|
18
18
|
"process"
|
|
19
19
|
],
|
|
20
|
-
"author": "",
|
|
20
|
+
"author": "Tejaswan Kalluri",
|
|
21
21
|
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/tejaswankalluri/portclean.git"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/tejaswankalluri/portclean/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/tejaswankalluri/portclean#readme",
|
|
22
30
|
"dependencies": {
|
|
23
31
|
"mri": "^1.2.0",
|
|
24
32
|
"picocolors": "^1.0.0"
|