Files
ccpm-claude-code-pm/ccpm/commands/pm/epic-merge.md
Ran Aroussi 3c8e0e7f67 Fix: Resolve bash command truncation and syntax errors (#958)
* fix: resolve bash command truncation and syntax errors

- Convert long one-liner bash commands to multiline format to prevent truncation
- Fix awk syntax errors in epic-sync.md (replace literal \n with proper newlines)
- Add missing directory separators in file path patterns
- Replace chained && operators with proper if-then blocks
- Break down complex pipe chains into step-by-step operations

Key changes:
* ccpm/scripts/pm/*.sh: Convert complex dependency parsing from one-liners to readable multiline blocks
* ccpm/ccpm.config: Break down repository URL processing into clear steps
* ccpm/commands/pm/epic-sync.md: Fix awk print statements for proper newline handling

Fixes command truncation errors like:
- Error: (eval):1: parse error near ')'
- awk: syntax error at source line 1
- command not found: !

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: additional bash syntax fixes in command documentation

- epic-merge.md: Convert complex nested commands to multiline format
  - Fix feature list generation with proper error handling
  - Break down epic issue number extraction
  - Add proper file existence checks
- epic-refresh.md: Fix task issue extraction with error handling
- epic-sync.md: Re-fix awk syntax for proper newline handling
- test-runner.md: Remove MUXI-specific reference

Prevents additional command truncation in:
- Complex subshell operations with cd and loops
- Chained grep operations for GitHub issue extraction
- Nested command substitution patterns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: address CodeRabbit feedback on dependency parsing and SSH URL handling

- ccpm.config: Add support for ssh://git@github.com/ and ssh://github.com/ URL schemes
  - Ensures all GitHub URL variants are properly normalized
- All PM scripts: Fix dependency parsing to handle whitespace-only cases
  - Trim leading/trailing whitespace after bracket removal
  - Properly handle empty dependency lists like "depends_on: [ ]"
  - Normalize whitespace-only strings to empty strings
  - Prevents false positive dependency detection

Fixes issues where:
- SSH URLs starting with ssh://git@github.com/ would fail parsing
- Empty dependency arrays with whitespace were treated as non-empty
- Tasks with "depends_on: [ ]" were incorrectly blocked

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-24 22:32:39 +01:00

6.2 KiB

allowed-tools
allowed-tools
Bash, Read, Write

Epic Merge

Merge completed epic from worktree back to main branch.

Usage

/pm:epic-merge <epic_name>

Quick Check

  1. Verify worktree exists:

    git worktree list | grep "epic-$ARGUMENTS" || echo "❌ No worktree for epic: $ARGUMENTS"
    
  2. Check for active agents: Read .claude/epics/$ARGUMENTS/execution-status.md If active agents exist: "⚠️ Active agents detected. Stop them first with: /pm:epic-stop $ARGUMENTS"

Instructions

1. Pre-Merge Validation

Navigate to worktree and check status:

cd ../epic-$ARGUMENTS

# Check for uncommitted changes
if [[ $(git status --porcelain) ]]; then
  echo "⚠️ Uncommitted changes in worktree:"
  git status --short
  echo "Commit or stash changes before merging"
  exit 1
fi

# Check branch status
git fetch origin
git status -sb
# Look for test commands based on project type
if [ -f package.json ]; then
  npm test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f pom.xml ]; then
  mvn test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f build.gradle ] || [ -f build.gradle.kts ]; then
  ./gradlew test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f composer.json ]; then
  ./vendor/bin/phpunit || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f *.sln ] || [ -f *.csproj ]; then
  dotnet test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f Cargo.toml ]; then
  cargo test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f go.mod ]; then
  go test ./... || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f Gemfile ]; then
  bundle exec rspec || bundle exec rake test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f pubspec.yaml ]; then
  flutter test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f Package.swift ]; then
  swift test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f CMakeLists.txt ]; then
  cd build && ctest || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
elif [ -f Makefile ]; then
  make test || echo "⚠️ Tests failed. Continue anyway? (yes/no)"
fi

3. Update Epic Documentation

Get current datetime: date -u +"%Y-%m-%dT%H:%M:%SZ"

Update .claude/epics/$ARGUMENTS/epic.md:

  • Set status to "completed"
  • Update completion date
  • Add final summary

4. Attempt Merge

# Return to main repository
cd {main-repo-path}

# Ensure main is up to date
git checkout main
git pull origin main

# Attempt merge
echo "Merging epic/$ARGUMENTS to main..."
git merge epic/$ARGUMENTS --no-ff -m "Merge epic: $ARGUMENTS

Completed features:
# Generate feature list
feature_list=""
if [ -d ".claude/epics/$ARGUMENTS" ]; then
  cd .claude/epics/$ARGUMENTS
  for task_file in [0-9]*.md; do
    [ -f "$task_file" ] || continue
    task_name=$(grep '^name:' "$task_file" | cut -d: -f2 | sed 's/^ *//')
    feature_list="$feature_list\n- $task_name"
  done
  cd - > /dev/null
fi

echo "$feature_list"

# Extract epic issue number
epic_github_line=$(grep 'github:' .claude/epics/$ARGUMENTS/epic.md 2>/dev/null || true)
if [ -n "$epic_github_line" ]; then
  epic_issue=$(echo "$epic_github_line" | grep -oE '[0-9]+' || true)
  if [ -n "$epic_issue" ]; then
    echo "\nCloses epic #$epic_issue"
  fi
fi"

5. Handle Merge Conflicts

If merge fails with conflicts:

# Check conflict status
git status

echo "
❌ Merge conflicts detected!

Conflicts in:
$(git diff --name-only --diff-filter=U)

Options:
1. Resolve manually:
   - Edit conflicted files
   - git add {files}
   - git commit
   
2. Abort merge:
   git merge --abort
   
3. Get help:
   /pm:epic-resolve $ARGUMENTS

Worktree preserved at: ../epic-$ARGUMENTS
"
exit 1

6. Post-Merge Cleanup

If merge succeeds:

# Push to remote
git push origin main

# Clean up worktree
git worktree remove ../epic-$ARGUMENTS
echo "✅ Worktree removed: ../epic-$ARGUMENTS"

# Delete branch
git branch -d epic/$ARGUMENTS
git push origin --delete epic/$ARGUMENTS 2>/dev/null || true

# Archive epic locally
mkdir -p .claude/epics/archived/
mv .claude/epics/$ARGUMENTS .claude/epics/archived/
echo "✅ Epic archived: .claude/epics/archived/$ARGUMENTS"

7. Update GitHub Issues

Close related issues:

# Get issue numbers from epic
# Extract epic issue number
epic_github_line=$(grep 'github:' .claude/epics/archived/$ARGUMENTS/epic.md 2>/dev/null || true)
if [ -n "$epic_github_line" ]; then
  epic_issue=$(echo "$epic_github_line" | grep -oE '[0-9]+$' || true)
else
  epic_issue=""
fi

# Close epic issue
gh issue close $epic_issue -c "Epic completed and merged to main"

# Close task issues
for task_file in .claude/epics/archived/$ARGUMENTS/[0-9]*.md; do
  [ -f "$task_file" ] || continue
  # Extract task issue number
  task_github_line=$(grep 'github:' "$task_file" 2>/dev/null || true)
  if [ -n "$task_github_line" ]; then
    issue_num=$(echo "$task_github_line" | grep -oE '[0-9]+$' || true)
  else
    issue_num=""
  fi
  if [ ! -z "$issue_num" ]; then
    gh issue close $issue_num -c "Completed in epic merge"
  fi
done

8. Final Output

✅ Epic Merged Successfully: $ARGUMENTS

Summary:
  Branch: epic/$ARGUMENTS → main
  Commits merged: {count}
  Files changed: {count}
  Issues closed: {count}
  
Cleanup completed:
  ✓ Worktree removed
  ✓ Branch deleted
  ✓ Epic archived
  ✓ GitHub issues closed
  
Next steps:
  - Deploy changes if needed
  - Start new epic: /pm:prd-new {feature}
  - View completed work: git log --oneline -20

Conflict Resolution Help

If conflicts need resolution:

The epic branch has conflicts with main.

This typically happens when:
- Main has changed since epic started
- Multiple epics modified same files
- Dependencies were updated

To resolve:
1. Open conflicted files
2. Look for <<<<<<< markers
3. Choose correct version or combine
4. Remove conflict markers
5. git add {resolved files}
6. git commit
7. git push

Or abort and try later:
  git merge --abort

Important Notes

  • Always check for uncommitted changes first
  • Run tests before merging when possible
  • Use --no-ff to preserve epic history
  • Archive epic data instead of deleting
  • Close GitHub issues to maintain sync