mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
fix(trae): harden install and uninstall flow
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Everything Claude Code for Trae
|
# Everything Claude Code for Trae
|
||||||
|
|
||||||
Bring [Everything Claude Code](https://github.com/anthropics/courses/tree/master/everything-claude-code) (ECC) workflows to Trae IDE. This repository provides custom commands, agents, skills, and rules that can be installed into any Trae project with a single command.
|
Bring Everything Claude Code (ECC) workflows to Trae IDE. This repository provides custom commands, agents, skills, and rules that can be installed into any Trae project with a single command.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -76,11 +76,12 @@ This creates `~/.trae-cn/` with all ECC components. All Trae projects will use t
|
|||||||
### Force Environment
|
### Force Environment
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Force CN environment (global setting)
|
# From project root, force the CN environment
|
||||||
TRAE_ENV=cn ./install.sh
|
TRAE_ENV=cn .trae/install.sh
|
||||||
|
|
||||||
# Use default environment (default)
|
# From inside the .trae folder
|
||||||
./install.sh
|
cd .trae
|
||||||
|
TRAE_ENV=cn ./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: `TRAE_ENV` is a global environment variable that applies to the entire installation session.
|
**Note**: `TRAE_ENV` is a global environment variable that applies to the entire installation session.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Everything Claude Code for Trae
|
# Everything Claude Code for Trae
|
||||||
|
|
||||||
为 Trae IDE 带来 [Everything Claude Code](https://github.com/anthropics/courses/tree/master/everything-claude-code) (ECC) 工作流。此仓库提供自定义命令、智能体、技能和规则,可以通过单个命令安装到任何 Trae 项目中。
|
为 Trae IDE 带来 Everything Claude Code (ECC) 工作流。此仓库提供自定义命令、智能体、技能和规则,可以通过单个命令安装到任何 Trae 项目中。
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
@@ -84,10 +84,11 @@ TRAE_ENV=cn .trae/install.sh ~
|
|||||||
### 强制指定环境
|
### 强制指定环境
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 强制使用 CN 环境
|
# 从项目根目录强制使用 CN 环境
|
||||||
TRAE_ENV=cn ./install.sh
|
TRAE_ENV=cn .trae/install.sh
|
||||||
|
|
||||||
# 使用默认环境
|
# 进入 .trae 目录后使用默认环境
|
||||||
|
cd .trae
|
||||||
./install.sh
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,16 @@ get_trae_dir() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_manifest_entry() {
|
||||||
|
local manifest="$1"
|
||||||
|
local entry="$2"
|
||||||
|
|
||||||
|
touch "$manifest"
|
||||||
|
if ! grep -Fqx "$entry" "$manifest"; then
|
||||||
|
echo "$entry" >> "$manifest"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Install function
|
# Install function
|
||||||
do_install() {
|
do_install() {
|
||||||
local target_dir="$PWD"
|
local target_dir="$PWD"
|
||||||
@@ -70,7 +80,7 @@ do_install() {
|
|||||||
|
|
||||||
# Manifest file to track installed files
|
# Manifest file to track installed files
|
||||||
MANIFEST="$trae_full_path/.ecc-manifest"
|
MANIFEST="$trae_full_path/.ecc-manifest"
|
||||||
rm -f "$MANIFEST"
|
touch "$MANIFEST"
|
||||||
|
|
||||||
# Counters for summary
|
# Counters for summary
|
||||||
commands=0
|
commands=0
|
||||||
@@ -86,9 +96,11 @@ do_install() {
|
|||||||
local_name=$(basename "$f")
|
local_name=$(basename "$f")
|
||||||
target_path="$trae_full_path/commands/$local_name"
|
target_path="$trae_full_path/commands/$local_name"
|
||||||
if [ ! -f "$target_path" ]; then
|
if [ ! -f "$target_path" ]; then
|
||||||
cp "$f" "$target_path" 2>/dev/null || true
|
cp "$f" "$target_path"
|
||||||
echo "commands/$local_name" >> "$MANIFEST"
|
ensure_manifest_entry "$MANIFEST" "commands/$local_name"
|
||||||
commands=$((commands + 1))
|
commands=$((commands + 1))
|
||||||
|
else
|
||||||
|
ensure_manifest_entry "$MANIFEST" "commands/$local_name"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -100,9 +112,11 @@ do_install() {
|
|||||||
local_name=$(basename "$f")
|
local_name=$(basename "$f")
|
||||||
target_path="$trae_full_path/agents/$local_name"
|
target_path="$trae_full_path/agents/$local_name"
|
||||||
if [ ! -f "$target_path" ]; then
|
if [ ! -f "$target_path" ]; then
|
||||||
cp "$f" "$target_path" 2>/dev/null || true
|
cp "$f" "$target_path"
|
||||||
echo "agents/$local_name" >> "$MANIFEST"
|
ensure_manifest_entry "$MANIFEST" "agents/$local_name"
|
||||||
agents=$((agents + 1))
|
agents=$((agents + 1))
|
||||||
|
else
|
||||||
|
ensure_manifest_entry "$MANIFEST" "agents/$local_name"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -113,15 +127,21 @@ do_install() {
|
|||||||
[ -d "$d" ] || continue
|
[ -d "$d" ] || continue
|
||||||
skill_name="$(basename "$d")"
|
skill_name="$(basename "$d")"
|
||||||
target_skill_dir="$trae_full_path/skills/$skill_name"
|
target_skill_dir="$trae_full_path/skills/$skill_name"
|
||||||
if [ ! -d "$target_skill_dir" ]; then
|
skill_copied=0
|
||||||
mkdir -p "$target_skill_dir"
|
|
||||||
cp -r "$d"* "$target_skill_dir/" 2>/dev/null || true
|
while IFS= read -r source_file; do
|
||||||
for skill_file in "$target_skill_dir"/*; do
|
relative_path="${source_file#$d}"
|
||||||
[ -f "$skill_file" ] || continue
|
target_path="$target_skill_dir/$relative_path"
|
||||||
relative_path="skills/$skill_name/$(basename "$skill_file")"
|
|
||||||
echo "$relative_path" >> "$MANIFEST"
|
mkdir -p "$(dirname "$target_path")"
|
||||||
done
|
if [ ! -f "$target_path" ]; then
|
||||||
echo "skills/$skill_name" >> "$MANIFEST"
|
cp "$source_file" "$target_path"
|
||||||
|
skill_copied=1
|
||||||
|
fi
|
||||||
|
ensure_manifest_entry "$MANIFEST" "skills/$skill_name/$relative_path"
|
||||||
|
done < <(find "$d" -type f | sort)
|
||||||
|
|
||||||
|
if [ "$skill_copied" -eq 1 ]; then
|
||||||
skills=$((skills + 1))
|
skills=$((skills + 1))
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -129,18 +149,17 @@ do_install() {
|
|||||||
|
|
||||||
# Copy rules from repo root
|
# Copy rules from repo root
|
||||||
if [ -d "$REPO_ROOT/rules" ]; then
|
if [ -d "$REPO_ROOT/rules" ]; then
|
||||||
if [ -d "$REPO_ROOT/rules/common" ]; then
|
while IFS= read -r rule_file; do
|
||||||
for f in "$REPO_ROOT/rules/common"/*.md; do
|
relative_path="${rule_file#$REPO_ROOT/rules/}"
|
||||||
[ -f "$f" ] || continue
|
target_path="$trae_full_path/rules/$relative_path"
|
||||||
local_name=$(basename "$f")
|
|
||||||
target_path="$trae_full_path/rules/$local_name"
|
mkdir -p "$(dirname "$target_path")"
|
||||||
if [ ! -f "$target_path" ]; then
|
if [ ! -f "$target_path" ]; then
|
||||||
cp "$f" "$target_path" 2>/dev/null || true
|
cp "$rule_file" "$target_path"
|
||||||
echo "rules/$local_name" >> "$MANIFEST"
|
rules=$((rules + 1))
|
||||||
rules=$((rules + 1))
|
fi
|
||||||
fi
|
ensure_manifest_entry "$MANIFEST" "rules/$relative_path"
|
||||||
done
|
done < <(find "$REPO_ROOT/rules" -type f | sort)
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Copy README files from this directory
|
# Copy README files from this directory
|
||||||
@@ -149,9 +168,11 @@ do_install() {
|
|||||||
local_name=$(basename "$readme_file")
|
local_name=$(basename "$readme_file")
|
||||||
target_path="$trae_full_path/$local_name"
|
target_path="$trae_full_path/$local_name"
|
||||||
if [ ! -f "$target_path" ]; then
|
if [ ! -f "$target_path" ]; then
|
||||||
cp "$readme_file" "$target_path" 2>/dev/null || true
|
cp "$readme_file" "$target_path"
|
||||||
echo "$local_name" >> "$MANIFEST"
|
ensure_manifest_entry "$MANIFEST" "$local_name"
|
||||||
other=$((other + 1))
|
other=$((other + 1))
|
||||||
|
else
|
||||||
|
ensure_manifest_entry "$MANIFEST" "$local_name"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -162,16 +183,18 @@ do_install() {
|
|||||||
local_name=$(basename "$script_file")
|
local_name=$(basename "$script_file")
|
||||||
target_path="$trae_full_path/$local_name"
|
target_path="$trae_full_path/$local_name"
|
||||||
if [ ! -f "$target_path" ]; then
|
if [ ! -f "$target_path" ]; then
|
||||||
cp "$script_file" "$target_path" 2>/dev/null || true
|
cp "$script_file" "$target_path"
|
||||||
chmod +x "$target_path" 2>/dev/null || true
|
chmod +x "$target_path"
|
||||||
echo "$local_name" >> "$MANIFEST"
|
ensure_manifest_entry "$MANIFEST" "$local_name"
|
||||||
other=$((other + 1))
|
other=$((other + 1))
|
||||||
|
else
|
||||||
|
ensure_manifest_entry "$MANIFEST" "$local_name"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Add manifest file itself to manifest
|
# Add manifest file itself to manifest
|
||||||
echo ".ecc-manifest" >> "$MANIFEST"
|
ensure_manifest_entry "$MANIFEST" ".ecc-manifest"
|
||||||
|
|
||||||
# Installation summary
|
# Installation summary
|
||||||
echo "Installation complete!"
|
echo "Installation complete!"
|
||||||
|
|||||||
@@ -26,6 +26,22 @@ get_trae_dir() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
# Main uninstall function
|
||||||
do_uninstall() {
|
do_uninstall() {
|
||||||
local target_dir="$PWD"
|
local target_dir="$PWD"
|
||||||
@@ -61,6 +77,8 @@ do_uninstall() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
trae_root_resolved="$(resolve_path "$trae_full_path")"
|
||||||
|
|
||||||
# Manifest file path
|
# Manifest file path
|
||||||
MANIFEST="$trae_full_path/.ecc-manifest"
|
MANIFEST="$trae_full_path/.ecc-manifest"
|
||||||
|
|
||||||
@@ -101,17 +119,34 @@ do_uninstall() {
|
|||||||
while IFS= read -r file_path; do
|
while IFS= read -r file_path; do
|
||||||
[ -z "$file_path" ] && continue
|
[ -z "$file_path" ] && continue
|
||||||
|
|
||||||
full_path="$trae_full_path/$file_path"
|
if ! is_valid_manifest_entry "$file_path"; then
|
||||||
|
echo "Skipped: $file_path (invalid manifest entry)"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f "$full_path" ]; then
|
full_path="$trae_full_path/$file_path"
|
||||||
rm -f "$full_path"
|
resolved_full="$(resolve_path "$full_path")"
|
||||||
|
|
||||||
|
case "$resolved_full" in
|
||||||
|
"$trae_root_resolved"|"$trae_root_resolved"/*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Skipped: $file_path (invalid manifest entry)"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -f "$resolved_full" ]; then
|
||||||
|
rm -f "$resolved_full"
|
||||||
echo "Removed: $file_path"
|
echo "Removed: $file_path"
|
||||||
removed=$((removed + 1))
|
removed=$((removed + 1))
|
||||||
elif [ -d "$full_path" ]; then
|
elif [ -d "$resolved_full" ]; then
|
||||||
# Only remove directory if it's empty
|
# Only remove directory if it's empty
|
||||||
if [ -z "$(ls -A "$full_path" 2>/dev/null)" ]; then
|
if [ -z "$(ls -A "$resolved_full" 2>/dev/null)" ]; then
|
||||||
rmdir "$full_path" 2>/dev/null || true
|
rmdir "$resolved_full" 2>/dev/null || true
|
||||||
if [ ! -d "$full_path" ]; then
|
if [ ! -d "$resolved_full" ]; then
|
||||||
echo "Removed: $file_path/"
|
echo "Removed: $file_path/"
|
||||||
removed=$((removed + 1))
|
removed=$((removed + 1))
|
||||||
fi
|
fi
|
||||||
@@ -124,17 +159,15 @@ do_uninstall() {
|
|||||||
fi
|
fi
|
||||||
done < "$MANIFEST"
|
done < "$MANIFEST"
|
||||||
|
|
||||||
# Try to remove subdirectories if they're empty
|
while IFS= read -r empty_dir; do
|
||||||
for subdir in commands agents skills rules; do
|
[ "$empty_dir" = "$trae_full_path" ] && continue
|
||||||
subdir_path="$trae_full_path/$subdir"
|
relative_dir="${empty_dir#$trae_full_path/}"
|
||||||
if [ -d "$subdir_path" ] && [ -z "$(ls -A "$subdir_path" 2>/dev/null)" ]; then
|
rmdir "$empty_dir" 2>/dev/null || true
|
||||||
rmdir "$subdir_path" 2>/dev/null || true
|
if [ ! -d "$empty_dir" ]; then
|
||||||
if [ ! -d "$subdir_path" ]; then
|
echo "Removed: $relative_dir/"
|
||||||
echo "Removed: $subdir/"
|
removed=$((removed + 1))
|
||||||
removed=$((removed + 1))
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done < <(find "$trae_full_path" -depth -type d -empty 2>/dev/null | sort -r)
|
||||||
|
|
||||||
# Try to remove the main trae directory if it's empty
|
# Try to remove the main trae directory if it's empty
|
||||||
if [ -d "$trae_full_path" ] && [ -z "$(ls -A "$trae_full_path" 2>/dev/null)" ]; then
|
if [ -d "$trae_full_path" ] && [ -z "$(ls -A "$trae_full_path" 2>/dev/null)" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user