Skip to content

Pipeline Design 1

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

Now I have all the context needed. Let me write the ADR.

Design: Add shell completion installation to shipwright init

Context

Shipwright already has shell completions for bash, zsh, and fish in the completions/ directory, and a standalone installer script at scripts/install-completions.sh. However, the shipwright init command — the primary onboarding path — does not install completions. Users must know to separately run scripts/install-completions.sh or shipwright completions install (which doesn't exist yet in the CLI router). The install.sh summary mentions "Tab completions: shipwright completions install" (line 691) but this command is not routed.

Current state:

  • completions/shipwright.bash, completions/_shipwright (zsh), completions/shipwright.fish exist with full subcommand coverage
  • scripts/install-completions.sh (64 lines) handles all three shells: detects $SHELL, copies completion files to standard per-user directories, warns about fpath for zsh
  • scripts/cct (CLI router) has no completions case in its main() dispatch
  • scripts/cct-init.sh (439 lines) installs tmux config, overlay, templates, Claude Code settings, hooks, CLAUDE.md, and deploy setup — but not completions
  • install.sh (697 lines) also does not install completions, though its summary references the command

Constraints:

  • Bash 3.2 compatibility (no associative arrays, no readarray, no ${var,,})
  • set -euo pipefail in all scripts
  • Output must use info(), success(), warn(), error() helpers
  • Atomic operations — no partial writes
  • The completions/ directory is relative to $REPO_DIR, resolved from $SCRIPT_DIR/..

Decision

Add shell completion installation as a new section in scripts/cct-init.sh and wire up a completions subcommand in the CLI router (scripts/cct). The implementation delegates to the existing scripts/install-completions.sh to avoid duplicating shell-detection logic.

Data flow:

  1. shipwright initcct-init.sh → calls $SCRIPT_DIR/install-completions.sh after hooks/CLAUDE.md and before the tmux reload + doctor run
  2. shipwright completions installcct router → exec $SCRIPT_DIR/install-completions.sh "$@"

Error handling:

  • If completions/ directory doesn't exist (e.g., npm global install without completions packaged), skip gracefully with warn — don't fail the entire init
  • If install-completions.sh exits non-zero (e.g., unsupported shell), catch with || true so init continues
  • The standalone completions command surfaces errors directly (no || true)

Non-interactive by default in init: The completions section in cct-init.sh runs without prompting since init is designed to be non-interactive (the "no prompts" design — see header comment line 5). This matches how other sections like templates and hooks work in init.

Alternatives Considered

  1. Inline the completion logic into cct-init.sh — Pros: self-contained, no exec dependency / Cons: duplicates the 64-line shell-detection logic in install-completions.sh, creates two copies to maintain, violates DRY
  2. Only add completions CLI subcommand, don't integrate into init — Pros: minimal change / Cons: new users still won't get completions during onboarding, they must know to run a separate command
  3. Add to install.sh instead of cct-init.sh — Pros: the interactive installer is already the "full setup" / Cons: install.sh is the initial install path and users may not re-run it; init is the repeatable onboarding command that users run in each repo

Implementation Plan

  • Files to modify:

    • scripts/cct-init.sh — Add a "Shell Completions" section (~10 lines) between the CLAUDE.md per-repo section (line 275) and the tmux reload (line 277). Guard with [[ -x "$SCRIPT_DIR/install-completions.sh" ]]. Call the script with || true to avoid breaking init if completions fail.
    • scripts/cct — Add a completions case in the main() router (around line 227, after init). Route to exec "$SCRIPT_DIR/install-completions.sh" "$@". Also add completions to the show_help() output.
    • install.sh — Add install-completions.sh to the list of subcommand scripts installed to $BIN_DIR (line 384).
  • Files to create: None — all completion files and the installer script already exist.

  • Dependencies: None new. The completion files (completions/shipwright.bash, completions/_shipwright, completions/shipwright.fish) are already in the repo.

  • Risk areas:

    • $COMPLETIONS_DIR resolution in install-completions.sh (line 8): Uses cd "$SCRIPT_DIR/../completions" && pwd which will fail with set -e if the completions/ directory doesn't exist. This is fine for the standalone command (should error visibly) but must be caught with || true when called from init.
    • npm global install path: When installed via npm, symlinks resolve through $SCRIPT_DIR back to node_modules/. The completions/ directory needs to be in the npm package (check .npmignore — it's already listed under included files).
    • $BIN_DIR install path: When scripts are copied to ~/.local/bin/ by install.sh, install-completions.sh resolves $COMPLETIONS_DIR relative to its own location. After copying to ~/.local/bin/, the ../completions/ path won't resolve. The install.sh should also copy the completions directory, or install-completions.sh needs a fallback to $HOME/.shipwright/completions/ or the repo path from the manifest.

Validation Criteria

  • shipwright init installs completions for the user's shell without prompting
  • shipwright init succeeds even if completions/ directory is missing (graceful skip with warning)
  • shipwright completions install works as a standalone command and shows success/error output
  • shipwright help lists completions in the command list
  • install.sh installs install-completions.sh to $BIN_DIR alongside other subcommands
  • After init, tab-completing shipwright <TAB> shows subcommands in bash/zsh/fish
  • All scripts remain Bash 3.2 compatible (no associative arrays, no readarray)
  • Existing npm test suite passes (no regressions in pipeline/daemon/prep/fleet/fix/memory tests)
  • The completions/ directory is included in the npm package (verify .npmignore doesn't exclude it)

Clone this wiki locally