diff --git a/scripts/install.sh b/scripts/install.sh index 4e1b9103..2f8e9a91 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -314,7 +314,20 @@ resolve_dest() { hermes) var="HERMES_PLUGIN_DIR" ;; vibe) var="VIBE_HOME" ;; esac - if [[ -n "$var" && -n "${!var:-}" ]]; then printf '%s' "${!var}"; else printf '%s' "$def"; fi + if [[ -n "$var" && -n "${!var:-}" ]]; then + if [[ "$tool" == "claude-code" ]]; then + # CLAUDE_CONFIG_DIR is the config root (it replaces ~/.claude); + # agents live in its agents/ subdirectory (fixes #578). Strip one + # trailing slash; a value already ending in /agents is used verbatim + # so users who worked around the old bug are not double-nested. + local cfg="${!var}"; cfg="${cfg%/}" + if [[ "$cfg" == */agents ]]; then printf '%s' "$cfg"; else printf '%s' "$cfg/agents"; fi + else + printf '%s' "${!var}" + fi + else + printf '%s' "$def" + fi } # resolve_tool_path — best-effort binary path for the detection UI. @@ -415,7 +428,7 @@ check_integrations() { # --------------------------------------------------------------------------- # Tool detection # --------------------------------------------------------------------------- -detect_claude_code() { [[ -d "${HOME}/.claude" ]]; } +detect_claude_code() { [[ -d "${CLAUDE_CONFIG_DIR:-${HOME}/.claude}" ]]; } detect_copilot() { command -v code >/dev/null 2>&1 || [[ -d "${HOME}/.github" || -d "${HOME}/.copilot" ]]; } detect_antigravity() { [[ -d "${HOME}/.gemini/config/skills" ]]; } detect_gemini_cli() { command -v gemini >/dev/null 2>&1 || [[ -d "${HOME}/.gemini" ]]; } diff --git a/scripts/test-install.sh b/scripts/test-install.sh index 01a14611..f161e6cf 100755 --- a/scripts/test-install.sh +++ b/scripts/test-install.sh @@ -186,6 +186,37 @@ RUN_OUT="$(HOME="$home" COPILOT_AGENT_DIR="$home/from-env" "$INSTALL" --no-inter assert_eq "$TOTAL_AGENTS" "$(count_md "$home/from-flag")" "--path wins over the env var" assert_eq 0 "$(count_md "$home/from-env")" "env var destination is unused when --path is given" +# --------------------------------------------------------------------------- +# 3b. CLAUDE_CONFIG_DIR is the config root, not the agents dir (issue #578) +# +# Claude Code replaces ~/.claude with $CLAUDE_CONFIG_DIR, so agents belong in +# $CLAUDE_CONFIG_DIR/agents — matching the default ${HOME}/.claude/agents. +# Before the fix, resolve_dest returned the variable verbatim and agents +# landed in the config root where Claude Code never loads them; detection +# also missed relocated configs entirely. +# --------------------------------------------------------------------------- +home="$(sandbox claude-config-dir)" +cfg="$home/.config/claude-code" +RUN_OUT="$(HOME="$home" CLAUDE_CONFIG_DIR="$cfg" "$INSTALL" --no-interactive --tool claude-code 2>&1)"; RUN_STATUS=$? +assert_eq 0 "$RUN_STATUS" "CLAUDE_CONFIG_DIR install exits 0" +assert_eq "$TOTAL_AGENTS" "$(count_md "$cfg/agents")" "CLAUDE_CONFIG_DIR installs agents into \$CLAUDE_CONFIG_DIR/agents" +assert_eq 0 "$(count_md "$cfg")" "CLAUDE_CONFIG_DIR leaves the config root itself empty" + +# Trailing slash and a pre-existing /agents suffix both resolve cleanly. +home="$(sandbox claude-config-dir-slash)" +cfg="$home/.config/claude-code/" +RUN_OUT="$(HOME="$home" CLAUDE_CONFIG_DIR="$cfg" "$INSTALL" --no-interactive --tool claude-code 2>&1)"; RUN_STATUS=$? +assert_eq 0 "$RUN_STATUS" "trailing-slash CLAUDE_CONFIG_DIR install exits 0" +assert_eq "$TOTAL_AGENTS" "$(count_md "$home/.config/claude-code/agents")" \ + "a trailing slash on CLAUDE_CONFIG_DIR still resolves to .../agents" + +home="$(sandbox claude-config-dir-agents)" +cfg="$home/.config/claude-code/agents" +RUN_OUT="$(HOME="$home" CLAUDE_CONFIG_DIR="$cfg" "$INSTALL" --no-interactive --tool claude-code 2>&1)"; RUN_STATUS=$? +assert_eq 0 "$RUN_STATUS" "pre-suffixed CLAUDE_CONFIG_DIR install exits 0" +assert_eq "$TOTAL_AGENTS" "$(count_md "$cfg")" \ + "a CLAUDE_CONFIG_DIR already ending in /agents is used verbatim (no double-nesting)" + # --------------------------------------------------------------------------- # 4. Paths with spaces (regression: word-splitting in the install loop) # ---------------------------------------------------------------------------