Skip to content

nssh: add Eternal Terminal (et) as a third transport#15

Open
abizer wants to merge 2 commits into
masterfrom
et-transport
Open

nssh: add Eternal Terminal (et) as a third transport#15
abizer wants to merge 2 commits into
masterfrom
et-transport

Conversation

@abizer
Copy link
Copy Markdown
Owner

@abizer abizer commented Jun 3, 2026

What

Wires Eternal Terminal (et) in as a third interactive transport alongside ssh and mosh.

  • New --et flag, mutually exclusive with --ssh/--mosh.
  • Auto-selection (when unforced): et → mosh → ssh. et wins when et is on the local PATH and etserver is on the remote PATH — binary-presence check only, mirroring the existing mosh-server probe.
  • et launches as et <host> (resolves the host via ~/.ssh/config, default port); like the mosh path, extra ssh flags aren't forwarded. No LC_ALL override (mosh-specific).

How

  • The selection decision is factored into a pure pickTransport(force, localMosh, remoteMosh, localET, remoteET) and covered by a 12-case truth-table test (transport_test.go). selectTransport feeds it real LookPath + remote command -v probes, folded into one remoteHasCommand helper. Remote SSH probes are skipped when a transport is forced or its local binary is absent.
  • Since a bool can't express three transports, the session-end log's Mosh *bool becomes Transport string (ssh/mosh/et). status rendering and docs/protocol.md updated to match; old logs' mosh field is harmlessly ignored.

Why this is cleanly scoped

nssh's clipboard/URL bridge runs over ntfy and is transport-agnostic — the interactive transport is just the subprocess runSession execs after the remote-prepare step. ET slots in as a peer of mosh with no changes to the ntfy subscriber, wire format, shims, remote prepare, or collision logic.

Out of scope

  • et_port config knob (default port only).
  • nssh sweep for et/etterminal (etserver is a shared daemon).
  • Forwarding extra ssh flags to et (mirrors the existing mosh limitation).

Verification

go build, go vet, full go test ./... green; gofmt clean. Confirmed against the built binary: usage shows [--ssh|--mosh|--et], and --ssh --et errors with the mutual-exclusion message.

Design doc: docs/superpowers/specs/2026-06-03-eternal-terminal-transport-design.md

🤖 Generated with Claude Code


Note

Low Risk
Additive transport and logging only; ntfy bridge, shims, and auth boundaries are untouched, with unit tests on selection logic.

Overview
Adds Eternal Terminal (et) as a third interactive shell transport next to ssh and mosh, with a new --et flag (mutually exclusive with --ssh / --mosh). When no transport is forced, auto-selection is now etmoshssh, using local LookPath plus remote command -v for etserver / mosh-server via a shared remoteHasCommand helper; the pure decision is in pickTransport, covered by transport_test.go.

Session logging replaces Mosh *bool on session-end with Transport (ssh / mosh / et); nssh status --tail and docs/protocol.md match. Docs (README, CLAUDE.md, internals) describe ET behavior and note the ntfy clipboard/URL bridge is unchanged.

Reviewed by Cursor Bugbot for commit a09bc54. Bugbot is set up for automated code reviews on this repo. Configure here.

abizer and others added 2 commits June 3, 2026 09:04
Adds et as a third interactive transport alongside ssh/mosh, with
ET-preferred auto-detection (binary check only) and a Mosh->Transport
log schema change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wires `et` in alongside ssh and mosh in selectTransport. With no
--ssh/--mosh/--et flag, auto-selection now prefers et (local `et` +
remote `etserver`), then mosh, else ssh — binary-presence check only,
mirroring the existing mosh detection.

The pure decision is factored into pickTransport and covered by a
truth-table test (transport_test.go); selectTransport feeds it real
LookPath + remote `command -v` probes (the two probes are folded into
one remoteHasCommand helper). Remote probes are skipped when a transport
is forced or its local binary is absent.

The session-end log's `Mosh *bool` becomes `Transport string`
("ssh"|"mosh"|"et") since a bool can't express three transports; status
rendering and protocol.md updated to match. Docs (CLAUDE.md, internals,
README) describe the new transport and selection order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a09bc54386

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/nssh/session.go
switch pickTransport(force, localMosh, remoteMosh, localET, remoteET) {
case "et":
fmt.Fprintln(os.Stderr, "nssh: using et for interactive session")
return exec.Command("et", sshTarget), "et"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Report missing ET client instead of succeeding

When users force the new --et path on a machine without the local ET client, this branch still returns a command that cannot be started. runSession returns that start error, but nsshMain only converts *exec.ExitError into a non-zero exitCode, so this scenario prints using et, logs transport=et with exit=0, and exits successfully without explaining that et was not found. Please either check exec.LookPath("et") before selecting this forced transport or make start errors propagate as a non-zero failure.

Useful? React with 👍 / 👎.

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.

1 participant