Skip to content

feat: auto-install shell completions via install#504

Open
lockwobr wants to merge 2 commits intomainfrom
feat/auto-completions-338
Open

feat: auto-install shell completions via install#504
lockwobr wants to merge 2 commits intomainfrom
feat/auto-completions-338

Conversation

@lockwobr
Copy link
Copy Markdown
Contributor

@lockwobr lockwobr commented Apr 7, 2026

Summary

  • Auto-install bash, zsh, and fish shell completions in the install script, with OS-aware path resolution (Linux system dirs vs macOS Homebrew
    prefix detection) and user-local XDG fallback
  • Add generate_completions_from_executable to the Homebrew formula in .goreleaser.yaml so brew install handles completions automatically
  • Update installation docs to reflect automatic completions, document AICR_NO_COMPLETIONS=1 opt-out, and list completion file paths in the
    uninstall section

Test plan

  • Run ./install on macOS — verify bash/zsh completions installed, fish skipped if not installed
  • Run AICR_NO_COMPLETIONS=1 ./install — verify completions are skipped
  • Run shellcheck ./install — no new warnings
  • Run go test ./pkg/cli/ -run TestCompletion — existing completion tests pass
  • Run goreleaser check — validates formula template with new line
  • Verify uninstall docs list all paths the install script can write to

Motivation / Context

Closes #338

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Build/CI/tooling

Component(s) Affected

  • CLI (cmd/aicr, pkg/cli)
  • API server (cmd/aicrd, pkg/api, pkg/server)
  • Recipe engine / data (pkg/recipe)
  • Bundlers (pkg/bundler, pkg/component/*)
  • Collectors / snapshotter (pkg/collector, pkg/snapshotter)
  • Validator (pkg/validator)
  • Core libraries (pkg/errors, pkg/k8s)
  • Docs/examples (docs/, examples/)
  • Other: ____________

Risk Assessment

  • Low — Isolated change, well-tested, easy to revert
  • Medium — Touches multiple components or has broader impact
  • High — Breaking change, affects critical paths, or complex rollout

Rollout notes:

Checklist

  • Tests pass locally (make test with -race)
  • Linter passes (make lint)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality
  • I updated docs if user-facing behavior changed
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S) — GPG signing info

@lockwobr lockwobr self-assigned this Apr 7, 2026
@lockwobr lockwobr requested review from a team as code owners April 7, 2026 22:35
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Coverage Report ✅

Metric Value
Coverage 74.1%
Threshold 70%
Status Pass
Coverage Badge
![Coverage](https://img.shields.io/badge/coverage-74.1%25-green)

No Go source files changed in this PR.

Copy link
Copy Markdown
Contributor

@yuanchen8911 yuanchen8911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline comments from cross-review (Claude Code + Codex + CodeRabbit)

@yuanchen8911
Copy link
Copy Markdown
Contributor

Cross-Review Summary (Iterative Consensus)

Reviewers: Claude Code, Codex, CodeRabbit
Rounds: 2 (independent reviews → cross-review with AGREE/DISAGREE)
Consensus reached: Yes

Confirmed Issues (all three reviewers agree)

# File Line Severity Description
1 install (write_completion) ~119, 127 Major mktemp creates files with 0600 permissions. After sudo mv to a system completion dir, non-root users can't read the file — completions silently fail. Add chmod 644 "$tmp_file" before the mv.
2 install (setup_fish_completions) ~170 Minor Fish completions only install to user dir (~/.config/fish/). Under sudo, this goes to /root/.config/fish/. Unlike bash/zsh which try system dirs first, fish has no system-dir fallback.
3 install ~407 Minor `setup_completions

Contested Issues (2-1 split)

# File Severity Description For Against
4 install (~L139, ~L157) Minor Hardcoded [[ -d /opt/homebrew ]] duplicated in bash+zsh functions. Claude Code, CodeRabbit Codex — standard ecosystem idiom; brew --prefix requires brew in PATH which isn't guaranteed under sudo; no realistic false-positive.

Dismissed Findings

  • Orphaned temp file on sudo mkdir path (CodeRabbit) — Dismissed by Claude Code + Codex: the -w "$target_dir" check correctly routes to sudo mv when the dir is root-owned, and both branches clean up temp files on failure.

Positive Observations

  • Clean per-shell function separation with proper error handling
  • AICR_NO_COMPLETIONS=1 opt-out is good UX
  • XDG fallback for user-local installs is well implemented
  • Non-empty output validation before installing completion files
  • .goreleaser.yaml uses standard Homebrew DSL correctly

Iterative cross-review by Claude Code + Codex + CodeRabbit (2 rounds)

Copy link
Copy Markdown
Contributor

@yuanchen8911 yuanchen8911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline comments from iterative cross-review (Claude Code + Codex + CodeRabbit, 2 rounds)

local target_dir tmp_file
target_dir=$(dirname "$target")
mkdir -p "$target_dir" 2>/dev/null || sudo mkdir -p "$target_dir" 2>/dev/null || return 1
tmp_file=$(mktemp) || return 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major — confirmed by all 3 reviewers] mktemp creates files with 0600 permissions. After sudo mv to a system completion dir, non-root users can't read the file — completions silently fail. Add chmod 644 "$tmp_file" before the mv.

Iterative cross-review: Claude Code AGREE, Codex AGREE, CodeRabbit AGREE

setup_fish_completions() {
local bin_path="$1"
local fish_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish"
[[ -d "$fish_dir" ]] || return 0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor — confirmed by all 3 reviewers] Fish completions only install to user dir. Under sudo, $HOME resolves to /root, so completions land in /root/.config/fish/ — useless for the actual user. Bash/zsh try system dirs first with a user-dir fallback, but fish has no system-dir attempt. Consider adding a system path fallback (e.g., /usr/share/fish/vendor_completions.d/).

Iterative cross-review: Claude Code AGREE (Low), Codex AGREE (Medium), CodeRabbit AGREE

}

# ==============================================================================
# GitHub API Functions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor — confirmed by all 3 reviewers] || true swallows all errors from setup_completions, including catastrophic failures like get_os failing. The individual sub-functions already warn, but a top-level catch would help edge cases. Consider: setup_completions || warn "Shell completion setup failed (non-fatal)"

Iterative cross-review: Claude Code AGREE, Codex AGREE, CodeRabbit AGREE

Copy link
Copy Markdown
Contributor

@ArangoGutierrez ArangoGutierrez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one! Love that completions are automatic now — been wanting this. Just one real blocker (the mktemp permissions thing) and a couple small suggestions. Should be quick to fix.

if [[ -w "$target_dir" ]]; then
mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; }
else
sudo mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main thing — mktemp creates files 0600, so after sudo mv nobody else can read them and completions silently break. Slap a chmod 644 "$tmp_file" before the sudo mv branch and you're good.

setup_fish_completions() {
local bin_path="$1"
local fish_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish"
[[ -d "$fish_dir" ]] || return 0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the script runs under sudo, $HOME is /root so fish completions end up in /root/.config/fish/ — not super useful. Bash/zsh handle this by trying system dirs first. Maybe try /usr/share/fish/vendor_completions.d/ before falling back to the user dir?

}

# ==============================================================================
# GitHub API Functions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: || true eats everything silently. Maybe || warn "Shell completion setup failed (non-fatal)" so there's at least a breadcrumb if something weird happens?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: auto install of completions via install script

4 participants