link.sh 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #!/usr/bin/env bash
  2. # Symlink this repo into ~/.claude/
  3. set -euo pipefail
  4. REPO="$(cd "$(dirname "$0")" && pwd)"
  5. CLAUDE="$HOME/.claude"
  6. CHANGED=0
  7. mkdir -p "$CLAUDE"
  8. link_file() {
  9. local src="$1" dst="$2"
  10. if [ -L "$dst" ] && [ "$(readlink "$dst")" = "$src" ]; then
  11. return # already correct
  12. fi
  13. ln -sf "$src" "$dst"
  14. CHANGED=$((CHANGED + 1))
  15. }
  16. link_file "$REPO/CLAUDE.md" "$CLAUDE/CLAUDE.md"
  17. link_file "$REPO/settings.json" "$CLAUDE/settings.json"
  18. for item in hooks agents skills lib templates; do
  19. target="$CLAUDE/$item"
  20. if [ -L "$target" ]; then
  21. if [ "$(readlink "$target")" = "$REPO/$item" ]; then
  22. continue # already correct
  23. fi
  24. rm -f "$target"
  25. elif [ -d "$target" ]; then
  26. echo "⚠️ ~/.claude/$item is a real directory. Rename or remove it, then re-run link.sh."
  27. continue
  28. fi
  29. ln -sf "$REPO/$item" "$target"
  30. CHANGED=$((CHANGED + 1))
  31. done
  32. # GStack is exposed via per-skill symlinks under skills/ (browse,
  33. # canary, autoplan, design-review, …) created by gstack's own
  34. # `./setup`. A global `skills/gstack -> skills-external/gstack/`
  35. # symlink duplicated the top-level gstack SKILL.md alongside those
  36. # individual skills, producing two entries with the same description
  37. # ("Fast headless browser for QA testing…"). Remove any stale global
  38. # link — only per-skill entries remain.
  39. if [ -L "$REPO/skills/gstack" ] || [ -L "$CLAUDE/skills/gstack" ]; then
  40. rm -f "$REPO/skills/gstack" "$CLAUDE/skills/gstack"
  41. CHANGED=$((CHANGED + 1))
  42. fi
  43. if [ ! -d "$REPO/skills-external/gstack" ]; then
  44. echo "⚠️ GStack submodule not found — run: git submodule update --init"
  45. fi
  46. if [ -d "$REPO/skills-external/emil-design-eng" ]; then
  47. if [ -L "$CLAUDE/skills/emil-design-eng" ] && [ "$(readlink "$CLAUDE/skills/emil-design-eng")" = "$REPO/skills-external/emil-design-eng" ]; then
  48. : # already correct
  49. else
  50. ln -sf "$REPO/skills-external/emil-design-eng" "$CLAUDE/skills/emil-design-eng"
  51. CHANGED=$((CHANGED + 1))
  52. fi
  53. else
  54. echo "⚠️ emil-design-eng not found — run: make plugin"
  55. fi
  56. # External skills installed via `npx skills add` live under
  57. # $HOME/.agents/skills/. We symlink them into $REPO/skills/ with
  58. # absolute paths so the link stays valid regardless of where the
  59. # repo is cloned (relative ../../ paths broke on repos deeper than
  60. # one level below $HOME).
  61. NPX_EXTERNAL_SKILLS=(darwin-skill find-skills)
  62. for _ext in "${NPX_EXTERNAL_SKILLS[@]}"; do
  63. _target="$HOME/.agents/skills/$_ext"
  64. _link="$REPO/skills/$_ext"
  65. if [ ! -d "$_target" ]; then
  66. echo "⚠️ $_ext not installed at $_target — run: make plugin"
  67. continue
  68. fi
  69. if [ -L "$_link" ] && [ "$(readlink "$_link")" = "$_target" ]; then
  70. continue
  71. fi
  72. rm -f "$_link"
  73. ln -sf "$_target" "$_link"
  74. CHANGED=$((CHANGED + 1))
  75. done
  76. if [ "$CHANGED" -eq 0 ]; then
  77. echo "✅ All symlinks already up to date."
  78. else
  79. echo "✅ $CHANGED symlink(s) updated in ~/.claude/"
  80. fi
  81. echo " Next: bash install-plugins.sh"