0.1.0
Release Notes
Changed
-
Windows TUI/CLI termination now separates user intent from the underlying
delivery mechanism: lowercasex/ non---forceis a normal termination
request withyconfirmation, while uppercaseX/--forcekeeps the
stronger typedforceconfirmation. Windows still delivers both through
TerminateProcessbecause Kickoutchi does not have a reliable graceful
process-handle equivalent; the confirmation copy and project notes now state
that plainly instead of making lowercasexlook like an accidental force key. -
The Windows protected-process defaults now include core Windows process names
such asSystem,svchost.exe,services.exe,lsass.exe,wininit.exe,
and Docker/Postgres.exevariants. The system/service classifier also treats
PID 4, known Windows OS process names, and children ofservices.exeas
system/service rows for warning and optional hiding. -
CLI kill now performs a best-effort post-kill port refresh after a successful
termination and reports whether the confirmed target ports are still visible,
instead of only telling the user to refresh manually. -
Linux termination now opens a pidfd before the mandatory pre-signal
revalidation and sendsSIGTERM/SIGKILLthroughpidfd_send_signalinstead
of rawkill(pid, signal). This keeps the signal tied to the prepared process
handle after the PID/start-time/port checks pass. It raises the floor for
termination to Linux 5.3+ (pidfd_open); older kernels fail closed with an
actionable error that names the requirement, without sending a signal. -
TUI refresh now uses a single in-flight background worker instead of running
the full Linux/proc/<pid>/fdowner scan on the render/input loop. The last
good snapshot remains visible while refresh is running. The first snapshot is
still collected synchronously so the TUI opens onto real rows instead of a
blank table, and any in-flight background refresh is abandoned when a
synchronous snapshot (such as the post-kill refresh) is applied, so a stale
scan cannot overwrite newer rows. -
Safe termination now carries an internal Linux process-start identity from
/proc/<pid>/statthrough confirmation and pre-signal revalidation. The raw
tick value is not rendered or serialized, but it lets Kickoutchi refuse a kill
if PID reuse is detected before the signal boundary. -
Post-Phase-6 internal cleanup, no external behavior change: collapsed the
duplicateKillTargetconstructor into a singlefrom_entries, switched the
confirmation modal's force-mode check from a signal-label string comparison to
KillModeequality, and narrowedcurrent_user_idto private. -
Comment accuracy, no behavior change:
PortEntry.child_pidsis now documented
as a reserved field that stays empty on real rows (the Linux collector never
fills it; selected-row children live inProcessContext, and it remains only
for thelist --jsonshape and the fake fixture); the already-exited TUI kill
test no longer describes the removed "refreshed snapshot" status wording; and
parse_process_start_time_ticksnow explains why it right-splits on") "so
an unescaped)insidecommcannot be mistaken for the field terminator. -
The
KillTargetconstruction invariants are now release assertions instead of
debug-only ones: the target must contain at least one row, and every row's PID
must match the target PID. A future caller that builds a kill target from no
rows, or from rows owned by another PID, now fails fast on the termination path
instead of carrying a degenerate, port-less, or mis-targeted target forward. -
Linux collector owner resolution now only records owners for socket inodes
found in the collected/proc/net/*rows. It keeps every PID that references a
target socket inode, so forked or inherited listening sockets are represented
as multiple candidate owners instead of being collapsed to whichever PID was
scanned first. -
Linux collector now reads
/proc/<pid>/statusthrough a byte-bounded reader,
matching the existing cap on/proc/<pid>/cmdline, so every/procread in the
collector is explicitly limited;PPidsits near the top ofstatus, so the
cap never truncates the parent PID. -
TUI/CLI query matching now normalizes text filter needles once per query and
avoids formatting socket-address strings unless the search text is
socket-shaped, reducing per-keypress allocations in search mode. -
Removed the unused direct
anyhowdependency fromCargo.toml; typed module
errors remain the current error boundary. -
No-match port related-process diagnostics now use stricter rules that keep the
main table limited to OS-confirmed sockets, preserve CLI exit codes, avoid
polluting JSON output, and require port-shaped matchers instead of raw
substring matching. -
protected_processesin the config file now extends the built-in defaults
instead of replacing them, with exact-match de-duplication. Addingredis
no longer silently removes protection fromsystemd,postgres, and the
other defaults; this matches the documented "can be extended in config"
behavior. -
Internal restructure: shared application code moved from
src/main.rsto
src/lib.rs(public surface: a singlekickoutchi::run()), with thin
binary wrappers insrc/bin/kickoutchi.rsandsrc/bin/kick.rs. Behavior
is unchanged; the shared code now compiles once for both binaries, unit
tests no longer run twice, and the duplicate-target Cargo warning is gone.
Fixed
-
Docker details enrichment now runs through a selected-row background worker, so
opening details on a slow Docker host no longer blocks TUI input. Docker
enrichment also works for partial-metadata rows with no readable process name
when Docker reports a matching published host port. -
Windows termination liveness check now uses
WaitForSingleObject(handle, 0)
instead of comparingGetExitCodeProcessagainstSTILL_ACTIVE, removing
the ambiguity where exit code 259 was indistinguishable from "still running". -
Protected-process confirmation now compares user input against the
sanitized process name, so what the prompt displays is exactly what the
user must type (PID fallback still works). -
Windows TUI Caps Lock behavior no longer turns an intended lowercase
xinto
force-kill. The force-kill key now requires an explicit Shift-modifiedX, so
a Caps Lock uppercaseXstays on the normal termination path. -
Typed force confirmation now accepts
forcecase-insensitively, soFORCE
does not trap users who entered the confirmation prompt with Caps Lock enabled. -
Protected-process confirmation now matches process names case-insensitively on
Windows, matching Windows protected-name policy. -
Windows termination now waits briefly for a successful
TerminateProcesscall
to complete before reporting success, reducing stale post-kill refreshes where
a port can still appear immediately after the kill request. -
No-match related-process diagnostics now skip Kickoutchi's current process and
its ancestors, avoiding false hints for the parent PowerShell/cargo command
that launchedkick list --port <PORT>. -
CLI
kill --yesnow prints the target banner — identity, ports, equivalent
command, and any safety warnings (system/service process, ownership by another
uid, partial metadata, child processes) — to stderr before signalling, instead
of showing them only on the interactive confirmation path.--yesopts out of
the prompt, not the warnings; the protected-process and unsafe-PID gates are
unchanged, and stdout and exit codes are untouched so scripts are unaffected. -
TUI kill status lines now report only the signal outcome instead of also
claiming a refreshed snapshot before the post-kill re-collect has run. The freed
port still drops from the table via the best-effort refresh, but a failed
re-collect surfaces as the usual error line rather than a status that overstates
a refresh that did not happen. -
TUI header now lists
x/X killso the force-kill key is discoverable from the
main screen, matching the input handling and the help modal. -
TUI termination now re-collects the port snapshot when a target exits between
confirmation andpidfd_open. The prepare-error already-exited path returned
without re-collecting, leaving the freed port on the table for up to one refresh
interval. Other prepare failures (permission denied, an old kernel) leave the
process running, so the table is already current for them. -
Termination confirmations now warn when a target is classified as a
system/service process, not only when it is on the protected-process list. -
Pre-signal revalidation now reports ownership unavailable if any confirmed
target port becomes visible without a readable PID, including mixed cases where
another confirmed port still has the original PID. -
No-match related-process diagnostics no longer treat colon-shaped incidental
tokens such asduration:3000msorhost:3000abcas socket evidence. -
kill --portnow refuses inherited/shared listening sockets instead of
signaling one arbitrary owner and reporting success while another process keeps
the port open. The Linux collector emits one row per PID referencing the same
socket inode, which lets the existing ambiguous-target guard list every
candidate and require--pid. -
kill --porton a visible port whose owning PID is unavailable now exits with
the documented permission-denied code4instead of the no-match code3,
including when ownership becomes unavailable during the mandatory pre-signal
revalidation. -
kill --pidnow matcheskill --portand the TUI when a confirmed target port
stays visible but its owning PID becomes unreadable during pre-signal
revalidation: it exits with the permission-denied code4instead of the
no-match code3, and still sends no signal. A shared ownership-unavailable
check now backs all three paths so they cannot drift. -
TUI pre-signal revalidation now reports an owner whose PID became unreadable as
ownership-unavailable, matching the CLI, instead of labelling it a changed
target; both still refuse to send a signal. -
Removed the stale
#[allow(dead_code)]fromExitReason; every variant is
now constructed by the CLI exit path, so the lint suppression would have
hidden genuinely unreachable variants in future refactors. -
TUI
Escno longer quits when a filter is still applied after search editing
finished: with no modal open and a non-empty filter,Escnow clears the
filter and only quits on a second press once nothing is left to clear. An open
modal still takes precedence. Previously, pressingEnterto finish a search
and then reflexively pressingEscended the session instead of dropping the
filter. -
TUI auto-refresh now schedules the next refresh from collection completion
time instead of collection start time, avoiding an immediate repeat refresh
when a slow/procscan takes longer than the configured interval. -
CLI
listnow printsno open ports visiblewhenhide_system_processes
suppresses every collected row, instead of implying the machine has no open
ports at all. -
TUI help modal title now reads
Kickoutchiinstead of an outdated
phase-specific title. -
TUI status bar, borders, titles, and muted text now use terminal-default or
bold-reversed styles instead of fixed dark-gray/black combinations, so the
interface remains readable in both light and dark terminal themes. -
Linux collection no longer fails the whole scan when optional IPv6 socket
tables such as/proc/net/tcp6or/proc/net/udp6are absent; IPv4 socket
tables remain required. -
IPv4-mapped IPv6 socket addresses such as
::ffff:127.0.0.1are normalized
or classified as IPv4 loopback/local addresses instead of being mislabeled as
generic local IPv6 binds. -
Terminal-state leak on TUI startup errors: a failure between enabling raw
mode and constructing the terminal (entering the alternate screen, or the
terminal's initial size query) now restores the terminal before the error
propagates, instead of leaving the shell stuck in raw mode. Clean exits,
propagated errors after startup, and panics were already covered by the
guard and panic hook; this closes the remaining error window during setup.
Added
-
Release/distribution setup:
cargo-distnow generates a GitHub Release
workflow for Linux, macOS, and Windows archives, with shell and PowerShell
installers, per-artifact checksums,sha256.sum, anddist-manifest.json.
The repository also includes a Nix flake fornix run/nix profile install
and Archkickoutchi/kickoutchi-binPKGBUILD templates. -
Optional Docker port-ownership enrichment in TUI details: Docker-looking or
metadata-hidden port owners can be matched to running containers by published
host port, protocol, and host address through a bounded
docker container ls --filter publish=...lookup. Details can show container
name/ID, Compose project/service labels, and a saferdocker stop <container>
command when exactly one container matches; Docker failures remain non-fatal
enrichment misses. -
Native macOS support:
kickoutchi/kicknow lists TCP listeners and bound UDP
sockets throughlibproc/sysctl, enriches rows with process metadata when
available, uses start-time-guarded single-PIDSIGTERM/SIGKILL
termination, and renders macOS equivalent commands askill <PID>or
kill -9 <PID>. The default macOS path has nolsofdependency. -
macOS validation coverage now includes Darwin socket/procargs unit tests,
a macOS-only CLI listener/interactive-kill smoke test, a GitHub Actions macOS
job, andmisetasks for Linux-hosted Darwincargo check/ strict Clippy
runs on bothx86_64-apple-darwinandaarch64-apple-darwin. -
Human-display sanitizer that strips control characters, newlines, and ANSI
escape sequences from OS-provided process metadata before rendering it in
CLI table output, TUI table/details/confirm modals, kill banners, and
confirmation prompts. JSON output stays raw and structured. -
Short
kickbinary integration test verifying that--helpreports
Usage: kick,--versionreports the canonicalkickoutchiname, and
list --jsonprints valid JSON. -
Windows CLI contract coverage now starts a real local TCP listener, verifies
list --portsees it, confirmskill --pidinteractively withy, waits for
the helper to exit, and verifies the port disappears. This complements the
existing Windows unit coverage for IP Helper row normalization and Windows
termination error mapping. -
mise.tomlnow includes local task aliases for formatting, strict Clippy,
tests, the combined CI-equivalent check, and commonrun/listcommands. -
Linux
/proc/<pid>/statstart-time parsing is now tested for acommthat
contains), pinning the right-split that keeps the parse robust against
unescaped parentheses in the process name. -
Linux CLI contract coverage now includes a real
SIGTERMpath: a controlled
helper process binds a TCP listener,kickoutchi kill --pid --yesterminates
it, and a follow-up list confirms the port disappears. -
TUI confirmed-kill execution is now covered with injected collection/context/
termination seams, including successful refresh and stale process-identity
refusal without sending a signal. -
GitHub Actions CI now runs on Linux pushes and pull requests, using the pinned
Rust toolchain to check formatting, strict Clippy, and the full test suite.
Release/CD automation remains deferred to the dedicatedcargo-distworkflow. -
CLI contract integration tests now exercise script-facing
listbehavior with
the real binary: human no-match diagnostics go to stderr,list --jsonstays
unpolluted, and explicit no-match filters exit3. The helper process uses
sh, so the suite needs no Python (or any other interpreter) on PATH. -
Safe termination MVP: Linux
killnow sends realSIGTERMor
SIGKILLthrough a smalllibcboundary instead of shelling out, with typed
outcomes for success, permission denied, already exited, cancelled, protected
process, stale confirmed target, unsafe PID, and unknown failure. Real signal
delivery is Linux-only until native non-Linux collectors exist. -
Shared kill command rendering in
command.rsshows the equivalent user-facing
command (kill <PID>,kill -9 <PID>, or future platform equivalents) in both
CLI and TUI confirmation flows. -
CLI
kickoutchi kill --pid <PID>andkickoutchi kill --port <PORT>now use
the same safety rules as the TUI: PID0, PID1, and Kickoutchi's own PID
are blocked; protected processes require typing the PID or process name;
--yescannot bypass protected-process confirmation; andkill --port
refuses ambiguous targets instead of guessing. After confirmation, the target
is re-collected and must still match the confirmed PID and port rows before a
signal is sent. -
TUI termination flow:
xopens normal termination confirmation,Xopens
force-kill confirmation, force kill requires typingforce, protected
processes require typing the PID or process name, child/owner/permission
warnings are shown when available, and the table refreshes immediately after a
kill attempt. -
Safe-termination tests cover PID guardrails, target ambiguity, confirmation decisions,
command rendering, TUI confirmation state/rendering, and CLI exit-code mapping. -
TUI kill confirmation now lists every port owned by the target PID, gathered
from the full snapshot so active filters cannot hide a port the signal will
still free. -
Process context and protected-process policy: the selected TUI row
now resolves direct child PIDs and child process names only when the user opens
the details modal, shows owner UID when available, and keeps the child scan
bounded so scrolling the table does not walk the process list. -
Protected-process matching now lives in
protection.rs, with exact
case-sensitive matching on Unix-like platforms and exact case-insensitive
matching ready for Windows. -
No-match port diagnostics for human CLI output: when an explicit port query
finds no confirmed listening TCP or bound UDP socket, Kickoutchi can print
evidence-only related-process hints to stderr based on strict port-shaped
command-line matches such as:3000,--port 3000,--port=3000,-p 3000,
PORT=3000, andpython3 -m http.server 3000. -
Diagnostic hints do not create fake table rows, do not claim ownership, do not
change thelist --portno-match exit code, and do not pollutelist --json. -
Filtering, sorting, and refresh: the TUI now supports manual
refresh withr, automatic refresh using the configured interval, search mode
with/, and sort cycling withs. -
Shared query engine for CLI and TUI filtering: plain search matches visible
row fields such as port, PID, protocol, address, process name, executable
path, command line, bind scope, and parent process; structured filters support
pid:,port:,proto:,scope:,protected:, andparent:. -
Additional sort modes for parent process and bind scope, with scope sorting
surfacing public binds before local and loopback binds. -
Linux parent-process collection backing the parent filter and sort:
parent_pid
from/proc/<pid>/statusand the parent name from/proc/<ppid>/comm, feeding
theparent:filter, parent sorting, the details-panel parent line, and PID-1
child hiding. Implemented alongside filtering and sorting so the parent filter
and sort operate on real data instead of always-empty fields. -
TUI refresh state now keeps the last successful snapshot separate from the
latest collector error, so a failed refresh reports the error without erasing
the last good table. -
Selection preservation across refresh/filter/sort by PID, protocol, local
address, and port, falling back to the nearest sensible row when the selected
process disappears. -
kickoutchi list --filter <TEXT>andkickoutchi list --sort <MODE>for the
same search/filter/sort behavior used by the TUI. -
Config support for
hide_system_processes, implemented conservatively for
PID 0/1, direct PID-1 children, and known OS process names without hiding
protected app processes such aspostgresby default. -
Linux native collector: on Linux,
kickoutchi/kicknow reads
/proc/net/tcp,/proc/net/tcp6,/proc/net/udp, and/proc/net/udp6
directly, keeps TCPLISTENsockets and bound UDP sockets, decodes IPv4 and
IPv6 local addresses, extracts socket inodes, and maps them to owning PIDs by
walking/proc/<pid>/fdsymlinks. -
Linux process metadata enrichment: readable owners now include process name,
executable path, and command line from/proc/<pid>/comm,/proc/<pid>/exe,
and/proc/<pid>/cmdline; restricted or raced metadata keeps the port row and
marks it partial instead of dropping it. -
Deterministic Linux collector tests for
/proc/netparsing, TCP state filtering, UDP
bound rows, IPv4/IPv6 decoding, malformed rows, socket inode parsing,
command-line decoding, and partial metadata behavior. -
Static TUI skeleton: the bare
kickoutchi/kickcommand now opens
a full fake-data TUI with a header, the open-ports table, a selected-row
details panel, and a status bar showing row count, refresh age, sort mode,
and filter state. -
TUI app state (
app.rs) and key-to-action input mapping (input.rs):
boundedj/k/Up/Down selection,Enterfor a details modal,?for a
help modal,Escclosing modals (or quitting when none is open), and rows
marked protected and sorted through the same shared model code as the CLI. -
UI modules
table,details,help, andtheme: missing metadata renders
as-, partial-permission and protected rows get distinct styling with the
reason explained in the details panel, child PIDs distinguish "not loaded"
from none, andNO_COLORdisables colors while keeping non-color emphasis. -
Terminal-size fallback message when the viewport is smaller than 80x20.
-
Render tests over a ratatui
TestBackend(default frame, help modal,
details modal, too-small fallback) plus app-state transition tests for
selection bounds, modal flow, and empty-row behavior. -
Short binary name
kick: the crate now installs bothkickoutchi
(canonical) andkick(short alias for CLI use) from the same source, with
default-runkeepingcargo runon the canonical binary. The help usage
line follows the invoked name;--versionreports the canonical name. -
Shared domain model:
PortEntrywith the full
protocol/address/port/state/process/parent/permission shape, plus the
Protocol,SocketState,Platform,PermissionStatus, andSortMode
vocabulary shared by the CLI, TUI, and future collectors. -
Collectortrait with a deterministicFakeCollectorcovering full
metadata, permission-restricted partial rows, IPv6, bound UDP, and a
default-protected process name. -
Config file support:
~/.config/kickoutchi/config.toml(XDG viadirs)
withrefresh_interval_seconds,default_sort,confirm_force_kill, and
protected_processes; missing file means safe defaults, invalid file is a
hard error naming the file and the bad value; bounded values and a capped
protected list. -
Non-TUI CLI:
kickoutchi list(--port,--process,--json) and the
kickoutchi killcommand shape (--pid/--port,--force,--yes) with
confirmation prompts routed to a stub until real termination lands; CLI
commands never open the TUI. -
Stable script-facing exit codes (0–6) defined and tested in one place;
--yesnever bypasses the protected-process path (exit 6). -
CLI-over-config precedence via global
--config <FILE>and
--refresh-interval <SECONDS>flags, with shared bounds enforced by clap at
parse time. -
Table and JSON output layer; missing metadata renders as
-in tables and
nullin JSON, and the JSON field/enum shape is pinned by tests. -
Cargo manifest metadata (
description,license,repository,authors,
readme) required for latercargo publish/cargo-distrelease work. -
Project foundation: Rust 1.95.0 pinned via
mise.toml, edition
2024, and strict lints (warnings = "deny",clippy::pedantic). -
Core dependency set: ratatui, crossterm, clap, serde, serde_json, toml,
thiserror, anyhow, tracing, and tracing-subscriber. -
Module boundaries:
main,config,error, andui. -
Safe terminal lifecycle: an RAII
TerminalGuardthat enters raw mode and the
alternate screen and restores both on drop (clean exit, propagated error, or
panic), plus a panic hook that restores the terminal before the message prints. -
Minimal event loop with a bounded poll that quits on
q,Esc, orCtrl+C. -
tracingdiagnostics routed to stderr only, never the TUI surface. -
Unit tests for the quit predicate, including the key-release edge case.
Install kickoutchi 0.1.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/nuggocto/kickoutchi/releases/download/v0.1.0/kickoutchi-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/nuggocto/kickoutchi/releases/download/v0.1.0/kickoutchi-installer.ps1 | iex"Download kickoutchi 0.1.0
| File | Platform | Checksum |
|---|---|---|
| kickoutchi-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| kickoutchi-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| kickoutchi-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| kickoutchi-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| kickoutchi-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |