# Verifying shell completion This guide verifies the **`completions`** command — the completion scripts that `dsh-skills-nexus completions --shell ` emits: - `--shell` accepts `bash`, `zsh`, `fish` or `powershell` and writes that shell's script to stdout. Any other value is a usage error (exit 2) with **empty stdout** — a script that pipes the output never receives half a template. - Each script completes three layers: the subcommand, the flags of that subcommand, and — for the name-taking commands — the installed skill names. "First positional" is counted by ignoring `-`-prefixed words, so `remove --yes ` still offers names. - The name layer shells out to `dsh-skills-nexus list --names`; no script reads `manifest.json`, so an internal schema change cannot silently break completion. > **Shell warning — run each block in the shell named in its heading.** The > bash block runs in Git Bash (Windows) or any POSIX shell; the PowerShell > block runs in PowerShell; the zsh / fish block runs where those shells exist > (macOS, Linux, WSL). Do not paste a POSIX block into PowerShell or vice > versa. Blocks use absolute paths or `git -C `; none of them leaves a > `cd` behind (the fish part swaps to a temp dir with `pushd` and back), so > your working tree cannot be polluted. Everything below is safe: it uses an isolated `DSH_HOME` under a temp dir, two local `file://` upstream repos stand in for GitHub (no network), and your real `~/.dsh` is never touched. Delete the temp dirs at the end. ## Prerequisites - Node.js ≥ 20 and git on `PATH`, plus the shell you want to verify - Repo checked out and `npm install` done (the test suite runs via `tsx` from `node_modules`) - If you changed `src/`, run `npm run build` first — the walkthrough runs the compiled CLI from `lib/` --- ## Part 1 — test suite (quality gates) ```bash npm run typecheck # tsc --noEmit (strict + noUncheckedIndexedAccess) npm run lint # ESLint 9 + typescript-eslint npm test # node:test + tsx — expected: all tests pass npm run build # tsc → lib/ node --import tsx --test test/completions.test.ts # just this feature ``` | test file | what it verifies | |---|---| | `test/completions.test.ts` | argument parsing (`--shell` in both spellings, unsupported shells, usage errors leaving stdout empty); the four templates as text (subcommand list vs. the CLI router, per-command flags, no `--yes` for update/pull, `list --names` and never `manifest.json`, pure ASCII); and **three execution tests that run the emitted scripts in a real bash / zsh / fish** | The three execution tests self-skip when their shell is missing — a Windows dev box has bash (Git Bash) but neither zsh nor fish, so there two tests skip. The CI Linux job installs both shells so every template is executed on each push; macOS runs zsh natively. PowerShell has no runner in this project's CI, so its template is pinned as text and its rules were measured by hand on PS 5.1 (see Part 2 / Part 3). --- ## Part 2 — end-to-end walkthrough Each block is self-contained for the shell in its heading: it builds an isolated fixture (`DSH_HOME` under a temp dir, two `file://` upstream repos standing in for GitHub), installs two skills (`alpha`, `beta`) as the dynamic name source, loads the emitted template, and then prints the candidates for a fixed set of command lines — one `label|candidates` line per case. ### bash — Git Bash (Windows) or any POSIX shell ```bash PROJECT=~/Downloads/dsh-skills-nexus # ← your checkout path PROJECT_WIN="$(cygpath -m "$PROJECT")" # POSIX shells: skip this, use "$PROJECT" TROOT="$(cygpath -m "$TEMP")/nexus-completions" # isolated playground UP_A="$TROOT/up-alpha" UP_B="$TROOT/up-beta" export DSH_HOME="$TROOT/home" BIN="$TROOT/bin" rm -rf "$TROOT" # clean slate mkdir -p "$UP_A" "$UP_B" "$BIN" # ---- two upstream repos (stand in for GitHub): one repo per skill, because a # ---- repo can only be registered under a single name (the clone dir is the slug) git -C "$UP_A" init -q -b main # git >= 2.28 git -C "$UP_A" config user.email t@t git -C "$UP_A" config user.name t printf -- '---\nname: alpha\ndescription: alpha skill\n---\n# alpha\n' > "$UP_A/SKILL.md" git -C "$UP_A" add . git -C "$UP_A" commit -q -m init git -C "$UP_B" init -q -b main git -C "$UP_B" config user.email t@t git -C "$UP_B" config user.name t printf -- '---\nname: beta\ndescription: beta skill\n---\n# beta\n' > "$UP_B/SKILL.md" git -C "$UP_B" add . git -C "$UP_B" commit -q -m init # ---- stub CLI on PATH: the templates call `dsh-skills-nexus list --names`, # ---- and this puts that name on PATH without a global install printf '#!/bin/sh\nexec node "%s/lib/cli/index.js" "$@"\n' "$PROJECT_WIN" > "$BIN/dsh-skills-nexus" chmod +x "$BIN/dsh-skills-nexus" export PATH="$BIN:$PATH" # ---- install both skills as the dynamic name source ---- dsh-skills-nexus add "file:///$UP_A" --name alpha dsh-skills-nexus add "file:///$UP_B" --name beta dsh-skills-nexus list --names # alpha, beta # ---- load the emitted template ---- eval "$(dsh-skills-nexus completions --shell bash)" # ---- drive it: hand the function the words bash would hand it ---- probe() { # probe