Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Pipeline Design 1

ezigus edited this page Feb 21, 2026 · 2 revisions

Design: Add shell completion installation to shipwright init

Context

shipwright init is the one-command bootstrap for new users. Prior to this change, the completions/ directory shipped three completion scripts (_shipwright for zsh, shipwright.bash, shipwright.fish) but nothing installed them during init. Users had to manually copy files and configure their shell rc files — a friction point that caused completions to go unused. The goal is to make tab completion work out-of-the-box as part of the standard setup flow.

Constraints from the codebase:

  • All scripts must be Bash 3.2 compatible (set -euo pipefail; no declare -A, no readarray)
  • sw-init.sh runs in bash regardless of the user's login shell, so $BASH_VERSION is always set — $SHELL is the only reliable signal for the user's actual shell
  • Init is designed to be idempotent (safe to run multiple times); rc file mutations must check before appending
  • The test harness in sw-init-test.sh sandboxes $HOME via $TEMP_DIR/home — completion install logic must respect $HOME to remain testable
  • The completions/ source directory is located relative to $REPO_DIR, not the install target path

Decision

Install completions as a discrete section in sw-init.sh immediately after the pipeline templates block (line 387), before the Claude Code settings block. Shell type is detected exclusively from $SHELL (with $ZSH_VERSION/$BASH_VERSION as last-resort fallbacks). Per-shell installation follows the XDG/conventional locations for each shell. All rc file mutations are guarded by grep -q idempotency checks. An unknown or unset shell silently warns and skips rather than failing init.

Data flow:

$SHELL env var
 → SHELL_TYPE (zsh|bash|fish|"")
 → copy completions/$SOURCE → $HOME/SHELL_SPECIFIC_PATH
 → grep -q guard → append to rc file if absent
 → print reload hint

Error handling:

  • $SHELL unset or unrecognized → warn + skip (install_completions stays 0)
  • Source file missing in completions/ → silently skip that shell's block (inner [[ -f ]] guard)
  • ~/.zshrc absent → create minimal file with fpath + compinit rather than failing

Alternatives Considered

  1. Detect shell via ps / $PPID — Pros: works even when $SHELL is wrong. Cons: fragile on macOS (different ps flags), adds subprocess overhead, Bash 3.2 incompatibility risk, harder to override in tests. Rejected in favor of $SHELL.

  2. System-wide completion install (e.g., /usr/local/share/zsh/site-functions/) — Pros: available to all users. Cons: requires sudo, not appropriate for a developer tool installer, breaks sandboxed test harness. Rejected; user-local paths are correct for this audience.

  3. Delegate to a separate shipwright completions install subcommand — Pros: composable, skippable. Cons: users must know to run a second command; defeats the "one-command setup" goal. Rejected; inline in init is the right place.

  4. Overwrite rc files entirely — Pros: simpler code. Cons: destroys user customizations; catastrophic for idempotency. Rejected unconditionally.

Implementation Plan

  • Files to create: none (completion scripts already exist in completions/)
  • Files to modify:
    • scripts/sw-init.sh — Shell Completions section, lines 387–489 (already implemented on this branch)
    • scripts/sw-init-test.sh — Tests 22–26 (already implemented on this branch)
  • Dependencies: none (pure bash, no new external tools)
  • Risk areas:
    • rc file corruption under pipefail: The grep -c || echo "0" anti-pattern (documented in CLAUDE.md) must not appear; current implementation uses grep -q ... || { append; } which is safe
    • $HOME expansion in rc lines: The bash completion source line uses $HOME in a heredoc-style append — must be verified it resolves at write time, not at source time (current code uses literal $HOME in the echo string, which will write the variable name, not the expanded path — this is a known edge case worth verifying)
    • compinit placement: Appending compinit after user customizations in .zshrc can conflict if a user already loads it conditionally; the guard grep -q "compinit" mitigates but cannot handle all cases
    • Fish auto-discovery: Fish reads ~/.config/fish/completions/ natively with no rc change needed — this is correctly leveraged; no rc mutation for fish

Validation Criteria

  • Running SHELL=/bin/zsh bash scripts/sw-init.sh creates ~/.zsh/completions/_shipwright and appends fpath+=~/.zsh/completions to ~/.zshrc exactly once
  • Running SHELL=/bin/bash bash scripts/sw-init.sh creates ~/.local/share/bash-completion/completions/shipwright
  • Running SHELL=/usr/local/bin/fish bash scripts/sw-init.sh creates ~/.config/fish/completions/shipwright.fish
  • Running init twice with SHELL=/bin/zsh results in exactly one fpath line in ~/.zshrc (no duplicates)
  • Running init with SHELL="" or SHELL=/bin/sh exits 0 and prints a warn message, no completion files created
  • All 26 tests in scripts/sw-init-test.sh pass
  • npm test (all 102 suites) passes with no regressions
  • The source line written to ~/.bashrc resolves $HOME to the actual path at shell load time (not the literal string $HOME)

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /