mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-02 07:03:28 +08:00
* feat(install): add CodeBuddy(Tencent) adaptation with installation scripts * fix: add codebuddy to SUPPORTED_INSTALL_TARGETS * fix(codebuddy): resolve installer path issues, unused vars, and uninstall safety
185 lines
5.5 KiB
Bash
Executable File
185 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# ECC CodeBuddy Uninstaller
|
|
# Uninstalls Everything Claude Code workflows from a CodeBuddy project.
|
|
#
|
|
# Usage:
|
|
# ./uninstall.sh # Uninstall from current directory
|
|
# ./uninstall.sh ~ # Uninstall globally from ~/.codebuddy/
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
# Resolve the directory where this script lives
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
# CodeBuddy directory name
|
|
CODEBUDDY_DIR=".codebuddy"
|
|
|
|
resolve_path() {
|
|
python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$1"
|
|
}
|
|
|
|
is_valid_manifest_entry() {
|
|
local file_path="$1"
|
|
|
|
case "$file_path" in
|
|
""|/*|~*|*/../*|../*|*/..|..)
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
# Main uninstall function
|
|
do_uninstall() {
|
|
local target_dir="$PWD"
|
|
|
|
# Check if ~ was specified (or expanded to $HOME)
|
|
if [ "$#" -ge 1 ]; then
|
|
if [ "$1" = "~" ] || [ "$1" = "$HOME" ]; then
|
|
target_dir="$HOME"
|
|
fi
|
|
fi
|
|
|
|
# Check if we're already inside a .codebuddy directory
|
|
local current_dir_name="$(basename "$target_dir")"
|
|
local codebuddy_full_path
|
|
|
|
if [ "$current_dir_name" = ".codebuddy" ]; then
|
|
# Already inside the codebuddy directory, use it directly
|
|
codebuddy_full_path="$target_dir"
|
|
else
|
|
# Normal case: append CODEBUDDY_DIR to target_dir
|
|
codebuddy_full_path="$target_dir/$CODEBUDDY_DIR"
|
|
fi
|
|
|
|
echo "ECC CodeBuddy Uninstaller"
|
|
echo "=========================="
|
|
echo ""
|
|
echo "Target: $codebuddy_full_path/"
|
|
echo ""
|
|
|
|
if [ ! -d "$codebuddy_full_path" ]; then
|
|
echo "Error: $CODEBUDDY_DIR directory not found at $target_dir"
|
|
exit 1
|
|
fi
|
|
|
|
codebuddy_root_resolved="$(resolve_path "$codebuddy_full_path")"
|
|
|
|
# Manifest file path
|
|
MANIFEST="$codebuddy_full_path/.ecc-manifest"
|
|
|
|
if [ ! -f "$MANIFEST" ]; then
|
|
echo "Warning: No manifest file found (.ecc-manifest)"
|
|
echo ""
|
|
echo "This could mean:"
|
|
echo " 1. ECC was installed with an older version without manifest support"
|
|
echo " 2. The manifest file was manually deleted"
|
|
echo ""
|
|
read -p "Do you want to remove the entire $CODEBUDDY_DIR directory? (y/N) " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo "Uninstall cancelled."
|
|
exit 0
|
|
fi
|
|
rm -rf "$codebuddy_full_path"
|
|
echo "Uninstall complete!"
|
|
echo ""
|
|
echo "Removed: $codebuddy_full_path/"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Found manifest file - will only remove files installed by ECC"
|
|
echo ""
|
|
read -p "Are you sure you want to uninstall ECC from $CODEBUDDY_DIR? (y/N) " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo "Uninstall cancelled."
|
|
exit 0
|
|
fi
|
|
|
|
# Counters
|
|
removed=0
|
|
skipped=0
|
|
|
|
# Read manifest and remove files
|
|
while IFS= read -r file_path; do
|
|
[ -z "$file_path" ] && continue
|
|
|
|
if ! is_valid_manifest_entry "$file_path"; then
|
|
echo "Skipped: $file_path (invalid manifest entry)"
|
|
skipped=$((skipped + 1))
|
|
continue
|
|
fi
|
|
|
|
full_path="$codebuddy_full_path/$file_path"
|
|
|
|
# Security check: ensure the path resolves inside the target directory.
|
|
# Use Python to compute a reliable relative path so symlinks cannot
|
|
# escape the boundary.
|
|
relative="$(python3 -c 'import os,sys; print(os.path.relpath(os.path.abspath(sys.argv[1]), sys.argv[2]))' "$full_path" "$codebuddy_root_resolved")"
|
|
case "$relative" in
|
|
../*|..)
|
|
echo "Skipped: $file_path (outside target directory)"
|
|
skipped=$((skipped + 1))
|
|
continue
|
|
;;
|
|
esac
|
|
|
|
if [ -L "$full_path" ] || [ -f "$full_path" ]; then
|
|
rm -f "$full_path"
|
|
echo "Removed: $file_path"
|
|
removed=$((removed + 1))
|
|
elif [ -d "$full_path" ]; then
|
|
# Only remove directory if it's empty
|
|
if [ -z "$(ls -A "$full_path" 2>/dev/null)" ]; then
|
|
rmdir "$full_path" 2>/dev/null || true
|
|
if [ ! -d "$full_path" ]; then
|
|
echo "Removed: $file_path/"
|
|
removed=$((removed + 1))
|
|
fi
|
|
else
|
|
echo "Skipped: $file_path/ (not empty - contains user files)"
|
|
skipped=$((skipped + 1))
|
|
fi
|
|
else
|
|
skipped=$((skipped + 1))
|
|
fi
|
|
done < "$MANIFEST"
|
|
|
|
while IFS= read -r empty_dir; do
|
|
[ "$empty_dir" = "$codebuddy_full_path" ] && continue
|
|
relative_dir="${empty_dir#$codebuddy_full_path/}"
|
|
rmdir "$empty_dir" 2>/dev/null || true
|
|
if [ ! -d "$empty_dir" ]; then
|
|
echo "Removed: $relative_dir/"
|
|
removed=$((removed + 1))
|
|
fi
|
|
done < <(find "$codebuddy_full_path" -depth -type d -empty 2>/dev/null | sort -r)
|
|
|
|
# Try to remove the main codebuddy directory if it's empty
|
|
if [ -d "$codebuddy_full_path" ] && [ -z "$(ls -A "$codebuddy_full_path" 2>/dev/null)" ]; then
|
|
rmdir "$codebuddy_full_path" 2>/dev/null || true
|
|
if [ ! -d "$codebuddy_full_path" ]; then
|
|
echo "Removed: $CODEBUDDY_DIR/"
|
|
removed=$((removed + 1))
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
echo "Uninstall complete!"
|
|
echo ""
|
|
echo "Summary:"
|
|
echo " Removed: $removed items"
|
|
echo " Skipped: $skipped items (not found or user-modified)"
|
|
echo ""
|
|
if [ -d "$codebuddy_full_path" ]; then
|
|
echo "Note: $CODEBUDDY_DIR directory still exists (contains user-added files)"
|
|
fi
|
|
}
|
|
|
|
# Execute uninstall
|
|
do_uninstall "$@"
|