magellan 4.13.0

Deterministic codebase mapping tool for local development
Documentation
#!/usr/bin/env fish
# Magellan install script — fish shell
# Usage: fish install/install.fish [--no-service] [--no-hook]

set MAGELLAN_VERSION "4.9.1"
set INSTALL_SERVICE 1
set INSTALL_HOOK 1
set HOOK_THRESHOLD 15

for arg in $argv
    switch $arg
        case --no-service
            set INSTALL_SERVICE 0
        case --no-hook
            set INSTALL_HOOK 0
        case '*'
            echo "[magellan] ERROR: Unknown flag: $arg" >&2
            exit 1
    end
end

function info
    echo "[magellan] $argv"
end

function warn
    echo "[magellan] WARN: $argv" >&2
end

function die
    echo "[magellan] ERROR: $argv" >&2
    exit 1
end

# ── Prerequisites ─────────────────────────────────────────────────────────

if not command -q cargo
    die "Rust toolchain not found. Install from https://rustup.rs and re-run."
end
if not command -q git
    die "git not found."
end
if not command -q jq
    warn "jq not found — pre-commit blast-radius hook requires it."
end

# ── Install binary ────────────────────────────────────────────────────────

info "Installing magellan $MAGELLAN_VERSION via cargo..."
cargo install magellan --version $MAGELLAN_VERSION --locked

set MAGELLAN_BIN (set -q CARGO_HOME; and echo "$CARGO_HOME/bin/magellan"; or echo "$HOME/.cargo/bin/magellan")
if not test -x $MAGELLAN_BIN
    die "Binary not found at $MAGELLAN_BIN after install."
end

info "Installed: "(magellan --version)

# ── Directory layout ──────────────────────────────────────────────────────

set MAGELLAN_HOME "$HOME/.magellan"
set CONFIG_DIR "$HOME/.config/magellan"
mkdir -p $MAGELLAN_HOME $CONFIG_DIR
info "Data directory: $MAGELLAN_HOME"

# ── Fish environment setup ────────────────────────────────────────────────

set FISH_CONFIG_DIR "$HOME/.config/fish/conf.d"
mkdir -p $FISH_CONFIG_DIR

set ENV_FILE "$FISH_CONFIG_DIR/magellan.fish"
if not test -f $ENV_FILE
    info "Writing fish env → $ENV_FILE"
    echo '# Magellan environment — auto-generated by install.fish' > $ENV_FILE
    echo 'set -gx MAGELLAN_HOME "$HOME/.magellan"' >> $ENV_FILE
    echo '# Uncomment to set a default DB for a primary project:' >> $ENV_FILE
    echo '# set -gx MAGELLAN_DB "$HOME/.magellan/myproject/myproject.db"' >> $ENV_FILE
    echo '# Uncomment to set MIRAGE_DB (avoids --db on every mirage call):' >> $ENV_FILE
    echo '# set -gx MIRAGE_DB "$HOME/.magellan/myproject/myproject.db"' >> $ENV_FILE
else
    info "Fish env already exists at $ENV_FILE — skipping."
end

# ── Pre-commit blast-radius hook ──────────────────────────────────────────

set HOOK_SCRIPT "$HOME/.local/bin/pre-commit-blast-radius"
mkdir -p "$HOME/.local/bin"

if test $INSTALL_HOOK -eq 1
    info "Installing pre-commit blast-radius hook → $HOOK_SCRIPT"
    # Hook is bash for portability (git runs hooks via /bin/sh or bash)
    echo '#!/usr/bin/env bash' > $HOOK_SCRIPT
    echo '# Magellan blast-radius warning hook — warn only, never blocks commit.' >> $HOOK_SCRIPT
    echo "# Env vars: BLAST_RADIUS_THRESHOLD (default $HOOK_THRESHOLD), BLAST_RADIUS_MAX_SYMBOLS (default 8), BLAST_RADIUS_DEPTH (default 2)" >> $HOOK_SCRIPT
    cat >> $HOOK_SCRIPT << 'HOOK_EOF'
