From cc3e08bf349f968e24a60f1b46555d474a96f6d9 Mon Sep 17 00:00:00 2001 From: Eivind Date: Fri, 10 Apr 2026 14:37:22 +0200 Subject: [PATCH] fix: use relative symlinks for vendored/local installs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit link_claude_skill_dirs() was creating absolute symlinks for SKILL.md files regardless of install type. For vendored installs where gstack lives inside the project's .claude/skills/, this bakes in the machine- specific absolute path, breaking portability — other developers cloning the repo get dangling symlinks and git shows churn on every upgrade. Now detects when gstack is a direct child of skills_dir and uses relative paths (e.g., ../gstack/qa/SKILL.md) instead. Absolute paths are still used for global installs where the gstack directory lives outside the skills directory. Fixes #954 Co-Authored-By: Claude Opus 4.6 (1M context) --- setup | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/setup b/setup index f71f4552ca..e16009fba4 100755 --- a/setup +++ b/setup @@ -298,6 +298,13 @@ link_claude_skill_dirs() { local gstack_dir="$1" local skills_dir="$2" local linked=() + local gstack_basename="$(basename "$gstack_dir")" + # Use relative symlinks when gstack is inside skills_dir (vendored/local installs). + # Absolute paths break portability — other devs cloning the repo get dangling symlinks. + local resolved_parent="$(cd "$gstack_dir/.." 2>/dev/null && pwd -P)" + local resolved_skills="$(cd "$skills_dir" 2>/dev/null && pwd -P)" + local use_relative=0 + [ "$resolved_parent" = "$resolved_skills" ] && use_relative=1 for skill_dir in "$gstack_dir"/*/; do if [ -f "$skill_dir/SKILL.md" ]; then dir_name="$(basename "$skill_dir")" @@ -320,12 +327,16 @@ link_claude_skill_dirs() { if [ -L "$target" ]; then rm -f "$target" fi - # Create real directory with symlinked SKILL.md (absolute path) + # Create real directory with symlinked SKILL.md # Use mkdir -p unconditionally (idempotent) to avoid TOCTOU race mkdir -p "$target" # Validate target isn't a symlink before creating the link if [ -L "$target/SKILL.md" ]; then rm "$target/SKILL.md"; fi - ln -snf "$gstack_dir/$dir_name/SKILL.md" "$target/SKILL.md" + if [ "$use_relative" -eq 1 ]; then + ln -snf "../$gstack_basename/$dir_name/SKILL.md" "$target/SKILL.md" + else + ln -snf "$gstack_dir/$dir_name/SKILL.md" "$target/SKILL.md" + fi linked+=("$link_name") fi done