2026-06-13 12:26:27 -04:00
|
|
|
#!/bin/bash
|
|
|
|
|
# Migrate a project from the old copy-based model to the additive extension model.
|
|
|
|
|
# Usage: ./migrate-project.sh /path/to/project
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
FRAMEWORK_DIR="$HOME/.automaton"
|
|
|
|
|
PROJECT_DIR="${1}"
|
|
|
|
|
|
|
|
|
|
if [ -z "$PROJECT_DIR" ]; then
|
|
|
|
|
echo "Usage: $0 /path/to/project"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
PROJECT_AUTOMATON="$PROJECT_DIR/.automaton"
|
|
|
|
|
|
|
|
|
|
if [ ! -d "$PROJECT_AUTOMATON" ]; then
|
|
|
|
|
echo "No .automaton/ directory found at $PROJECT_AUTOMATON"
|
|
|
|
|
echo "Nothing to migrate."
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
EXTENSIONS_DIR="$PROJECT_AUTOMATON/extensions"
|
|
|
|
|
DELETED=()
|
|
|
|
|
MOVED=()
|
|
|
|
|
KEPT=()
|
|
|
|
|
ERRORS=()
|
|
|
|
|
|
|
|
|
|
# Directories in the framework that projects may have copied
|
|
|
|
|
SCAN_DIRS=("prompts" "contracts" "scripts")
|
|
|
|
|
|
|
|
|
|
# Function to diff a file with its global counterpart
|
|
|
|
|
diff_file() {
|
|
|
|
|
local project_file="$1"
|
|
|
|
|
local global_file="$2"
|
|
|
|
|
if [ ! -f "$global_file" ]; then
|
|
|
|
|
return 2 # file doesn't exist in global
|
|
|
|
|
fi
|
|
|
|
|
if diff -q "$project_file" "$global_file" >/dev/null 2>&1; then
|
|
|
|
|
return 0 # identical
|
|
|
|
|
else
|
|
|
|
|
return 1 # different
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Check root-level framework files
|
|
|
|
|
echo "Scanning $PROJECT_AUTOMATON for stale framework files..."
|
|
|
|
|
echo ""
|
|
|
|
|
|
|
|
|
|
for dir in "${SCAN_DIRS[@]}"; do
|
|
|
|
|
project_dir="$PROJECT_AUTOMATON/$dir"
|
|
|
|
|
global_dir="$FRAMEWORK_DIR/$dir"
|
|
|
|
|
|
|
|
|
|
if [ ! -d "$project_dir" ]; then
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Find all files in the project's copy of this directory
|
|
|
|
|
while IFS= read -r -d '' project_file; do
|
|
|
|
|
rel_path="${project_file#$PROJECT_AUTOMATON/}"
|
|
|
|
|
global_file="$FRAMEWORK_DIR/$rel_path"
|
|
|
|
|
|
|
|
|
|
if diff_file "$project_file" "$global_file"; then
|
|
|
|
|
# Identical to global — safe to delete
|
|
|
|
|
rm "$project_file"
|
|
|
|
|
DELETED+=("$rel_path")
|
|
|
|
|
echo " DELETED $rel_path (identical to global)"
|
|
|
|
|
elif [ $? -eq 1 ]; then
|
|
|
|
|
# Different from global — move to extensions/
|
|
|
|
|
ext_path="$EXTENSIONS_DIR/$dir/$(basename "$project_file")"
|
|
|
|
|
mkdir -p "$(dirname "$ext_path")"
|
|
|
|
|
mv "$project_file" "$ext_path"
|
|
|
|
|
MOVED+=("$rel_path -> extensions/$dir/$(basename "$project_file")")
|
|
|
|
|
echo " MOVED $rel_path → extensions/$dir/$(basename "$project_file") (customized)"
|
|
|
|
|
fi
|
|
|
|
|
done < <(find "$project_dir" -type f -print0 2>/dev/null || true)
|
|
|
|
|
|
|
|
|
|
# Remove empty directories after moving/deleting files
|
|
|
|
|
rmdir "$project_dir" 2>/dev/null || true
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# Check for other stale root-level files (templates/, references/, etc.)
|
|
|
|
|
while IFS= read -r -d '' project_file; do
|
|
|
|
|
rel_path="${project_file#$PROJECT_AUTOMATON/}"
|
|
|
|
|
global_file="$FRAMEWORK_DIR/$rel_path"
|
|
|
|
|
|
|
|
|
|
# Skip protected files
|
|
|
|
|
basename_file=$(basename "$rel_path")
|
|
|
|
|
if [ "$basename_file" = ".agent.md" ] || [ "$basename_file" = ".rules.md" ]; then
|
|
|
|
|
KEPT+=("$rel_path")
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ ! -f "$global_file" ]; then
|
|
|
|
|
continue # not a framework file, skip
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if diff_file "$project_file" "$global_file"; then
|
|
|
|
|
rm "$project_file"
|
|
|
|
|
DELETED+=("$rel_path")
|
|
|
|
|
echo " DELETED $rel_path (identical to global)"
|
|
|
|
|
elif [ $? -eq 1 ]; then
|
|
|
|
|
ext_path="$EXTENSIONS_DIR/$(basename "$rel_path")"
|
|
|
|
|
mkdir -p "$(dirname "$ext_path")"
|
|
|
|
|
mv "$project_file" "$ext_path"
|
|
|
|
|
MOVED+=("$rel_path -> extensions/$(basename "$rel_path")")
|
|
|
|
|
echo " MOVED $rel_path → extensions/$(basename "$rel_path") (customized)"
|
|
|
|
|
fi
|
2026-06-22 10:40:58 -04:00
|
|
|
done < <(find "$PROJECT_AUTOMATON" -maxdepth 1 -type f \( -name "*.md" -o -name "*.sh" \) -print0 2>/dev/null || true)
|
2026-06-13 12:26:27 -04:00
|
|
|
|
2026-06-13 21:37:13 -04:00
|
|
|
# Task directory — tasks always live in .automaton/tasks/ for all modes
|
|
|
|
|
ROOT_TASKS="$PROJECT_DIR/tasks"
|
|
|
|
|
AUTOMATON_TASKS="$PROJECT_AUTOMATON/tasks"
|
|
|
|
|
if [ -d "$ROOT_TASKS" ] && [ ! -e "$AUTOMATON_TASKS" ]; then
|
|
|
|
|
echo " MOVING tasks/ → .automaton/tasks/ (tasks belong in .automaton/)"
|
|
|
|
|
mv "$ROOT_TASKS" "$AUTOMATON_TASKS"
|
|
|
|
|
MOVED+=("tasks/ -> .automaton/tasks/")
|
|
|
|
|
elif [ -d "$ROOT_TASKS" ] && [ -d "$AUTOMATON_TASKS" ]; then
|
|
|
|
|
echo " MERGING tasks/ contents into .automaton/tasks/"
|
|
|
|
|
cp -r "$ROOT_TASKS"/* "$AUTOMATON_TASKS/" 2>/dev/null || true
|
|
|
|
|
rm -rf "$ROOT_TASKS"
|
|
|
|
|
MOVED+=("tasks/ merged -> .automaton/tasks/")
|
2026-06-13 21:33:23 -04:00
|
|
|
fi
|
|
|
|
|
|
2026-06-13 12:26:27 -04:00
|
|
|
# Report
|
|
|
|
|
echo ""
|
|
|
|
|
echo "=== Migration Summary ==="
|
|
|
|
|
echo " Deleted: ${#DELETED[@]} (identical to global, removed)"
|
|
|
|
|
echo " Moved: ${#MOVED[@]} (customized, moved to extensions/)"
|
|
|
|
|
echo " Kept: ${#KEPT[@]} (.agent.md and .rules.md preserved)"
|
|
|
|
|
|
|
|
|
|
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
|
|
|
echo " Errors: ${#ERRORS[@]}"
|
|
|
|
|
for err in "${ERRORS[@]}"; do
|
|
|
|
|
echo " - $err"
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Migration complete."
|