diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index 9ea3220..9420a22 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -1,161 +1,411 @@ #!/usr/bin/env pwsh -[CmdletBinding()] -param([string]$AgentType) +<#! +.SYNOPSIS +Update agent context files with information from plan.md (PowerShell version) + +.DESCRIPTION +Mirrors the behavior of scripts/bash/update-agent-context.sh: + 1. Environment Validation + 2. Plan Data Extraction + 3. Agent File Management (create from template or update existing) + 4. Content Generation (technology stack, recent changes, timestamp) + 5. Multi-Agent Support (claude, gemini, copilot, cursor, qwen, opencode, codex, windsurf) + +.PARAMETER AgentType +Optional agent key to update a single agent. If omitted, updates all existing agent files (creating a default Claude file if none exist). + +.EXAMPLE +./update-agent-context.ps1 -AgentType claude + +.EXAMPLE +./update-agent-context.ps1 # Updates all existing agent files + +.NOTES +Relies on common helper functions in common.ps1 +#> +param( + [Parameter(Position=0)] + [ValidateSet('claude','gemini','copilot','cursor','qwen','opencode','codex','windsurf')] + [string]$AgentType +) + $ErrorActionPreference = 'Stop' -# Load common functions -. "$PSScriptRoot/common.ps1" +# Import common helpers +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +. (Join-Path $ScriptDir 'common.ps1') -# Get all paths and variables from common functions -$paths = Get-FeaturePathsEnv +# Acquire environment paths +$envData = Get-FeaturePathsEnv +$REPO_ROOT = $envData.REPO_ROOT +$CURRENT_BRANCH = $envData.CURRENT_BRANCH +$HAS_GIT = $envData.HAS_GIT +$IMPL_PLAN = $envData.IMPL_PLAN +$NEW_PLAN = $IMPL_PLAN -$newPlan = $paths.IMPL_PLAN -if (-not (Test-Path $newPlan)) { - Write-Error "ERROR: No plan.md found at $newPlan" - if (-not $paths.HAS_GIT) { - Write-Output "Use: `$env:SPECIFY_FEATURE='your-feature-name' or create a new feature first" +# Agent file paths +$CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' +$GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' +$COPILOT_FILE = Join-Path $REPO_ROOT '.github/copilot-instructions.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' +$WINDSURF_FILE = Join-Path $REPO_ROOT '.windsurf/rules/specify-rules.md' + +$TEMPLATE_FILE = Join-Path $REPO_ROOT '.specify/templates/agent-file-template.md' + +# Parsed plan data placeholders +$script:NEW_LANG = '' +$script:NEW_FRAMEWORK = '' +$script:NEW_DB = '' +$script:NEW_PROJECT_TYPE = '' + +function Write-Info { + param( + [Parameter(Mandatory=$true)] + [string]$Message + ) + Write-Host "INFO: $Message" +} + +function Write-Success { + param( + [Parameter(Mandatory=$true)] + [string]$Message + ) + Write-Host "$([char]0x2713) $Message" +} + +function Write-WarningMsg { + param( + [Parameter(Mandatory=$true)] + [string]$Message + ) + Write-Warning $Message +} + +function Write-Err { + param( + [Parameter(Mandatory=$true)] + [string]$Message + ) + Write-Host "ERROR: $Message" -ForegroundColor Red +} + +function Validate-Environment { + if (-not $CURRENT_BRANCH) { + Write-Err 'Unable to determine current feature' + if ($HAS_GIT) { Write-Info "Make sure you're on a feature branch" } else { Write-Info 'Set SPECIFY_FEATURE environment variable or create a feature first' } + exit 1 + } + if (-not (Test-Path $NEW_PLAN)) { + Write-Err "No plan.md found at $NEW_PLAN" + Write-Info 'Ensure you are working on a feature with a corresponding spec directory' + if (-not $HAS_GIT) { Write-Info 'Use: $env:SPECIFY_FEATURE=your-feature-name or create a new feature first' } + exit 1 + } + if (-not (Test-Path $TEMPLATE_FILE)) { + Write-Err "Template file not found at $TEMPLATE_FILE" + Write-Info 'Run specify init to scaffold .specify/templates, or add agent-file-template.md there.' } - exit 1 } -$claudeFile = Join-Path $paths.REPO_ROOT 'CLAUDE.md' -$geminiFile = Join-Path $paths.REPO_ROOT 'GEMINI.md' -$copilotFile = Join-Path $paths.REPO_ROOT '.github/copilot-instructions.md' -$cursorFile = Join-Path $paths.REPO_ROOT '.cursor/rules/specify-rules.mdc' -$qwenFile = Join-Path $paths.REPO_ROOT 'QWEN.md' -$agentsFile = Join-Path $paths.REPO_ROOT 'AGENTS.md' -$windsurfFile = Join-Path $paths.REPO_ROOT '.windsurf/rules/specify-rules.md' - -Write-Output "=== Updating agent context files for feature $($paths.CURRENT_BRANCH) ===" - -function Get-PlanValue($pattern) { - if (-not (Test-Path $newPlan)) { return '' } - $line = Select-String -Path $newPlan -Pattern $pattern | Select-Object -First 1 - if ($line) { return ($line.Line -replace "^\*\*$pattern\*\*: ", '') } - return '' +function Extract-PlanField { + param( + [Parameter(Mandatory=$true)] + [string]$FieldPattern, + [Parameter(Mandatory=$true)] + [string]$PlanFile + ) + if (-not (Test-Path $PlanFile)) { return '' } + # Lines like **Language/Version**: Python 3.12 + $regex = "^\*\*$([Regex]::Escape($FieldPattern))\*\*: (.+)$" + Get-Content -LiteralPath $PlanFile | ForEach-Object { + if ($_ -match $regex) { + $val = $Matches[1].Trim() + if ($val -notin @('NEEDS CLARIFICATION','N/A')) { return $val } + } + } | Select-Object -First 1 } -$newLang = Get-PlanValue 'Language/Version' -$newFramework = Get-PlanValue 'Primary Dependencies' -$newTesting = Get-PlanValue 'Testing' -$newDb = Get-PlanValue 'Storage' -$newProjectType = Get-PlanValue 'Project Type' +function Parse-PlanData { + param( + [Parameter(Mandatory=$true)] + [string]$PlanFile + ) + if (-not (Test-Path $PlanFile)) { Write-Err "Plan file not found: $PlanFile"; return $false } + Write-Info "Parsing plan data from $PlanFile" + $script:NEW_LANG = Extract-PlanField -FieldPattern 'Language/Version' -PlanFile $PlanFile + $script:NEW_FRAMEWORK = Extract-PlanField -FieldPattern 'Primary Dependencies' -PlanFile $PlanFile + $script:NEW_DB = Extract-PlanField -FieldPattern 'Storage' -PlanFile $PlanFile + $script:NEW_PROJECT_TYPE = Extract-PlanField -FieldPattern 'Project Type' -PlanFile $PlanFile -function Format-TechnologyStack($lang, $framework) { + if ($NEW_LANG) { Write-Info "Found language: $NEW_LANG" } else { Write-WarningMsg 'No language information found in plan' } + if ($NEW_FRAMEWORK) { Write-Info "Found framework: $NEW_FRAMEWORK" } + if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Info "Found database: $NEW_DB" } + if ($NEW_PROJECT_TYPE) { Write-Info "Found project type: $NEW_PROJECT_TYPE" } + return $true +} + +function Format-TechnologyStack { + param( + [Parameter(Mandatory=$false)] + [string]$Lang, + [Parameter(Mandatory=$false)] + [string]$Framework + ) $parts = @() - - # Add non-empty parts (excluding "NEEDS CLARIFICATION" and "N/A") - if ($lang -and $lang -ne 'NEEDS CLARIFICATION') { $parts += $lang } - if ($framework -and $framework -ne 'NEEDS CLARIFICATION' -and $framework -ne 'N/A') { $parts += $framework } - - # Join with proper formatting - if ($parts.Count -eq 0) { - return '' - } elseif ($parts.Count -eq 1) { - return $parts[0] - } else { - return ($parts -join ' + ') + if ($Lang -and $Lang -ne 'NEEDS CLARIFICATION') { $parts += $Lang } + if ($Framework -and $Framework -notin @('NEEDS CLARIFICATION','N/A')) { $parts += $Framework } + if (-not $parts) { return '' } + return ($parts -join ' + ') +} + +function Get-ProjectStructure { + param( + [Parameter(Mandatory=$false)] + [string]$ProjectType + ) + if ($ProjectType -match 'web') { return "backend/`nfrontend/`ntests/" } else { return "src/`ntests/" } +} + +function Get-CommandsForLanguage { + param( + [Parameter(Mandatory=$false)] + [string]$Lang + ) + switch -Regex ($Lang) { + 'Python' { return "cd src; pytest; ruff check ." } + 'Rust' { return "cargo test; cargo clippy" } + 'JavaScript|TypeScript' { return "npm test; npm run lint" } + default { return "# Add commands for $Lang" } } } -function Initialize-AgentFile($targetFile, $agentName) { - if (Test-Path $targetFile) { return } - $template = Join-Path $paths.REPO_ROOT '.specify/templates/agent-file-template.md' - if (-not (Test-Path $template)) { Write-Error "Template not found: $template"; return } - $content = Get-Content $template -Raw - $content = $content.Replace('[PROJECT NAME]', (Split-Path $paths.REPO_ROOT -Leaf)) - $content = $content.Replace('[DATE]', (Get-Date -Format 'yyyy-MM-dd')) +function Get-LanguageConventions { + param( + [Parameter(Mandatory=$false)] + [string]$Lang + ) + if ($Lang) { "${Lang}: Follow standard conventions" } else { 'General: Follow standard conventions' } +} + +function New-AgentFile { + param( + [Parameter(Mandatory=$true)] + [string]$TargetFile, + [Parameter(Mandatory=$true)] + [string]$ProjectName, + [Parameter(Mandatory=$true)] + [datetime]$Date + ) + if (-not (Test-Path $TEMPLATE_FILE)) { Write-Err "Template not found at $TEMPLATE_FILE"; return $false } + $temp = New-TemporaryFile + Copy-Item -LiteralPath $TEMPLATE_FILE -Destination $temp -Force + + $projectStructure = Get-ProjectStructure -ProjectType $NEW_PROJECT_TYPE + $commands = Get-CommandsForLanguage -Lang $NEW_LANG + $languageConventions = Get-LanguageConventions -Lang $NEW_LANG + + $escaped_lang = $NEW_LANG + $escaped_framework = $NEW_FRAMEWORK + $escaped_branch = $CURRENT_BRANCH + + $content = Get-Content -LiteralPath $temp -Raw + $content = $content -replace '\[PROJECT NAME\]',$ProjectName + $content = $content -replace '\[DATE\]',$Date.ToString('yyyy-MM-dd') - $techStack = Format-TechnologyStack $newLang $newFramework + # Build the technology stack string safely + $techStackForTemplate = "" + if ($escaped_lang -and $escaped_framework) { + $techStackForTemplate = "- $escaped_lang + $escaped_framework ($escaped_branch)" + } elseif ($escaped_lang) { + $techStackForTemplate = "- $escaped_lang ($escaped_branch)" + } elseif ($escaped_framework) { + $techStackForTemplate = "- $escaped_framework ($escaped_branch)" + } + + $content = $content -replace '\[EXTRACTED FROM ALL PLAN.MD FILES\]',$techStackForTemplate + # For project structure we manually embed (keep newlines) + $escapedStructure = [Regex]::Escape($projectStructure) + $content = $content -replace '\[ACTUAL STRUCTURE FROM PLANS\]',$escapedStructure + # Replace escaped newlines placeholder after all replacements + $content = $content -replace '\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]',$commands + $content = $content -replace '\[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE\]',$languageConventions + + # Build the recent changes string safely + $recentChangesForTemplate = "" + if ($escaped_lang -and $escaped_framework) { + $recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang} + ${escaped_framework}" + } elseif ($escaped_lang) { + $recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang}" + } elseif ($escaped_framework) { + $recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_framework}" + } + + $content = $content -replace '\[LAST 3 FEATURES AND WHAT THEY ADDED\]',$recentChangesForTemplate + # Convert literal \n sequences introduced by Escape to real newlines + $content = $content -replace '\\n',[Environment]::NewLine + + $parent = Split-Path -Parent $TargetFile + if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null } + Set-Content -LiteralPath $TargetFile -Value $content -NoNewline + Remove-Item $temp -Force + return $true +} + +function Update-ExistingAgentFile { + param( + [Parameter(Mandatory=$true)] + [string]$TargetFile, + [Parameter(Mandatory=$true)] + [datetime]$Date + ) + if (-not (Test-Path $TargetFile)) { return (New-AgentFile -TargetFile $TargetFile -ProjectName (Split-Path $REPO_ROOT -Leaf) -Date $Date) } + + $techStack = Format-TechnologyStack -Lang $NEW_LANG -Framework $NEW_FRAMEWORK + $newTechEntries = @() if ($techStack) { - $content = $content.Replace('[EXTRACTED FROM ALL PLAN.MD FILES]', "- $techStack ($($paths.CURRENT_BRANCH))") + $escapedTechStack = [Regex]::Escape($techStack) + if (-not (Select-String -Pattern $escapedTechStack -Path $TargetFile -Quiet)) { + $newTechEntries += "- $techStack ($CURRENT_BRANCH)" + } + } + if ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) { + $escapedDB = [Regex]::Escape($NEW_DB) + if (-not (Select-String -Pattern $escapedDB -Path $TargetFile -Quiet)) { + $newTechEntries += "- $NEW_DB ($CURRENT_BRANCH)" + } + } + $newChangeEntry = '' + if ($techStack) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${techStack}" } + elseif ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${NEW_DB}" } + + $lines = Get-Content -LiteralPath $TargetFile + $output = New-Object System.Collections.Generic.List[string] + $inTech = $false; $inChanges = $false; $techAdded = $false; $changeAdded = $false; $existingChanges = 0 + + for ($i=0; $i -lt $lines.Count; $i++) { + $line = $lines[$i] + if ($line -eq '## Active Technologies') { + $output.Add($line) + $inTech = $true + continue + } + if ($inTech -and $line -match '^##\s') { + if (-not $techAdded -and $newTechEntries.Count -gt 0) { $newTechEntries | ForEach-Object { $output.Add($_) }; $techAdded = $true } + $output.Add($line); $inTech = $false; continue + } + if ($inTech -and [string]::IsNullOrWhiteSpace($line)) { + if (-not $techAdded -and $newTechEntries.Count -gt 0) { $newTechEntries | ForEach-Object { $output.Add($_) }; $techAdded = $true } + $output.Add($line); continue + } + if ($line -eq '## Recent Changes') { + $output.Add($line) + if ($newChangeEntry) { $output.Add($newChangeEntry); $changeAdded = $true } + $inChanges = $true + continue + } + if ($inChanges -and $line -match '^##\s') { $output.Add($line); $inChanges = $false; continue } + if ($inChanges -and $line -match '^- ') { + if ($existingChanges -lt 2) { $output.Add($line); $existingChanges++ } + continue + } + if ($line -match '\*\*Last updated\*\*: .*\d{4}-\d{2}-\d{2}') { + $output.Add(($line -replace '\d{4}-\d{2}-\d{2}',$Date.ToString('yyyy-MM-dd'))) + continue + } + $output.Add($line) + } + + Set-Content -LiteralPath $TargetFile -Value ($output -join [Environment]::NewLine) + return $true +} + +function Update-AgentFile { + param( + [Parameter(Mandatory=$true)] + [string]$TargetFile, + [Parameter(Mandatory=$true)] + [string]$AgentName + ) + if (-not $TargetFile -or -not $AgentName) { Write-Err 'Update-AgentFile requires TargetFile and AgentName'; return $false } + Write-Info "Updating $AgentName context file: $TargetFile" + $projectName = Split-Path $REPO_ROOT -Leaf + $date = Get-Date + + $dir = Split-Path -Parent $TargetFile + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null } + + if (-not (Test-Path $TargetFile)) { + if (New-AgentFile -TargetFile $TargetFile -ProjectName $projectName -Date $date) { Write-Success "Created new $AgentName context file" } else { Write-Err 'Failed to create new agent file'; return $false } } else { - $content = $content.Replace('[EXTRACTED FROM ALL PLAN.MD FILES]', '') + if (-not (Get-Item $TargetFile).Attributes) { Write-Err "Cannot access existing file: $TargetFile"; return $false } + if (Update-ExistingAgentFile -TargetFile $TargetFile -Date $date) { Write-Success "Updated existing $AgentName context file" } else { Write-Err 'Failed to update agent file'; return $false } } - if ($newProjectType -match 'web') { $structure = "backend/`nfrontend/`ntests/" } else { $structure = "src/`ntests/" } - $content = $content.Replace('[ACTUAL STRUCTURE FROM PLANS]', $structure) - if ($newLang -match 'Python') { $commands = 'cd src && pytest && ruff check .' } - elseif ($newLang -match 'Rust') { $commands = 'cargo test && cargo clippy' } - elseif ($newLang -match 'JavaScript|TypeScript') { $commands = 'npm test && npm run lint' } - else { $commands = "# Add commands for $newLang" } - $content = $content.Replace('[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]', $commands) - $content = $content.Replace('[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]', "${newLang}: Follow standard conventions") - - $techStack = Format-TechnologyStack $newLang $newFramework - if ($techStack) { - $content = $content.Replace('[LAST 3 FEATURES AND WHAT THEY ADDED]', "- $($paths.CURRENT_BRANCH): Added $techStack") - } else { - $content = $content.Replace('[LAST 3 FEATURES AND WHAT THEY ADDED]', '') - } - $content | Set-Content $targetFile -Encoding UTF8 + return $true } -function Update-AgentFile($targetFile, $agentName) { - if (-not (Test-Path $targetFile)) { Initialize-AgentFile $targetFile $agentName; return } - $content = Get-Content $targetFile -Raw - - $techStack = Format-TechnologyStack $newLang $newFramework - if ($techStack -and ($content -notmatch [regex]::Escape($techStack))) { - $content = $content -replace '(## Active Technologies\n)', "`$1- $techStack ($($paths.CURRENT_BRANCH))`n" +function Update-SpecificAgent { + param( + [Parameter(Mandatory=$true)] + [string]$Type + ) + 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' } + 'cursor' { 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' } + 'codex' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex CLI' } + 'windsurf' { Update-AgentFile -TargetFile $WINDSURF_FILE -AgentName 'Windsurf' } + default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf'; return $false } } - - if ($newDb -and $newDb -ne 'N/A' -and $newDb -ne 'NEEDS CLARIFICATION' -and ($content -notmatch [regex]::Escape($newDb))) { - $content = $content -replace '(## Active Technologies\n)', "`$1- $newDb ($($paths.CURRENT_BRANCH))`n" - } - - if ($content -match '## Recent Changes\n([\s\S]*?)(\n\n|$)') { - $changesBlock = $matches[1].Trim().Split("`n") - - if ($techStack) { - $changesBlock = ,"- $($paths.CURRENT_BRANCH): Added $techStack" + $changesBlock - } elseif ($newDb -and $newDb -ne 'N/A' -and $newDb -ne 'NEEDS CLARIFICATION') { - $changesBlock = ,"- $($paths.CURRENT_BRANCH): Added $newDb" + $changesBlock - } - - $changesBlock = $changesBlock | Where-Object { $_ } | Select-Object -First 3 - $joined = ($changesBlock -join "`n") - $content = [regex]::Replace($content, '## Recent Changes\n([\s\S]*?)(\n\n|$)', "## Recent Changes`n$joined`n`n") - } - $content = [regex]::Replace($content, 'Last updated: \d{4}-\d{2}-\d{2}', "Last updated: $(Get-Date -Format 'yyyy-MM-dd')") - $content | Set-Content $targetFile -Encoding UTF8 - Write-Output "✓ $agentName context file updated successfully" } -switch ($AgentType) { - 'claude' { Update-AgentFile $claudeFile 'Claude Code' } - 'gemini' { Update-AgentFile $geminiFile 'Gemini CLI' } - 'copilot' { Update-AgentFile $copilotFile 'GitHub Copilot' } - 'cursor' { Update-AgentFile $cursorFile 'Cursor IDE' } - 'qwen' { Update-AgentFile $qwenFile 'Qwen Code' } - 'opencode' { Update-AgentFile $agentsFile 'opencode' } - 'windsurf' { Update-AgentFile $windsurfFile 'Windsurf' } - 'codex' { Update-AgentFile $agentsFile 'Codex CLI' } - '' { - foreach ($pair in @( - @{file=$claudeFile; name='Claude Code'}, - @{file=$geminiFile; name='Gemini CLI'}, - @{file=$copilotFile; name='GitHub Copilot'}, - @{file=$cursorFile; name='Cursor IDE'}, - @{file=$qwenFile; name='Qwen Code'}, - @{file=$agentsFile; name='opencode'}, - @{file=$windsurfFile; name='Windsurf'}, - @{file=$agentsFile; name='Codex CLI'} - )) { - if (Test-Path $pair.file) { Update-AgentFile $pair.file $pair.name } - } - if (-not (Test-Path $claudeFile) -and -not (Test-Path $geminiFile) -and -not (Test-Path $copilotFile) -and -not (Test-Path $cursorFile) -and -not (Test-Path $qwenFile) -and -not (Test-Path $agentsFile) -and -not (Test-Path $windsurfFile)) { - Write-Output 'No agent context files found. Creating Claude Code context file by default.' - Update-AgentFile $claudeFile 'Claude Code' - } +function Update-AllExistingAgents { + $found = $false + $ok = $true + 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 } + 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 } + if (Test-Path $WINDSURF_FILE) { if (-not (Update-AgentFile -TargetFile $WINDSURF_FILE -AgentName 'Windsurf')) { $ok = $false }; $found = $true } + if (-not $found) { + Write-Info 'No existing agent files found, creating default Claude file...' + if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false } } - Default { Write-Error "ERROR: Unknown agent type '$AgentType'. Use: claude, gemini, copilot, cursor, qwen, opencode, windsurf, codex or leave empty for all."; exit 1 } + return $ok } -Write-Output '' -Write-Output 'Summary of changes:' -if ($newLang) { Write-Output "- Added language: $newLang" } -if ($newFramework) { Write-Output "- Added framework: $newFramework" } -if ($newDb -and $newDb -ne 'N/A') { Write-Output "- Added database: $newDb" } +function Print-Summary { + Write-Host '' + Write-Info 'Summary of changes:' + if ($NEW_LANG) { Write-Host " - Added language: $NEW_LANG" } + if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" } + if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" } + Write-Host '' + Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf]' +} -Write-Output '' -Write-Output 'Usage: ./update-agent-context.ps1 [claude|gemini|copilot|cursor|qwen|opencode|windsurf|codex]' +function Main { + Validate-Environment + Write-Info "=== Updating agent context files for feature $CURRENT_BRANCH ===" + if (-not (Parse-PlanData -PlanFile $NEW_PLAN)) { Write-Err 'Failed to parse plan data'; exit 1 } + $success = $true + if ($AgentType) { + Write-Info "Updating specific agent: $AgentType" + if (-not (Update-SpecificAgent -Type $AgentType)) { $success = $false } + } + else { + Write-Info 'No agent specified, updating all existing agent files...' + if (-not (Update-AllExistingAgents)) { $success = $false } + } + Print-Summary + if ($success) { Write-Success 'Agent context update completed successfully'; exit 0 } else { Write-Err 'Agent context update completed with errors'; exit 1 } +} + +Main