mirror of
https://github.com/github/spec-kit.git
synced 2026-07-06 14:01:01 +08:00
- Add forge case to bash and PowerShell update-agent-context scripts
- Add FORGE_FILE variable mapping to AGENTS.md (like opencode/codex/pi)
- Add forge to all usage/help text and ValidateSet parameters
- Include forge in update_all_existing_agents functions
Wrapper script improvements:
- Simplify Forge wrapper scripts to unconditionally delegate to shared script
- Remove complex fallback logic that created stub AGENTS.md files
- Add clear error messages if shared script is missing/not executable
- Align with pattern used by other integrations (opencode, bob, etc.)
Benefits:
- Plan command's {AGENT_SCRIPT} now works for Forge users
- No more incomplete/stub context files masking missing support
- Cleaner, more maintainable code (-39 lines in wrappers)
- Consistent architecture across all integrations
Update AGENTS.md to document that Forge integration ensures shared scripts
include forge support for context updates.
Addresses reviewer feedback about Forge support being incomplete for
workflow steps that run {AGENT_SCRIPT}.
486 lines
23 KiB
PowerShell
486 lines
23 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, junie, kilocode, auggie, roo, codebuddy, amp, shai, tabnine, kiro-cli, agy, bob, vibe, qodercli, kimi, trae, pi, iflow, forge, generic)
|
|
|
|
.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','junie','kilocode','auggie','roo','codebuddy','amp','shai','tabnine','kiro-cli','agy','bob','qodercli','vibe','kimi','trae','pi','iflow','forge','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/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'
|
|
$JUNIE_FILE = Join-Path $REPO_ROOT '.junie/AGENTS.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'
|
|
$TABNINE_FILE = Join-Path $REPO_ROOT 'TABNINE.md'
|
|
$KIRO_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'
|
|
$VIBE_FILE = Join-Path $REPO_ROOT '.vibe/agents/specify-agents.md'
|
|
$KIMI_FILE = Join-Path $REPO_ROOT 'KIMI.md'
|
|
$TRAE_FILE = Join-Path $REPO_ROOT '.trae/rules/AGENTS.md'
|
|
$IFLOW_FILE = Join-Path $REPO_ROOT 'IFLOW.md'
|
|
$FORGE_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' }
|
|
'junie' { Update-AgentFile -TargetFile $JUNIE_FILE -AgentName 'Junie' }
|
|
'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' }
|
|
'tabnine' { Update-AgentFile -TargetFile $TABNINE_FILE -AgentName 'Tabnine CLI' }
|
|
'kiro-cli' { Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI' }
|
|
'agy' { Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity' }
|
|
'bob' { Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob' }
|
|
'vibe' { Update-AgentFile -TargetFile $VIBE_FILE -AgentName 'Mistral Vibe' }
|
|
'kimi' { Update-AgentFile -TargetFile $KIMI_FILE -AgentName 'Kimi Code' }
|
|
'trae' { Update-AgentFile -TargetFile $TRAE_FILE -AgentName 'Trae' }
|
|
'pi' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Pi Coding Agent' }
|
|
'iflow' { Update-AgentFile -TargetFile $IFLOW_FILE -AgentName 'iFlow CLI' }
|
|
'forge' { Update-AgentFile -TargetFile $FORGE_FILE -AgentName 'Forge' }
|
|
'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|junie|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli|kimi|trae|pi|iflow|forge|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 $JUNIE_FILE) { if (-not (Update-AgentFile -TargetFile $JUNIE_FILE -AgentName 'Junie')) { $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 $TABNINE_FILE) { if (-not (Update-AgentFile -TargetFile $TABNINE_FILE -AgentName 'Tabnine CLI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $KIRO_FILE) { if (-not (Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro 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 (Test-Path $VIBE_FILE) { if (-not (Update-AgentFile -TargetFile $VIBE_FILE -AgentName 'Mistral Vibe')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $KIMI_FILE) { if (-not (Update-AgentFile -TargetFile $KIMI_FILE -AgentName 'Kimi Code')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $TRAE_FILE) { if (-not (Update-AgentFile -TargetFile $TRAE_FILE -AgentName 'Trae')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $IFLOW_FILE) { if (-not (Update-AgentFile -TargetFile $IFLOW_FILE -AgentName 'iFlow CLI')) { $ok = $false }; $found = $true }
|
|
if (Test-Path $FORGE_FILE) { if (-not (Update-AgentFile -TargetFile $FORGE_FILE -AgentName 'Forge')) { $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|junie|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli|kimi|trae|pi|iflow|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
|