mirror of
https://github.com/github/spec-kit.git
synced 2026-03-16 18:33:07 +00:00
* feat: add Kimi Code (kimi) CLI agent support - Register kimi in AGENT_CONFIG with folder `.kimi/`, markdown format, requires_cli=True - Register kimi in CommandRegistrar.AGENT_CONFIGS - Add kimi to supported agents table in AGENTS.md and README.md - Add kimi to release packaging scripts (bash and PowerShell) - Add kimi CLI installation to devcontainer post-create script - Add kimi support to update-agent-context scripts (bash and PowerShell) - Add 4 consistency tests covering all kimi integration surfaces - Bump version to 0.1.14 and update CHANGELOG * fix: include .specify/templates/ and real command files in release ZIPs - Copy real command files from templates/commands/ (with speckit. prefix) instead of generating stubs, so slash commands have actual content - Add .specify/templates/ to every ZIP so ensure_constitution_from_template can find constitution-template.md on init - Add .vscode/settings.json to every ZIP - Having 3 top-level dirs prevents the extraction flatten heuristic from incorrectly stripping the agent config folder (.kimi/, .claude/, etc.) - Bump version to 0.1.14.1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(kimi): use .kimi/skills/<name>/SKILL.md structure for Kimi Code CLI Kimi Code CLI uses a skills system, not flat command files: - Skills live in .kimi/skills/<name>/SKILL.md (project-level) - Invoked with /skill:<name> (e.g. /skill:speckit.specify) - Each skill is a directory containing SKILL.md with YAML frontmatter Changes: - AGENT_CONFIG["kimi"]["commands_subdir"] = "skills" (was "commands") - create-release-packages.sh: new create_kimi_skills() function creates skill directories with SKILL.md from real template content - Bump version to 0.1.14.2 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(test): align kimi commands_subdir assertion with skills structure * fix: use forward slashes for tabnine path in create-release-packages.ps1 * fix: align kimi to .kimi/skills convention and fix ARGUMENTS unbound variable * fix: address PR review comments for kimi agent support - Fix VERSION_NO_V undefined variable in create-github-release.sh - Restore version $1 argument handling in create-release-packages.sh - Fix tabnine/vibe/generic cases calling undefined generate_commands - Align roo path .roo/rules -> .roo/commands with AGENT_CONFIG - Fix kimi extension to use per-skill SKILL.md directory structure - Add parent mkdir before dest_file.write_text for nested paths - Restore devcontainer tools removed by regression + add Kimi CLI - Strengthen test_kimi_in_powershell_validate_set assertion * fix: restore release scripts and address all PR review comments - Restore create-release-packages.sh to original with full generate_commands/ rewrite_paths logic; add kimi case using create_kimi_skills function - Restore create-release-packages.ps1 to original with full Generate-Commands/ Rewrite-Paths logic; add kimi case using New-KimiSkills function - Restore create-github-release.sh to original with proper $1 argument handling and VERSION_NO_V; add kimi zip entries - Add test_ai_help_includes_kimi for consistency with other agents - Strengthen test_kimi_in_powershell_validate_set to check ValidateSet * fix: address second round of PR review comments - Add __AGENT__ and {AGENT_SCRIPT} substitutions in create_kimi_skills (bash) - Add __AGENT__ and {AGENT_SCRIPT} substitutions in New-KimiSkills (PowerShell) - Replace curl|bash Kimi installer with pipx install kimi-cli in post-create.sh * fix: align kimi skill naming and add extension registrar test - Fix install_ai_skills() to use speckit.<cmd> naming for kimi (dot separator) instead of speckit-<cmd>, matching /skill:speckit.<cmd> invocation convention and packaging scripts - Add test_kimi_in_extension_registrar to verify CommandRegistrar.AGENT_CONFIGS includes kimi with correct dir and SKILL.md extension * fix(test): align kimi skill name assertion with dot-separator convention test_skills_install_for_all_agents now expects speckit.specify (dot) for kimi and speckit-specify (hyphen) for all other agents, matching the install_ai_skills() implementation added in the previous commit. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
473 lines
22 KiB
PowerShell
473 lines
22 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, tabnine, kiro-cli, agy, bob, vibe, qodercli, kimi, 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','kilocode','auggie','roo','codebuddy','amp','shai','tabnine','kiro-cli','agy','bob','qodercli','vibe','kimi','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'
|
|
$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'
|
|
|
|
$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' }
|
|
'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' }
|
|
'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|tabnine|kiro-cli|agy|bob|vibe|qodercli|kimi|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 $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 (-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|tabnine|kiro-cli|agy|bob|vibe|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
|