purple-ssh 3.31.0

Free, open-source terminal SSH manager and SSH config editor in Rust for macOS and Linux that keeps ~/.ssh/config in sync with 18 cloud providers, monitors live SSH tunnels and manages Docker and Podman containers fleet-wide. Spin up a VM, it shows up. Destroy it, it dims. Plus scp, Vault SSH certs and an MCP server for AI agents. MIT licensed.
Documentation
# Contributing

Thanks for taking the time. Bug reports, fixes and features are all welcome.

## Before you open a pull request

Run the full gate:

```
./scripts/precommit.sh
```

Everything CI checks runs there: formatting, clippy with warnings denied, the
test suite, the MSRV build, the design and message conventions, the visual
goldens and the asset pipeline. Green locally means green on CI.

## Tests

Every new code path needs a test. Unit tests for logic, render tests for UI.
Tests that write to disk use `tempfile::tempdir()` for isolation, never a path
built from the process id alone.

Code behind `std::process::exit` cannot be reached from a unit test. Spawn the
real binary against a temp `HOME` instead and assert on the exit status plus
what lands on disk. `tests/provider_add_e2e.rs` is the pattern to copy.

The color mode, the theme and the demo flag are process globals. A test that
sets one of them, directly or through `demo::build_demo_app()`, holds
`crate::demo_flag::GLOBAL_TEST_LOCK` for its whole run so it never overlaps a
parallel render test. Take it poison-tolerant
(`.lock().unwrap_or_else(|e| e.into_inner())`) so one failing test does not
cascade into `PoisonError` in every other. `./scripts/check-conventions.sh`
rejects a test file that calls a mutator without naming the shared lock.

## Changing the UI

Every screen has a golden baseline under `tests/visual_golden/`. After an
intentional visual change:

```
./scripts/update-golden.sh
git diff tests/visual_golden/
```

Review the diff before staging it. Never hand-edit a golden file.

A new `Screen` variant also needs a `visual_<name>` test in
`src/visual_regression_tests.rs`.

## Text

Everything that ships is in English: code, comments, commit messages, docs and
user-facing text.

User-facing strings live in the `messages` module, never inline in handler,
CLI or UI code. `./scripts/check-messages.sh` enforces it.

## Commits

Conventional Commits, so `feat:`, `fix:`, `change:`, `chore:`, `docs:` or
`refactor:` in the subject. Stage specific files rather than `git add -A`.
Bumping a version in `Cargo.toml` means staging `Cargo.lock` with it, since CI
builds with `--locked`.

## Providers

Every cloud provider API call needs a deserialization or HTTP test. Adding or
changing one means adding a golden fixture under `tests/api_contracts/` plus a
contract test in `tests/contract_snapshots.rs`. Changing which fields get
deserialized means updating the OpenAPI fragments under
`tests/api_contracts/openapi/`.