set -euo pipefail
THRESHOLD="${BLAST_RADIUS_THRESHOLD:-15}"
MAX_SYMBOLS="${BLAST_RADIUS_MAX_SYMBOLS:-8}"
DEPTH="${BLAST_RADIUS_DEPTH:-2}"
PROJECT=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)")
MAGELLAN_DB="$HOME/.magellan/$PROJECT/$PROJECT.db"
[[ ! -f "$MAGELLAN_DB" ]] && exit 0
STAGED=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null \
  | grep -E '\.(rs|py|c|cpp|h|hpp|ts|js|go)$' || true)
[[ -z "$STAGED" ]] && exit 0
WARNED=0; CHECKED=0
for file in $STAGED; do
  [[ "$CHECKED" -ge "$MAX_SYMBOLS" ]] && break
  SYMBOLS=$(magellan query --db "$MAGELLAN_DB" --file "$file" --output json 2>/dev/null \
    | jq -r '.data.symbols[].name' 2>/dev/null || true)
  for sym in $SYMBOLS; do
    [[ "$CHECKED" -ge "$MAX_SYMBOLS" ]] && break
    CHECKED=$((CHECKED + 1))
    RESULT=$(magellan context impact --db "$MAGELLAN_DB" --name "$sym" --depth "$DEPTH" --output json 2>/dev/null || true)
    [[ -z "$RESULT" ]] && continue
    TOTAL=$(echo "$RESULT" | jq -r '.data.total_records // 0' 2>/dev/null || echo 0)
    if [[ "$TOTAL" -gt "$THRESHOLD" ]]; then
      [[ "$WARNED" -eq 0 ]] && echo "" && echo "BLAST RADIUS WARNING (warn-only, commit proceeds)" && echo "──────────────────────────────────────────────────"
      echo "  ⚠  $sym → $TOTAL symbols affected (depth $DEPTH)  [$file]"
      WARNED=1
    fi
  done
done
if [[ "$WARNED" -eq 1 ]]; then
  echo ""
  echo "Inspect: magellan context impact --db $MAGELLAN_DB --name <symbol> --depth 3"
  echo "──────────────────────────────────────────────────"
  echo ""
fi
exit 0
HOOK_EOF
    chmod +x $HOOK_SCRIPT
    info "Hook installed. Enable per-project: ln -sf ~/.local/bin/pre-commit-blast-radius .git/hooks/pre-commit"
end

# ── systemd user service (Linux only) ────────────────────────────────────

if test $INSTALL_SERVICE -eq 1; and command -q systemctl
    set SERVICE_DIR "$HOME/.config/systemd/user"
    mkdir -p $SERVICE_DIR
    set SERVICE_FILE "$SERVICE_DIR/magellan.service"

    echo '[Unit]' > $SERVICE_FILE
    echo 'Description=Magellan code intelligence service daemon' >> $SERVICE_FILE
    echo 'Documentation=https://github.com/oldnordic/magellan/blob/main/MANUAL.md' >> $SERVICE_FILE
    echo 'After=network.target' >> $SERVICE_FILE
    echo '' >> $SERVICE_FILE
    echo '[Service]' >> $SERVICE_FILE
    echo 'Type=simple' >> $SERVICE_FILE
    echo 'ExecStart=%h/.cargo/bin/magellan service-daemon' >> $SERVICE_FILE
    echo 'Restart=on-failure' >> $SERVICE_FILE
    echo 'RestartSec=5' >> $SERVICE_FILE
    echo 'KillMode=process' >> $SERVICE_FILE
    echo 'TimeoutStopSec=30' >> $SERVICE_FILE
    echo '' >> $SERVICE_FILE
    echo '[Install]' >> $SERVICE_FILE
    echo 'WantedBy=default.target' >> $SERVICE_FILE

    systemctl --user daemon-reload
    systemctl --user enable magellan.service
    systemctl --user start magellan.service
    info "systemd service enabled and started."
    info "Status: systemctl --user status magellan"
end

# ── Done ──────────────────────────────────────────────────────────────────

info ""
info "Installation complete — magellan $MAGELLAN_VERSION"
info ""
info "Quick start:"
info "  magellan init --path /your/project"
info "  magellan watch --root /your/project/src --db ~/.magellan/<project>/<project>.db --scan-initial"
info "  magellan orient --db ~/.magellan/<project>/<project>.db --repo /your/project"
info ""
info "Reload fish env: source ~/.config/fish/conf.d/magellan.fish"
info "Full manual: https://github.com/oldnordic/magellan/blob/main/MANUAL.md"