Skip to content

stop: bare in a terminal, a picker chooses what to stop - #31

Merged
pyjeebz merged 2 commits into
mainfrom
feat/stop-picker
Nov 8, 2026
Merged

pyjeebz merged 2 commits into
mainfrom
feat/stop-picker

Conversation

@pyjeebz

@pyjeebz pyjeebz commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Closes #22

Why

Typing ports stop and then hunting for the port number is the common case. In a terminal, bare ports stop now opens a picker over the listing: ↑/↓ (or k/j), Enter, then y to confirm.

What

  • Picker (cmd/picker.go): the table's own rows (inspect.TableRows). Rows only sudo can stop, and Windows-side rows seen from WSL, are dimmed and skipped. Esc, q or Ctrl-C leave with exit 130. The list scrolls to fit the terminal height and lines are cut to its width; a terminal under 7 lines is refused. Raw mode is restored on return and on SIGTERM/SIGQUIT/SIGHUP. Input that arrives with the Enter (a paste) is discarded, so it can't answer the confirm.
  • Stops only what was confirmed (stopPicked): after the confirm, ports rescans and stops only the chosen target (container ID, else pid plus start time, else systemd unit), never whatever holds the port now. If that target no longer holds the port, nothing is stopped, with a message to run ports stop again (exit 1). The confirm lists every port the target holds.
  • Never in scripts: off a terminal, or with --json, bare ports stop is a usage error (exit 2).
  • Docs: the stop section of commands.mdx.
  • New dependency: golang.org/x/term.

Evidence

  • Unit tests:
    • moving, cancelling and drawing;
    • a paste never confirms;
    • the confirm names every port;
    • windowing;
    • Windows rows;
    • too-short terminal;
    • TestStopPickedStopsOnlyTheConfirmed: the scan is swapped between pick and stop for four cases (another process took the port, a reused pid, a moved port, and two pids sharing the port), and only the confirmed pid is ever stopped.
  • Integration test TestStopPicker drives a real PTY through script:
    • a --dry-run confirm says "would stop";
    • Esc exits 130 and leaves the server running;
    • bare stop off a TTY exits 2.
  • Gate:
    • go test ./internal/... ./cmd/... and ./test/... pass;
    • golangci-lint reports 0 issues;
    • the Windows and darwin builds succeed;
    • npm run lint and npm run build pass in web/.
  • Risky tier: a fresh-context review blocked the first cut, which re-resolved the port at stop time. This revision fixes that, and the re-review found no blockers. Known gaps: a paste split across reads can still deliver a y, and resizing the terminal while the picker is open isn't handled.

Rollback

Revert the squash commit. The picker is reached only through bare ports stop, which was a usage error before this change.


Generated by Claude Code

@pyjeebz
pyjeebz merged commit cb3467f into main Nov 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stop: an interactive picker when run bare in a terminal

2 participants