ssh-cli 0.5.4

Native Rust CLI that gives LLMs (Claude Code, Cursor, Windsurf) the ability to operate remote servers via SSH over stdin/stdout
Documentation
# Integrações

> **0.5.4** — release de segurança e agent-native. Corrige DoS remoto pré-auth no banner SSH (A1), impede que bits setuid enviados pelo servidor caiam no arquivo baixado (A3), fecha a janela de leitura pública em chaves privadas ACME/mTLS (A2) e adiciona flags de redução de payload (`--select`, `--filter`, `--limit`, `--sort`, `--dedupe-by`, `--count-only`, `--truncate-content`, `--max-output-bytes`) aplicadas antes da serialização. BREAKING: falha parcial multi-host agora sai com exit **1** (era 65); `--bind` fora do loopback exige `--i-accept-network-exposure`. Novo evento `tunnel_closed`.


> Conecte 10+ agentes de coding a servidores remotos com ssh-cli one-shot.

- Read this document in [English](INTEGRATIONS.md).
- Combine este catálogo com [docs/AGENTS.pt-BR.md](docs/AGENTS.pt-BR.md) e [skills/ssh-cli-pt/SKILL.md](skills/ssh-cli-pt/SKILL.md).


## Aliases de flags
### Aliases camelCase implementados no clap (não invente outros)
- Use `--sudoPassword` como alias de `--sudo-password`.
- Use `--suPassword` como alias de `--su-password`.
- Use `--maxChars` como alias legado mapeado para `max_command_chars`.
- Use `--disableSudo` como alias de `--disable-sudo`.
- **Não** há alias camelCase para `--config-dir`, `--output-format` ou `--no-color` — use exatamente o kebab-case.

