Skip to content

Pipeline Design 1

Seth Ford edited this page Feb 8, 2026 · 2 revisions

Now I have everything I need. Let me produce the ADR. I notice an important conflict between the original plan and the existing design document — the plan proposes inlining the completion logic, while the design document (Pipeline-Design-1.md) recommends delegating to install-completions.sh. There's also a critical .npmignore issue. Let me write the ADR.

Design: Add shell completion installation to shipwright init

Context

Shipwright has shell completions for bash, zsh, and fish in completions/ and a standalone installer at scripts/install-completions.sh (64 lines). However, the primary onboarding command shipwright init does not install completions. Users must discover and run the standalone script separately.

Current state:

  • completions/_shipwright (zsh), completions/shipwright.bash, completions/shipwright.fish — full subcommand/flag coverage
  • scripts/install-completions.sh — detects $SHELL, copies to per-user dirs, installs for all three aliases (shipwright, sw, cct), warns about fpath
  • scripts/cct (CLI router, line 160-243) — no completions case in main()
  • scripts/cct-init.sh (439 lines) — installs tmux, overlay, templates, settings, hooks, CLAUDE.md, deploy — no completions
  • install.sh line 690 references shipwright completions install but the command doesn't exist
  • .npmignore line 8 excludes scripts/install-completions.sh from npm packages, but the completions/ directory itself is not excluded (it ships)

Constraints:

  • Bash 3.2 compatibility — no declare -A, no readarray, no ${var,,}/${var^^}
  • set -euo pipefail in all scripts
  • Output via info(), success(), warn(), error() helpers
  • cct-init.sh is designed as non-interactive ("one command, no prompts")

Decision

Delegate to install-completions.sh from cct-init.sh rather than inlining the shell-detection logic. Also wire up shipwright completions install as a standalone CLI subcommand.

Approach — three changes:

  1. scripts/cct-init.sh — Insert a # ─── Shell Completions section between the CLAUDE.md per-repo block (line 275) and the tmux reload (line 277). Guard with [[ -x "$SCRIPT_DIR/install-completions.sh" ]]. Call with || true so init never fails on completion errors.

  2. scripts/cct — Add a completions) case in main() that execs $SCRIPT_DIR/install-completions.sh "$@". Add completions to show_help().

  3. install.sh — Add install-completions.sh to the subcommand scripts copied to $BIN_DIR (line 384 list), and copy the completions/ source directory to $HOME/.shipwright/completions/ so the script works when invoked from ~/.local/bin/.

Error handling:

  • cct-init.sh catches failures with || true — completions are nice-to-have, not blocking
  • Standalone shipwright completions install surfaces errors directly
  • If completions/ source directory is missing (e.g., npm install where it wasn't packaged), install-completions.sh fails on its cd at line 8 — caught by || true in init, shown as error in standalone

Idempotency: install-completions.sh uses cp unconditionally (quick overwrite). The plan's cmp -s approach would add value for messaging ("already installed" vs "installed"), but adds complexity. Recommend keeping the simple cp — completions are tiny files and overwriting is harmless. The zsh fpath check already uses grep -q to avoid duplicate .zshrc entries.

Path resolution risk: When install-completions.sh is copied to ~/.local/bin/, its SCRIPT_DIR/../completions resolves to ~/.local/completions which doesn't exist. Fix by also copying completions/ to ~/.shipwright/completions/ in install.sh, and adding a fallback in install-completions.sh:

COMPLETIONS_DIR="$(cd "$SCRIPT_DIR/../completions" 2>/dev/null && pwd)" \
    || COMPLETIONS_DIR="$HOME/.shipwright/completions"

Alternatives Considered

  1. Inline completion logic into cct-init.sh (the plan's approach) — Pros: self-contained, no external script dependency, can add cmp -s idempotency naturally / Cons: duplicates 64 lines of shell-detection logic already in install-completions.sh, creates two copies to maintain, doesn't give users a standalone completions command. The plan proposes single-file-only changes but this leaves the existing install-completions.sh orphaned and divergent.

  2. Only add completions subcommand, skip init integration — Pros: minimal change (router only) / Cons: new users still miss completions during onboarding, which defeats the purpose.

  3. Remove install-completions.sh and only inline — Pros: single source of truth / Cons: breaks install.sh's reference at line 690, breaks install-remote.sh which calls it at line 125-127, breaks Homebrew formula expectations. Too many consumers.

Implementation Plan

  • Files to create: None
  • Files to modify:
    • scripts/cct-init.sh — Add ~8-line Shell Completions section at line 276 (after CLAUDE.md per-repo, before tmux reload)
    • scripts/cct — Add completions) case in main() (~2 lines at line 227). Add entry in show_help() (~1 line at line 87)
    • install.sh — Add install-completions.sh to the script install loop (line 384). Add completions/ directory copy to ~/.shipwright/completions/ (~4 lines after line 451)
    • scripts/install-completions.sh — Add fallback path resolution for COMPLETIONS_DIR (line 8, ~2 line change) so it works from ~/.local/bin/
  • Dependencies: None new
  • Risk areas:
    • .npmignore excludes install-completions.sh (line 8) — npm users won't have the standalone installer. The completions/ directory is shipped, so init could fallback to inline logic for npm installs, but the simplest fix is to remove line 8 from .npmignore. This should be a conscious decision.
    • install-completions.sh path resolution when run from ~/.local/bin/ — mitigated by the COMPLETIONS_DIR fallback and copying completions to ~/.shipwright/completions/
    • Homebrew installs bypass both init and install.sh — Homebrew formula already handles completions at lines 54-58 via bash_completion.install, zsh_completion.install, fish_completion.install. No change needed there.

Validation Criteria

  • shipwright init installs completions for the current shell without prompting, and shows success/warn output
  • shipwright init succeeds when completions/ directory is missing (graceful warn + skip)
  • shipwright init succeeds when install-completions.sh is missing (graceful warn + skip)
  • shipwright completions install works as a standalone command
  • shipwright help lists completions in the command list
  • Running shipwright init twice doesn't produce errors or duplicate .zshrc entries
  • After init, shipwright <TAB> shows subcommands in the user's shell
  • install.sh copies install-completions.sh and completions/ to appropriate locations
  • install-completions.sh works correctly when invoked from ~/.local/bin/ (fallback path)
  • All scripts remain Bash 3.2 compatible
  • npm test passes with no regressions
  • Decide whether to remove install-completions.sh from .npmignore (line 8) — if kept, npm users only get completions via init with inline fallback; if removed, standalone command also works for npm installs

Clone this wiki locally