|
#!/bin/bash |
|
# migrate_claude_to_antigravity.sh |
|
# |
|
# Description: |
|
# Migrates Claude Code resources (Skills, Agents, Commands) to Antigravity format. |
|
# Supports both Global (~/.claude) and Project-Local (.claude) configurations. |
|
# Project-Local settings take precedence over Global settings. |
|
# This script is idempotent; it will only update files if the source is newer. |
|
# |
|
# Usage: |
|
# ./migrate_claude_to_antigravity.sh [repo_root] |
|
# |
|
# If repo_root is not provided, defaults to current directory. |
|
|
|
set -e |
|
|
|
REPO_ROOT="${1:-.}" |
|
AGENT_DIR="$REPO_ROOT/.agent" |
|
SKILLS_DIR="$AGENT_DIR/skills" |
|
WORKFLOWS_DIR="$AGENT_DIR/workflows" |
|
|
|
# Colors for output |
|
GREEN='\033[0;32m' |
|
BLUE='\033[0;34m' |
|
YELLOW='\033[1;33m' |
|
NC='\033[0m' # No Color |
|
|
|
echo -e "${BLUE}=== Antigravity Migration Tool ===${NC}" |
|
echo -e "Target Directory: ${AGENT_DIR}" |
|
|
|
# Ensure directories exist |
|
mkdir -p "$SKILLS_DIR" |
|
mkdir -p "$WORKFLOWS_DIR" |
|
|
|
# --- Functions --- |
|
|
|
# Function: migrate_skill |
|
# Arguments: $1=SourcePath, $2=SkillName, $3=IsOverride (true/false) |
|
migrate_skill() { |
|
local src="$1" |
|
local name="$2" |
|
local override="$3" |
|
local dest="$SKILLS_DIR/$name" |
|
|
|
if [ -d "$src" ]; then |
|
if [ -d "$dest" ] && [ "$override" = "false" ]; then |
|
echo -e "${YELLOW}Skipping Global Skill '${name}' (Local override exists)${NC}" |
|
return |
|
fi |
|
|
|
# If destination is a file (legacy/incorrect migration), remove it |
|
if [ -f "$dest" ]; then |
|
echo -e "${YELLOW}Removing file collision at '${dest}'${NC}" |
|
rm "$dest" |
|
fi |
|
|
|
echo -e "Migrating Skill: ${name}..." |
|
mkdir -p "$dest" |
|
# Copy contents. On MacOS/BSD cp doesn't have -u. |
|
# relying on explicit order: Global first (creates), Local second (overwrites). |
|
cp -R "$src/"* "$dest/" |
|
fi |
|
} |
|
|
|
# Function: migrate_agent |
|
# Arguments: $1=SourceFile, $2=AgentName, $3=IsOverride |
|
migrate_agent() { |
|
local src="$1" |
|
local name="$2" |
|
local override="$3" |
|
local dest_dir="$SKILLS_DIR/$name" |
|
local dest_file="$dest_dir/SKILL.md" |
|
|
|
if [ -f "$src" ]; then |
|
if [ -d "$dest_dir" ] && [ "$override" = "false" ]; then |
|
# Verify if SKILL.md exists to really confirm it's skipped |
|
if [ -f "$dest_file" ]; then |
|
echo -e "${YELLOW}Skipping Global Agent '${name}' (Local override exists)${NC}" |
|
return |
|
fi |
|
fi |
|
|
|
echo -e "Migrating Agent: ${name}..." |
|
mkdir -p "$dest_dir" |
|
cp "$src" "$dest_file" |
|
fi |
|
} |
|
|
|
# Function: migrate_command |
|
# Arguments: $1=SourceFile, $2=CommandName, $3=IsOverride |
|
migrate_command() { |
|
local src="$1" |
|
local name="$2" |
|
local override="$3" |
|
local dest="$WORKFLOWS_DIR/$name.md" |
|
|
|
if [ -f "$src" ]; then |
|
if [ -f "$dest" ] && [ "$override" = "false" ]; then |
|
echo -e "${YELLOW}Skipping Global Workflow '${name}' (Local override exists)${NC}" |
|
return |
|
fi |
|
|
|
echo -e "Migrating Workflow: ${name}..." |
|
cp "$src" "$dest" |
|
fi |
|
} |
|
|
|
# Function: migrate_project_context |
|
# Arguments: $1=RepoRoot |
|
migrate_project_context() { |
|
local repo_root="$1" |
|
local dest_dir="$SKILLS_DIR/project-context" |
|
local dest_file="$dest_dir/SKILL.md" |
|
|
|
# Find all CLAUDE.md files |
|
# We use 'find' to get them all. Warning: names might behave oddly with spaces, assuming standard compilation |
|
local files=$(find "$repo_root" -name "CLAUDE.md" | sort) |
|
|
|
if [ -z "$files" ]; then |
|
return |
|
fi |
|
|
|
echo -e "Migrating Project Context (including nested CLAUDE.md)..." |
|
mkdir -p "$dest_dir" |
|
|
|
# Create valid skill frontmatter |
|
echo "---" > "$dest_file" |
|
echo "name: project-context" >> "$dest_file" |
|
echo "description: Project-specific context, rules, and commands automatically migrated from all CLAUDE.md files in the repo. Use this to understand the project structure and conventions." >> "$dest_file" |
|
echo "triggers:" >> "$dest_file" |
|
echo " - project context" >> "$dest_file" |
|
echo " - project rules" >> "$dest_file" |
|
echo " - explain project" >> "$dest_file" |
|
echo "---" >> "$dest_file" |
|
echo "" >> "$dest_file" |
|
|
|
# Process each file |
|
echo "$files" | while read -r filepath; do |
|
[ -e "$filepath" ] || continue |
|
|
|
# Calculate relative path for header |
|
# If it's the root CLAUDE.md, treat as main context |
|
rel_path=${filepath#$repo_root/} |
|
# Remove leading slash if present |
|
rel_path=${rel_path#/} |
|
|
|
if [ "$filepath" = "$repo_root/CLAUDE.md" ]; then |
|
echo -e "# Root Context (CLAUDE.md)\n" >> "$dest_file" |
|
else |
|
echo -e "\n\n# Context from $rel_path\n" >> "$dest_file" |
|
fi |
|
|
|
cat "$filepath" >> "$dest_file" |
|
done |
|
} |
|
|
|
# --- Execution --- |
|
|
|
# 1. Migrate Global Resources (Low Priority) |
|
GLOBAL_CLAUDE_HOME="${HOME}/.claude" |
|
if [ -d "$GLOBAL_CLAUDE_HOME" ]; then |
|
echo -e "\n${BLUE}Processing Global Resources (~/.claude)...${NC}" |
|
|
|
# Skills |
|
if [ -d "$GLOBAL_CLAUDE_HOME/skills" ]; then |
|
for path in "$GLOBAL_CLAUDE_HOME/skills/"*; do |
|
[ -e "$path" ] || continue |
|
name=$(basename "$path") |
|
migrate_skill "$path" "$name" "false" |
|
done |
|
fi |
|
|
|
# Agents |
|
if [ -d "$GLOBAL_CLAUDE_HOME/agents" ]; then |
|
for path in "$GLOBAL_CLAUDE_HOME/agents/"*.md; do |
|
[ -e "$path" ] || continue |
|
name=$(basename "$path" .md) |
|
migrate_agent "$path" "$name" "false" |
|
done |
|
fi |
|
|
|
# Commands |
|
if [ -d "$GLOBAL_CLAUDE_HOME/commands" ]; then |
|
for path in "$GLOBAL_CLAUDE_HOME/commands/"*.md; do |
|
[ -e "$path" ] || continue |
|
name=$(basename "$path" .md) |
|
migrate_command "$path" "$name" "false" |
|
done |
|
fi |
|
else |
|
echo -e "${YELLOW}No global .claude directory found at $GLOBAL_CLAUDE_HOME${NC}" |
|
fi |
|
|
|
# 2. Migrate Local Resources (High Priority) |
|
LOCAL_CLAUDE_HOME="$REPO_ROOT/.claude" |
|
if [ -d "$LOCAL_CLAUDE_HOME" ]; then |
|
echo -e "\n${BLUE}Processing Local Resources (.claude)...${NC}" |
|
|
|
# Skills |
|
if [ -d "$LOCAL_CLAUDE_HOME/skills" ]; then |
|
for path in "$LOCAL_CLAUDE_HOME/skills/"*; do |
|
[ -e "$path" ] || continue |
|
name=$(basename "$path") |
|
migrate_skill "$path" "$name" "true" |
|
done |
|
fi |
|
|
|
# Agents |
|
if [ -d "$LOCAL_CLAUDE_HOME/agents" ]; then |
|
for path in "$LOCAL_CLAUDE_HOME/agents/"*.md; do |
|
[ -e "$path" ] || continue |
|
name=$(basename "$path" .md) |
|
migrate_agent "$path" "$name" "true" |
|
done |
|
fi |
|
|
|
# Commands |
|
if [ -d "$LOCAL_CLAUDE_HOME/commands" ]; then |
|
for path in "$LOCAL_CLAUDE_HOME/commands/"*.md; do |
|
[ -e "$path" ] || continue |
|
name=$(basename "$path" .md) |
|
migrate_command "$path" "$name" "true" |
|
done |
|
fi |
|
else |
|
echo -e "${YELLOW}No local .claude directory found at $LOCAL_CLAUDE_HOME${NC}" |
|
fi |
|
|
|
# 3. Migrate Project Context (All CLAUDE.md files) |
|
echo -e "\n${BLUE}Processing Project Context...${NC}" |
|
migrate_project_context "$REPO_ROOT" |
|
|
|
echo -e "\n${GREEN}Migration Complete!${NC}" |
|
echo -e "Skills: $(find "$SKILLS_DIR" -maxdepth 1 -mindepth 1 -type d | wc -l)" |
|
echo -e "Workflows: $(find "$WORKFLOWS_DIR" -maxdepth 1 -name "*.md" | wc -l)" |