## Novas flags por versão
### Acompanhe o crescimento da superfície sem ler o código
- `0.5.4` **modos de tunnel (G-TUN-R01/R02/R03):** `tunnel --reverse` (servidor escuta e entrega de volta; `REMOTE_PORT 0` = servidor aloca), `tunnel --socks5` (proxy SOCKS5 local, RFC 1928 no-auth + CONNECT, destino por conexão, `REMOTE_HOST`/`REMOTE_PORT` omitidos), `tunnel --remote-socket <CAMINHO>` (socket Unix remoto via `direct-streamlocal@openssh.com`; caminho absoluto ou exit **64**). O `mode` no JSON é `local` | `reverse` | `socks5` | `streamlocal`.
- `0.5.4` **redução de payload agent-native:** globais `--select` (apelido `--fields`), `--filter` (`chave=valor` | `chave!=valor` | `chave~substring`, repetível com AND), `--limit`, `--sort`, `--dedupe-by`, `--count-only` (→ `{"count": N}`), `--truncate-content` (caracteres, nunca bytes), `--max-output-bytes` (descarta registros do fim, nunca fatia o JSON) — todas aplicadas **antes** da serialização. Mais as globais `--no-input` e `--dry-run` (honrada somente por `vps remove`, `vps import`, `sftp rm`, `sftp rmdir`, `secrets init`, `secrets reencrypt`; nos demais, exit **64**).
- `0.5.4` **BREAKING + segurança:** falha parcial multi-host sai com exit **1** (era 65; G-ERR-R02); `tunnel --bind` fora do loopback exige `--i-accept-network-exposure` (G-TUN-R13); novo evento `tunnel_closed` (`reason`, `forwards_served`, `capacity_waits`); `schema dry-run` / `schema tunnel-closed` agora saem com exit **0**; A1 aplica o teto de log `AUTH_BANNER_MAX_CHARS` (512), que já existia, em fronteira de caractere e não por índice de byte, removendo um abort disparável remotamente, A2 cria chaves ACME/mTLS em `0600` em vez de restringir depois de criar, A3 mascara os modos de entrada com `SFTP_PERM_MASK_UNTRUSTED` (`0o0777`) para que setuid/setgid/sticky não peguem carona num download.
- `0.5.3` **integridade SFTP + segurança para agentes (G1–G19):** upload SFTP não trunca mais destinos a 0 bytes (`FileAttributes::empty`); SETSTAT envia atime+mtime juntos; `set_metadata` fail-closed; bits de permissão via `SFTP_PERM_MASK` (`0o7777`); download sinaliza falhas de `set_permissions` local; download SCP faz `sync_data` antes do rename; cancel de batch preenche resto cancelled (`results.len() == input.len()`); `exec --json` um único objeto NDJSON; E2E SFTP com checksums E17/E18. Prefira **0.5.3+** para qualquer transferência SFTP.
- `0.5.3` **verbosidade graduada (G2/G14):** `-v` info / `-vv` debug / `-vvv` trace via `ArgAction::Count`, sempre com allowlist crate-scoped `warn,ssh_cli=*` — nunca debug global bare (sem dump de senha do russh). `RUST_LOG` ambiente continua ignorado. Mesmo `-vvv` **não** habilita dumps de canal cifrado do russh.
- `0.5.2+` **SFTP (G-SFTP):** `ssh-cli sftp upload|download|ls|mkdir|rmdir|rm|stat|rename` via `russh-sftp` 2.3. Upload/download com `--recursive` (sem seguir symlink), multi-host `--all`/`--hosts`, eventos JSON `sftp-transfer` / `sftp-list` / `sftp-fs-op` / `sftp-batch`. SCP continua só arquivo regular. **Use 0.5.3+** para as correções de integridade SFTP acima.
- `0.5.2+` **fan-out multi-host (concorrência limitada):** `exec|sudo-exec|su-exec|scp|sftp|health-check --all` roda sessões SSH concorrentes limitadas por `--max-concurrency N` (1..=64; auto CPUs×4 vs RAM livre/2 / 16 MiB). Envelopes batch: `health-check-batch` / `exec-batch` / `scp-batch` / `sftp-batch` (`docs/schemas/*-batch.schema.json`, campo `max_concurrency`). Prefira um processo com `--all` a N spawns single-host para frota. Accepts de tunnel compartilham o mesmo gate.
- `0.5.2` **E2E residual + export/import agent-first + wire v3**: root `schema`/`doctor`; um único `vps-added` + `secrets_key_auto_created`; `RUST_LOG` ambiente ignorado; ACME permanente 64; `vps add --use-agent`; export redacted `***` (`FIXED_MASK`); sem GH Actions de produto; mais o corpo de `vps export` segue o formato de saída resolvido (JSON em qualquer stdout non-TTY, TOML somente com `--output-format text`); `vps import` aceita TOML (chaves EN + aliases PT) **ou** envelopes JSON `vps-export`; dual-read serialize EN + aliases PT; host **schema v3**; flags CLI `--allow-plaintext-secrets`, `--secrets-key-file`, `--use-keyring` (prefira ao env); eventos `secrets init|reencrypt --json` `secrets-init` / `secrets-reencrypt`; a 1ª gravação define `secrets_key_auto_created` no mesmo documento `vps-added`; caminhos de sucesso CRUD usam eventos JSON `emit_success`; `--include-secrets` em pipe/non-TTY exige `-o`/`--output` ou `--i-understand-secrets-on-stdout`; tunnel `--bind` (default `127.0.0.1`); import `TomlDe` → exit **65**; `SshAuthentication` → **77**; SCP missing `file not found: <path>` (exit **66**); warn de timeout se `<1000` ms; warn stderr de password em argv; doctor `secrets_plaintext_opt_out` é **bool**.
- `0.4.2` tunnel porta efêmera `local_port=0` reporta porta atribuída pelo SO após bind (TUN-003); SCP remoto ausente → exit **66** (IO-010); envelope `vps export --json` com `event: "vps-export"`; e2e E15/E16; suite `gaps_v042`.
- `0.4.1` AUD-POST + SCP **somente arquivos regulares** (herda wire 0.4.0; sem `-r` / sem SFTP): wire SCP sólido (evite crates.io **0.3.9** SCP quebrado); flags scp `--timeout`, `--password-stdin`, `--key`, `--key-passphrase` / `--key-passphrase-stdin`, `--json` → `docs/schemas/scp-transfer.schema.json` com `event: "scp-transfer"` obrigatório (IO-009); download grava `{path}.ssh-cli.partial` e faz rename; preserve mtime/mode bi-dir; upload em stream 32 KiB; `tunnel --json` emite `tunnel_listening` após bind e deadline pós-bind sai **0** (TUN-002); export redacted não emite `sshcli-enc:` para secret vazio (EXP-001); paridade auth `tunnel` (CLI-005) e `health-check` (CLI-006); envelope JSON de erro scp em stderr com `--json`.
- `0.4.0` wire SCP sólido (corrige crates.io **0.3.9**); transfers file-only; `tunnel --json` / `tunnel_listening`.
- `0.3.9` filtro de tracing default `error` (agent-first); senha vazia serializa como JSON `null` em hosts só-chave; `health-check --timeout <ms>`; auditoria de docs de product line.
- `0.3.8` russh 0.62.2; stdout de tunnel limpo para agentes; sem VPS ativa sai com `66` (`EX_NOINPUT`); `cargo deny` com `yanked=deny`.
- `0.3.7` `--output-format` no CRUD VPS; `health-check --json`; `--quiet`; envelope JSON de erro; timeout do tunnel cobre connect.
- `0.3.6` adiciona cifragem at-rest default, `secrets status|init|reencrypt`, `SSH_CLI_ALLOW_PLAINTEXT_SECRETS`, campos doctor de secrets, `scripts/e2e_real_ssh.sh`.
- `0.3.5` adiciona caminhos de passphrase stdin, JSON auto em non-TTY, doctor `secrets_at_rest`, export atômico residual.
- `0.3.4` adiciona `--key`, `--key-passphrase`, `--password-stdin`, `--sudo-password-stdin`, `--su-password-stdin`, `--timeout-ms` (tunnel), `--disable-sudo`, `--description`, `--replace-host-key`, `max_command_chars`, `max_output_chars`, `vps doctor`, `vps export`, `vps import`, `su-exec`.
- `0.2.0` adiciona overrides runtime `--password`, `--sudo-password`, `--timeout` e aliases camelCase.
- Prefira **0.5.3+** para integridade SFTP (G1–G19), verbosidade graduada crate-scoped, roundtrip export/import, wire schema v3, SCP funcional + `tunnel --json` / `--bind`, automação SSH completa, cifragem default e supply-chain limpa.

