diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index ed244282..8e8bcf6c 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -80,9 +80,56 @@ find_repo_root() { return 1 } +# Function to get highest number from specs directory +get_highest_from_specs() { + local specs_dir="$1" + local highest=0 + + if [ -d "$specs_dir" ]; then + for dir in "$specs_dir"/*; do + [ -d "$dir" ] || continue + dirname=$(basename "$dir") + number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") + number=$((10#$number)) + if [ "$number" -gt "$highest" ]; then + highest=$number + fi + done + fi + + echo "$highest" +} + +# Function to get highest number from git branches +get_highest_from_branches() { + local highest=0 + + # Get all branches (local and remote) + branches=$(git branch -a 2>/dev/null || echo "") + + if [ -n "$branches" ]; then + while IFS= read -r branch; do + # Clean branch name: remove leading markers and remote prefixes + clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||') + + # Extract feature number if branch matches pattern ###-* + if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then + number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0") + number=$((10#$number)) + if [ "$number" -gt "$highest" ]; then + highest=$number + fi + fi + done <<< "$branches" + fi + + echo "$highest" +} + # Function to check existing branches (local and remote) and return next available number check_existing_branches() { local short_name="$1" + local specs_dir="$2" # Fetch all remotes to get latest branch info (suppress errors if no remotes) git fetch --all --prune 2>/dev/null || true @@ -95,8 +142,8 @@ check_existing_branches() { # Check specs directory as well local spec_dirs="" - if [ -d "$SPECS_DIR" ]; then - spec_dirs=$(find "$SPECS_DIR" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n) + if [ -d "$specs_dir" ]; then + spec_dirs=$(find "$specs_dir" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n) fi # Combine all sources and get the highest number @@ -111,6 +158,12 @@ check_existing_branches() { echo $((max_num + 1)) } +# Function to clean and format a branch name +clean_branch_name() { + local name="$1" + echo "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//' +} + # Resolve repository root. Prefer git information when available, but fall back # to searching for repository markers so the workflow still functions in repositories that # were initialised with --no-git. @@ -133,48 +186,6 @@ cd "$REPO_ROOT" SPECS_DIR="$REPO_ROOT/specs" mkdir -p "$SPECS_DIR" -# Get highest number from specs directory -HIGHEST_FROM_SPECS=0 -if [ -d "$SPECS_DIR" ]; then - for dir in "$SPECS_DIR"/*; do - [ -d "$dir" ] || continue - dirname=$(basename "$dir") - number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") - number=$((10#$number)) - if [ "$number" -gt "$HIGHEST_FROM_SPECS" ]; then HIGHEST_FROM_SPECS=$number; fi - done -fi - -# Get highest number from branch names (both local and remote) -HIGHEST_FROM_BRANCHES=0 -if [ "$HAS_GIT" = true ]; then - # Get all branches (local and remote) - branches=$(git branch -a 2>/dev/null || echo "") - - if [ -n "$branches" ]; then - while IFS= read -r branch; do - # Clean branch name: remove leading markers and remote prefixes - clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||') - - # Extract feature number if branch matches pattern ###-* - if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then - number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0") - number=$((10#$number)) - if [ "$number" -gt "$HIGHEST_FROM_BRANCHES" ]; then HIGHEST_FROM_BRANCHES=$number; fi - fi - done <<< "$branches" - fi -fi - -# Use the highest number from either source -HIGHEST=$HIGHEST_FROM_SPECS -if [ "$HIGHEST_FROM_BRANCHES" -gt "$HIGHEST" ]; then - HIGHEST=$HIGHEST_FROM_BRANCHES -fi - -NEXT=$((HIGHEST + 1)) -FEATURE_NUM=$(printf "%03d" "$NEXT") - # Function to generate branch name with stop word filtering and length filtering generate_branch_name() { local description="$1" @@ -218,14 +229,15 @@ generate_branch_name() { echo "$result" else # Fallback to original logic if no meaningful words found - echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//' | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//' + local cleaned=$(clean_branch_name "$description") + echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//' fi } # Generate branch name if [ -n "$SHORT_NAME" ]; then # Use provided short name, just clean it up - BRANCH_SUFFIX=$(echo "$SHORT_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//') + BRANCH_SUFFIX=$(clean_branch_name "$SHORT_NAME") else # Generate from description with smart filtering BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION") @@ -235,19 +247,10 @@ fi if [ -z "$BRANCH_NUMBER" ]; then if [ "$HAS_GIT" = true ]; then # Check existing branches on remotes - BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX") + BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX" "$SPECS_DIR") else # Fall back to local directory check - HIGHEST=0 - if [ -d "$SPECS_DIR" ]; then - for dir in "$SPECS_DIR"/*; do - [ -d "$dir" ] || continue - dirname=$(basename "$dir") - number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") - number=$((10#$number)) - if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi - done - fi + HIGHEST=$(get_highest_from_specs "$SPECS_DIR") BRANCH_NUMBER=$((HIGHEST + 1)) fi fi diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index fcb525ac..a375bdc9 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -62,7 +62,6 @@ AGENT_TYPE="${1:-}" CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" COPILOT_FILE="$REPO_ROOT/.github/agents/copilot-instructions.md" -COPILOT_AGENTS_FILE="$REPO_ROOT/AGENTS.md" CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" QWEN_FILE="$REPO_ROOT/QWEN.md" AGENTS_FILE="$REPO_ROOT/AGENTS.md" @@ -588,7 +587,6 @@ update_specific_agent() { ;; copilot) update_agent_file "$COPILOT_FILE" "GitHub Copilot" - update_agent_file "$COPILOT_AGENTS_FILE" "GitHub Copilot (AGENTS.md)" ;; cursor-agent) update_agent_file "$CURSOR_FILE" "Cursor IDE" @@ -650,12 +648,6 @@ update_all_existing_agents() { found_agent=true fi - # Also update AGENTS.md for Copilot if the Copilot directory exists - if [[ -d "$REPO_ROOT/.github/agents" ]]; then - update_agent_file "$COPILOT_AGENTS_FILE" "GitHub Copilot (AGENTS.md)" - found_agent=true - fi - if [[ -f "$CURSOR_FILE" ]]; then update_agent_file "$CURSOR_FILE" "Cursor IDE" found_agent=true diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index db92c3f7..351f4e9e 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -59,6 +59,46 @@ function Find-RepositoryRoot { } } +function Get-HighestNumberFromSpecs { + param([string]$SpecsDir) + + $highest = 0 + if (Test-Path $SpecsDir) { + Get-ChildItem -Path $SpecsDir -Directory | ForEach-Object { + if ($_.Name -match '^(\d+)') { + $num = [int]$matches[1] + if ($num -gt $highest) { $highest = $num } + } + } + } + return $highest +} + +function Get-HighestNumberFromBranches { + param() + + $highest = 0 + try { + $branches = git branch -a 2>$null + if ($LASTEXITCODE -eq 0) { + foreach ($branch in $branches) { + # Clean branch name: remove leading markers and remote prefixes + $cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', '' + + # Extract feature number if branch matches pattern ###-* + if ($cleanBranch -match '^(\d+)-') { + $num = [int]$matches[1] + if ($num -gt $highest) { $highest = $num } + } + } + } + } catch { + # If git command fails, return 0 + Write-Verbose "Could not check Git branches: $_" + } + return $highest +} + function Get-NextBranchNumber { param( [string]$ShortName, @@ -127,6 +167,12 @@ function Get-NextBranchNumber { # Return next number return $maxNum + 1 } + +function ConvertTo-CleanBranchName { + param([string]$Name) + + return $Name.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', '' +} $fallbackRoot = (Find-RepositoryRoot -StartDir $PSScriptRoot) if (-not $fallbackRoot) { Write-Error "Error: Could not determine repository root. Please run this script from within the repository." @@ -150,46 +196,6 @@ Set-Location $repoRoot $specsDir = Join-Path $repoRoot 'specs' New-Item -ItemType Directory -Path $specsDir -Force | Out-Null -# Get highest number from specs directory -$highestFromSpecs = 0 -if (Test-Path $specsDir) { - Get-ChildItem -Path $specsDir -Directory | ForEach-Object { - if ($_.Name -match '^(\d{3})') { - $num = [int]$matches[1] - if ($num -gt $highestFromSpecs) { $highestFromSpecs = $num } - } - } -} - -# Get highest number from branch names (both local and remote) -$highestFromBranches = 0 -try { - $branches = git branch -a 2>$null - if ($LASTEXITCODE -eq 0) { - foreach ($branch in $branches) { - # Clean branch name: remove leading markers and remote prefixes - # The following regex removes: - # - Git's current branch marker ('*') and leading whitespace (e.g., '* main') - # - Remote prefixes (e.g., 'remotes/origin/') - $cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', '' - - # Extract feature number if branch matches pattern ###-* - if ($cleanBranch -match '^(\d{3})-') { - $num = [int]$matches[1] - if ($num -gt $highestFromBranches) { $highestFromBranches = $num } - } - } - } -} catch { - # If git command fails, just continue with specs-only check - Write-Verbose "Could not check Git branches: $_" -} - -# Use the highest number from either source -$highest = [Math]::Max($highestFromSpecs, $highestFromBranches) -$next = $highest + 1 -$featureNum = ('{0:000}' -f $next) - # Function to generate branch name with stop word filtering and length filtering function Get-BranchName { param([string]$Description) @@ -229,7 +235,7 @@ function Get-BranchName { return $result } else { # Fallback to original logic if no meaningful words found - $result = $Description.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', '' + $result = ConvertTo-CleanBranchName -Name $Description $fallbackWords = ($result -split '-') | Where-Object { $_ } | Select-Object -First 3 return [string]::Join('-', $fallbackWords) } @@ -238,7 +244,7 @@ function Get-BranchName { # Generate branch name if ($ShortName) { # Use provided short name, just clean it up - $branchSuffix = $ShortName.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', '' + $branchSuffix = ConvertTo-CleanBranchName -Name $ShortName } else { # Generate from description with smart filtering $branchSuffix = Get-BranchName -Description $featureDesc @@ -251,16 +257,7 @@ if ($Number -eq 0) { $Number = Get-NextBranchNumber -ShortName $branchSuffix -SpecsDir $specsDir } else { # Fall back to local directory check - $highest = 0 - if (Test-Path $specsDir) { - Get-ChildItem -Path $specsDir -Directory | ForEach-Object { - if ($_.Name -match '^(\d{3})') { - $num = [int]$matches[1] - if ($num -gt $highest) { $highest = $num } - } - } - } - $Number = $highest + 1 + $Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1 } } diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index a439cc43..741a55a6 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -47,7 +47,6 @@ $NEW_PLAN = $IMPL_PLAN $CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' $COPILOT_FILE = Join-Path $REPO_ROOT '.github/agents/copilot-instructions.md' -$COPILOT_AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' $CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' $QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' @@ -371,10 +370,7 @@ function Update-SpecificAgent { switch ($Type) { 'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' } 'gemini' { Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI' } - 'copilot' { - Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' - Update-AgentFile -TargetFile $COPILOT_AGENTS_FILE -AgentName 'GitHub Copilot (AGENTS.md)' - } + 'copilot' { Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' } 'cursor-agent' { Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE' } 'qwen' { Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code' } 'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' } @@ -396,8 +392,6 @@ function Update-AllExistingAgents { if (Test-Path $CLAUDE_FILE) { if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }; $found = $true } if (Test-Path $GEMINI_FILE) { if (-not (Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI')) { $ok = $false }; $found = $true } if (Test-Path $COPILOT_FILE) { if (-not (Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot')) { $ok = $false }; $found = $true } - # Also update AGENTS.md for Copilot if the Copilot directory exists - if (Test-Path (Join-Path $REPO_ROOT '.github/agents')) { if (-not (Update-AgentFile -TargetFile $COPILOT_AGENTS_FILE -AgentName 'GitHub Copilot (AGENTS.md)')) { $ok = $false }; $found = $true } if (Test-Path $CURSOR_FILE) { if (-not (Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE')) { $ok = $false }; $found = $true } if (Test-Path $QWEN_FILE) { if (-not (Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code')) { $ok = $false }; $found = $true } if (Test-Path $AGENTS_FILE) { if (-not (Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex/opencode')) { $ok = $false }; $found = $true }