From a1c2efef1cebcc8bd658592134dc6370a319e901 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Tue, 17 Feb 2026 11:07:03 -0600 Subject: [PATCH] fix: harden skill linking to avoid canonical path corruption --- bin/mosaic-sync-skills | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/bin/mosaic-sync-skills b/bin/mosaic-sync-skills index 10e14ff..b95e44f 100755 --- a/bin/mosaic-sync-skills +++ b/bin/mosaic-sync-skills @@ -91,13 +91,21 @@ link_targets=( "$HOME/.config/opencode/skills" ) +canonical_real="$(readlink -f "$MOSAIC_SKILLS_DIR")" + link_skill_into_target() { local skill_path="$1" local target_dir="$2" - local name + local name link_path name="$(basename "$skill_path")" - local link_path="$target_dir/$name" + + # Do not distribute hidden/system skill directories globally. + if [[ "$name" == .* ]]; then + return + fi + + link_path="$target_dir/$name" if [[ -L "$link_path" ]]; then ln -sfn "$skill_path" "$link_path" @@ -105,9 +113,8 @@ link_skill_into_target() { fi if [[ -e "$link_path" ]]; then - local backup="$link_path.mosaic-backup.$(date +%Y%m%d%H%M%S)" - mv "$link_path" "$backup" - echo "[mosaic-skills] Backed up existing entry: $link_path -> $backup" + echo "[mosaic-skills] Preserve existing runtime-specific entry: $link_path" + return fi ln -s "$skill_path" "$link_path" @@ -116,6 +123,13 @@ link_skill_into_target() { for target in "${link_targets[@]}"; do mkdir -p "$target" + # If target already resolves to canonical dir, skip to avoid self-link recursion/corruption. + target_real="$(readlink -f "$target" 2>/dev/null || true)" + if [[ -n "$target_real" && "$target_real" == "$canonical_real" ]]; then + echo "[mosaic-skills] Skip target (already canonical): $target" + continue + fi + while IFS= read -r -d '' skill; do link_skill_into_target "$skill" "$target" done < <(find "$MOSAIC_SKILLS_DIR" -mindepth 1 -maxdepth 1 -type d -print0)