mirror of
https://github.com/automazeio/ccpm.git
synced 2025-10-09 13:41:06 +03:00
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>
This commit is contained in:
@@ -6,7 +6,7 @@ model: inherit
|
||||
color: blue
|
||||
---
|
||||
|
||||
You are an expert test execution and analysis specialist for the MUXI Runtime system. Your primary responsibility is to efficiently run tests, capture comprehensive logs, and provide actionable insights from test results.
|
||||
You are an expert test execution and analysis specialist. Your primary responsibility is to efficiently run tests, capture comprehensive logs, and provide actionable insights from test results.
|
||||
|
||||
## Core Responsibilities
|
||||
|
||||
|
||||
@@ -11,8 +11,15 @@ get_github_repo() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Handle both SSH and HTTPS, with or without .git extension
|
||||
local repo=$(echo "$remote_url" | sed -E 's#^(https://|git@)github\.com[:/]##; s#\.git$##')
|
||||
# Handle HTTPS, SSH, and SCP-style URLs
|
||||
local repo="$remote_url"
|
||||
# Remove various GitHub URL prefixes
|
||||
repo=$(echo "$repo" | sed -E 's#^https://github\.com/##')
|
||||
repo=$(echo "$repo" | sed -E 's#^git@github\.com:##')
|
||||
repo=$(echo "$repo" | sed -E 's#^ssh://git@github\.com/##')
|
||||
repo=$(echo "$repo" | sed -E 's#^ssh://github\.com/##')
|
||||
# Remove .git suffix if present
|
||||
repo=$(echo "$repo" | sed 's#\.git$##')
|
||||
|
||||
# Validate format
|
||||
if [[ ! "$repo" =~ ^[^/]+/[^/]+$ ]]; then
|
||||
|
||||
@@ -98,11 +98,28 @@ echo "Merging epic/$ARGUMENTS to main..."
|
||||
git merge epic/$ARGUMENTS --no-ff -m "Merge epic: $ARGUMENTS
|
||||
|
||||
Completed features:
|
||||
$(cd .claude/epics/$ARGUMENTS && ls *.md | grep -E '^[0-9]+' | while read f; do
|
||||
echo "- $(grep '^name:' $f | cut -d: -f2)"
|
||||
done)
|
||||
# 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
|
||||
|
||||
Closes epic #$(grep 'github:' .claude/epics/$ARGUMENTS/epic.md | grep -oE '#[0-9]+')"
|
||||
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
|
||||
@@ -161,14 +178,27 @@ echo "✅ Epic archived: .claude/epics/archived/$ARGUMENTS"
|
||||
Close related issues:
|
||||
```bash
|
||||
# Get issue numbers from epic
|
||||
epic_issue=$(grep 'github:' .claude/epics/archived/$ARGUMENTS/epic.md | grep -oE '[0-9]+$')
|
||||
# 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
|
||||
issue_num=$(grep 'github:' $task_file | grep -oE '[0-9]+$')
|
||||
[ -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
|
||||
|
||||
@@ -43,7 +43,13 @@ if [ ! -z "$epic_issue" ]; then
|
||||
|
||||
# For each task, check its status and update checkbox
|
||||
for task_file in .claude/epics/$ARGUMENTS/[0-9]*.md; do
|
||||
task_issue=$(grep 'github:' $task_file | grep -oE '[0-9]+$')
|
||||
# Extract task issue number
|
||||
task_github_line=$(grep 'github:' "$task_file" 2>/dev/null || true)
|
||||
if [ -n "$task_github_line" ]; then
|
||||
task_issue=$(echo "$task_github_line" | grep -oE '[0-9]+$' || true)
|
||||
else
|
||||
task_issue=""
|
||||
fi
|
||||
task_status=$(grep 'status:' $task_file | cut -d: -f2 | tr -d ' ')
|
||||
|
||||
if [ "$task_status" = "closed" ]; then
|
||||
|
||||
@@ -79,7 +79,8 @@ awk '
|
||||
in_tasks=0
|
||||
# When we hit the next section after Tasks Created, add Stats
|
||||
if (total_tasks) {
|
||||
print "## Stats\n"
|
||||
print "## Stats"
|
||||
print ""
|
||||
print "Total tasks: " total_tasks
|
||||
print "Parallel tasks: " parallel_tasks " (can be worked on simultaneously)"
|
||||
print "Sequential tasks: " sequential_tasks " (have dependencies)"
|
||||
@@ -99,7 +100,8 @@ awk '
|
||||
END {
|
||||
# If we were still in tasks section at EOF, add stats
|
||||
if (in_tasks && total_tasks) {
|
||||
print "## Stats\n"
|
||||
print "## Stats"
|
||||
print ""
|
||||
print "Total tasks: " total_tasks
|
||||
print "Parallel tasks: " parallel_tasks " (can be worked on simultaneously)"
|
||||
print "Sequential tasks: " sequential_tasks " (have dependencies)"
|
||||
|
||||
@@ -13,15 +13,28 @@ for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
epic_name=$(basename "$epic_dir")
|
||||
|
||||
for task_file in "$epic_dir"[0-9]*.md; do
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
# Check if task is open
|
||||
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
[ "$status" != "open" ] && [ -n "$status" ] && continue
|
||||
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check for dependencies
|
||||
deps=$(grep "^depends_on:" "$task_file" | head -1 | sed 's/^depends_on: *\[//' | sed 's/\]//' | sed 's/,/ /g')
|
||||
# Extract dependencies from task file
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//')
|
||||
deps=$(echo "$deps" | sed 's/^\[//' | sed 's/\]$//')
|
||||
deps=$(echo "$deps" | sed 's/,/ /g')
|
||||
# Trim whitespace and handle empty cases
|
||||
deps=$(echo "$deps" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
|
||||
if [ -n "$deps" ] && [ "$deps" != "depends_on:" ]; then
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
|
||||
@@ -3,8 +3,15 @@ echo "Getting epics..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
[ ! -d ".claude/epics" ] && echo "📁 No epics directory found. Create your first epic with: /pm:prd-parse <feature-name>" && exit 0
|
||||
[ -z "$(ls -d .claude/epics/*/ 2>/dev/null)" ] && echo "📁 No epics found. Create your first epic with: /pm:prd-parse <feature-name>" && exit 0
|
||||
if [ ! -d ".claude/epics" ]; then
|
||||
echo "📁 No epics directory found. Create your first epic with: /pm:prd-parse <feature-name>"
|
||||
exit 0
|
||||
fi
|
||||
epic_dirs=$(ls -d .claude/epics/*/ 2>/dev/null || true)
|
||||
if [ -z "$epic_dirs" ]; then
|
||||
echo "📁 No epics found. Create your first epic with: /pm:prd-parse <feature-name>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "📚 Project Epics"
|
||||
echo "================"
|
||||
@@ -31,7 +38,7 @@ for dir in .claude/epics/*/; do
|
||||
[ -z "$p" ] && p="0%"
|
||||
|
||||
# Count tasks
|
||||
t=$(ls "$dir"[0-9]*.md 2>/dev/null | wc -l)
|
||||
t=$(ls "$dir"/[0-9]*.md 2>/dev/null | wc -l)
|
||||
|
||||
# Format output with GitHub issue number if available
|
||||
if [ -n "$g" ]; then
|
||||
|
||||
@@ -14,15 +14,27 @@ for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
epic_name=$(basename "$epic_dir")
|
||||
|
||||
for task_file in "$epic_dir"[0-9]*.md; do
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
# Check if task is open
|
||||
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
[ "$status" != "open" ] && [ -n "$status" ] && continue
|
||||
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check dependencies
|
||||
deps=$(grep "^depends_on:" "$task_file" | head -1 | sed 's/^depends_on: *\[//' | sed 's/\]//')
|
||||
# Extract dependencies from task file
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//')
|
||||
deps=$(echo "$deps" | sed 's/^\[//' | sed 's/\]$//')
|
||||
# Trim whitespace and handle empty cases
|
||||
deps=$(echo "$deps" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
|
||||
# If no dependencies or empty, task is available
|
||||
if [ -z "$deps" ] || [ "$deps" = "depends_on:" ]; then
|
||||
|
||||
@@ -51,12 +51,24 @@ echo "⏭️ Next Available Tasks:"
|
||||
count=0
|
||||
for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
for task_file in "$epic_dir"[0-9]*.md; do
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
[ "$status" != "open" ] && [ -n "$status" ] && continue
|
||||
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
deps=$(grep "^depends_on:" "$task_file" | head -1 | sed 's/^depends_on: *\[//' | sed 's/\]//')
|
||||
# Extract dependencies from task file
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//')
|
||||
deps=$(echo "$deps" | sed 's/^\[//' | sed 's/\]$//')
|
||||
# Trim whitespace and handle empty cases
|
||||
deps=$(echo "$deps" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
if [ -z "$deps" ] || [ "$deps" = "depends_on:" ]; then
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
task_num=$(basename "$task_file" .md)
|
||||
|
||||
@@ -42,7 +42,18 @@ echo "🔗 Reference Check:"
|
||||
for task_file in .claude/epics/*/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
deps=$(grep "^depends_on:" "$task_file" | head -1 | sed 's/^depends_on: *\[//' | sed 's/\]//' | sed 's/,/ /g')
|
||||
# Extract dependencies from task file
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//')
|
||||
deps=$(echo "$deps" | sed 's/^\[//' | sed 's/\]$//')
|
||||
deps=$(echo "$deps" | sed 's/,/ /g')
|
||||
# Trim whitespace and handle empty cases
|
||||
deps=$(echo "$deps" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
if [ -n "$deps" ] && [ "$deps" != "depends_on:" ]; then
|
||||
epic_dir=$(dirname "$task_file")
|
||||
for dep in $deps; do
|
||||
@@ -54,7 +65,9 @@ for task_file in .claude/epics/*/[0-9]*.md; do
|
||||
fi
|
||||
done
|
||||
|
||||
[ $warnings -eq 0 ] && [ $errors -eq 0 ] && echo " ✅ All references valid"
|
||||
if [ $warnings -eq 0 ] && [ $errors -eq 0 ]; then
|
||||
echo " ✅ All references valid"
|
||||
fi
|
||||
|
||||
# Check frontmatter
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user