# Vendor a trimmed Playbook snapshot into a target project (offline copy), # then run sync_standards to materialize rulesets\\ and .gitattributes in # the target project root. # # Usage: # powershell -File scripts/vendor_playbook.ps1 -DestRoot # powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs tsl,cpp # powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs @("tsl","cpp") # # Notes: # - Snapshot is written to: \docs\standards\playbook\ # - Existing snapshot is backed up before overwrite. [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$DestRoot, [Parameter(Mandatory = $false)] [string[]]$Langs ) $ErrorActionPreference = "Stop" function Normalize-Langs([string[]]$InputLangs) { if (-not $InputLangs -or $InputLangs.Count -eq 0) { return @("tsl") } $result = New-Object System.Collections.Generic.List[string] foreach ($item in $InputLangs) { if (-not $item) { continue } foreach ($part in $item.Split(@(',', ' '), [System.StringSplitOptions]::RemoveEmptyEntries)) { if (-not $part) { continue } $result.Add($part) } } if ($result.Count -eq 0) { return @("tsl") } return $result.ToArray() } $Langs = Normalize-Langs $Langs foreach ($lang in $Langs) { if ($lang -match '[\\/]' -or $lang -match '\.\.') { throw "Invalid lang=$lang" } } $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $Src = (Resolve-Path (Join-Path $ScriptDir "..")).Path New-Item -ItemType Directory -Path $DestRoot -Force | Out-Null $DestRootAbs = (Resolve-Path $DestRoot).Path $StandardsDir = Join-Path $DestRootAbs "docs/standards" $DestPrefix = Join-Path $StandardsDir "playbook" New-Item -ItemType Directory -Path $StandardsDir -Force | Out-Null $timestamp = Get-Date -Format "yyyyMMddHHmmss" if (Test-Path $DestPrefix) { $bak = Join-Path $StandardsDir "playbook.bak.$timestamp" Move-Item $DestPrefix $bak Write-Host "Backed up existing snapshot -> docs\\standards\\$(Split-Path -Leaf $bak)" } New-Item -ItemType Directory -Path $DestPrefix -Force | Out-Null Copy-Item (Join-Path $Src ".gitattributes") (Join-Path $DestPrefix ".gitattributes") -Force Copy-Item (Join-Path $Src "scripts") $DestPrefix -Recurse -Force Copy-Item (Join-Path $Src "codex") $DestPrefix -Recurse -Force Copy-Item (Join-Path $Src "SKILLS.md") (Join-Path $DestPrefix "SKILLS.md") -Force $DocsDir = Join-Path $DestPrefix "docs" New-Item -ItemType Directory -Path $DocsDir -Force | Out-Null Copy-Item (Join-Path $Src "docs/common") $DocsDir -Recurse -Force $AgentsDir = Join-Path $DestPrefix "rulesets" New-Item -ItemType Directory -Path $AgentsDir -Force | Out-Null Copy-Item (Join-Path $Src "rulesets/index.md") (Join-Path $AgentsDir "index.md") -Force $TemplatesDir = Join-Path $DestPrefix "templates" New-Item -ItemType Directory -Path $TemplatesDir -Force | Out-Null $ciTplSrc = Join-Path (Join-Path $Src "templates") "ci" if (Test-Path $ciTplSrc) { Copy-Item $ciTplSrc $TemplatesDir -Recurse -Force } foreach ($lang in $Langs) { $docsSrc = Join-Path (Join-Path $Src "docs") $lang if (-not (Test-Path $docsSrc)) { throw "Docs not found for lang=$lang ($docsSrc)" } Copy-Item $docsSrc $DocsDir -Recurse -Force $agentsSrc = Join-Path (Join-Path $Src "rulesets") $lang if (-not (Test-Path $agentsSrc)) { throw "Agents ruleset not found for lang=$lang ($agentsSrc)" } Copy-Item $agentsSrc $AgentsDir -Recurse -Force $tplSrc = Join-Path (Join-Path $Src "templates") $lang if (Test-Path $tplSrc) { Copy-Item $tplSrc $TemplatesDir -Recurse -Force } } $langsCsv = ($Langs -join ",") $docLines = New-Object System.Collections.Generic.List[string] $docLines.Add("# 文档导航(Docs Index)") $docLines.Add("") $docLines.Add("本快照为裁剪版 Playbook(langs: $langsCsv)。") $docLines.Add("") $docLines.Add("## 跨语言(common)") $docLines.Add("") $docLines.Add('- 提交信息与版本号:`common/commit_message.md`') function Append-DocsSection([string]$Lang) { switch ($Lang) { "tsl" { $docLines.Add("") $docLines.Add("## TSL(tsl)") $docLines.Add("") $docLines.Add('- 代码风格:`tsl/code_style.md`') $docLines.Add('- 命名规范:`tsl/naming.md`') $docLines.Add('- 语法手册:`tsl/syntax_book/index.md`') $docLines.Add('- 工具链与验证命令(模板):`tsl/toolchain.md`') break } "cpp" { $docLines.Add("") $docLines.Add("## C++(cpp)") $docLines.Add("") $docLines.Add('- 代码风格:`cpp/code_style.md`') $docLines.Add('- 命名规范:`cpp/naming.md`') $docLines.Add('- 工具链与验证命令(模板):`cpp/toolchain.md`') $docLines.Add('- 第三方依赖(Conan):`cpp/dependencies_conan.md`') $docLines.Add('- clangd 配置:`cpp/clangd.md`') break } "python" { $docLines.Add("") $docLines.Add("## Python(python)") $docLines.Add("") $docLines.Add('- 代码风格:`python/style_guide.md`') $docLines.Add('- 工具链:`python/tooling.md`') $docLines.Add('- 配置清单:`python/configuration.md`') break } "markdown" { $docLines.Add("") $docLines.Add("## Markdown(markdown)") $docLines.Add("") $docLines.Add('- 代码块与行内代码格式:`markdown/index.md`') break } } } foreach ($lang in $Langs) { Append-DocsSection $lang } ($docLines -join "`n") | Set-Content -Path (Join-Path $DocsDir "index.md") -Encoding UTF8 $commit = "" try { $commit = (git -C $Src rev-parse HEAD 2>$null) } catch { $commit = "" } if (-not $commit) { $commit = "N/A" } @" # Playbook(裁剪快照) 本目录为从 Playbook vendoring 的裁剪快照(langs: $langsCsv)。 ## 使用 在目标项目根目录执行(多语言一次同步): ```sh sh docs/standards/playbook/scripts/sync_standards.sh $langsCsv ``` 查看规范入口: - `docs/standards/playbook/docs/index.md` - `.agents/index.md` ## Codex skills(可选) 安装到本机(需要先在 `~/.codex/config.toml` 启用 skills;见 `docs/standards/playbook/SKILLS.md`): ```sh sh docs/standards/playbook/scripts/install_codex_skills.sh ``` ## CI templates(可选) 目标项目可复制启用的 CI 示例模板(如 Gitea Actions):`templates/ci/`。 "@ | Set-Content -Path (Join-Path $DestPrefix "README.md") -Encoding UTF8 @" # SOURCE - Source: $Src - Commit: $commit - Date: $(Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") - Langs: $langsCsv - Generated-by: scripts/vendor_playbook.ps1 "@ | Set-Content -Path (Join-Path $DestPrefix "SOURCE.md") -Encoding UTF8 Write-Host "Vendored snapshot -> $DestPrefix" $ProjectAgentsRoot = Join-Path $DestRootAbs ".agents" $ProjectAgentsIndex = Join-Path $ProjectAgentsRoot "index.md" New-Item -ItemType Directory -Path $ProjectAgentsRoot -Force | Out-Null if (-not (Test-Path $ProjectAgentsIndex)) { $agentLines = New-Object System.Collections.Generic.List[string] $agentLines.Add("# .agents(多语言)") $agentLines.Add("") $agentLines.Add("本目录用于存放仓库级/语言级的代理规则集。") $agentLines.Add("") $agentLines.Add("本项目已启用的规则集:") foreach ($lang in $Langs) { switch ($lang) { "tsl" { $agentLines.Add("- .agents/tsl/:TSL 相关规则集(适用于 .tsl/.tsf)"); break } "cpp" { $agentLines.Add("- .agents/cpp/:C++ 相关规则集(C++23,含 Modules)"); break } "python" { $agentLines.Add("- .agents/python/:Python 相关规则集"); break } "markdown" { $agentLines.Add("- .agents/markdown/:Markdown 相关规则集(仅代码格式化)"); break } } } $agentLines.Add("") $agentLines.Add("入口建议从:") foreach ($lang in $Langs) { $agentLines.Add("- .agents/$lang/index.md") } $agentLines.Add("") $agentLines.Add("标准快照文档入口:") $agentLines.Add("") $agentLines.Add("- docs/standards/playbook/docs/index.md") ($agentLines -join "`n") | Set-Content -Path $ProjectAgentsIndex -Encoding UTF8 } $oldSyncRoot = $env:SYNC_ROOT $env:SYNC_ROOT = $DestRootAbs try { & (Join-Path $DestPrefix "scripts/sync_standards.ps1") -Langs $Langs } finally { $env:SYNC_ROOT = $oldSyncRoot } Write-Host "Done."