## Descoberta para agentes
- `ssh-cli commands` — árvore completa de comandos (vps, connect, exec, sudo-exec, su-exec, scp, sftp, tunnel, health-check, secrets, completions, commands, schema, doctor, locale, tls).
- `ssh-cli schema [NAME]` — catálogo/corpo de JSON Schema embarcado.
- `ssh-cli doctor` — alias root de `vps doctor` (local + probe SSH opcional).
- `ssh-cli locale show|set|clear` — preferência de locale da UI (XDG; não é env de produto).
- `ssh-cli tls provider|paths|mtls|acme` — material opcional de SSH-over-TLS sob XDG `tls/`.


## Tabela resumo

| Agent / Platform | Integration style | JSON | Notes |
| --- | --- | --- | --- |
| Claude Code | subprocess CLI + skill | yes | Prefer skill package |
| Cursor | shell / agent tools | yes | Use `--json` |
| Windsurf | shell tool | yes | One-shot per task |
| Codex CLI | shell tool | yes | Map sysexits |
| OpenCode | shell tool | yes | One-shot only |
| Aider | shell commands | yes | Store hosts once |
| Continue | custom command | yes | XDG multi-host |
| Gemini CLI | shell tool | yes | Prefer stdin secrets |
| OpenHands | sandbox shell | yes | Bound tunnel timeouts |
| Generic bash/zsh | direct install | yes | Completions available |


## Claude Code
- Instale `ssh-cli` no PATH com `cargo install ssh-cli --locked`.
- Carregue [skills/ssh-cli-pt/SKILL.md](skills/ssh-cli-pt/SKILL.md) ou o pacote en.
- Cadastre hosts uma vez com `vps add` (prefira `--password-stdin`) e chame `exec` por tarefa.
- Prefira envelopes `--json` para resultados estruturados.
- Faça parse só do stdout; stderr default fica silencioso no nível de tracing `error` (passe `-v`/`-vv`/`-vvv` ao depurar — allowlist crate-scoped; `RUST_LOG` ambiente é ignorado).
- Use `ssh-cli secrets status` / `vps doctor --json` / `ssh-cli commands` como preflight de cifragem, paths e descoberta de superfície.


## Cursor
- Adicione regra de projeto que prefere `ssh-cli` a processos Node SSH de longa duração.
- Mantenha credenciais fora do chat usando hosts salvos e flags stdin.
- Faça parse só do JSON em stdout; stderr default fica silencioso no nível de tracing `error` (ignore tracing salvo se passar `-v`/`-vv`/`-vvv`; `RUST_LOG` ambiente é ignorado).


## Windsurf
- Invoque comandos one-shot após o cadastro de hosts.
- Nunca mantenha tunnel aberto sem `--timeout-ms`.


## Codex CLI
- Trate exits não zero como falhas tipadas usando a tabela de exit codes do README.
- Faça retry só em códigos transitórios de IO/timeout, nunca em auth ou usage.


## OpenCode
- Use modo shell tool com arrays de argv explícitos.
- Evite embutir senhas no texto do prompt; use registry ou stdin.


## Aider
- Documente nomes de hosts no repo sem segredos.
- Chame `ssh-cli exec <name> "..."` para ops remotas durante loops de edição.


## Continue
- Mapeie custom commands para subcomandos `ssh-cli` com `--json`.
- Use `vps doctor --json` como preflight de saúde para sessões de agente.


## Gemini CLI
- Prefira auth por chave e `vps show` mascarado para verificação.
- Mantenha elevação desabilitada salvo quando a tarefa exigir root.


## OpenHands
- Rode dentro do sandbox com policy de rede que permite só hosts alvo.
- Force tunnels limitados e timeouts curtos.


## Shell genérico
- Instale completions com `ssh-cli completions <shell>`.
- Use `--config-dir` apenas para sandboxes de teste isolados (o produto não lê `SSH_CLI_HOME`).