Skip to content

CDPATH breaks all bin/ scripts — cd outputs path to stdout, corrupting variable assignments #824

@taige

Description

@taige

Bug

When CDPATH is set (common with zsh/bash users who use zoxide or custom navigation), every bin/ script silently fails because cd prints the resolved path to stdout, doubling the output of $(cd ... && pwd).

Root cause

Bash behavior: when CDPATH is set and cd resolves a directory through CDPATH, it prints the absolute path to stdout. This means:

# With CDPATH='.:/Users/me:/Users/me/Workspaces'
GSTACK_DIR="$(cd "$(dirname "$0")/.." && pwd)"
# cd outputs: /path/to/gstack
# pwd outputs: /path/to/gstack
# GSTACK_DIR = "/path/to/gstack\n/path/to/gstack" (two lines!)

This corrupts VERSION_FILE, CACHE_FILE, and every other path derived from GSTACK_DIR.

Specific impact on gstack-update-check: VERSION_FILE becomes a two-line string, [ -f "$VERSION_FILE" ] fails, LOCAL stays empty, script exits at line 68 (if [ -z "$LOCAL" ]; then exit 0; fi). Result: upgrade check always reports "up to date" regardless of actual version.

Affected scripts (18 total)

All scripts in bin/ that use the $(cd "$(dirname "$0")/.." && pwd) pattern:

  • gstack-update-check (most impactful - blocks all upgrade detection)
  • gstack-telemetry-log, gstack-telemetry-sync
  • gstack-community-dashboard, gstack-uninstall
  • gstack-timeline-log, gstack-timeline-read
  • gstack-specialist-stats, gstack-review-log, gstack-review-read
  • gstack-platform-detect, gstack-repo-mode, gstack-relink
  • gstack-learnings-log, gstack-learnings-search
  • gstack-extension, dev-setup, dev-teardown

Reproduction

export CDPATH='.:/Users/me:/Users/me/Workspaces'
~/.claude/skills/gstack/bin/gstack-update-check --force
# No output - silently exits, never checks remote VERSION

Fix

Redirect cd stdout to /dev/null in all path resolution patterns:

# Before (broken with CDPATH)
GSTACK_DIR="$(cd "$(dirname "$0")/.." && pwd)"

# After (works with any CDPATH)
GSTACK_DIR="$(cd "$(dirname "$0")/.." >/dev/null && pwd)"

Or use CDPATH= to suppress:

GSTACK_DIR="$(CDPATH= cd "$(dirname "$0")/.." && pwd)"

Environment

  • gstack v0.15.9.0 (also affects v0.11.10.0 and likely all versions)
  • macOS 14 (Darwin 24.6.0), bash 5.x
  • CDPATH set via zoxide (eval "$(zoxide init bash)" adds alias cd=z)
  • Also reproducible with manual CDPATH export

Workaround

Users can unset CDPATH before running gstack, but since gstack-update-check runs automatically in skill preambles, there is no practical workaround without patching the scripts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions