Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions .agent/scripts/version-manager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,11 @@ check_working_tree_clean() {
}

# Function to extract task IDs from commit messages since last tag
# Supports formats: t001, t001.1, feat(t001):, fix(t002):, closes t003, completes t004
# Only extracts from commits that indicate task COMPLETION, not mere mentions
# Completion patterns:
# - Conventional commits with task scope: feat(t001):, fix(t002):, docs(t003):
# - Explicit completion phrases: "mark t001 done", "complete t002", "closes t003"
# - Multi-task with explicit marker: "mark t001, t002 done" (tasks before "done")
extract_task_ids_from_commits() {
local prev_tag
prev_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
Expand All @@ -542,9 +546,47 @@ extract_task_ids_from_commits() {
commits=$(git log --oneline -50 --pretty=format:"%s" 2>/dev/null)
fi

# Extract task IDs (t001, t001.1, etc.) from commit messages
# Patterns: t001, feat(t001):, fix(t002):, closes t003, completes t004, mark t005
echo "$commits" | grep -oE '\bt[0-9]{3}(\.[0-9]+)*\b' | sort -u
local task_ids=""

while IFS= read -r commit; do
[[ -z "$commit" ]] && continue

# Pattern 1: Conventional commits with task ID in scope
# e.g., feat(t001):, fix(t002):, docs(t003.1):, refactor(t004):
if [[ "$commit" =~ ^(feat|fix|docs|refactor|perf|test|chore|style|build|ci)\(t[0-9]{3}(\.[0-9]+)*\): ]]; then
local id
id=$(echo "$commit" | grep -oE '\(t[0-9]{3}(\.[0-9]+)*\)' | tr -d '()')
task_ids="$task_ids $id"
fi

# Pattern 2: "mark tXXX done/complete" - extract task IDs between "mark" and "done/complete"
# e.g., "mark t004, t048, t069 done" -> t004, t048, t069
if [[ "$commit" =~ mark[[:space:]]+(.*)[[:space:]]+(done|complete) ]]; then
local segment="${BASH_REMATCH[1]}"
local ids
ids=$(echo "$segment" | grep -oE '\bt[0-9]{3}(\.[0-9]+)*\b')
task_ids="$task_ids $ids"
fi

# Pattern 3: "complete/completes/closes tXXX" - task ID immediately after keyword
# e.g., "complete t037", "closes t001"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex mark[[:space:]]+(.*)[[:space:]]+(done|complete) can match inside other words (e.g. remark) and the greedy (.*) can extend to the last done/complete, potentially pulling in task IDs from unrelated trailing text. That could reintroduce false-positive task completions in some commit subjects that contain multiple done/complete words.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

local ids
ids=$(echo "$commit" | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' | grep -oE 't[0-9]{3}(\.[0-9]+)*')
if [[ -n "$ids" ]]; then
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grep -oE '\bt[0-9]{3}(\.[0-9]+)*\b' relies on \b acting like a word boundary, but in many grep -E implementations it’s treated as a backspace escape, which can make extraction inconsistent across environments. If this script runs on BSD/macOS grep, task ID detection here may silently fail or behave unexpectedly.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

task_ids="$task_ids $ids"
fi

# Pattern 4: "tXXX complete/done/finished" - task ID before completion word
# e.g., "t001 complete", "t002 done"
ids=$(echo "$commit" | grep -oE 't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)' | grep -oE 't[0-9]{3}(\.[0-9]+)*')
if [[ -n "$ids" ]]; then
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern 3 doesn’t require a word boundary around (completes?|closes?), so subjects like incomplete t021 or encloses t021 could still match and incorrectly mark a task as completed. Consider requiring a clear token boundary/separator around the completion keyword to avoid substring matches.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

task_ids="$task_ids $ids"
fi
Comment on lines +562 to +584
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file and the specific function
cat -n .agent/scripts/version-manager.sh | head -100

Repository: marcusquinn/aidevops

Length of output: 3633


🏁 Script executed:

# Look at the extract_task_ids_from_commits function around lines 532-590
sed -n '530,595p' .agent/scripts/version-manager.sh

Repository: marcusquinn/aidevops

Length of output: 2854


🏁 Script executed:

# Test grep \b behavior in ERE mode to verify the claim
echo "Test 1: Does \\b work as word boundary in grep -E?"
printf 't001 test\n' | grep -oE '\bt[0-9]{3}\b' && echo "Match found" || echo "No match"

echo -e "\nTest 2: Does \\b work without explicit escape?"
printf 't001 test\n' | grep -oE '\\bt[0-9]{3}\\b' && echo "Match found" || echo "No match"

echo -e "\nTest 3: Test false positive - does 'remark' match?"
printf 'remark t001\n' | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' && echo "False positive: matched 'remark'" || echo "Correctly rejected"

echo -e "\nTest 4: Test false positive - does 'incomplete' match?"
printf 'incomplete t021\n' | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' && echo "False positive: matched 'incomplete'" || echo "Correctly rejected"

echo -e "\nTest 5: Test mark pattern with \\b"
printf 'mark t004 done\n' | grep -oE '\bt[0-9]{3}(\.[0-9]+)*\b' && echo "Mark pattern match found" || echo "Mark pattern: No match"

Repository: marcusquinn/aidevops

Length of output: 427


🏁 Script executed:

# Test if the patterns within complete/closes word actually match
echo -e "\nTest 6: Does 'completest004' match (boundary issue)?"
printf 'completest004 something\n' | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' && echo "Matched inside word" || echo "Correctly rejected with space requirement"

echo -e "\nTest 7: What about 'complete t004' (should match)"
printf 'complete t004\n' | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' && echo "Matched correctly" || echo "No match"

Repository: marcusquinn/aidevops

Length of output: 242


🏁 Script executed:

# Let's also check what the actual final filter looks like by searching for it
grep -n "final filter\|^t\[0-9\]\{3\}" .agent/scripts/version-manager.sh | head -20

Repository: marcusquinn/aidevops

Length of output: 46


🏁 Script executed:

# Look at the complete extract_task_ids_from_commits function
sed -n '532,610p' .agent/scripts/version-manager.sh

Repository: marcusquinn/aidevops

Length of output: 3288


🏁 Script executed:

# Test Pattern 4 boundary issue
echo "Test Pattern 4 boundary: does 't001 completely' match?"
printf 't001 completely\n' | grep -oE 't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)' && echo "Matched (false positive)" || echo "Correctly rejected"

echo -e "\nTest additional: 'refactor t005 incomplete' - should NOT match"
printf 'refactor t005 incomplete\n' | grep -oE 't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)' && echo "Matched (false positive)" || echo "Correctly rejected"

echo -e "\nTest word boundary with alternation: Does '(completes?|closes?) \b' format help?"
printf 'incomplete t021\n' | grep -oE '(^|[^[:alnum:]_])(completes?|closes?)[[:space:]]+t[0-9]{3}' && echo "With boundary: Matched" || echo "With boundary: Correctly rejected"

Repository: marcusquinn/aidevops

Length of output: 355


🏁 Script executed:

# Verify final output format to ensure deduplication works correctly
echo -e "\nTest final filter output quality:"
printf 't001\nt001\nt002\nincomplet\nfragment\nt003' | grep -E '^t[0-9]{3}' | sort -u

Repository: marcusquinn/aidevops

Length of output: 113


Review contains incorrect technical analysis—\b word boundaries work correctly, but real boundary issues exist in Patterns 3 and 4.

The \b assertion is incorrect: testing confirms \b in grep -E functions properly as a word boundary. Pattern 2 (mark…done) works as designed.

However, two genuine reliability issues remain:

  1. Pattern 3 ((completes?|closes?)[[:space:]]+t[0-9]{3}…): Lacks left word boundary. "incomplete t021" incorrectly matches "complete" within the word.
  2. Pattern 4 (t[0-9]{3}…[[:space:]]+(complete|done|finished)): Lacks right word boundary. "t001 completely" incorrectly matches "complete" within the word.

For automation script reliability (per coding guidelines), add word boundaries:

🔧 Suggested fix (correct boundaries)
         # Pattern 3: "complete/completes/closes tXXX" - task ID immediately after keyword
         # e.g., "complete t037", "closes t001"
         local ids
-        ids=$(echo "$commit" | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' | grep -oE 't[0-9]{3}(\.[0-9]+)*')
+        ids=$(echo "$commit" | grep -oE '(^|[^[:alnum:]_])(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' | grep -oE 't[0-9]{3}(\.[0-9]+)*')
         if [[ -n "$ids" ]]; then
             task_ids="$task_ids $ids"
         fi
         
         # Pattern 4: "tXXX complete/done/finished" - task ID before completion word
         # e.g., "t001 complete", "t002 done"
         ids=$(echo "$commit" | grep -oE 't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)' | grep -oE 't[0-9]{3}(\.[0-9]+)*')
+        ids=$(echo "$commit" | grep -oE 't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)($|[^[:alnum:]_])' | grep -oE 't[0-9]{3}(\.[0-9]+)*')
🤖 Prompt for AI Agents
In @.agent/scripts/version-manager.sh around lines 562 - 584, Pattern 3 and
Pattern 4 regexes can match substrings inside larger words; update the grep -oE
invocations that populate the local variable ids so they require word
boundaries: for the completes?/closes? pattern used to set ids (the line
assigning ids from echo "$commit" | grep -oE
'(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' ...) add a left-side word
boundary (e.g., '\b(completes?|closes?)[[:space:]]+t...') and for the tXXX
before completion pattern (the line assigning ids from echo "$commit" | grep -oE
't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)' ...) add a right-side
word boundary on the completion words (e.g.,
'...([[:space:]]+(complete|done|finished)\b)') so that the populated ids and
appended task_ids only match whole words.


done <<< "$commits"
Comment on lines +551 to +586

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This while loop is a great improvement for correctness. It can be further optimized for efficiency and readability.

  1. Efficiency: The loop currently spawns multiple processes (echo, grep, tr) for each commit, which can be slow if there are many commits. You can make this more efficient by using bash's built-in regex matching (BASH_REMATCH) for pattern 1, and combining grep pipes with sed for patterns 3 and 4.
  2. Readability: The local declarations for id and ids are scattered and re-declared, which can be confusing. It's better practice to declare all loop-specific variables once at the top of the loop.

Here's a suggested refactoring of the loop that addresses these points:

    while IFS= read -r commit; do
        local id segment ids
        [[ -z "$commit" ]] && continue
        
        # Pattern 1: Conventional commits with task ID in scope (more efficient)
        if [[ "$commit" =~ ^(feat|fix|docs|refactor|perf|test|chore|style|build|ci)\((t[0-9]{3}(\.[0-9]+)*)\): ]]; then
            id="${BASH_REMATCH[2]}"
            task_ids="$task_ids $id"
        fi
        
        # Pattern 2: "mark tXXX done/complete" - extract task IDs between "mark" and "done/complete"
        # e.g., "mark t004, t048, t069 done" -> t004, t048, t069
        if [[ "$commit" =~ mark[[:space:]]+(.*)[[:space:]]+(done|complete) ]]; then
            segment="${BASH_REMATCH[1]}"
            ids=$(echo "$segment" | grep -oE '\bt[0-9]{3}(\.[0-9]+)*\b')
            task_ids="$task_ids $ids"
        fi
        
        # Pattern 3: "complete/completes/closes tXXX" - task ID immediately after keyword (more efficient)
        # e.g., "complete t037", "closes t001"
        ids=$(echo "$commit" | grep -oE '(completes?|closes?)[[:space:]]+t[0-9]{3}(\.[0-9]+)*' | sed -E 's/.*[[:space:]]+//')
        if [[ -n "$ids" ]]; then
            task_ids="$task_ids $ids"
        fi
        
        # Pattern 4: "tXXX complete/done/finished" - task ID before completion word (more efficient)
        # e.g., "t001 complete", "t002 done"
        ids=$(echo "$commit" | grep -oE 't[0-9]{3}(\.[0-9]+)*[[:space:]]+(complete|done|finished)' | sed -E 's/[[:space:]]+(complete|done|finished)$//')
        if [[ -n "$ids" ]]; then
            task_ids="$task_ids $ids"
        fi
        
    done <<< "$commits"


# Deduplicate and sort
echo "$task_ids" | tr ' ' '\n' | grep -E '^t[0-9]{3}' | sort -u
Comment on lines +588 to +589
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Test 1: Verify regex behavior with the original pattern
echo "=== Testing original pattern: ^t[0-9]{3} ==="
printf '%s\n' "t001" "t0012" "t001foo" "t001.1" | grep -E '^t[0-9]{3}' && echo "---" && echo "Pattern matched above"

echo ""
echo "=== Testing suggested pattern: ^t[0-9]{3}(\.[0-9]+)*$ ==="
printf '%s\n' "t001" "t0012" "t001foo" "t001.1" | grep -E '^t[0-9]{3}(\.[0-9]+)*$' && echo "---" && echo "Pattern matched above"

Repository: marcusquinn/aidevops

Length of output: 257


🏁 Script executed:

# Examine the actual file at lines 588-589
sed -n '580,600p' .agent/scripts/version-manager.sh | cat -n

Repository: marcusquinn/aidevops

Length of output: 944


🏁 Script executed:

# Search for task ID patterns and usage in the script
rg 't[0-9]{3}' .agent/scripts/version-manager.sh -A 2 -B 2 | head -50

Repository: marcusquinn/aidevops

Length of output: 1935


🏁 Script executed:

# Check what task IDs actually look like in the codebase
rg '\bt[0-9]{3}' --type sh -A 1 -B 1 | head -40

Repository: marcusquinn/aidevops

Length of output: 3106


Anchor the final task-id filter to prevent partial-ID matches.

The pattern ^t[0-9]{3} accepts unwanted matches: t0012 (4 digits instead of 3) and t001foo (text after ID). Since task IDs follow the strict format t[0-9]{3}(\.[0-9]+)*, add end-of-line anchor and optional sub-task support to enforce correctness at the deduplication stage.

Suggested fix
-    echo "$task_ids" | tr ' ' '\n' | grep -E '^t[0-9]{3}' | sort -u
+    echo "$task_ids" | tr ' ' '\n' | grep -E '^t[0-9]{3}(\.[0-9]+)*$' | sort -u
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Deduplicate and sort
echo "$task_ids" | tr ' ' '\n' | grep -E '^t[0-9]{3}' | sort -u
# Deduplicate and sort
echo "$task_ids" | tr ' ' '\n' | grep -E '^t[0-9]{3}(\.[0-9]+)*$' | sort -u
🤖 Prompt for AI Agents
In @.agent/scripts/version-manager.sh around lines 588 - 589, The current
pipeline that deduplicates task IDs (echo "$task_ids" | tr ' ' '\n' | grep -E
'^t[0-9]{3}' | sort -u) allows partial matches like t0012 or t001foo; update the
grep pattern to strictly match the task-id format used by the script by
anchoring the end and allowing optional sub-tasks, e.g. replace the grep -E
pattern with one that enforces start and end anchors and optional dot-separated
numeric subparts (use '^t[0-9]{3}(\\.[0-9]+)*$') so only valid IDs from the
task_ids variable pass to sort -u.

return 0
}

Expand Down
Loading