mirror of
https://github.com/github/spec-kit.git
synced 2026-03-17 02:43:08 +00:00
* fix: prepend YAML frontmatter to Cursor .mdc files for auto-inclusion Cursor IDE requires YAML frontmatter with `alwaysApply: true` in .mdc rule files for them to be automatically loaded. Without this frontmatter, users must manually configure glob patterns for the rules to take effect. This fix adds frontmatter generation to both the bash and PowerShell update-agent-context scripts, handling three scenarios: - New .mdc file creation (frontmatter prepended after template processing) - Existing .mdc file update without frontmatter (frontmatter added) - Existing .mdc file with frontmatter (no duplication) Closes #669 🤖 Generated with [Claude Code](https://claude.com/code) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: address Copilot review suggestions - Handle CRLF line endings in frontmatter detection (grep '^---' instead of '^---$') - Fix double blank line after frontmatter in PowerShell New-AgentFile - Remove unused tempfile import from tests - Add encoding="utf-8" to all open() calls for cross-platform safety Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
465 lines
21 KiB
PowerShell
465 lines
21 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
<#!
|
|
.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-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, q, agy, bob, qodercli)
|
|
|
|
.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-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','q','agy','bob','qodercli','generic')]
|
|
[string]$AgentType
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# Import common helpers
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
. (Join-Path $ScriptDir 'common.ps1')
|
|
|
|
# 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
|
|
|
|
# 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/agents/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'
|
|
$KILOCODE_FILE = Join-Path $REPO_ROOT '.kilocode/rules/specify-rules.md'
|
|
$AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md'
|
|
$ROO_FILE = Join-Path $REPO_ROOT '.roo/rules/specify-rules.md'
|
|
$CODEBUDDY_FILE = Join-Path $REPO_ROOT 'CODEBUDDY.md'
|
|
$QODER_FILE = Join-Path $REPO_ROOT 'QODER.md'
|
|
$AMP_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
|
$SHAI_FILE = Join-Path $REPO_ROOT 'SHAI.md'
|
|
$Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
|
$AGY_FILE = Join-Path $REPO_ROOT '.agent/rules/specify-rules.md'
|
|
$BOB_FILE = Join-Path $REPO_ROOT 'AGENTS.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
|
|
}
|
|
}
|
|
|
|
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 -Encoding utf8 | ForEach-Object {
|
|
if ($_ -match $regex) {
|
|
$val = $Matches[1].Trim()
|
|
if ($val -notin @('NEEDS CLARIFICATION','N/A')) { return $val }
|
|
}
|
|
} | Select-Object -First 1
|
|
}
|
|
|
|
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
|
|
|
|
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 = @()
|
|
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 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 -Encoding utf8
|
|
$content = $content -replace '\[PROJECT NAME\]',$ProjectName
|
|
$content = $content -replace '\[DATE\]',$Date.ToString('yyyy-MM-dd')
|
|
|
|
# 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
|
|
|
|
# Prepend Cursor frontmatter for .mdc files so rules are auto-included
|
|
if ($TargetFile -match '\.mdc$') {
|
|
$frontmatter = @('---','description: Project Development Guidelines','globs: ["**/*"]','alwaysApply: true','---','') -join [Environment]::NewLine
|
|
$content = $frontmatter + $content
|
|
}
|
|
|
|
$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 -Encoding utf8
|
|
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) {
|
|
$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 -Encoding utf8
|
|
$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)
|
|
}
|
|
|
|
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
|
|
if ($inTech -and -not $techAdded -and $newTechEntries.Count -gt 0) {
|
|
$newTechEntries | ForEach-Object { $output.Add($_) }
|
|
}
|
|
|
|
# Ensure Cursor .mdc files have YAML frontmatter for auto-inclusion
|
|
if ($TargetFile -match '\.mdc$' -and $output.Count -gt 0 -and $output[0] -ne '---') {
|
|
$frontmatter = @('---','description: Project Development Guidelines','globs: ["**/*"]','alwaysApply: true','---','')
|
|
$output.InsertRange(0, $frontmatter)
|
|
}
|
|
|
|
Set-Content -LiteralPath $TargetFile -Value ($output -join [Environment]::NewLine) -Encoding utf8
|
|
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 {
|
|
try {
|
|
if (Update-ExistingAgentFile -TargetFile $TargetFile -Date $date) { Write-Success "Updated existing $AgentName context file" } else { Write-Err 'Failed to update agent file'; return $false }
|
|
} catch {
|
|
Write-Err "Cannot access or update existing file: $TargetFile. $_"
|
|
return $false
|
|
}
|
|
}
|
|
return $true
|
|
}
|
|
|
|
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-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' }
|
|
'codex' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex CLI' }
|
|
'windsurf' { Update-AgentFile -TargetFile $WINDSURF_FILE -AgentName 'Windsurf' }
|
|
'kilocode' { Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code' }
|
|
'auggie' { Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI' }
|
|
'roo' { Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code' }
|
|
'codebuddy' { Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI' }
|
|
'qodercli' { Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI' }
|
|
'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' }
|
|
'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' }
|
|
'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' }
|
|
'agy' { Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity' }
|
|
'bob' { Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob' }
|
|
'generic' { Write-Info 'Generic agent: no predefined context file. Use the agent-specific update script for your agent.' }
|
|
default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli|generic'; return $false }
|
|
}
|
|
}
|
|
|
|
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 (Test-Path $KILOCODE_FILE) { if (-not (Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $AUGGIE_FILE) { if (-not (Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $ROO_FILE) { if (-not (Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $QODER_FILE) { if (-not (Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $AGY_FILE) { if (-not (Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $BOB_FILE) { if (-not (Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob')) { $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 }
|
|
}
|
|
return $ok
|
|
}
|
|
|
|
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-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli|generic]'
|
|
}
|
|
|
|
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
|
|
|