267 lines
7.9 KiB
PowerShell
267 lines
7.9 KiB
PowerShell
# Sync project templates to target project.
|
||
# - Copies templates/memory-bank/ -> <project-root>/memory-bank/
|
||
# - Copies templates/prompts/ -> <project-root>/docs/prompts/
|
||
# - Copies templates/AGENTS.template.md -> <project-root>/AGENTS.md
|
||
# - Copies templates/AGENT_RULES.template.md -> <project-root>/AGENT_RULES.md
|
||
# Existing targets are backed up before overwrite.
|
||
[CmdletBinding()]
|
||
param(
|
||
[Parameter(Mandatory = $false, Position = 0)]
|
||
[string]$ProjectRoot,
|
||
|
||
[Parameter(Mandatory = $false)]
|
||
[string]$ProjectName,
|
||
|
||
[Parameter(Mandatory = $false)]
|
||
[string]$Date,
|
||
|
||
[Parameter(Mandatory = $false)]
|
||
[switch]$NoBackup,
|
||
|
||
[Parameter(Mandatory = $false)]
|
||
[switch]$Force,
|
||
|
||
[Parameter(Mandatory = $false)]
|
||
[switch]$Full
|
||
)
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||
$Src = (Resolve-Path (Join-Path $ScriptDir "..")).Path
|
||
|
||
# Defaults
|
||
if (-not $Date) {
|
||
$Date = Get-Date -Format "yyyy-MM-dd"
|
||
}
|
||
|
||
# Determine project root
|
||
if (-not $ProjectRoot) {
|
||
$ProjectRoot = (git -C $ScriptDir rev-parse --show-toplevel 2>$null)
|
||
if (-not $ProjectRoot) { $ProjectRoot = (Get-Location).Path }
|
||
}
|
||
$ProjectRoot = (Resolve-Path $ProjectRoot).Path
|
||
|
||
# Source directories
|
||
$TemplatesDir = Join-Path $Src "templates"
|
||
$MemoryBankSrc = Join-Path $TemplatesDir "memory-bank"
|
||
$PromptsSrc = Join-Path $TemplatesDir "prompts"
|
||
$AgentsSrc = Join-Path $TemplatesDir "AGENTS.template.md"
|
||
$AgentRulesSrc = Join-Path $TemplatesDir "AGENT_RULES.template.md"
|
||
|
||
# Check source exists
|
||
if (-not (Test-Path $TemplatesDir)) {
|
||
throw "Templates directory not found: $TemplatesDir"
|
||
}
|
||
|
||
# Skip if source equals destination
|
||
if ($Src -ieq $ProjectRoot) {
|
||
Write-Host "Skip: playbook root equals project root."
|
||
Write-Host "Done."
|
||
exit 0
|
||
}
|
||
|
||
$timestamp = Get-Date -Format "yyyyMMddHHmmss"
|
||
|
||
# Function: backup file/directory
|
||
function Backup-IfExists {
|
||
param([string]$Target)
|
||
|
||
if ((Test-Path $Target) -and -not $NoBackup) {
|
||
$backup = "$Target.bak.$timestamp"
|
||
Move-Item $Target $backup
|
||
Write-Host "Backed up: $(Split-Path -Leaf $Target) -> $(Split-Path -Leaf $backup)"
|
||
}
|
||
}
|
||
|
||
# Function: replace placeholders in file
|
||
function Replace-Placeholders {
|
||
param([string]$File)
|
||
|
||
if (-not (Test-Path $File)) { return }
|
||
|
||
$content = Get-Content -Raw -Path $File
|
||
if ($ProjectName) {
|
||
$content = $content.Replace("{{PROJECT_NAME}}", $ProjectName)
|
||
}
|
||
$content = $content.Replace("{{DATE}}", $Date)
|
||
Set-Content -Path $File -Value $content -Encoding UTF8 -NoNewline
|
||
}
|
||
|
||
# Function: replace placeholders in directory
|
||
function Replace-PlaceholdersDir {
|
||
param([string]$Dir)
|
||
|
||
if (-not (Test-Path $Dir)) { return }
|
||
|
||
Get-ChildItem -Path $Dir -Filter "*.md" -Recurse -File | ForEach-Object {
|
||
Replace-Placeholders -File $_.FullName
|
||
}
|
||
}
|
||
|
||
Write-Host "Syncing templates to: $ProjectRoot"
|
||
Write-Host ""
|
||
|
||
# 1. Sync memory-bank/
|
||
if (Test-Path $MemoryBankSrc) {
|
||
$MemoryBankDst = Join-Path $ProjectRoot "memory-bank"
|
||
|
||
if ((Test-Path $MemoryBankDst) -and -not $Force) {
|
||
Write-Host "memory-bank/ already exists. Use -Force to overwrite."
|
||
} else {
|
||
Backup-IfExists -Target $MemoryBankDst
|
||
New-Item -ItemType Directory -Path $MemoryBankDst -Force | Out-Null
|
||
Copy-Item -Path (Join-Path $MemoryBankSrc "*") -Destination $MemoryBankDst -Recurse -Force
|
||
|
||
# Rename .template.md to .md
|
||
Get-ChildItem -Path $MemoryBankDst -Filter "*.template.md" -File | ForEach-Object {
|
||
$newName = $_.Name -replace "\.template\.md$", ".md"
|
||
Rename-Item -Path $_.FullName -NewName $newName
|
||
}
|
||
|
||
Replace-PlaceholdersDir -Dir $MemoryBankDst
|
||
Write-Host "Synced: memory-bank/"
|
||
}
|
||
} else {
|
||
Write-Host "Skip: memory-bank/ templates not found"
|
||
}
|
||
|
||
# 2. Sync docs/prompts/
|
||
if (Test-Path $PromptsSrc) {
|
||
$PromptsDst = Join-Path $ProjectRoot "docs\prompts"
|
||
|
||
if ((Test-Path $PromptsDst) -and -not $Force) {
|
||
Write-Host "docs/prompts/ already exists. Use -Force to overwrite."
|
||
} else {
|
||
Backup-IfExists -Target $PromptsDst
|
||
$DocsDir = Join-Path $ProjectRoot "docs"
|
||
New-Item -ItemType Directory -Path $DocsDir -Force | Out-Null
|
||
New-Item -ItemType Directory -Path $PromptsDst -Force | Out-Null
|
||
Copy-Item -Path (Join-Path $PromptsSrc "*") -Destination $PromptsDst -Recurse -Force
|
||
|
||
# Rename .template.md to .md recursively
|
||
Get-ChildItem -Path $PromptsDst -Filter "*.template.md" -Recurse -File | ForEach-Object {
|
||
$newName = $_.Name -replace "\.template\.md$", ".md"
|
||
Rename-Item -Path $_.FullName -NewName $newName
|
||
}
|
||
|
||
Replace-PlaceholdersDir -Dir $PromptsDst
|
||
Write-Host "Synced: docs/prompts/"
|
||
}
|
||
} else {
|
||
Write-Host "Skip: prompts/ templates not found"
|
||
}
|
||
|
||
# 3. Sync AGENTS.md
|
||
# Choose markers based on -Full flag
|
||
if ($Full) {
|
||
$MarkerStart = "<!-- playbook:framework:start -->"
|
||
$MarkerEnd = "<!-- playbook:framework:end -->"
|
||
$SectionName = "framework"
|
||
} else {
|
||
$MarkerStart = "<!-- playbook:templates:start -->"
|
||
$MarkerEnd = "<!-- playbook:templates:end -->"
|
||
$SectionName = "templates"
|
||
}
|
||
|
||
if (Test-Path $AgentsSrc) {
|
||
$AgentsDst = Join-Path $ProjectRoot "AGENTS.md"
|
||
|
||
if (-not (Test-Path $AgentsDst)) {
|
||
# AGENTS.md doesn't exist: create from full template
|
||
Copy-Item -Path $AgentsSrc -Destination $AgentsDst -Force
|
||
Replace-Placeholders -File $AgentsDst
|
||
Write-Host "Created: AGENTS.md"
|
||
} else {
|
||
# AGENTS.md exists: update or append section
|
||
# Extract snippet from template
|
||
$templateContent = Get-Content -Raw -Path $AgentsSrc
|
||
$extractPattern = "(?s)(" + [regex]::Escape($MarkerStart) + ".*?" + [regex]::Escape($MarkerEnd) + ")"
|
||
if ($templateContent -match $extractPattern) {
|
||
$snippetContent = $Matches[1]
|
||
|
||
$content = Get-Content -Raw -Path $AgentsDst
|
||
|
||
if ($content -match [regex]::Escape($MarkerStart)) {
|
||
# Has markers: replace content between markers
|
||
$replacePattern = "(?s)" + [regex]::Escape($MarkerStart) + ".*?" + [regex]::Escape($MarkerEnd)
|
||
$newContent = $content -replace $replacePattern, $snippetContent
|
||
Set-Content -Path $AgentsDst -Value $newContent -Encoding UTF8 -NoNewline
|
||
Replace-Placeholders -File $AgentsDst
|
||
Write-Host "Updated: AGENTS.md ($SectionName section)"
|
||
} else {
|
||
# No markers: append snippet at the end
|
||
$newContent = $content.TrimEnd() + "`n`n" + $snippetContent
|
||
Set-Content -Path $AgentsDst -Value $newContent -Encoding UTF8 -NoNewline
|
||
Replace-Placeholders -File $AgentsDst
|
||
Write-Host "Appended: AGENTS.md ($SectionName section)"
|
||
}
|
||
} else {
|
||
Write-Host "Skip: markers not found in template"
|
||
}
|
||
}
|
||
} else {
|
||
Write-Host "Skip: AGENTS.template.md not found"
|
||
}
|
||
|
||
# 4. Sync AGENT_RULES.md
|
||
if (Test-Path $AgentRulesSrc) {
|
||
$AgentRulesDst = Join-Path $ProjectRoot "AGENT_RULES.md"
|
||
|
||
if ((Test-Path $AgentRulesDst) -and -not $Force) {
|
||
Write-Host "AGENT_RULES.md already exists. Use -Force to overwrite."
|
||
} else {
|
||
Backup-IfExists -Target $AgentRulesDst
|
||
Copy-Item -Path $AgentRulesSrc -Destination $AgentRulesDst -Force
|
||
Replace-Placeholders -File $AgentRulesDst
|
||
Write-Host "Synced: AGENT_RULES.md"
|
||
}
|
||
} else {
|
||
Write-Host "Skip: AGENT_RULES.template.md not found"
|
||
}
|
||
|
||
# 5. Create TODO.md and CONFIRM.md if not exist
|
||
$TodoPath = Join-Path $ProjectRoot "TODO.md"
|
||
if (-not (Test-Path $TodoPath)) {
|
||
@"
|
||
# TODO
|
||
|
||
## Plan 1: [计划名称]
|
||
|
||
- [ ] 任务 1
|
||
- [ ] 任务 2
|
||
|
||
---
|
||
|
||
**最后更新**:$Date
|
||
"@ | Set-Content -Path $TodoPath -Encoding UTF8
|
||
Write-Host "Created: TODO.md"
|
||
}
|
||
|
||
$ConfirmPath = Join-Path $ProjectRoot "CONFIRM.md"
|
||
if (-not (Test-Path $ConfirmPath)) {
|
||
@"
|
||
# 待确认事项
|
||
|
||
## 待确认
|
||
|
||
<!-- 记录需要确认的事项 -->
|
||
|
||
## 已确认
|
||
|
||
<!-- 已确认的事项移到这里 -->
|
||
|
||
---
|
||
|
||
**最后更新**:$Date
|
||
"@ | Set-Content -Path $ConfirmPath -Encoding UTF8
|
||
Write-Host "Created: CONFIRM.md"
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Host "Done."
|
||
Write-Host ""
|
||
Write-Host "Next steps:"
|
||
Write-Host " 1. Edit memory-bank/*.md to fill in project-specific content"
|
||
Write-Host " 2. Replace remaining {{PLACEHOLDER}} values"
|
||
Write-Host " 3. Run sync_standards.ps1 to sync .agents/ rules"
|