Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions extensions/portreaper/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Portreaper Changelog

## [Initial Version] - {PR_MERGE_DATE}

- List every process listening on a TCP port, plus **orphaned dev processes that hold no port at all** (an `electron-vite` main process left behind when its parent `node` was killed is invisible to a port scan, but is exactly the kind of residue worth reaping)
- Zombie-suspect classification with confidence tiers (`confirmed` / `likely` / `possible`) and the evidence behind each verdict
- Terminate or force-kill a process, with PID-reuse protection: the engine re-checks the process creation time before killing, so a recycled PID can never be hit by mistake
- Star a process to exempt it from suspicion — the whitelist is the same file the desktop app uses, so stars cross over in both directions
- Detail panel showing the launcher chain, subtree CPU (a headless browser burns CPU in child processes while its main process reads ~0%), memory, and uptime
- The classification engine is downloaded from the project's GitHub release on first run and verified against its published SHA-256 checksum
44 changes: 44 additions & 0 deletions extensions/portreaper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Portreaper

Find the orphaned dev-server processes squatting on your ports, and reap them from Raycast.

You kill a terminal, but the `vite` / `node` / `cargo run` it launched keeps running — reparented to the OS, still holding port 3000. Next time you `npm run dev` the port is "already in use" and you have no idea which ghost to kill.

Portreaper is not a generic port viewer. Its job is to **decide which listeners are orphaned dev-server zombies**, so you can act on a verdict instead of a raw process list.

## What you get

- **Every TCP listener**, plus **orphaned dev processes that hold no port at all**. A leftover `electron-vite` main process — adopted by launchd after its parent `node` died, listening on nothing — is invisible to a port scan, but it is exactly the kind of residue worth clearing.
- **A verdict with its evidence.** Suspects are tiered `confirmed` / `likely` / `possible`, and every row shows the signals behind the call: reparented to PID 1, launcher chain ends at a dead shell, dead terminal session, dev-server command line, duplicate instance of the same project.
- **Exemptions applied automatically.** Processes managed by `launchd`, `brew services`, or `pm2`, and anything installed in a standard location, are never flagged.
- **Detail on demand:** launcher chain, uptime, memory, and subtree CPU — a headless browser burns CPU in child processes while its own row reads ~0%, so the subtree total is what tells you it is actually spinning.
- **Star anything to exempt it permanently.** A daemon you detached on purpose is behaviorally identical to an accidental zombie; star it once and it stops being flagged.

## Terminating is safe by construction

The engine captures each process's creation time during the scan and **re-checks it immediately before killing**. If it moved, the kill is refused. That closes the window where a PID gets recycled between the moment you look at the list and the moment you press Enter — killing a recycled PID would mean terminating an unrelated process.

Termination always asks for confirmation first.

## Shared with the desktop app

Portreaper also ships as a macOS menubar app. Both frontends run the same classification engine and read the same whitelist file, so a star you add here shows up in the desktop app's next scan (within ~2 seconds) and vice versa.

The desktop app is optional — this extension works on its own.

## First run: the engine binary

The classification logic lives in a small command-line binary, `portreaper-cli`. On first use the extension **downloads it from the project's GitHub release and verifies it against the published SHA-256 checksum**; a binary that fails verification is deleted, never executed. Nothing is installed system-wide — the binary lives in the extension's own support directory.

If you already have it (built from source, or installed via `cargo install`), the extension finds it automatically. To point at a copy in an unusual location, set **portreaper-cli path** in the extension preferences.

## Why verdict reasons look like `ppid1_orphan`

Reason codes are shown exactly as the engine emits them. This extension is for developers, and `ppid1_orphan` carries more information than a vague paraphrase — it names the precise signal that fired. The desktop app's detail panel explains each code in prose.

## Links

- [Portreaper on GitHub](https://github.com/fanhefeng/portreaper) — source, releases, and the desktop app
- [How detection works](https://github.com/fanhefeng/portreaper#how-detection-works) — the full signal/exemption/confidence model

MIT licensed.
Binary file added extensions/portreaper/assets/command-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extensions/portreaper/metadata/portreaper-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extensions/portreaper/metadata/portreaper-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extensions/portreaper/metadata/portreaper-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extensions/portreaper/metadata/portreaper-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading