feat(cli): add pty-relay completions <shell> (bash/fish/zsh) - #35
Merged
Conversation
pty-relay shipped no completions at all. Add a generator that emits all three shells from ONE declarative spec of the command tree, so they can't drift apart — the same design as `pty completions` and `st completions`, extended with nested verbs for pty-relay's `server`/`client`/`local`/ `clients` groups. The spec is derived from the `switch` dispatch in cli.ts (including CLIENT_PASSTHROUGH_COMMANDS), not from the prose `--help` text. Peer/host names are deliberately not completed dynamically: peers live in the encrypted secret store, so there is no cheap reliable source at completion time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1xLDkqUDCYUMMADdMqVgP agent-session-id: 312caff5-3274-4d97-baa4-8ff06ab03fc5 agent-tool: Claude Code agent-tool-version: 2.1.215 agent-model: claude-opus-4-8 agent-runtime-profile: /nix/store/acr8a3l2v366jgmwiq8xdrhgz1py0db5-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/sj1v5j91h8v8d1w9lca4040302lwrd6v-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
Packaging lived out-of-tree (in a dotfiles wrapper) and therefore had to fetchFromGitHub a pinned rev. In-repo it builds from `self`, so the flake tracks the checkout it ships with. Inputs are nixpkgs, flake-utils and the sibling `pty` flake only — no private tooling — so `nix build` works standalone. Notes on what changed versus the out-of-tree wrapper: - The npm name is `@compoundingtech/pty`, and it is now a `file:../pty` link dependency rather than a peerDependency. `npm ci` resolves it to a dangling symlink in the sandbox, so no `--legacy-peer-deps` is needed; installPhase replaces the link with the store path from the `pty` flake. The mapping is a declarative npm-name -> store-path attrset. - One `nodejs` binding feeds both the derivation and the bin shim, so a build and a run cannot disagree on the interpreter. - Completions are generated at build time from the just-built binary and installed via installShellCompletion, so they cannot lag the CLI. Verified: `nix build .#default` and `nix flake check` pass, and `pty-relay --help`, `pty-relay completions fish` and `pty-relay doctor` (which resolves the sibling pty link) all work from the built output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1xLDkqUDCYUMMADdMqVgP agent-session-id: 312caff5-3274-4d97-baa4-8ff06ab03fc5 agent-tool: Claude Code agent-tool-version: 2.1.215 agent-model: claude-opus-4-8 agent-runtime-profile: /nix/store/acr8a3l2v366jgmwiq8xdrhgz1py0db5-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/sj1v5j91h8v8d1w9lca4040302lwrd6v-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
`nix build` drops a `result` symlink holding a full copy of the source tree, so `vitest run` collected and ran every test twice. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1xLDkqUDCYUMMADdMqVgP agent-session-id: 312caff5-3274-4d97-baa4-8ff06ab03fc5 agent-tool: Claude Code agent-tool-version: 2.1.215 agent-model: claude-opus-4-8 agent-runtime-profile: /nix/store/acr8a3l2v366jgmwiq8xdrhgz1py0db5-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/sj1v5j91h8v8d1w9lca4040302lwrd6v-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
pty-relay had no CI. Rather than a bespoke Node workflow — awkward while `@compoundingtech/pty` is a `file:../pty` link dependency with no sibling checkout on the runner — the flake is the gate: its inputs resolve the sibling from the `pty` flake. Modeled on compoundingtech/pty's .github/workflows/nix.yml, but running `nix flake check` rather than `nix build` so checks.* actually gate. Also adds checks.typecheck, running the repo's own `tsc --noEmit` against the built tree (where the sibling resolves; it cannot pass against a bare checkout). The vitest suite is deliberately not gated: under the nix sandbox test/daemon-runtime.test.ts hangs indefinitely at 0/14 and blocks two more files, while the other 69/72 pass. The same suite is fully green against the built tree outside the sandbox. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1xLDkqUDCYUMMADdMqVgP agent-session-id: 312caff5-3274-4d97-baa4-8ff06ab03fc5 agent-tool: Claude Code agent-tool-version: 2.1.215 agent-model: claude-opus-4-8 agent-runtime-profile: /nix/store/acr8a3l2v366jgmwiq8xdrhgz1py0db5-coding-agent-runtime-profile/share/coding-agents/profile.json agent-skills-manifest: /nix/store/sj1v5j91h8v8d1w9lca4040302lwrd6v-agent-skills-corpus/share/agent-skills/manifest.json tooling-profile: dotfiles@unknown-dirty
…-07-20-nix-flake feat(nix): add a self-contained flake building pty-relay from source
schickling
marked this pull request as ready for review
July 20, 2026 20:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
pty-relayships no shell completions at all, while both sibling CLIs do:ptygainedpty completions <shell>in compoundingtech/pty#106, andsthasst completions. Downstream packaging (Nix, Home Manager) hasnothing to call.
What
Adds
pty-relay completions <shell>forbash,fishandzsh.All three scripts are emitted from ONE declarative spec of the command
tree in
src/completions.ts, so they cannot drift apart. The spec isderived from the actual
switchdispatch insrc/cli.ts—main,dispatchServer,dispatchClient,dispatchLocaland theCLIENT_PASSTHROUGH_COMMANDSset — not from the prose--helptext.Coverage: the 26 top-level commands (including the
list/lsalias),the
server(11 verbs),client(signin/join + 9 passthroughs),local(3 verbs) and
clients(4 verbs) groups, their flags, the enum-valuedflags (
init --backend,server rotate --role) and enum positionals(
server totp show|code,completions bash|fish|zsh).How
src/completions.tsis the generator. It followspty's module shape(side-effect free,
console/exit-code based, sameFlagSpec/CommandSpecvocabulary) and borrows
st's nestedverbsbecause pty-relay — unlikepty— has namespaced groups. Verb names such asstart/status/resetcollide across groups, so the fish guards are scoped on both the verb and
its group.
src/cli.tsgains acase "completions". It setsprocess.exitCoderather than calling
process.exit(), so a redirected script is fullyflushed.
completionsis added to the list of commands excluded from thegeneric per-command
--helpshort-circuit, socompletions --helpdocuments its own shell list.
--experimental-strip-typessubset (typeannotations and
as constonly), since pty-relay runs raw.ts.Deliberately not dynamic
ptycompletes live session names off disk. pty-relay's peers live in theencrypted secret store — the plaintext
~/.config/pty-relay/peersfile isoptional and usually absent — so there is no cheap, reliable source for
host-label completion at completion time. Subcommands and flags only.
Verification
test/completions.test.ts(new, 41 cases): dispatch and exit codes viaspawnSync(importingcli.tsrunsmain()), the generated fishsurface, a spec-covers-real-dispatch assertion listing every user-typeable
caselabel, andbash -n/fish -n/zsh -nsyntax checks that skipwhen the shell is absent. All pass.
test/cli.test.tsstill passes except twodoctorcases that fail onmaintoo, in any checkout without a linked@compoundingtech/pty.