portrm 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 +735 -0
- package/bin/ptrm.js +45 -0
- package/install.js +95 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Portrm Abhishek Verma
|
|
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,735 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<p align="center">
|
|
3
|
+
<img width="220" height="220" alt="Portrm" src="https://cdn.jsdelivr.net/gh/abhishekayu/portrm@main/assets/logo.png" />
|
|
4
|
+
</p>
|
|
5
|
+
<h1 align="center">Portrm</h1>
|
|
6
|
+
<p align="center"><strong>Stop guessing what's running on your machine.</strong></p>
|
|
7
|
+
<p align="center">portrm is a fast, cross-platform CLI to inspect ports, understand processes, and recover broken dev environments - built for real-world development workflows.</p>
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://crates.io/crates/portrm"><img src="https://img.shields.io/crates/v/portrm.svg" alt="crates.io"></a>
|
|
10
|
+
<a href="https://www.npmjs.com/package/portrm"><img src="https://img.shields.io/npm/v/portrm.svg" alt="npm"></a>
|
|
11
|
+
<a href="https://github.com/abhishekayu/portrm/releases"><img src="https://img.shields.io/github/v/release/abhishekayu/portrm" alt="release"></a>
|
|
12
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license"></a>
|
|
13
|
+
<a href="https://marketplace.visualstudio.com/items?itemName=abhishekayu.portrm"><img src="https://img.shields.io/visual-studio-marketplace/v/abhishekayu.portrm?label=VS%20Code" alt="VS Code Marketplace"></a>
|
|
14
|
+
</p>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<br>
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
$ ptrm fix 3000
|
|
21
|
+
|
|
22
|
+
⚡ Port 3000 in use
|
|
23
|
+
→ Next.js (PID 81106) running for 7m 21s
|
|
24
|
+
→ 🛡 safe to kill
|
|
25
|
+
|
|
26
|
+
• Sending SIGTERM to PID 81106
|
|
27
|
+
• Verified: PID 81106 has exited
|
|
28
|
+
|
|
29
|
+
✔ Port 3000 is now free
|
|
30
|
+
Restart: npm run dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
<b>Detects the process. Checks if it's safe. Kills it gracefully. Tells you how to restart.</b><br>
|
|
35
|
+
Try it now: <code>npx portrm scan</code>
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## The Problem Every Developer Hits
|
|
41
|
+
|
|
42
|
+
You've seen this before:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Error: listen EADDRINUSE: address already in use :::3000
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A crashed dev server. A zombie process. Something unknown squatting on your port.
|
|
49
|
+
|
|
50
|
+
So you do the ritual:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
lsof -i :3000 # wall of text
|
|
54
|
+
kill -9 <pid> # hope it's not PostgreSQL
|
|
55
|
+
# ...was that important?
|
|
56
|
+
# how do I restart this thing?
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This is fragile. It's blind. It tells you nothing about what you just killed.
|
|
60
|
+
|
|
61
|
+
**portrm replaces this entire workflow with one command.** A single CLI tool for port conflict resolution, process inspection, and dev server recovery.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Instant Port Inspection
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
$ ptrm 3000
|
|
69
|
+
|
|
70
|
+
⚡ Port 3000 in use
|
|
71
|
+
→ Next.js (PID 81106)
|
|
72
|
+
→ running for 7m 21s
|
|
73
|
+
→ memory 42.9 MB
|
|
74
|
+
→ detected Next.js (95% confidence)
|
|
75
|
+
→ 🛡 safe to kill
|
|
76
|
+
|
|
77
|
+
📂 Detected project: Next.js
|
|
78
|
+
→ dev command: npm run dev
|
|
79
|
+
→ default port: 3000
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
portrm tells you **what** is running, **whether it's safe** to kill, and **how to restart** it.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Port Debugging: Before vs After
|
|
87
|
+
|
|
88
|
+
| Task | Before | After |
|
|
89
|
+
| -------------------------- | ------------------------------------------- | ----------------------- |
|
|
90
|
+
| Port 3000 stuck | `lsof -i :3000 \| awk ... \| xargs kill -9` | `ptrm fix 3000` |
|
|
91
|
+
| "What's on my ports?" | `lsof -iTCP -sTCP:LISTEN` (unreadable) | `ptrm scan` |
|
|
92
|
+
| "Is this safe to kill?" | Google the process name | portrm tells you |
|
|
93
|
+
| "How do I restart?" | Dig through package.json | ptrm shows the command |
|
|
94
|
+
| Zombie processes | Hunt them one by one | `ptrm doctor -y` |
|
|
95
|
+
| Which port is my frontend? | Check config files | `ptrm group` |
|
|
96
|
+
| Start entire dev stack | Open 5 terminals, run commands manually | `ptrm up` |
|
|
97
|
+
| Stop everything | Find and kill each process | `ptrm down` |
|
|
98
|
+
| "Is my port free?" | `lsof -i :3000` and parse output | `ptrm preflight 3000` |
|
|
99
|
+
| Monitor a flaky server | Watch logs + manual restart | `ptrm watch 3000` |
|
|
100
|
+
| Duplicate port assignments | Manually diff config files | `ptrm registry check` |
|
|
101
|
+
| Run all checks in CI | Write custom scripts | `ptrm ci` |
|
|
102
|
+
| Switch dev/staging config | Edit .env files manually | `ptrm use staging` |
|
|
103
|
+
| Restart a crashed service | Find port, kill, cd, re-run command | `ptrm restart frontend` |
|
|
104
|
+
| "Are my services running?" | Check each port manually | `ptrm status` |
|
|
105
|
+
| Stream logs from a port | Figure out which container or log file | `ptrm log 3000` |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Install
|
|
110
|
+
|
|
111
|
+
> **Native binary. No Node. No runtime dependencies.** ~1.2MB, runs instantly.
|
|
112
|
+
|
|
113
|
+
### One-line install (recommended)
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
curl -fsSL https://raw.githubusercontent.com/abhishekayu/portrm/main/install.sh | sh
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Package managers
|
|
120
|
+
|
|
121
|
+
| Platform | Command |
|
|
122
|
+
| ------------------- | --------------------------------------------------------------------------------------------- |
|
|
123
|
+
| **Homebrew** | `brew install abhishekayu/tap/portrm` |
|
|
124
|
+
| **Cargo** | `cargo install portrm` |
|
|
125
|
+
| **npm** | `npm install -g portrm` |
|
|
126
|
+
| **Scoop** (Windows) | `scoop bucket add portrm https://github.com/abhishekayu/scoop-portrm && scoop install portrm` |
|
|
127
|
+
| **Debian/Ubuntu** | Download `.deb` from [releases](https://github.com/abhishekayu/portrm/releases) |
|
|
128
|
+
|
|
129
|
+
### Try instantly (no install)
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx portrm scan
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Build from source
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
git clone https://github.com/abhishekayu/portrm.git
|
|
139
|
+
cd portrm
|
|
140
|
+
cargo install --path .
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> **Supports** macOS (Intel + Apple Silicon), Linux (x86_64 + ARM64), and Windows.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Usage Examples
|
|
148
|
+
|
|
149
|
+
### Scan all listening ports
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
$ ptrm scan
|
|
153
|
+
|
|
154
|
+
⚡ 5 active ports
|
|
155
|
+
|
|
156
|
+
PORT PROCESS PID SERVICE MEMORY UPTIME USER
|
|
157
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
3000 node 81106 Next.js 42.9 MB 7m 17s abhishek
|
|
159
|
+
3898 Code Helper (Plugin) 34290 Python 20.2 MB 3h 12m abhishek
|
|
160
|
+
5237 Code Helper (Plugin) 34073 Python 20.1 MB 3h 12m abhishek
|
|
161
|
+
5932 Code Helper (Plugin) 61773 Python 57.5 MB 58m 35s abhishek
|
|
162
|
+
42050 OneDrive Sync Serv.. 36643 Unknown 14.4 MB 3d 1h abhishek
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Fix port conflicts and auto-restart
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
$ ptrm fix 3000 --run "npm run dev"
|
|
169
|
+
|
|
170
|
+
✔ Killed safely port 3000 is now free
|
|
171
|
+
🚀 Restarting: npm run dev
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
One command. Port cleared, dev server restarted.
|
|
175
|
+
|
|
176
|
+
### Diagnose dev environment issues
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
$ ptrm doctor
|
|
180
|
+
|
|
181
|
+
🩺 2 issues found
|
|
182
|
+
|
|
183
|
+
1. Idle process Code Helper (PID 34290) at 0.0% CPU [auto-fixable]
|
|
184
|
+
→ Idle Code Helper on port 3898 -- consider killing to free resources
|
|
185
|
+
2. Idle process Code Helper (PID 34073) at 0.0% CPU [auto-fixable]
|
|
186
|
+
→ Idle Code Helper on port 5237 -- consider killing to free resources
|
|
187
|
+
|
|
188
|
+
⚙ Run ptrm doctor -y to auto-fix 2 issues
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Group ports by service role
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
$ ptrm group --dev
|
|
195
|
+
|
|
196
|
+
⚡ 4 active ports in 2 groups
|
|
197
|
+
|
|
198
|
+
⚙ Frontend (2)
|
|
199
|
+
────────────────────────────────────────────────────────────────────────────
|
|
200
|
+
3000 node 81106 Next.js 42.9 MB 7m 21s abhishek
|
|
201
|
+
3898 Code Helper (Plugin) 34290 Python 20.2 MB 3h 12m abhishek
|
|
202
|
+
|
|
203
|
+
⚙ Backend (2)
|
|
204
|
+
────────────────────────────────────────────────────────────────────────────
|
|
205
|
+
5237 Code Helper (Plugin) 34073 Python 20.0 MB 3h 12m abhishek
|
|
206
|
+
5932 Code Helper (Plugin) 61773 Python 57.5 MB 58m 39s abhishek
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Interactive terminal UI
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
$ ptrm ui
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Arrow keys to navigate, enter to inspect, `f` to fix. Full interactive TUI for port management, powered by ratatui.
|
|
216
|
+
|
|
217
|
+
### Define your dev stack with `.ptrm.toml`
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
$ ptrm init
|
|
221
|
+
|
|
222
|
+
✔ Created .ptrm.toml
|
|
223
|
+
→ Detected Next.js project (port 3050)
|
|
224
|
+
→ Port 3050 found in package.json scripts
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
portrm reads your `package.json` scripts and detects hardcoded ports (`--port 3050`, `-p 8080`, etc.). In a monorepo, it scans subdirectories and generates a multi-service config automatically.
|
|
228
|
+
|
|
229
|
+
Edit the generated config to declare your services:
|
|
230
|
+
|
|
231
|
+
```toml
|
|
232
|
+
[project]
|
|
233
|
+
name = "my-app"
|
|
234
|
+
|
|
235
|
+
[services.frontend]
|
|
236
|
+
port = 3000
|
|
237
|
+
run = "npm run dev"
|
|
238
|
+
cwd = "./frontend"
|
|
239
|
+
preflight = true
|
|
240
|
+
|
|
241
|
+
[services.api]
|
|
242
|
+
port = 8080
|
|
243
|
+
run = "cargo run"
|
|
244
|
+
cwd = "./backend"
|
|
245
|
+
preflight = true
|
|
246
|
+
|
|
247
|
+
[services.worker]
|
|
248
|
+
port = 9090
|
|
249
|
+
run = "python worker.py"
|
|
250
|
+
env = { PYTHON_ENV = "development" }
|
|
251
|
+
|
|
252
|
+
[profiles.staging]
|
|
253
|
+
frontend = { port = 3100 }
|
|
254
|
+
api = { port = 8180, env = { RUST_LOG = "info" } }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Start your entire dev stack
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
$ ptrm up
|
|
261
|
+
|
|
262
|
+
🚀 Starting 3 services...
|
|
263
|
+
|
|
264
|
+
✔ api started on port 8080
|
|
265
|
+
✔ frontend started on port 3050
|
|
266
|
+
✔ worker started on port 9090
|
|
267
|
+
|
|
268
|
+
✔ 3/3 services started.
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Pre-flight checks run automatically. If a port is busy, portrm tells you. Add `-y` to auto-fix conflicts before starting.
|
|
272
|
+
|
|
273
|
+
portrm tracks spawned PIDs in `.ptrm.pids`. If a framework binds a different port than configured (e.g., Next.js auto-increments when a port is taken), ptrm detects the actual port and reports it:
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
✔ frontend started on port 3001 (configured: 3000)
|
|
277
|
+
⚠ port 3000 was busy, update .ptrm.toml to match
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Stop everything
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
$ ptrm down
|
|
284
|
+
|
|
285
|
+
🛑 Stopping 3 services...
|
|
286
|
+
|
|
287
|
+
✔ api stopped (port 8080)
|
|
288
|
+
✔ frontend stopped (port 3050)
|
|
289
|
+
✔ worker stopped (port 9090)
|
|
290
|
+
|
|
291
|
+
✔ 3/3 services stopped.
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`down` uses a 3-tier strategy to find and stop processes: checks the declared port, then the actual port from `.ptrm.pids` (if the process moved), then kills by saved PID directly.
|
|
295
|
+
|
|
296
|
+
### Pre-flight port check
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
$ ptrm preflight 3000 8080 5432
|
|
300
|
+
|
|
301
|
+
🔍 Pre-flight check for 3 ports...
|
|
302
|
+
|
|
303
|
+
✔ Port 3000 is free
|
|
304
|
+
✔ Port 8080 is free
|
|
305
|
+
✘ Port 5432 is busy -- postgres (PID 1234, PostgreSQL)
|
|
306
|
+
|
|
307
|
+
⚠ 1 port is already in use. Run ptrm fix <port> to fix.
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Run without arguments to check all ports from `.ptrm.toml`.
|
|
311
|
+
|
|
312
|
+
### Watch a port and auto-restart on crash
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
$ ptrm watch 3000
|
|
316
|
+
|
|
317
|
+
👀 Watching port 3000 (every 2s, Ctrl-C to stop)
|
|
318
|
+
|
|
319
|
+
✔ Port 3000 is up -- Next.js (PID 81106)
|
|
320
|
+
✘ Port 3000 went down -- Unknown crash reason (was PID 81106)
|
|
321
|
+
🚀 Auto-restarting: npm run dev
|
|
322
|
+
✔ Port 3000 recovered (PID 82001, Next.js) -- downtime: 3s
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
If a `.ptrm.toml` defines a `run` command for the watched port, portrm auto-restarts it when it crashes.
|
|
326
|
+
|
|
327
|
+
### Validate port assignments
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
$ ptrm registry check
|
|
331
|
+
|
|
332
|
+
🔍 Checking port registry...
|
|
333
|
+
|
|
334
|
+
✔ No port conflicts found across 3 services.
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Detects duplicate ports across services and profile overrides in `.ptrm.toml`.
|
|
338
|
+
|
|
339
|
+
### Run all checks in CI
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
$ ptrm ci
|
|
343
|
+
|
|
344
|
+
▶ Step 1/4: Validate config... ✔
|
|
345
|
+
▶ Step 2/4: Registry check... ✔
|
|
346
|
+
▶ Step 3/4: Pre-flight check... ✔
|
|
347
|
+
▶ Step 4/4: Doctor... ✔
|
|
348
|
+
|
|
349
|
+
✔ All checks passed.
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Non-interactive runner for CI/CD pipelines. Runs config validation, registry check, preflight, and doctor in sequence. Exits 1 on failure. Supports `--json`.
|
|
353
|
+
|
|
354
|
+
### Switch profiles
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
$ ptrm use staging
|
|
358
|
+
|
|
359
|
+
✔ Switched to profile: staging
|
|
360
|
+
→ frontend port: 3100
|
|
361
|
+
→ api port: 8180
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Switch between named profiles defined in `.ptrm.toml`. The active profile is persisted to `.ptrm.state` and applied automatically to `up`, `down`, `watch`, and `preflight`.
|
|
365
|
+
|
|
366
|
+
### Restart a single service
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
$ ptrm restart frontend
|
|
370
|
+
|
|
371
|
+
🔄 Restarting frontend (port 3000)...
|
|
372
|
+
✔ Stopped process on port 3000 (PID 81106)
|
|
373
|
+
✔ Started frontend on port 3000
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Restarts a named service from `.ptrm.toml`. Stops whatever is on the port (local process or Docker container), then re-runs the configured `run` command. Respects the active profile.
|
|
377
|
+
|
|
378
|
+
### Check service status
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
$ ptrm status
|
|
382
|
+
|
|
383
|
+
📊 test-app status
|
|
384
|
+
|
|
385
|
+
SERVICE PORT STATUS PROCESS PID
|
|
386
|
+
──────────────────────────────────────────────────────
|
|
387
|
+
frontend 3000 🟢 Running node 81106
|
|
388
|
+
api 8080 🔴 Stopped
|
|
389
|
+
worker 9090 🟡 Conflict python3 92001
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Shows the live status of every service in `.ptrm.toml`. Compares the actual process on each port against the expected service to flag conflicts. Supports `--json`.
|
|
393
|
+
|
|
394
|
+
### Stream logs from a port
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
$ ptrm log 3000
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Streams live logs from the process on a port. Works with Docker containers (`docker logs -f`) and local processes (detects log files via `lsof`). If the process writes to a TTY, suggests how to redirect output to a file.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## CLI Commands Reference
|
|
405
|
+
|
|
406
|
+
| Command | Description | Example |
|
|
407
|
+
| ------------------------ | ----------------------------------------------------- | ----------------------------------- |
|
|
408
|
+
| `ptrm scan` | List all listening ports with service, memory, uptime | `ptrm scan` |
|
|
409
|
+
| `ptrm <port>` | Inspect a single port in detail | `ptrm 3000` |
|
|
410
|
+
| `ptrm fix <ports>` | Safely kill the process on one or more ports | `ptrm fix 3000 8080` |
|
|
411
|
+
| `ptrm fix <ports> --run` | Kill and auto-restart a dev server | `ptrm fix 3000 --run "npm run dev"` |
|
|
412
|
+
| `ptrm fix <ports> -y` | Skip confirmation prompt | `ptrm fix 3000 8080 -y` |
|
|
413
|
+
| `ptrm kill <ports>` | Direct kill with safety confirmation | `ptrm kill 3000 8080` |
|
|
414
|
+
| `ptrm group` | Ports organized by role (frontend/backend/db/infra) | `ptrm group --dev` |
|
|
415
|
+
| `ptrm doctor` | Find stale servers, idle processes, conflicts | `ptrm doctor` |
|
|
416
|
+
| `ptrm doctor -y` | Auto-fix all safe issues | `ptrm doctor -y` |
|
|
417
|
+
| `ptrm history` | View past actions with timestamps | `ptrm history` |
|
|
418
|
+
| `ptrm history --stats` | Kill stats: success rate, top ports, top processes | `ptrm history --stats` |
|
|
419
|
+
| `ptrm project` | Detect project type, suggest dev commands | `ptrm project` |
|
|
420
|
+
| `ptrm ui` | Interactive TUI with keyboard navigation | `ptrm ui` |
|
|
421
|
+
| `ptrm init` | Create a `.ptrm.toml` (auto-detects ports) | `ptrm init` |
|
|
422
|
+
| `ptrm up` | Start all services from `.ptrm.toml` | `ptrm up` |
|
|
423
|
+
| `ptrm up -y` | Start services, auto-fix port conflicts first | `ptrm up -y` |
|
|
424
|
+
| `ptrm down` | Stop all services from `.ptrm.toml` | `ptrm down` |
|
|
425
|
+
| `ptrm preflight` | Check if ports are free before starting | `ptrm preflight 3000 8080` |
|
|
426
|
+
| `ptrm watch <port>` | Monitor a port, alert on crash, auto-restart | `ptrm watch 3000` |
|
|
427
|
+
| `ptrm registry check` | Validate port assignments for conflicts | `ptrm registry check` |
|
|
428
|
+
| `ptrm ci` | Run all checks non-interactively (CI/CD mode) | `ptrm ci --json` |
|
|
429
|
+
| `ptrm use <profile>` | Switch to a named profile from `.ptrm.toml` | `ptrm use staging` |
|
|
430
|
+
| `ptrm restart <service>` | Restart a named service from `.ptrm.toml` | `ptrm restart frontend` |
|
|
431
|
+
| `ptrm status` | Show live status of all services from config | `ptrm status` |
|
|
432
|
+
| `ptrm log <port>` | Stream live logs from a port (Docker or local) | `ptrm log 3000` |
|
|
433
|
+
|
|
434
|
+
> All commands support `--json` for scripting and CI pipelines.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Why portrm Over kill-port, fkill, or lsof
|
|
439
|
+
|
|
440
|
+
**It's not `kill -9` with extra steps.**
|
|
441
|
+
|
|
442
|
+
portrm is a process classification engine built for developer productivity:
|
|
443
|
+
|
|
444
|
+
- **Identifies services** -- Next.js, Vite, Django, Flask, Express, PostgreSQL, Redis, Docker, and 13+ categories with confidence scores
|
|
445
|
+
- **Safety system** -- blocks system-critical processes (PID 1, sshd, launchd), warns about databases (data loss risk), approves dev servers
|
|
446
|
+
- **Graceful shutdown** -- SIGTERM first, waits for clean exit, escalates to SIGKILL only if needed
|
|
447
|
+
- **Project-aware** -- reads package.json, Cargo.toml, pyproject.toml to suggest the right restart command
|
|
448
|
+
- **Docker-aware** -- detects container ports vs host ports
|
|
449
|
+
- **History** -- every action logged to `~/.ptrm/history.json` with timestamps and outcomes
|
|
450
|
+
|
|
451
|
+
### How portrm works under the hood
|
|
452
|
+
|
|
453
|
+
1. **Scan** -- queries the OS for all listening ports, resolves PIDs via sysinfo
|
|
454
|
+
2. **Classify** -- identifies the service type (Next.js, PostgreSQL, Docker, etc.)
|
|
455
|
+
3. **Assess** -- safety check: SAFE / WARN / BLOCK
|
|
456
|
+
4. **Strategy** -- picks the right approach: Graceful, Escalating, or Force
|
|
457
|
+
5. **Execute** -- sends signals, waits for exit, verifies the port is free
|
|
458
|
+
6. **Recover** -- detects the project, suggests restart, or auto-restarts with `--run`
|
|
459
|
+
|
|
460
|
+
### Safety tiers
|
|
461
|
+
|
|
462
|
+
| Verdict | Examples | Behavior |
|
|
463
|
+
| ----------- | ----------------------------------------------------------- | ----------------------------------------------- |
|
|
464
|
+
| **BLOCKED** | PID 0/1, launchd, systemd, sshd, kernel_task | Refuses to kill |
|
|
465
|
+
| **WARNING** | PostgreSQL, MySQL, Redis, Docker, Nginx | Warns about consequences, asks for confirmation |
|
|
466
|
+
| **SAFE** | Next.js, Vite, Create React App, Django dev, Flask, Node.js | Kills gracefully |
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Developer Productivity Workflows
|
|
471
|
+
|
|
472
|
+
### "Port 3000 is already in use" after a crash
|
|
473
|
+
|
|
474
|
+
Your Next.js server crashed. The port is stuck. You just want to get back to coding.
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
ptrm fix 3000 -y --run "npm run dev"
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
Port cleared, server restarted. One line.
|
|
481
|
+
|
|
482
|
+
### Make `npm run dev` crash-proof
|
|
483
|
+
|
|
484
|
+
Add ptrm to your scripts so port conflicts resolve themselves:
|
|
485
|
+
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"scripts": {
|
|
489
|
+
"dev": "ptrm fix 3000 -y --run 'next dev'",
|
|
490
|
+
"dev:api": "ptrm fix 8080 -y --run 'node server.js'",
|
|
491
|
+
"dev:clean": "ptrm doctor -y && npm run dev"
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Now `npm run dev` works every time, even if something is already on port 3000.
|
|
497
|
+
|
|
498
|
+
### Morning dev environment reset
|
|
499
|
+
|
|
500
|
+
You open your laptop. Stale servers from yesterday are hogging ports and memory.
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
ptrm doctor -y
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
Finds zombie processes, idle servers, and cleans them up automatically.
|
|
507
|
+
|
|
508
|
+
### "What is using port 8080?"
|
|
509
|
+
|
|
510
|
+
Something is squatting on your API port but you have no idea what.
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
ptrm 8080
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Shows the process name, PID, service type, memory, uptime, project directory, and whether it's safe to kill.
|
|
517
|
+
|
|
518
|
+
### Full-stack dev with `.ptrm.toml`
|
|
519
|
+
|
|
520
|
+
Frontend on 3000, API on 8080, worker on 9090. Define them once, manage them forever:
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
# Initialize config
|
|
524
|
+
ptrm init
|
|
525
|
+
|
|
526
|
+
# Start everything (runs preflight checks automatically)
|
|
527
|
+
ptrm up
|
|
528
|
+
|
|
529
|
+
# Stop everything at end of day
|
|
530
|
+
ptrm down
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
No more opening 5 terminals and running commands manually.
|
|
534
|
+
|
|
535
|
+
### Monitor a flaky dev server
|
|
536
|
+
|
|
537
|
+
Your dev server keeps crashing. Let ptrm watch it and auto-restart:
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
ptrm watch 3000
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
If a `.ptrm.toml` defines a `run` command for port 3000, portrm auto-restarts it when it goes down.
|
|
544
|
+
|
|
545
|
+
### Pre-flight check before deployment scripts
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
# Check all ports from .ptrm.toml are free
|
|
549
|
+
ptrm preflight
|
|
550
|
+
|
|
551
|
+
# Check specific ports
|
|
552
|
+
ptrm preflight 3000 8080 5432
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Shell aliases for daily use
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
# ~/.zshrc or ~/.bashrc
|
|
559
|
+
alias pf='ptrm fix'
|
|
560
|
+
alias pfs='ptrm scan'
|
|
561
|
+
alias pfd='ptrm doctor -y'
|
|
562
|
+
alias pu='ptrm up'
|
|
563
|
+
alias pd='ptrm down'
|
|
564
|
+
alias dev3='ptrm fix 3000 -y --run "npm run dev"'
|
|
565
|
+
alias dev8='ptrm fix 8080 -y --run "node server.js"'
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Fix multiple ports at once
|
|
569
|
+
|
|
570
|
+
Clearing out a full dev environment before starting fresh:
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
# Fix multiple ports in one command
|
|
574
|
+
ptrm fix 3000 8080 5173 -y
|
|
575
|
+
|
|
576
|
+
# Or with .ptrm.toml
|
|
577
|
+
ptrm down && ptrm up
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### CI / pre-commit: ensure clean ports
|
|
581
|
+
|
|
582
|
+
```bash
|
|
583
|
+
# Run all checks in one command (exits 1 on failure)
|
|
584
|
+
ptrm ci
|
|
585
|
+
|
|
586
|
+
# Or with JSON output for CI parsing
|
|
587
|
+
ptrm ci --json
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Validate port assignments before deploying
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
# Check for duplicate ports across services and profiles
|
|
594
|
+
ptrm registry check
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### Switch between dev and staging
|
|
598
|
+
|
|
599
|
+
```bash
|
|
600
|
+
# Define profiles in .ptrm.toml, then switch:
|
|
601
|
+
ptrm use staging
|
|
602
|
+
ptrm up
|
|
603
|
+
|
|
604
|
+
# Switch back to default
|
|
605
|
+
ptrm use default
|
|
606
|
+
ptrm up
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Pipe to scripts with JSON output
|
|
610
|
+
|
|
611
|
+
```bash
|
|
612
|
+
# Get all listening ports as JSON
|
|
613
|
+
ptrm scan --json | jq '.[] | select(.service == "Next.js")'
|
|
614
|
+
|
|
615
|
+
# Count active dev servers
|
|
616
|
+
ptrm scan --json | jq '[.[] | select(.service != "Unknown")] | length'
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## Comparison: portrm vs kill-port vs fkill
|
|
622
|
+
|
|
623
|
+
| | kill-port | fkill | **portrm** |
|
|
624
|
+
| ---------------------- | --------- | --------- | ----------------------------------- |
|
|
625
|
+
| Service identification | No | Name only | Full (service, memory, uptime, CWD) |
|
|
626
|
+
| Safety checks | No | No | Yes (safe / warn / block) |
|
|
627
|
+
| Graceful shutdown | No | No | Yes (SIGTERM, then escalate) |
|
|
628
|
+
| Restart hints | No | No | Yes (project-aware) |
|
|
629
|
+
| Auto-restart | No | No | Yes (`--run`) |
|
|
630
|
+
| Docker awareness | No | No | Yes |
|
|
631
|
+
| Auto-diagnosis | No | No | Yes (`doctor`) |
|
|
632
|
+
| Port grouping | No | No | Yes (by role) |
|
|
633
|
+
| Action history | No | No | Yes |
|
|
634
|
+
| Interactive TUI | No | Yes | Yes |
|
|
635
|
+
| Project config file | No | No | Yes (`.ptrm.toml`) |
|
|
636
|
+
| Dev stack up/down | No | No | Yes (`up` / `down`) |
|
|
637
|
+
| Service restart | No | No | Yes (`restart <service>`) |
|
|
638
|
+
| Service status | No | No | Yes (`status`) |
|
|
639
|
+
| Log streaming | No | No | Yes (`log <port>`) |
|
|
640
|
+
| Port monitoring | No | No | Yes (`watch`) |
|
|
641
|
+
| Pre-flight checks | No | No | Yes (`preflight`) |
|
|
642
|
+
| Crash detection | No | No | Yes (signal, OOM, zombie) |
|
|
643
|
+
| Port registry | No | No | Yes (conflict detection) |
|
|
644
|
+
| CI/CD mode | No | No | Yes (`ci` command) |
|
|
645
|
+
| Profiles | No | No | Yes (`use` for dev/staging/prod) |
|
|
646
|
+
| Platform | Node.js | Node.js | Native binary |
|
|
647
|
+
| Size | ~50MB | ~50MB | ~1.2MB |
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
## Architecture & Performance
|
|
652
|
+
|
|
653
|
+
```
|
|
654
|
+
src/
|
|
655
|
+
scanner/ Batch port scanning with sysinfo process resolution
|
|
656
|
+
classifier/ 13+ service classifiers with confidence scoring
|
|
657
|
+
engine/ Safety checks, strategy selection, graceful kill with retry
|
|
658
|
+
platform/ macOS (lsof + libc) / Linux (/proc/net/tcp) / Windows (netstat)
|
|
659
|
+
project/ Filesystem project detection (package.json, Cargo.toml, etc.)
|
|
660
|
+
docker/ Container awareness via docker ps
|
|
661
|
+
grouping/ Port role classification (frontend/backend/database/infra)
|
|
662
|
+
doctor/ Stale servers, idle processes, crowded ports
|
|
663
|
+
history/ Action log persisted to ~/.ptrm/history.json
|
|
664
|
+
config/ .ptrm.toml project config loader (monorepo, port detection)
|
|
665
|
+
watch/ Continuous port monitoring with crash detection
|
|
666
|
+
stack/ Dev stack orchestration (up/down with PID tracking)
|
|
667
|
+
preflight/ Pre-flight port availability checks
|
|
668
|
+
crash/ Crash reason detection (signal, OOM, zombie)
|
|
669
|
+
restart/ Single-service restart (stop + start from config)
|
|
670
|
+
status/ Live service status dashboard (running/stopped/conflict)
|
|
671
|
+
log/ Log streaming for Docker containers and local processes
|
|
672
|
+
registry/ Port conflict detection across services and profiles
|
|
673
|
+
ci/ Non-interactive CI/CD runner (config + registry + preflight + doctor)
|
|
674
|
+
plugin/ Extensible ServiceDetector trait for custom detectors
|
|
675
|
+
cli/ Clap v4 + colored output + ratatui TUI
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
Built in Rust for speed and reliability. Ships as a single ~1.2MB static binary with zero runtime dependencies. No Node.js, no Python -- just a fast native CLI tool for managing ports and debugging dev environments.
|
|
679
|
+
|
|
680
|
+
---
|
|
681
|
+
|
|
682
|
+
## Contributing
|
|
683
|
+
|
|
684
|
+
```bash
|
|
685
|
+
git clone https://github.com/abhishekayu/portrm.git
|
|
686
|
+
cd portrm
|
|
687
|
+
cargo build
|
|
688
|
+
cargo test
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
- Report bugs or request features via [Issues](https://github.com/abhishekayu/portrm/issues)
|
|
692
|
+
- Add new service classifiers
|
|
693
|
+
- Improve platform support
|
|
694
|
+
- Write new doctor diagnostics
|
|
695
|
+
|
|
696
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
## VS Code Extension
|
|
701
|
+
|
|
702
|
+
Manage ports and services directly from the VS Code sidebar -- no terminal needed.
|
|
703
|
+
|
|
704
|
+
[](https://marketplace.visualstudio.com/items?itemName=abhishekayu.portrm)
|
|
705
|
+
|
|
706
|
+
**Features:**
|
|
707
|
+
|
|
708
|
+
- Sidebar dashboard showing all listening ports with process info
|
|
709
|
+
- Project-aware service management (reads `.ptrm.toml`)
|
|
710
|
+
- One-click Start All, Stop All, Fix, Doctor, Preflight, and 15+ actions
|
|
711
|
+
- Switch between dev/staging/production profiles
|
|
712
|
+
- Auto-install and update the ptrm CLI binary
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
code --install-extension abhishekayu.portrm
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
[View on Marketplace](https://marketplace.visualstudio.com/items?itemName=abhishekayu.portrm)
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
## License
|
|
723
|
+
|
|
724
|
+
[MIT](LICENSE) -- free for personal and commercial use.
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
<p align="center">
|
|
729
|
+
<strong>portrm</strong> -- an open-source CLI tool for port management, process debugging, and developer environment recovery.<br>
|
|
730
|
+
Built for developers who are tired of <code>lsof</code> + <code>kill -9</code>.<br>
|
|
731
|
+
Define your dev stack in <code>.ptrm.toml</code>, start with <code>ptrm up</code>, stop with <code>ptrm down</code>.<br>
|
|
732
|
+
Restart a service with <code>ptrm restart frontend</code>, check status with <code>ptrm status</code>.<br>
|
|
733
|
+
Switch profiles with <code>ptrm use staging</code>, validate with <code>ptrm ci</code>.<br>
|
|
734
|
+
Works with Next.js, Vite, Django, Flask, Express, Docker, PostgreSQL, Redis, and more.
|
|
735
|
+
</p>
|
package/bin/ptrm.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { execFileSync } = require("child_process");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
|
|
9
|
+
const binDir = path.join(__dirname);
|
|
10
|
+
|
|
11
|
+
function getBinaryPath() {
|
|
12
|
+
const platform = process.platform;
|
|
13
|
+
const arch = process.arch;
|
|
14
|
+
|
|
15
|
+
let binaryName = "ptrm";
|
|
16
|
+
if (platform === "win32") {
|
|
17
|
+
binaryName = "ptrm.exe";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const binaryPath = path.join(binDir, binaryName);
|
|
21
|
+
if (fs.existsSync(binaryPath)) {
|
|
22
|
+
return binaryPath;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.error(
|
|
26
|
+
`ptrm binary not found for ${platform}-${arch}.`,
|
|
27
|
+
`\nRun 'npm rebuild portrm' or install via: curl -fsSL https://raw.githubusercontent.com/abhishekayu/portrm/main/install.sh | sh`,
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const binary = getBinaryPath();
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const result = execFileSync(binary, args, {
|
|
37
|
+
stdio: "inherit",
|
|
38
|
+
env: process.env,
|
|
39
|
+
});
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (err.status !== undefined) {
|
|
42
|
+
process.exit(err.status);
|
|
43
|
+
}
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
package/install.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { execSync } = require("child_process");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
|
|
9
|
+
const VERSION = require("./package.json").version;
|
|
10
|
+
const REPO = "abhishekayu/portrm";
|
|
11
|
+
|
|
12
|
+
function getPlatformInfo() {
|
|
13
|
+
const platform = process.platform;
|
|
14
|
+
const arch = process.arch;
|
|
15
|
+
|
|
16
|
+
const platformMap = {
|
|
17
|
+
"darwin-x64": "portrm-darwin-amd64",
|
|
18
|
+
"darwin-arm64": "portrm-darwin-arm64",
|
|
19
|
+
"linux-x64": "portrm-linux-amd64",
|
|
20
|
+
"linux-arm64": "portrm-linux-arm64",
|
|
21
|
+
"win32-x64": "portrm-windows-amd64",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const key = `${platform}-${arch}`;
|
|
25
|
+
const name = platformMap[key];
|
|
26
|
+
|
|
27
|
+
if (!name) {
|
|
28
|
+
console.error(`Unsupported platform: ${key}`);
|
|
29
|
+
console.error("Install manually: cargo install portrm");
|
|
30
|
+
process.exit(0); // Don't fail npm install
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const ext = platform === "win32" ? ".zip" : ".tar.gz";
|
|
34
|
+
return { name, ext, platform };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function download(url) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
https
|
|
40
|
+
.get(url, (res) => {
|
|
41
|
+
if (
|
|
42
|
+
res.statusCode >= 300 &&
|
|
43
|
+
res.statusCode < 400 &&
|
|
44
|
+
res.headers.location
|
|
45
|
+
) {
|
|
46
|
+
return download(res.headers.location).then(resolve).catch(reject);
|
|
47
|
+
}
|
|
48
|
+
if (res.statusCode !== 200) {
|
|
49
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
50
|
+
}
|
|
51
|
+
const chunks = [];
|
|
52
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
53
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
54
|
+
res.on("error", reject);
|
|
55
|
+
})
|
|
56
|
+
.on("error", reject);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function install() {
|
|
61
|
+
const { name, ext, platform } = getPlatformInfo();
|
|
62
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${name}${ext}`;
|
|
63
|
+
const binDir = path.join(__dirname, "bin");
|
|
64
|
+
|
|
65
|
+
console.log(
|
|
66
|
+
`Downloading ptrm v${VERSION} for ${process.platform}-${process.arch}...`,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const data = await download(url);
|
|
71
|
+
const tmpFile = path.join(os.tmpdir(), `${name}${ext}`);
|
|
72
|
+
fs.writeFileSync(tmpFile, data);
|
|
73
|
+
|
|
74
|
+
if (platform === "win32") {
|
|
75
|
+
// Use PowerShell to extract zip
|
|
76
|
+
execSync(
|
|
77
|
+
`powershell -Command "Expand-Archive -Force '${tmpFile}' '${binDir}'"`,
|
|
78
|
+
{ stdio: "pipe" },
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
execSync(`tar xzf "${tmpFile}" -C "${binDir}"`, { stdio: "pipe" });
|
|
82
|
+
const binary = path.join(binDir, "ptrm");
|
|
83
|
+
fs.chmodSync(binary, 0o755);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fs.unlinkSync(tmpFile);
|
|
87
|
+
console.log("portrm installed successfully.");
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error(`Failed to download portrm: ${err.message}`);
|
|
90
|
+
console.error("Install manually: cargo install portrm");
|
|
91
|
+
// Don't fail npm install
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
install();
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "portrm",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "portrm is a fast, cross-platform CLI to inspect ports, understand processes, and recover broken dev environments - built for real-world development workflows.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/abhishekayu/portrm"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"port",
|
|
12
|
+
"kill-port",
|
|
13
|
+
"port-conflict",
|
|
14
|
+
"developer-tools",
|
|
15
|
+
"cli",
|
|
16
|
+
"devserver",
|
|
17
|
+
"process",
|
|
18
|
+
"debug",
|
|
19
|
+
"eaddrinuse",
|
|
20
|
+
"zombie-process",
|
|
21
|
+
"port-scanner",
|
|
22
|
+
"dev-environment",
|
|
23
|
+
"productivity"
|
|
24
|
+
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"ptrm": "bin/ptrm.js",
|
|
27
|
+
"portrm": "bin/ptrm.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"bin/",
|
|
31
|
+
"install.js",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"postinstall": "node install.js"
|
|
37
|
+
},
|
|
38
|
+
"os": [
|
|
39
|
+
"darwin",
|
|
40
|
+
"linux",
|
|
41
|
+
"win32"
|
|
42
|
+
],
|
|
43
|
+
"cpu": [
|
|
44
|
+
"x64",
|
|
45
|
+
"arm64"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=16"
|
|
49
|
+
}
|
|
50
|
+
}
|