portslayer 1.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 PortSlayer Contributors
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.
@@ -0,0 +1,359 @@
1
+ Metadata-Version: 2.4
2
+ Name: portslayer
3
+ Version: 1.1.0
4
+ Summary: Cross-platform CLI + interactive TUI to list and kill processes by port
5
+ Author: PortSlayer Contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/AppestoX/portslayer
8
+ Project-URL: Repository, https://github.com/AppestoX/portslayer
9
+ Project-URL: Issues, https://github.com/AppestoX/portslayer/issues
10
+ Keywords: port,process,kill,network,cli,tui,devtools
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: System :: Networking :: Monitoring
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: typer>=0.12
28
+ Requires-Dist: rich>=13
29
+ Requires-Dist: textual>=0.60
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8; extra == "dev"
32
+ Requires-Dist: pytest-cov>=5; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # PortSlayer ⚡
36
+
37
+ > Cross-platform CLI + interactive TUI to list active ports and safely kill processes by port number.
38
+
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
40
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://python.org)
41
+ [![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20Windows%20%7C%20macOS-lightgrey)](#)
42
+
43
+ ---
44
+
45
+ ## Features
46
+
47
+ - **Interactive TUI dashboard** — just run `pk` (or `portslayer`): arrow keys to navigate, `/` to search, `k` to kill, live auto-refresh
48
+ - **Short alias** — every command works as both `portslayer <cmd>` and the 2-letter `pk <cmd>`
49
+ - **List all active ports** — port, PID, process name, protocol, state, addresses
50
+ - **Filter** by port number, process name, or protocol (TCP/UDP)
51
+ - **Kill processes by port or by process name** — with mandatory confirmation before any destructive action
52
+ - **JSON output** (`--json`) for scripting, plus built-in shell completion (`--install-completion`)
53
+ - **Cross-platform** — Linux (via `ss`/`lsof`), Windows (via `netstat`/`taskkill`), macOS (via `lsof`)
54
+ - **Install however you like** — pip, npx/npm, or Homebrew/Scoop
55
+
56
+ ---
57
+
58
+ ## Tech Stack
59
+
60
+ | Layer | Technology | Reason |
61
+ |-----------|-----------------------------|---------------------------------------------------------|
62
+ | TUI | Python + Textual | Full-screen keyboard-driven dashboard, no extra runtime for users |
63
+ | CLI | Python + Typer + Rich | Single language, beautiful tables, type-safe commands |
64
+ | Core | Pure Python stdlib | No external dependencies for port scanning / killing |
65
+ | Tests | pytest | Simple, fast, widely adopted |
66
+ | Packaging | pyproject.toml (setuptools) | PEP 517/518 standard, pip-installable |
67
+
68
+ ---
69
+
70
+ ## Installation
71
+
72
+ Pick whichever package manager you already have — they all install the same
73
+ tool.
74
+
75
+ ```bash
76
+ pip install portslayer # Python / pip
77
+ npx @appestox/portslayer # Node.js — try it with zero install
78
+ npm install -g @appestox/portslayer # Node.js — install permanently
79
+ uvx portslayer # zero-install, no Python setup needed
80
+ brew install AppestoX/PortSlayer/portslayer # Homebrew (macOS/Linux)
81
+ scoop bucket add AppestoX https://github.com/AppestoX/scoop-bucket
82
+ scoop install portslayer # Scoop (Windows)
83
+ ```
84
+
85
+ The npm, Homebrew, and Scoop packages are thin wrappers that install the
86
+ same `portslayer` PyPI package underneath — see
87
+ [`packaging/`](packaging/) for how each is built and published.
88
+
89
+ ### Prerequisites
90
+
91
+ - Python 3.10 or later (the npm/Homebrew/Scoop wrappers install this
92
+ dependency for you if it's missing)
93
+
94
+ ### Install from source
95
+
96
+ ```bash
97
+ git clone https://github.com/AppestoX/portslayer.git
98
+ cd portslayer
99
+ pip install -e ".[dev]"
100
+ ```
101
+
102
+ ### Linux — additional notes
103
+
104
+ No extra system packages required. `ss` is available by default on all modern
105
+ Linux distributions (`iproute2`). `lsof` is used as a fallback if `ss` is
106
+ not available.
107
+
108
+ To see processes owned by other users you must run with `sudo`:
109
+
110
+ ```bash
111
+ sudo portslayer list
112
+ ```
113
+
114
+ ### Windows — additional notes
115
+
116
+ Run PowerShell or Command Prompt **as Administrator** to see all processes.
117
+ `netstat` and `taskkill` are built into every Windows installation.
118
+
119
+ ---
120
+
121
+ ## Usage
122
+
123
+ ### Interactive TUI (recommended)
124
+
125
+ ```bash
126
+ pk
127
+ ```
128
+
129
+ (`pk` is the short alias for `portslayer` — both commands are identical and installed together; use whichever you prefer. The rest of this doc uses `portslayer` for clarity, but `pk` works everywhere it does.)
130
+
131
+ Launches a full-screen dashboard — no flags to remember:
132
+
133
+ | Key | Action |
134
+ |-------------|----------------------------------|
135
+ | `↑` / `↓` | Navigate the port list |
136
+ | `/` | Search/filter (port, process, protocol, state) |
137
+ | `k` / `Del` | Kill the selected process (asks to confirm) |
138
+ | `r` | Refresh now (auto-refreshes every 3s anyway) |
139
+ | `Esc` | Clear search |
140
+ | `q` | Quit |
141
+
142
+ ### CLI
143
+
144
+ #### List all active ports
145
+
146
+ ```bash
147
+ portslayer list
148
+ ```
149
+
150
+ Sample output:
151
+
152
+ ```
153
+ ╭────────────────────────────────────────────────────────────────────╮
154
+ │ Active Ports (24 entries) │
155
+ ├──────┬──────────┬─────────────┬───────┬────────────┬──────────────┤
156
+ │ Port │ Protocol │ State │ PID │ Process │ Local Address│
157
+ ├──────┼──────────┼─────────────┼───────┼────────────┼──────────────┤
158
+ │ 22 │ TCP │ LISTEN │ 783 │ sshd │ 0.0.0.0:22 │
159
+ │ 80 │ TCP │ LISTEN │ 1042 │ nginx │ 0.0.0.0:80 │
160
+ │ 5432 │ TCP │ LISTEN │ 2103 │ postgres │ 127.0.0.1:… │
161
+ ╰──────┴──────────┴─────────────┴───────┴────────────┴──────────────╯
162
+ ```
163
+
164
+ #### Filter ports
165
+
166
+ ```bash
167
+ # By exact port number
168
+ portslayer list --port 443
169
+
170
+ # By partial port prefix — matches every port starting with these digits
171
+ portslayer list --port 808 # -> 8080, 8081, 8083, ...
172
+
173
+ # By process name (partial match)
174
+ portslayer list --process nginx
175
+
176
+ # By protocol
177
+ portslayer list --protocol tcp
178
+
179
+ # Only LISTENING ports
180
+ portslayer list --listening
181
+
182
+ # Combine filters
183
+ portslayer list --protocol tcp --listening
184
+ ```
185
+
186
+ #### Inspect a specific port — or a partial prefix
187
+
188
+ ```bash
189
+ portslayer find 8080 # exact port
190
+ portslayer find 808 # partial prefix -> matches 8080, 8081, 8083, ...
191
+ ```
192
+
193
+ Typing fewer digits is a feature, not an error — no need to remember or
194
+ type the full number if you just want to see everything in that range.
195
+
196
+ #### Kill the process on a port
197
+
198
+ ```bash
199
+ portslayer kill 3000
200
+ ```
201
+
202
+ `kill` always requires an **exact** port number (not a prefix) — this is a
203
+ deliberate safety choice so a mistyped digit can't broaden which processes
204
+ get terminated. Use `find`/`list` with a prefix first to see what's there,
205
+ then `kill` the exact port you want.
206
+
207
+ ```bash
208
+ # Kill by process name instead of port (kills every port that process owns)
209
+ portslayer kill --name node
210
+ ```
211
+
212
+ PortSlayer will:
213
+ 1. Show full process details
214
+ 2. Ask for explicit confirmation
215
+ 3. Kill the process only after `y` is entered
216
+
217
+ ```bash
218
+ # Skip confirmation (use with care)
219
+ portslayer kill 3000 --force
220
+ ```
221
+
222
+ #### Scripting with JSON output
223
+
224
+ `list` and `find` both accept `--json` for piping into `jq` or other tools
225
+ instead of printing a table:
226
+
227
+ ```bash
228
+ portslayer list --json | jq '.[] | select(.protocol == "TCP")'
229
+ portslayer find 808 --json
230
+ ```
231
+
232
+ #### Shell completion
233
+
234
+ Typer wires this up automatically — no extra setup needed:
235
+
236
+ ```bash
237
+ portslayer --install-completion # installs completion for your current shell
238
+ ```
239
+
240
+ #### Version
241
+
242
+ ```bash
243
+ portslayer --version
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Project Structure
249
+
250
+ ```
251
+ portslayer/
252
+ ├── portslayer/
253
+ │ ├── __init__.py # Package version / metadata
254
+ │ ├── cli.py # Typer CLI (list / find / kill) — bare invocation launches the TUI
255
+ │ ├── tui.py # Textual interactive dashboard
256
+ │ ├── core/
257
+ │ │ ├── __init__.py
258
+ │ │ ├── models.py # PortInfo dataclass
259
+ │ │ ├── port_scanner.py # Platform-specific scanning + parsers
260
+ │ │ └── process_killer.py# Safe process termination
261
+ │ └── utils/
262
+ │ ├── __init__.py
263
+ │ ├── platform_utils.py# OS detection, admin check
264
+ │ └── validators.py # Port number validation
265
+ ├── tests/
266
+ │ ├── test_validators.py
267
+ │ ├── test_port_scanner.py
268
+ │ └── test_process_killer.py
269
+ ├── packaging/
270
+ │ ├── npm/ # npm wrapper package (`npx @appestox/portslayer`)
271
+ │ ├── homebrew/ # Homebrew tap formula
272
+ │ └── scoop/ # Scoop bucket manifest
273
+ ├── pyproject.toml
274
+ ├── requirements.txt
275
+ ├── requirements-dev.txt
276
+ ├── LICENSE
277
+ └── README.md
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Running Tests
283
+
284
+ ```bash
285
+ pip install -e ".[dev]"
286
+ pytest
287
+ ```
288
+
289
+ With coverage:
290
+
291
+ ```bash
292
+ pytest --cov=portslayer --cov-report=term-missing
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Security
298
+
299
+ | Concern | Mitigation |
300
+ |----------------------------|------------------------------------------------------------------------|
301
+ | Command injection | All subprocess calls use **explicit argument lists** — never `shell=True` |
302
+ | Input validation | Port numbers are validated (regex + range check) before any system call |
303
+ | Confirmation requirement | Every kill operation requires explicit user confirmation |
304
+ | Privilege transparency | Users are warned when not running as root/Administrator |
305
+ | PID validation | PID existence is verified before sending signals |
306
+
307
+ **PortSlayer never executes raw shell input from the user.**
308
+
309
+ ---
310
+
311
+ ## Platform-Specific Commands Used
312
+
313
+ | Platform | List ports | Get process names | Kill process |
314
+ |----------|--------------------------------|-------------------------|-----------------------------|
315
+ | Linux | `ss -tulnp` → `lsof -i -n -P` | embedded in `ss` output | `os.kill(pid, SIGKILL)` |
316
+ | Windows | `netstat -ano` | `tasklist /FO CSV /NH` | `taskkill /PID <pid> /F` |
317
+ | macOS | `lsof -i -n -P` | embedded in `lsof` | `os.kill(pid, SIGKILL)` |
318
+
319
+ ---
320
+
321
+ ## Publishing (maintainers)
322
+
323
+ Order matters — the npm, Homebrew, and Scoop packages all install the PyPI
324
+ package under the hood, so PyPI goes first.
325
+
326
+ 1. **PyPI** (source of truth):
327
+ ```bash
328
+ python -m pip install build twine
329
+ python -m build
330
+ twine upload dist/*
331
+ ```
332
+ 2. **npm wrapper** (`packaging/npm/`) — bump `version` in
333
+ `packaging/npm/package.json` to match the PyPI release, then:
334
+ ```bash
335
+ cd packaging/npm && npm publish
336
+ ```
337
+ 3. **Homebrew tap** (`packaging/homebrew/`) — see
338
+ [`packaging/homebrew/README.md`](packaging/homebrew/README.md) for
339
+ generating dependency resource blocks and the sdist checksum, then push
340
+ to your `homebrew-portslayer` tap repo.
341
+ 4. **Scoop bucket** (`packaging/scoop/`) — see
342
+ [`packaging/scoop/README.md`](packaging/scoop/README.md) for the
343
+ checksum step, then push to your bucket repo. Winget requires a compiled
344
+ installer and is documented as a follow-up in the same file.
345
+
346
+ ---
347
+
348
+ ## Contributing
349
+
350
+ 1. Fork the repository
351
+ 2. Create a feature branch: `git checkout -b feat/my-feature`
352
+ 3. Run tests: `pytest`
353
+ 4. Open a pull request
354
+
355
+ ---
356
+
357
+ ## License
358
+
359
+ [MIT](LICENSE) — free to use, modify, and distribute.
@@ -0,0 +1,325 @@
1
+ # PortSlayer ⚡
2
+
3
+ > Cross-platform CLI + interactive TUI to list active ports and safely kill processes by port number.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://python.org)
7
+ [![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20Windows%20%7C%20macOS-lightgrey)](#)
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **Interactive TUI dashboard** — just run `pk` (or `portslayer`): arrow keys to navigate, `/` to search, `k` to kill, live auto-refresh
14
+ - **Short alias** — every command works as both `portslayer <cmd>` and the 2-letter `pk <cmd>`
15
+ - **List all active ports** — port, PID, process name, protocol, state, addresses
16
+ - **Filter** by port number, process name, or protocol (TCP/UDP)
17
+ - **Kill processes by port or by process name** — with mandatory confirmation before any destructive action
18
+ - **JSON output** (`--json`) for scripting, plus built-in shell completion (`--install-completion`)
19
+ - **Cross-platform** — Linux (via `ss`/`lsof`), Windows (via `netstat`/`taskkill`), macOS (via `lsof`)
20
+ - **Install however you like** — pip, npx/npm, or Homebrew/Scoop
21
+
22
+ ---
23
+
24
+ ## Tech Stack
25
+
26
+ | Layer | Technology | Reason |
27
+ |-----------|-----------------------------|---------------------------------------------------------|
28
+ | TUI | Python + Textual | Full-screen keyboard-driven dashboard, no extra runtime for users |
29
+ | CLI | Python + Typer + Rich | Single language, beautiful tables, type-safe commands |
30
+ | Core | Pure Python stdlib | No external dependencies for port scanning / killing |
31
+ | Tests | pytest | Simple, fast, widely adopted |
32
+ | Packaging | pyproject.toml (setuptools) | PEP 517/518 standard, pip-installable |
33
+
34
+ ---
35
+
36
+ ## Installation
37
+
38
+ Pick whichever package manager you already have — they all install the same
39
+ tool.
40
+
41
+ ```bash
42
+ pip install portslayer # Python / pip
43
+ npx @appestox/portslayer # Node.js — try it with zero install
44
+ npm install -g @appestox/portslayer # Node.js — install permanently
45
+ uvx portslayer # zero-install, no Python setup needed
46
+ brew install AppestoX/PortSlayer/portslayer # Homebrew (macOS/Linux)
47
+ scoop bucket add AppestoX https://github.com/AppestoX/scoop-bucket
48
+ scoop install portslayer # Scoop (Windows)
49
+ ```
50
+
51
+ The npm, Homebrew, and Scoop packages are thin wrappers that install the
52
+ same `portslayer` PyPI package underneath — see
53
+ [`packaging/`](packaging/) for how each is built and published.
54
+
55
+ ### Prerequisites
56
+
57
+ - Python 3.10 or later (the npm/Homebrew/Scoop wrappers install this
58
+ dependency for you if it's missing)
59
+
60
+ ### Install from source
61
+
62
+ ```bash
63
+ git clone https://github.com/AppestoX/portslayer.git
64
+ cd portslayer
65
+ pip install -e ".[dev]"
66
+ ```
67
+
68
+ ### Linux — additional notes
69
+
70
+ No extra system packages required. `ss` is available by default on all modern
71
+ Linux distributions (`iproute2`). `lsof` is used as a fallback if `ss` is
72
+ not available.
73
+
74
+ To see processes owned by other users you must run with `sudo`:
75
+
76
+ ```bash
77
+ sudo portslayer list
78
+ ```
79
+
80
+ ### Windows — additional notes
81
+
82
+ Run PowerShell or Command Prompt **as Administrator** to see all processes.
83
+ `netstat` and `taskkill` are built into every Windows installation.
84
+
85
+ ---
86
+
87
+ ## Usage
88
+
89
+ ### Interactive TUI (recommended)
90
+
91
+ ```bash
92
+ pk
93
+ ```
94
+
95
+ (`pk` is the short alias for `portslayer` — both commands are identical and installed together; use whichever you prefer. The rest of this doc uses `portslayer` for clarity, but `pk` works everywhere it does.)
96
+
97
+ Launches a full-screen dashboard — no flags to remember:
98
+
99
+ | Key | Action |
100
+ |-------------|----------------------------------|
101
+ | `↑` / `↓` | Navigate the port list |
102
+ | `/` | Search/filter (port, process, protocol, state) |
103
+ | `k` / `Del` | Kill the selected process (asks to confirm) |
104
+ | `r` | Refresh now (auto-refreshes every 3s anyway) |
105
+ | `Esc` | Clear search |
106
+ | `q` | Quit |
107
+
108
+ ### CLI
109
+
110
+ #### List all active ports
111
+
112
+ ```bash
113
+ portslayer list
114
+ ```
115
+
116
+ Sample output:
117
+
118
+ ```
119
+ ╭────────────────────────────────────────────────────────────────────╮
120
+ │ Active Ports (24 entries) │
121
+ ├──────┬──────────┬─────────────┬───────┬────────────┬──────────────┤
122
+ │ Port │ Protocol │ State │ PID │ Process │ Local Address│
123
+ ├──────┼──────────┼─────────────┼───────┼────────────┼──────────────┤
124
+ │ 22 │ TCP │ LISTEN │ 783 │ sshd │ 0.0.0.0:22 │
125
+ │ 80 │ TCP │ LISTEN │ 1042 │ nginx │ 0.0.0.0:80 │
126
+ │ 5432 │ TCP │ LISTEN │ 2103 │ postgres │ 127.0.0.1:… │
127
+ ╰──────┴──────────┴─────────────┴───────┴────────────┴──────────────╯
128
+ ```
129
+
130
+ #### Filter ports
131
+
132
+ ```bash
133
+ # By exact port number
134
+ portslayer list --port 443
135
+
136
+ # By partial port prefix — matches every port starting with these digits
137
+ portslayer list --port 808 # -> 8080, 8081, 8083, ...
138
+
139
+ # By process name (partial match)
140
+ portslayer list --process nginx
141
+
142
+ # By protocol
143
+ portslayer list --protocol tcp
144
+
145
+ # Only LISTENING ports
146
+ portslayer list --listening
147
+
148
+ # Combine filters
149
+ portslayer list --protocol tcp --listening
150
+ ```
151
+
152
+ #### Inspect a specific port — or a partial prefix
153
+
154
+ ```bash
155
+ portslayer find 8080 # exact port
156
+ portslayer find 808 # partial prefix -> matches 8080, 8081, 8083, ...
157
+ ```
158
+
159
+ Typing fewer digits is a feature, not an error — no need to remember or
160
+ type the full number if you just want to see everything in that range.
161
+
162
+ #### Kill the process on a port
163
+
164
+ ```bash
165
+ portslayer kill 3000
166
+ ```
167
+
168
+ `kill` always requires an **exact** port number (not a prefix) — this is a
169
+ deliberate safety choice so a mistyped digit can't broaden which processes
170
+ get terminated. Use `find`/`list` with a prefix first to see what's there,
171
+ then `kill` the exact port you want.
172
+
173
+ ```bash
174
+ # Kill by process name instead of port (kills every port that process owns)
175
+ portslayer kill --name node
176
+ ```
177
+
178
+ PortSlayer will:
179
+ 1. Show full process details
180
+ 2. Ask for explicit confirmation
181
+ 3. Kill the process only after `y` is entered
182
+
183
+ ```bash
184
+ # Skip confirmation (use with care)
185
+ portslayer kill 3000 --force
186
+ ```
187
+
188
+ #### Scripting with JSON output
189
+
190
+ `list` and `find` both accept `--json` for piping into `jq` or other tools
191
+ instead of printing a table:
192
+
193
+ ```bash
194
+ portslayer list --json | jq '.[] | select(.protocol == "TCP")'
195
+ portslayer find 808 --json
196
+ ```
197
+
198
+ #### Shell completion
199
+
200
+ Typer wires this up automatically — no extra setup needed:
201
+
202
+ ```bash
203
+ portslayer --install-completion # installs completion for your current shell
204
+ ```
205
+
206
+ #### Version
207
+
208
+ ```bash
209
+ portslayer --version
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Project Structure
215
+
216
+ ```
217
+ portslayer/
218
+ ├── portslayer/
219
+ │ ├── __init__.py # Package version / metadata
220
+ │ ├── cli.py # Typer CLI (list / find / kill) — bare invocation launches the TUI
221
+ │ ├── tui.py # Textual interactive dashboard
222
+ │ ├── core/
223
+ │ │ ├── __init__.py
224
+ │ │ ├── models.py # PortInfo dataclass
225
+ │ │ ├── port_scanner.py # Platform-specific scanning + parsers
226
+ │ │ └── process_killer.py# Safe process termination
227
+ │ └── utils/
228
+ │ ├── __init__.py
229
+ │ ├── platform_utils.py# OS detection, admin check
230
+ │ └── validators.py # Port number validation
231
+ ├── tests/
232
+ │ ├── test_validators.py
233
+ │ ├── test_port_scanner.py
234
+ │ └── test_process_killer.py
235
+ ├── packaging/
236
+ │ ├── npm/ # npm wrapper package (`npx @appestox/portslayer`)
237
+ │ ├── homebrew/ # Homebrew tap formula
238
+ │ └── scoop/ # Scoop bucket manifest
239
+ ├── pyproject.toml
240
+ ├── requirements.txt
241
+ ├── requirements-dev.txt
242
+ ├── LICENSE
243
+ └── README.md
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Running Tests
249
+
250
+ ```bash
251
+ pip install -e ".[dev]"
252
+ pytest
253
+ ```
254
+
255
+ With coverage:
256
+
257
+ ```bash
258
+ pytest --cov=portslayer --cov-report=term-missing
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Security
264
+
265
+ | Concern | Mitigation |
266
+ |----------------------------|------------------------------------------------------------------------|
267
+ | Command injection | All subprocess calls use **explicit argument lists** — never `shell=True` |
268
+ | Input validation | Port numbers are validated (regex + range check) before any system call |
269
+ | Confirmation requirement | Every kill operation requires explicit user confirmation |
270
+ | Privilege transparency | Users are warned when not running as root/Administrator |
271
+ | PID validation | PID existence is verified before sending signals |
272
+
273
+ **PortSlayer never executes raw shell input from the user.**
274
+
275
+ ---
276
+
277
+ ## Platform-Specific Commands Used
278
+
279
+ | Platform | List ports | Get process names | Kill process |
280
+ |----------|--------------------------------|-------------------------|-----------------------------|
281
+ | Linux | `ss -tulnp` → `lsof -i -n -P` | embedded in `ss` output | `os.kill(pid, SIGKILL)` |
282
+ | Windows | `netstat -ano` | `tasklist /FO CSV /NH` | `taskkill /PID <pid> /F` |
283
+ | macOS | `lsof -i -n -P` | embedded in `lsof` | `os.kill(pid, SIGKILL)` |
284
+
285
+ ---
286
+
287
+ ## Publishing (maintainers)
288
+
289
+ Order matters — the npm, Homebrew, and Scoop packages all install the PyPI
290
+ package under the hood, so PyPI goes first.
291
+
292
+ 1. **PyPI** (source of truth):
293
+ ```bash
294
+ python -m pip install build twine
295
+ python -m build
296
+ twine upload dist/*
297
+ ```
298
+ 2. **npm wrapper** (`packaging/npm/`) — bump `version` in
299
+ `packaging/npm/package.json` to match the PyPI release, then:
300
+ ```bash
301
+ cd packaging/npm && npm publish
302
+ ```
303
+ 3. **Homebrew tap** (`packaging/homebrew/`) — see
304
+ [`packaging/homebrew/README.md`](packaging/homebrew/README.md) for
305
+ generating dependency resource blocks and the sdist checksum, then push
306
+ to your `homebrew-portslayer` tap repo.
307
+ 4. **Scoop bucket** (`packaging/scoop/`) — see
308
+ [`packaging/scoop/README.md`](packaging/scoop/README.md) for the
309
+ checksum step, then push to your bucket repo. Winget requires a compiled
310
+ installer and is documented as a follow-up in the same file.
311
+
312
+ ---
313
+
314
+ ## Contributing
315
+
316
+ 1. Fork the repository
317
+ 2. Create a feature branch: `git checkout -b feat/my-feature`
318
+ 3. Run tests: `pytest`
319
+ 4. Open a pull request
320
+
321
+ ---
322
+
323
+ ## License
324
+
325
+ [MIT](LICENSE) — free to use, modify, and distribute.