slash-port 0.2.1 → 0.4.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/README.md +239 -27
- package/dist/cli.js +44 -5
- package/dist/describe.js +607 -171
- package/dist/docker.js +208 -0
- package/dist/explain.js +209 -0
- package/dist/format.js +34 -12
- package/dist/inspect.js +271 -0
- package/dist/kill.js +2 -3
- package/dist/mode.js +46 -0
- package/dist/scan/index.js +31 -11
- package/dist/ui/App.js +235 -25
- package/dist/ui/theme.js +124 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/Slash-ui">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/logo-slashui-dark.svg" />
|
|
5
|
+
<img src="docs/assets/logo-slashui-light.svg" alt="Slash UI" width="159" height="65" />
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
1
10
|
# slash-port
|
|
2
11
|
|
|
3
|
-
<!-- release:badge -->
|
|
12
|
+
<!-- release:badge -->
|
|
13
|
+
[](https://github.com/Slash-ui/slash-port/releases/tag/v0.4.0)<!-- /release:badge -->
|
|
4
14
|
[](https://www.npmjs.com/package/slash-port)
|
|
5
15
|
[](https://www.npmjs.com/package/slash-port)
|
|
6
16
|
[](https://github.com/Slash-ui/slash-port/actions/workflows/ci.yml)
|
|
@@ -19,15 +29,60 @@ a good idea. `slash-port` answers all three, then kills the process for you
|
|
|
19
29
|
after a confirmation that names it.
|
|
20
30
|
|
|
21
31
|
```
|
|
22
|
-
slash-port
|
|
23
|
-
PORT
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
slash-port 8/8 tcp · beginner
|
|
33
|
+
PORT WHAT IT IS OPEN AT CLOSE IT?
|
|
34
|
+
22/tcp OpenSSH server [protected] - No
|
|
35
|
+
3000/tcp Next.js (shop) http://localhost:3000 Yes
|
|
36
|
+
5173/tcp Vite dev server (admin) http://localhost:5173 Yes
|
|
37
|
+
5432/tcp Docker Desktop - Probably
|
|
38
|
+
6379/tcp Redis - Probably
|
|
39
|
+
8025/tcp Docker Desktop http://localhost:8025 Probably
|
|
40
|
+
49470/tcp Visual Studio Code (Node.js) - Probably
|
|
41
|
+
51061/tcp macOS Handoff - Better not
|
|
42
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
43
|
+
│ Port 3000 · Next.js (shop) - a web server │
|
|
44
|
+
│ Point a browser at it - that is what it is there for. │
|
|
45
|
+
│ Project shop │
|
|
46
|
+
│ Open http://localhost:3000 │
|
|
47
|
+
│ Started by you (slashui) · node · pid 41822 │
|
|
48
|
+
│ Close it Yes - yours, and as easy to start again as it was to start │
|
|
49
|
+
│ Afterwards Start it again with your dev command, usually `npm run dev`. │
|
|
50
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
51
|
+
↑↓ move · / find · x close it · r refresh · u udp · d details · m advanced · q …
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Every row says something the process name does not. The process behind
|
|
55
|
+
`Visual Studio Code` is called `Code Helper`, and the one behind `macOS
|
|
56
|
+
Handoff` is called `rapportd`. Neither name would have told you anything, which
|
|
57
|
+
is the point: when nothing at all can be worked out, the column says `-` rather
|
|
58
|
+
than repeating the process name back at you.
|
|
59
|
+
|
|
60
|
+
Press `m` for advanced mode, which trades the explanations for the facts that
|
|
61
|
+
tell two identical-looking dev servers apart:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
slash-port 8/8 tcp · advanced
|
|
65
|
+
PORT PID USER PROCESS ADDRESS DESCRIPTION
|
|
66
|
+
22/tcp 947 root sshd * OpenSSH server [protected]
|
|
67
|
+
3000/tcp 41822 slashui node * Next.js (shop)
|
|
68
|
+
5173/tcp 41905 slashui node * Vite dev server (admin)
|
|
69
|
+
5432/tcp 39044 slashui com.docker.backend * Docker Desktop
|
|
70
|
+
6379/tcp 788 slashui redis-server 127.0.0.1 Redis
|
|
71
|
+
8025/tcp 39044 slashui com.docker.backend * Docker Desktop
|
|
72
|
+
49470/tcp 1737 slashui Code Helper 127.0.0.1 Visual Studio Code (Node.js)
|
|
73
|
+
51061/tcp 694 slashui rapportd * macOS Handoff
|
|
74
|
+
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
75
|
+
│ Process node · pid 41822 · parent 1204 zsh │
|
|
76
|
+
│ User slashui │
|
|
77
|
+
│ Listening * · TCP · IPv4 │
|
|
78
|
+
│ Clients 3 connections open │
|
|
79
|
+
│ Running 2h 11m (since 14:02) │
|
|
80
|
+
│ Memory 431 MB · 0.4% CPU │
|
|
81
|
+
│ Directory /Users/slashui/code/shop │
|
|
82
|
+
│ Command node /Users/slashui/code/shop/node_modules/.bin/next dev │
|
|
83
|
+
│ Kill Yes - yours, and as easy to start again as it was to start. Start it again with your … │
|
|
84
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
85
|
+
↑↓/jk move · PgUp/PgDn/g/G jump · / filter · x kill · r rescan · u udp · d detail · m beginner · q …
|
|
31
86
|
```
|
|
32
87
|
|
|
33
88
|
## Install
|
|
@@ -46,9 +101,8 @@ Requires Node 22 or newer. Works on Linux, macOS, and Windows.
|
|
|
46
101
|
|
|
47
102
|
### Updating
|
|
48
103
|
|
|
49
|
-
The current release is
|
|
50
|
-
|
|
51
|
-
and what is published:
|
|
104
|
+
The current release is <!-- release:version -->0.4.0<!-- /release:version -->. To
|
|
105
|
+
see what you have, and what is published:
|
|
52
106
|
|
|
53
107
|
```sh
|
|
54
108
|
slash-port --version # the one you are running
|
|
@@ -90,15 +144,90 @@ reading before you take it.
|
|
|
90
144
|
## Use
|
|
91
145
|
|
|
92
146
|
```sh
|
|
93
|
-
slash-port # the interactive list
|
|
147
|
+
slash-port # the interactive list, in beginner mode
|
|
148
|
+
slash-port --advanced # the same list, with the full detail
|
|
94
149
|
slash-port 3000 # open on port 3000
|
|
95
150
|
slash-port 3xxx # every port from 3000 to 3999
|
|
96
151
|
slash-port 3000:3005 # every port in that range
|
|
97
152
|
slash-port --plain # a plain table, for a pipe or a script
|
|
98
153
|
slash-port --json # the same data as JSON
|
|
99
154
|
slash-port --udp # include UDP as well as TCP
|
|
155
|
+
slash-port --docker # name the container behind a published port
|
|
100
156
|
```
|
|
101
157
|
|
|
158
|
+
### Beginner and advanced
|
|
159
|
+
|
|
160
|
+
There are two modes, and **beginner is the default**. The person who does not
|
|
161
|
+
know what took port 3000 is the person who went looking for a tool that would
|
|
162
|
+
tell them; anyone who already knows can say `--advanced` once, or set
|
|
163
|
+
`SLASH_PORT_MODE=advanced` and never say it again. `m` switches between them
|
|
164
|
+
at any time, and `d` hides the panel in either.
|
|
165
|
+
|
|
166
|
+
| | Beginner | Advanced |
|
|
167
|
+
| --- | --- | --- |
|
|
168
|
+
| Columns | Port, what it is, where to open it, whether to close it | Port, pid, user, process, address, description |
|
|
169
|
+
| Narrow terminals | Keeps the verdict down to forty-two columns; the URL column stands down first, and stands down entirely when no row has one | Drops address, user, process, pid, in that order |
|
|
170
|
+
| Panel | What kind of thing it is, which project, who started it, whether closing it is a good idea, and how to start it again | Parent process, open connections, uptime, memory, working directory, full command line, and how the description was arrived at |
|
|
171
|
+
| Confirmation | Says what closing it costs and how to undo it | Names the signal |
|
|
172
|
+
| Cost | One scan | One scan, plus a lookup for the row under the cursor |
|
|
173
|
+
|
|
174
|
+
Both modes on a working machine, where the list is forty-two ports long
|
|
175
|
+
rather than the tidy eight above:
|
|
176
|
+
|
|
177
|
+

|
|
182
|
+
|
|
183
|
+

|
|
187
|
+
|
|
188
|
+
Advanced mode's extra facts are fetched for the selected row only. A machine
|
|
189
|
+
with four hundred listening sockets would otherwise pay four hundred times over
|
|
190
|
+
for facts you are reading one row at a time.
|
|
191
|
+
|
|
192
|
+
### Docker
|
|
193
|
+
|
|
194
|
+
A published container port shows as `Docker Desktop`, which is true and no help
|
|
195
|
+
at all - and the beginner panel says so rather than leaving you to wonder where
|
|
196
|
+
the name went:
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
200
|
+
│ Port 5432 · Docker Desktop - a container port │
|
|
201
|
+
│ Publishing a port on behalf of a container. │
|
|
202
|
+
│ Container not looked up - re-run with --docker to name it │
|
|
203
|
+
│ Started by you (slashui) · com.docker.backend · pid 39044 │
|
|
204
|
+
│ Close it Probably - yours, but something may be relying on it │
|
|
205
|
+
│ Afterwards Stopping the container that owns the port is the change you prob… │
|
|
206
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`--docker` asks the local engine which container is behind the port. The image
|
|
210
|
+
is read the same way a command line is, so `postgres:16` reports PostgreSQL and
|
|
211
|
+
is treated with the care a database deserves, and the compose project becomes
|
|
212
|
+
the hint - which is how two Supabase stacks on 5432 and 54322 stop being
|
|
213
|
+
interchangeable:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
217
|
+
│ Port 5432 · PostgreSQL in Docker (shop) - a database │
|
|
218
|
+
│ The container shop-db, from the shop compose project, running postgres:16-a… │
|
|
219
|
+
│ Container shop │
|
|
220
|
+
│ Started by you (slashui) · com.docker.backend · pid 39044 │
|
|
221
|
+
│ Close it Probably - stop the container instead: `docker stop shop-db` │
|
|
222
|
+
│ Afterwards Bring it back with `docker compose up -d db`. │
|
|
223
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
It stays off until you ask for it. Reading two local tables and stopping is the
|
|
227
|
+
property this tool is built around, and a nicer default is not worth trading it
|
|
228
|
+
for. `SLASH_PORT_DOCKER=1` turns it on for good if you would rather not type
|
|
229
|
+
it, and `--no-docker` overrules that for one run.
|
|
230
|
+
|
|
102
231
|
### Naming ports
|
|
103
232
|
|
|
104
233
|
`--port` and the interactive filter take the same three forms:
|
|
@@ -140,6 +269,8 @@ There is no flag combination that kills something without naming it first.
|
|
|
140
269
|
| `x` or `Enter` | Kill the selected port |
|
|
141
270
|
| `r` | Rescan |
|
|
142
271
|
| `u` | Show UDP as well as TCP |
|
|
272
|
+
| `m` | Switch between beginner and advanced |
|
|
273
|
+
| `d` | Show or hide the detail panel |
|
|
143
274
|
| `q` | Quit |
|
|
144
275
|
|
|
145
276
|
In the confirmation dialog: `y` sends SIGTERM, `f` forces with SIGKILL, `n`
|
|
@@ -150,7 +281,11 @@ cancels. The kill key is deliberately not next to a navigation key.
|
|
|
150
281
|
| Option | Does |
|
|
151
282
|
| --- | --- |
|
|
152
283
|
| `-p`, `--port <ports>` | Only these ports: `3000`, `3xxx`, or `3000:3005` |
|
|
284
|
+
| `--beginner` | Explain each port in plain language. The default |
|
|
285
|
+
| `--advanced` | Show the full detail instead of the explanations |
|
|
286
|
+
| `--mode <name>` | `beginner` or `advanced`. `SLASH_PORT_MODE` sets the default |
|
|
153
287
|
| `-u`, `--udp` | Include UDP sockets |
|
|
288
|
+
| `--docker` | Ask the local Docker socket which container holds a port. Off by default; `SLASH_PORT_DOCKER=1` sets the default |
|
|
154
289
|
| `--json` | Print JSON and exit |
|
|
155
290
|
| `--plain` | Print a plain table and exit |
|
|
156
291
|
| `--kill` | Kill the process on `--port`. Requires `--yes` |
|
|
@@ -162,6 +297,19 @@ cancels. The kill key is deliberately not next to a navigation key.
|
|
|
162
297
|
| `-h`, `--help` | Show help |
|
|
163
298
|
| `-v`, `--version` | Show the version |
|
|
164
299
|
|
|
300
|
+
### Output for scripts
|
|
301
|
+
|
|
302
|
+
`--json` is the stable machine surface. Fields are added over time and never
|
|
303
|
+
repurposed, so a `jq` expression written against an old version keeps working.
|
|
304
|
+
`description` is `null` rather than a copy of `process` when nothing could be
|
|
305
|
+
identified, which is the one thing worth knowing before parsing it: absence is
|
|
306
|
+
reported as absence.
|
|
307
|
+
|
|
308
|
+
`--plain` keeps the same six columns in both modes and always will, so anything
|
|
309
|
+
already splitting that output keeps working. A mode only ever appends a column
|
|
310
|
+
on the end - what closing it would mean in beginner mode, the full command line
|
|
311
|
+
in advanced.
|
|
312
|
+
|
|
165
313
|
### Exit codes
|
|
166
314
|
|
|
167
315
|
The same codes across every `slash-*` tool, so a script that wraps one can wrap
|
|
@@ -204,11 +352,28 @@ are fixed rather than configurable:
|
|
|
204
352
|
init process, `sshd` - killing it locks you out of a remote machine - macOS
|
|
205
353
|
and Windows session processes, `slash-port` itself, and the shell that
|
|
206
354
|
launched it.
|
|
355
|
+
- **Whether closing it is a good idea is settled before you decide.** Every row
|
|
356
|
+
carries a verdict - `Yes`, `Probably`, `Better not`, `No`, `Needs sudo` -
|
|
357
|
+
worked out from what it is, who owns it, and whether a guardrail already
|
|
358
|
+
refuses it. The verdict is a word in a column, never a colour alone.
|
|
359
|
+
- **The confirmation is never the thing that gets truncated.** On a terminal
|
|
360
|
+
too short to show it and the list behind it, the list gives way; a question
|
|
361
|
+
you cannot read is a question you cannot answer.
|
|
207
362
|
- **SIGTERM before SIGKILL.** A process that ignores SIGTERM is reported as
|
|
208
363
|
having survived. Escalating is a second, deliberate action, never automatic.
|
|
209
364
|
- **A process that has already exited is never signalled**, because by then its
|
|
210
365
|
pid may belong to something else.
|
|
211
366
|
|
|
367
|
+
The confirmation for a row that is safe to close names the process, says what
|
|
368
|
+
closing it costs, and keeps the polite close and the forced one on separate
|
|
369
|
+
keys:
|
|
370
|
+
|
|
371
|
+

|
|
376
|
+
|
|
212
377
|
On Windows there is no signal delivery: SIGTERM becomes `TerminateProcess`,
|
|
213
378
|
which a process cannot catch or ignore, so nothing there gets the chance to
|
|
214
379
|
shut down cleanly. The confirmation still applies - but "terminate" and "force"
|
|
@@ -216,9 +381,17 @@ do the same thing.
|
|
|
216
381
|
|
|
217
382
|
## Privacy
|
|
218
383
|
|
|
219
|
-
`slash-port` makes no network connections at any point.
|
|
220
|
-
socket table and the local process table, and
|
|
221
|
-
telemetry, no update check, and no
|
|
384
|
+
`slash-port` makes no network connections at any point. By default it reads
|
|
385
|
+
the local socket table and the local process table, and asks nothing else on
|
|
386
|
+
the machine anything either. There is no telemetry, no update check, and no
|
|
387
|
+
configuration file.
|
|
388
|
+
|
|
389
|
+
`--docker` is the single exception, and it is off until you ask for it. It
|
|
390
|
+
reads the local Docker socket - a file on this machine, the same as
|
|
391
|
+
`/proc/net/tcp` is - to name the container behind a published port. A
|
|
392
|
+
`DOCKER_HOST` pointing at another machine over TCP is ignored rather than
|
|
393
|
+
connected to. `SLASH_PORT_DOCKER=1` turns it on for good if you would rather
|
|
394
|
+
not type it; `--no-docker` still overrules that for one run.
|
|
222
395
|
|
|
223
396
|
## Terminal behaviour
|
|
224
397
|
|
|
@@ -233,19 +406,50 @@ telemetry, no update check, and no configuration file.
|
|
|
233
406
|
- The list is windowed to the visible rows, so a machine with four hundred
|
|
234
407
|
listening sockets renders a screenful, not four hundred lines.
|
|
235
408
|
- Columns are dropped in order of how little they carry as the window narrows,
|
|
236
|
-
and values that are cut are marked with an ellipsis.
|
|
409
|
+
and values that are cut are marked with an ellipsis. Beginner mode keeps all
|
|
410
|
+
four of its columns down to eighty, because the fourth is the answer.
|
|
411
|
+
- A column that has nothing to show stands down rather than printing a column
|
|
412
|
+
of dashes: `OPEN AT` appears when the rows on screen have URLs.
|
|
237
413
|
|
|
238
414
|
## How it identifies a process
|
|
239
415
|
|
|
240
|
-
|
|
416
|
+
The description column exists to say something the process column did not. So
|
|
417
|
+
the first rule is that it never repeats the process name: when nothing could be
|
|
418
|
+
worked out, it says `-`, because "slash-port has no idea" is a fact and
|
|
419
|
+
`figma_agent` beside `figma_agent` is a column doing nothing.
|
|
420
|
+
|
|
421
|
+
What it consults, in priority order:
|
|
241
422
|
|
|
242
423
|
1. **The command line.** Specific frameworks are matched before the runtimes
|
|
243
424
|
that host them, so `node …/vite` reports Vite rather than Node.js.
|
|
244
|
-
2. **The
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
425
|
+
2. **The container**, if you passed `--docker`. The local engine is asked which
|
|
426
|
+
container publishes the port, and the image is then read like a command
|
|
427
|
+
line, so `postgres:16` reports "PostgreSQL in Docker" and is treated with
|
|
428
|
+
the care a database deserves. The compose project - or the container name
|
|
429
|
+
when there is no project - becomes the hint, which is how `5432` and `54322`
|
|
430
|
+
stop being interchangeable. Without the flag a published port reports
|
|
431
|
+
`Docker Desktop`, and beginner mode says so rather than leaving you to
|
|
432
|
+
wonder why the name is missing.
|
|
433
|
+
3. **The application.** The bundle or install directory the binary sits in,
|
|
434
|
+
so `Code Helper` reports Visual Studio Code and `figma_agent` reports Figma.
|
|
435
|
+
The outermost bundle wins, and a vendor directory beats the bundle inside it.
|
|
436
|
+
4. **The project.** The directory above `node_modules` in the command line, so
|
|
437
|
+
two Vite servers on 5173 and 5174 can be told apart. A directory that only
|
|
438
|
+
names a convention - `lib`, `src`, `bin` - is passed over for the script
|
|
439
|
+
itself, which is why `…/google-cloud-sdk/lib/gcloud.py` reads as `gcloud`.
|
|
440
|
+
5. **A well-known port registry**, for processes that could not be identified
|
|
441
|
+
at all - mostly other users'. Generic entries are demoted rather than
|
|
442
|
+
suppressed: "dev server" loses to anything specific, and beats saying
|
|
443
|
+
nothing.
|
|
444
|
+
6. **The shape of the path.** A binary under `/usr/libexec` is a system service
|
|
445
|
+
whoever wrote it, which is worth more than its own name repeated back.
|
|
446
|
+
|
|
447
|
+
Beginner mode adds one more question on top of all that: whether closing it is
|
|
448
|
+
a good idea. That answer folds together what kind of thing it is, whether you
|
|
449
|
+
own it, and whether a guardrail already refuses it - and the last two win,
|
|
450
|
+
because they are facts about this machine rather than guesses about software. A
|
|
451
|
+
Postgres you do not own is `Needs sudo` whatever anyone thinks of closing
|
|
452
|
+
databases.
|
|
249
453
|
|
|
250
454
|
Per platform:
|
|
251
455
|
|
|
@@ -258,14 +462,22 @@ Per platform:
|
|
|
258
462
|
- **Windows** uses `netstat -ano` and `tasklist`, which exist on every edition
|
|
259
463
|
and avoid PowerShell's startup cost.
|
|
260
464
|
|
|
465
|
+
Advanced mode's per-row lookups follow the same rule of asking the cheapest
|
|
466
|
+
thing that can answer: `/proc` on Linux with no subprocess at all, `ps` and
|
|
467
|
+
`lsof` on macOS, and on Windows only what `tasklist` and `netstat` already
|
|
468
|
+
know. Parents, working directories, and start times need WMI or PowerShell
|
|
469
|
+
there, which cost about a second each, so those lines are left out rather than
|
|
470
|
+
paid for. A platform that cannot answer omits the line; it never guesses.
|
|
471
|
+
|
|
261
472
|
## Not built yet
|
|
262
473
|
|
|
263
474
|
Deliberate omissions, listed so you know they are choices rather than
|
|
264
475
|
oversights:
|
|
265
476
|
|
|
266
|
-
- **Docker awareness
|
|
267
|
-
|
|
268
|
-
is
|
|
477
|
+
- **Docker awareness by default.** `--docker` names the container behind a
|
|
478
|
+
published port, and it stays opt-in. Reading two local tables and stopping is
|
|
479
|
+
the property this tool is built around, and it is not worth trading for a
|
|
480
|
+
nicer default.
|
|
269
481
|
- **Process trees.** Killing a dev server sometimes leaves children behind. A
|
|
270
482
|
`--tree` option would signal the whole group.
|
|
271
483
|
- **Watch mode.** The list rescans on `r`, not on a timer.
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { plainTable, toJson } from './format.js';
|
|
5
5
|
import { killEntry } from './kill.js';
|
|
6
|
+
import { isMode, resolveDocker, resolveMode } from './mode.js';
|
|
6
7
|
import { describePortSelector, looksLikePort, matchesPort, parsePortSelector } from './ports.js';
|
|
7
8
|
import { scan } from './scan/index.js';
|
|
8
9
|
import { ScanError } from './types.js';
|
|
@@ -39,7 +40,9 @@ class UsageError extends Error {
|
|
|
39
40
|
function parseArgs(argv) {
|
|
40
41
|
const options = {
|
|
41
42
|
port: null,
|
|
43
|
+
mode: null,
|
|
42
44
|
udp: false,
|
|
45
|
+
docker: null,
|
|
43
46
|
json: false,
|
|
44
47
|
plain: false,
|
|
45
48
|
kill: false,
|
|
@@ -73,10 +76,29 @@ function parseArgs(argv) {
|
|
|
73
76
|
case '--port':
|
|
74
77
|
options.port = selector(value(argument, argv[++index]));
|
|
75
78
|
break;
|
|
79
|
+
case '--beginner':
|
|
80
|
+
options.mode = 'beginner';
|
|
81
|
+
break;
|
|
82
|
+
case '--advanced':
|
|
83
|
+
options.mode = 'advanced';
|
|
84
|
+
break;
|
|
85
|
+
case '--mode': {
|
|
86
|
+
const raw = value(argument, argv[++index]).toLowerCase();
|
|
87
|
+
if (!isMode(raw))
|
|
88
|
+
throw new UsageError(`${raw} is not a mode. Use beginner or advanced.`);
|
|
89
|
+
options.mode = raw;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
76
92
|
case '-u':
|
|
77
93
|
case '--udp':
|
|
78
94
|
options.udp = true;
|
|
79
95
|
break;
|
|
96
|
+
case '--docker':
|
|
97
|
+
options.docker = true;
|
|
98
|
+
break;
|
|
99
|
+
case '--no-docker':
|
|
100
|
+
options.docker = false;
|
|
101
|
+
break;
|
|
80
102
|
case '--json':
|
|
81
103
|
options.json = true;
|
|
82
104
|
break;
|
|
@@ -159,7 +181,11 @@ Ports
|
|
|
159
181
|
|
|
160
182
|
Options
|
|
161
183
|
-p, --port <ports> Only these ports, in any of the forms above
|
|
184
|
+
--beginner Explain each port in plain language (the default)
|
|
185
|
+
--advanced Show the full detail instead of the explanations
|
|
186
|
+
--mode <name> beginner or advanced. SLASH_PORT_MODE sets the default
|
|
162
187
|
-u, --udp Include UDP sockets as well as TCP
|
|
188
|
+
--docker Ask the local Docker socket which container holds a port
|
|
163
189
|
--json Print JSON to stdout and exit
|
|
164
190
|
--plain Print a plain table and exit
|
|
165
191
|
--kill Kill the process on --port. Requires --yes
|
|
@@ -175,6 +201,13 @@ Keys
|
|
|
175
201
|
up/down or j/k move / filter x or Enter kill
|
|
176
202
|
PgUp/PgDn page r rescan u toggle UDP
|
|
177
203
|
g / G first / last q quit y/f/n confirm dialog
|
|
204
|
+
m switch mode d show or hide the detail panel
|
|
205
|
+
|
|
206
|
+
Modes
|
|
207
|
+
Beginner mode is the default. It says what each port is in plain language,
|
|
208
|
+
where to open it, and whether closing it is a good idea. Advanced mode shows
|
|
209
|
+
pids, users, bind addresses, command lines, working directories, uptime, and
|
|
210
|
+
how many connections are open. Press m to switch, or set SLASH_PORT_MODE.
|
|
178
211
|
|
|
179
212
|
Exit codes
|
|
180
213
|
0 success
|
|
@@ -184,8 +217,12 @@ Exit codes
|
|
|
184
217
|
4 the operation was attempted and failed
|
|
185
218
|
|
|
186
219
|
slash-port never kills without confirmation; never kills init, sshd, your
|
|
187
|
-
session, or the shell that launched it; sends SIGTERM before SIGKILL
|
|
188
|
-
|
|
220
|
+
session, or the shell that launched it; and sends SIGTERM before SIGKILL.
|
|
221
|
+
|
|
222
|
+
It makes no network connections, and asks nothing else on the machine anything
|
|
223
|
+
either. --docker is the single exception: it reads the local Docker socket - a
|
|
224
|
+
file on this machine - for the name of the container behind a published port.
|
|
225
|
+
SLASH_PORT_DOCKER=1 turns that on for good.`;
|
|
189
226
|
function readVersion() {
|
|
190
227
|
try {
|
|
191
228
|
const manifest = readFileSync(new URL('../package.json', import.meta.url), 'utf8');
|
|
@@ -247,6 +284,8 @@ async function main(argv) {
|
|
|
247
284
|
process.stderr.write('\nRun slash-port --help for usage.\n');
|
|
248
285
|
return code;
|
|
249
286
|
}
|
|
287
|
+
const mode = resolveMode(options.mode);
|
|
288
|
+
const docker = resolveDocker(options.docker);
|
|
250
289
|
if (options.help) {
|
|
251
290
|
process.stdout.write(`${HELP}\n`);
|
|
252
291
|
return EXIT_OK;
|
|
@@ -261,7 +300,7 @@ async function main(argv) {
|
|
|
261
300
|
process.env['NO_COLOR'] = '1';
|
|
262
301
|
let entries;
|
|
263
302
|
try {
|
|
264
|
-
entries = await scan({ udp: options.udp });
|
|
303
|
+
entries = await scan({ udp: options.udp, docker });
|
|
265
304
|
}
|
|
266
305
|
catch (error) {
|
|
267
306
|
if (error instanceof ScanError) {
|
|
@@ -283,14 +322,14 @@ async function main(argv) {
|
|
|
283
322
|
process.stdout.write(`${JSON.stringify(toJson(selected), null, 2)}\n`);
|
|
284
323
|
}
|
|
285
324
|
else {
|
|
286
|
-
process.stdout.write(`${plainTable(selected)}\n`);
|
|
325
|
+
process.stdout.write(`${plainTable(selected, mode)}\n`);
|
|
287
326
|
}
|
|
288
327
|
// Asking about a port is a question with a yes-or-no answer, so an empty
|
|
289
328
|
// result means not found. Asking for the whole list is not a question.
|
|
290
329
|
return options.port !== null && selected.length === 0 ? EXIT_NOT_FOUND : EXIT_OK;
|
|
291
330
|
}
|
|
292
331
|
const [{ render }, { App }] = await Promise.all([import('ink'), import('./ui/App.js')]);
|
|
293
|
-
const instance = render(_jsx(App, { initialEntries: entries, initialFilter: options.port === null ? '' : options.port.text, udp: options.udp }));
|
|
332
|
+
const instance = render(_jsx(App, { initialEntries: entries, initialFilter: options.port === null ? '' : options.port.text, udp: options.udp, docker: docker, mode: mode }));
|
|
294
333
|
await instance.waitUntilExit();
|
|
295
334
|
return EXIT_OK;
|
|
296
335
|
}
|