feat(playbook): support multi-language standards layout

This commit is contained in:
csh 2025-12-12 23:19:22 +08:00
parent 5311f33802
commit 88f0842134
13 changed files with 396 additions and 171 deletions

View File

@ -4,7 +4,7 @@
## 1. 总体要求 ## 1. 总体要求
- 遵守 `docs/code_style.md` 与 `docs/naming.md`。 - 遵守本标准快照中的 `docs/tsl/code_style.md` 与 `docs/tsl/naming.md`(通常位于目标项目的 `docs/standards/tsl/docs/tsl/`
- 改动聚焦目标;避免“顺手重构”。 - 改动聚焦目标;避免“顺手重构”。
- API 变更要显式说明影响与迁移方式。 - API 变更要显式说明影响与迁移方式。

View File

@ -1,15 +1,21 @@
# .agents 指南索引 # TSL Playbook 代理规则集(.agents/tsl
本规则集用于存放 **AI/自动化代理在仓库内工作时必须遵守的规则**
在多语言项目中,推荐将本规则集放在目标项目的 `.agents/tsl/` 下(由 `scripts/sync_standards.*` 同步),并与其他语言规则集并行:
- `.agents/tsl/`TSL 标准规则集(本仓库提供)
- `.agents/cpp/`、`.agents/python/` 等:其他语言规则集(按需新增)
本目录用于存放 **AI/自动化代理在本仓库内工作时必须遵守的规则**
这些规则与 `docs/` 下的人类开发规范并行: 这些规则与 `docs/` 下的人类开发规范并行:
- `docs/`:给人看的编码/命名/提交规范 - `docs/`:给人看的编码/命名/提交规范
- `.agents/`:给代理看的任务边界、质量与安全要求 - `.agents/`:给代理看的任务边界、质量与安全要求
## 范围 ## 范围与优先级
- 适用于本仓库所有目录与文件,除非子目录另有更具体的 `.agents/*.md` 覆盖说明 - 作为仓库级基线规则集使用;更靠近代码目录的规则应更具体并可覆盖基线
- 当 `.agents` `docs` 发生冲突时: - 当代理规则`docs` 发生冲突时:
1. 安全/合规优先 1. 安全/合规优先
2. 其次保持仓库现有一致性 2. 其次保持仓库现有一致性
@ -27,8 +33,19 @@
- 代码质量:`code_quality.md` - 代码质量:`code_quality.md`
- 测试:`testing.md` - 测试:`testing.md`
## 分类(本仓库现状)
当前本规则集下的文件全部为 **跨语言通用规则**(不绑定具体语言语法/工具链):
- `auth.md`:敏感信息/鉴权边界
- `code_quality.md`:质量底线与 review 清单
- `performance.md`:性能原则与验证
- `testing.md`:测试策略
若需要 TSL/C++ 等语言专属的代理要求,建议在目标项目新增对应目录(例如 `.agents/tsl/`、`.agents/cpp/`)或在源码子目录放置更具体的 `.agents` 覆盖规则。
## 与开发规范的关系 ## 与开发规范的关系
- 代码风格:`docs/code_style.md` - 代码风格:标准快照 `docs/tsl/code_style.md`(通常位于目标项目 `docs/standards/tsl/docs/tsl/code_style.md`
- 命名规范:`docs/naming.md` - 命名规范:标准快照 `docs/tsl/naming.md`(通常位于目标项目 `docs/standards/tsl/docs/tsl/naming.md`
- 提交信息:`docs/commit_message.md` - 提交信息:标准快照 `docs/common/commit_message.md`(通常位于目标项目 `docs/standards/tsl/docs/common/commit_message.md`

130
README.md
View File

@ -23,9 +23,10 @@ TSL PlaybookTinysoft Language`.tsl` / `.tsf`)工程规范与代理规则
`docs/` 目录是给开发者阅读的工程规范,约束代码写法、命名与提交信息。 `docs/` 目录是给开发者阅读的工程规范,约束代码写法、命名与提交信息。
- `docs/code_style.md`:代码结构、格式、`begin/end` 代码块、注释与通用最佳实践。 - `docs/index.md`:文档导航(跨语言 common / TSL 专属)。
- `docs/naming.md`TSL 命名规范(顶层声明、文件同名规则、变量/成员/property、常量、集合命名等 - `docs/common/commit_message.md`提交信息与版本号规范type/scope/subject/body/footer、可选 Emoji 图例、SemVer
- `docs/commit_message.md`提交信息与版本号规范type/scope/subject/body/footer、可选 Emoji 图例、SemVer - `docs/tsl/code_style.md`TSL 代码结构、格式、`begin/end` 代码块、注释与通用最佳实践。
- `docs/tsl/naming.md`TSL 命名规范(顶层声明、文件同名规则、变量/成员/property、常量、集合命名等
## .agents/(代理规则) ## .agents/(代理规则)
@ -47,7 +48,7 @@ TSL PlaybookTinysoft Language`.tsl` / `.tsf`)工程规范与代理规则
```bash ```bash
git subtree add \ git subtree add \
--prefix docs/standards/tsl_playbook \ --prefix docs/standards/tsl \
https://git.mytsl.cn/csh/tsl-playbook.git \ https://git.mytsl.cn/csh/tsl-playbook.git \
main --squash main --squash
``` ```
@ -56,7 +57,7 @@ TSL PlaybookTinysoft Language`.tsl` / `.tsf`)工程规范与代理规则
```bash ```bash
git subtree pull \ git subtree pull \
--prefix docs/standards/tsl_playbook \ --prefix docs/standards/tsl \
https://git.mytsl.cn/csh/tsl-playbook.git \ https://git.mytsl.cn/csh/tsl-playbook.git \
main --squash main --squash
``` ```
@ -66,27 +67,33 @@ TSL PlaybookTinysoft Language`.tsl` / `.tsf`)工程规范与代理规则
目标项目推荐采用以下结构Playbook 快照与项目文档分离): 目标项目推荐采用以下结构Playbook 快照与项目文档分离):
```txt ```txt
.agents/ # 从 Playbook 同步后可按项目微调 .
.gitattributes # 从 Playbook 同步 ├── .agents/
docs/ │ ├── index.md # 多语言代理规则集索引(缺省时由脚本创建)
standards/ │ └── tsl/ # 从 Playbook 同步(仅覆盖该子目录)
tsl_playbook/ # git subtree 快照(只读) ├── .gitattributes # 从 Playbook 同步
docs/ # code_style.md / naming.md / commit_message.md ├── docs/
.agents/ # 标准代理规则快照 │ ├── standards/
.gitattributes │ │ └── tsl/ # git subtree 快照(只读)
SOURCE.md # 记录来源版本/commit项目自行维护 │ │ ├── docs/ # common/ + tsl/
project/ # 目标项目自己的文档 │ │ ├── .agents/ # 标准代理规则快照
README.md # 说明遵循 standards │ │ ├── .gitattributes
│ │ └── SOURCE.md # 记录来源版本/commit项目自行维护
│ └── project/ # 目标项目自己的文档
└── README.md # 说明遵循 standards
``` ```
根目录的 `.agents/``.gitattributes` 通过同步脚本获得: 根目录的 `.agents/tsl/` 与 `.gitattributes` 通过同步脚本获得:
- 直接运行 Playbook 提供的脚本(子树快照里自带): - 直接运行 Playbook 提供的脚本(子树快照里自带):
- `docs/standards/tsl_playbook/scripts/sync_playbook.sh` - `docs/standards/tsl/scripts/sync_standards.sh`(推荐)
- `docs/standards/tsl_playbook/scripts/sync_playbook.ps1` - `docs/standards/tsl/scripts/sync_standards.ps1`(推荐)
- `docs/standards/tsl_playbook/scripts/sync_playbook.bat` - `docs/standards/tsl/scripts/sync_standards.bat`(推荐)
- 脚本会从快照目录同步到项目根目录,并先备份旧文件(`.bak.*`)。 - 脚本会从快照目录同步到项目根目录,并先备份旧文件(`.bak.*`)。
注:`docs/standards/tsl/` 只是推荐目录名;你可以用任意 `--prefix`(例如 `docs/standards/tsl_playbook/`)。同步脚本会从脚本自身路径推导快照根目录,不再依赖目录名。
注:默认同步到 `.agents/tsl/`;如需指定规则集名称,可通过环境变量 `AGENTS_NS`(例如 `AGENTS_NS=tsl`、`AGENTS_NS=common`)。
这样 clone 任意项目时都能直接读取规范文件,不依赖外部访问权限。 这样 clone 任意项目时都能直接读取规范文件,不依赖外部访问权限。
### 方式二:手动复制快照 ### 方式二:手动复制快照
@ -95,17 +102,86 @@ TSL PlaybookTinysoft Language`.tsl` / `.tsf`)工程规范与代理规则
步骤: 步骤:
1. 在目标项目创建目录:`docs/standards/tsl_playbook/`。 1. 在目标项目创建目录:`docs/standards/tsl/`。
2. 从本仓库复制以下内容到目标项目: 2. 从本仓库复制以下内容到目标项目:
- `docs/``docs/standards/tsl_playbook/docs/` - `docs/``docs/standards/tsl/docs/`(包含 `docs/common/``docs/tsl/`
- `.agents/``docs/standards/tsl_playbook/.agents/` - `.agents/``docs/standards/tsl/.agents/`
- `.gitattributes``docs/standards/tsl_playbook/.gitattributes` - `.gitattributes``docs/standards/tsl/.gitattributes`
- `scripts/``docs/standards/tsl_playbook/scripts/` - `scripts/``docs/standards/tsl/scripts/`
3. 在目标项目根目录运行同步脚本,把 `.agents/` 与 `.gitattributes` 落到根目录(见上文脚本路径)。 3. 在目标项目根目录运行同步脚本,把 `.agents/tsl/` 与 `.gitattributes` 落到根目录(见上文脚本路径)。
4. 在 `docs/standards/tsl_playbook/SOURCE.md` 记录本次复制的来源版本/日期(建议写 Playbook 的 commit hash 4. 在 `docs/standards/tsl/SOURCE.md` 记录本次复制的来源版本/日期(建议写 Playbook 的 commit hash
该方式没有自动同步能力,后续更新需重复上述复制流程。 该方式没有自动同步能力,后续更新需重复上述复制流程。
### 多语言项目落地TSL + C++/其他语言)
多语言项目建议把规范拆成两类:
1. **仓库级(跨语言)共识**:对所有语言都成立的规则与流程。
- 提交信息:`docs/common/commit_message.md`
- 行尾与文本规范:`.gitattributes`
- 代理最低要求:`.agents/*`(工作原则、质量底线、安全边界)
2. **语言级Language-specific规范**:只对某个语言成立的风格与工具。
- 例如 TSL 的命名/文件顶层声明限制、C++ 的 `.clang-format/.clang-tidy`、Python 的 `ruff` 等。
建议:仓库级规则尽量少且稳定;语言级规则各自独立,避免互相“污染”。
本仓库提供的代理规则集(同步后位于目标项目的 `.agents/tsl/`)当前全部为**跨语言通用规则**
- `auth.md`:敏感信息/鉴权边界
- `code_quality.md`:质量底线与 review 清单
- `performance.md`:性能原则与验证
- `testing.md`:测试策略
#### `.agents` 的覆盖/合并策略(可执行流程)
同步脚本会同步到项目根目录的 `.agents/tsl/`(并不会覆盖 `.agents/` 下的其他语言目录)。若项目需要追加 C++ 等语言/模块专属规则,建议二选一:
1. **推荐:子目录规则覆盖(无需改同步脚本)**
- 让本 Playbook 的规则集固定落在 `.agents/tsl/`,由同步脚本维护。
- 在其他语言/模块目录下新增更具体规则,例如 `.agents/cpp/`、`cpp/.agents/`、`src/.agents/`。
2. **Overlay 合并:项目维护叠加层并在同步后覆盖回去**
- 约定项目自定义规则放在 `docs/project/agents_overlay/`(不叫 `.agents`,避免被同步覆盖)。
- 每次运行 `sync_standards.*` 后,再把 overlay 覆盖回 `.agents/tsl/`(建议封装成项目脚本)。
macOS/Linux 示例(目标项目的 `scripts/sync_standards.sh`
```sh
#!/usr/bin/env sh
set -eu
sh docs/standards/tsl/scripts/sync_standards.sh
OVERLAY="docs/project/agents_overlay"
if [ -d "$OVERLAY" ]; then
cp -R "$OVERLAY"/. ".agents/tsl/"
echo "Applied agents overlay."
fi
```
PowerShell 示例(目标项目的 `scripts/sync_standards.ps1`
```powershell
$ErrorActionPreference = "Stop"
& "docs/standards/tsl/scripts/sync_standards.ps1"
$overlay = "docs/project/agents_overlay"
if (Test-Path $overlay) {
Copy-Item "$overlay\\*" ".agents\\tsl" -Recurse -Force
Write-Host "Applied agents overlay."
}
```
#### 扩展新语言(模板)
当目标项目需要新增一门语言(例如 C++),建议按以下模板扩展:
- 文档:在目标项目增加 `docs/standards/cpp/docs/`(或另一个标准仓库 subtree并在项目 `README.md`/`docs/index.md` 链接入口。
- 代理规则:在目标项目增加 `.agents/cpp/`(与 `.agents/tsl/` 并行),只写 C++ 专属要求与工具链约束。
- 同步策略:每个规则集只同步到对应子目录(例如 `.agents/cpp/`),避免覆盖整个 `.agents/`
- CI/工具按文件类型分别执行格式化、lint、测试不要让 TSL 规则去约束 C++ 代码,反之亦然)。
## 版本与贡献 ## 版本与贡献
- 本项目会持续迭代;变更以 PR 形式提交。 - 本项目会持续迭代;变更以 PR 形式提交。

13
docs/index.md Normal file
View File

@ -0,0 +1,13 @@
# 文档导航Docs Index
本仓库文档按“跨语言共识 / 语言专属”分层组织,便于在多语言项目中扩展与复用。
## 跨语言common
- 提交信息与版本号:`common/commit_message.md`
## TSLtsl
- 代码风格:`tsl/code_style.md`
- 命名规范:`tsl/naming.md`

View File

@ -1,4 +1,4 @@
# 代码风格Code Style # TSL 代码风格Code Style
本章节规定 TSL 代码的结构与格式约定。 本章节规定 TSL 代码的结构与格式约定。

View File

@ -1,4 +1,4 @@
# 命名规范Naming # TSL 命名规范Naming
本仓库命名规则与 Google C++ Style Guide 对齐:通过名字的“形状”快速判断实体类型(类型/函数/变量/常量等),减少阅读成本。 本仓库命名规则与 Google C++ Style Guide 对齐:通过名字的“形状”快速判断实体类型(类型/函数/变量/常量等),减少阅读成本。

View File

@ -1,51 +0,0 @@
@echo off
setlocal enabledelayedexpansion
rem Sync TSL Playbook snapshot to project root.
rem - Copies docs\standards\tsl_playbook\.agents -> .agents
rem - Copies docs\standards\tsl_playbook\.gitattributes -> .gitattributes
rem Existing targets are backed up before overwrite.
for /f "delims=" %%R in ('git rev-parse --show-toplevel 2^>nul') do set "ROOT=%%R"
if "%ROOT%"=="" set "ROOT=%cd%"
set "SRC=%ROOT%\docs\standards\tsl_playbook"
set "AGENTS_SRC=%SRC%\.agents"
set "GITATTR_SRC=%SRC%\.gitattributes"
set "AGENTS_DST=%ROOT%\.agents"
set "GITATTR_DST=%ROOT%\.gitattributes"
if not exist "%AGENTS_SRC%" (
echo ERROR: Playbook snapshot not found at "%AGENTS_SRC%".
echo Run: git subtree add --prefix docs/standards/tsl_playbook ^<playbook-url^> main --squash
exit /b 1
)
if exist "%AGENTS_DST%" (
set "RAND=%RANDOM%"
set "BAK_NAME=.agents.bak.!RAND!"
ren "%AGENTS_DST%" "!BAK_NAME!"
echo Backed up existing .agents -> !BAK_NAME!
)
xcopy "%AGENTS_SRC%" "%AGENTS_DST%\" /e /i /y >nul
if errorlevel 1 (
echo ERROR: failed to copy .agents
exit /b 1
)
echo Synced .agents from Playbook.
if exist "%GITATTR_SRC%" (
if exist "%GITATTR_DST%" (
set "RAND=%RANDOM%"
set "BAK_NAME=.gitattributes.bak.!RAND!"
ren "%GITATTR_DST%" "!BAK_NAME!"
echo Backed up existing .gitattributes -> !BAK_NAME!
)
copy /y "%GITATTR_SRC%" "%GITATTR_DST%" >nul
echo Synced .gitattributes from Playbook.
)
echo Done.
endlocal

View File

@ -1,41 +0,0 @@
# Sync TSL Playbook snapshot to project root.
# - Copies docs/standards/tsl_playbook/.agents -> .agents
# - Copies docs/standards/tsl_playbook/.gitattributes -> .gitattributes
# Existing targets are backed up before overwrite.
$ErrorActionPreference = "Stop"
$Root = (git rev-parse --show-toplevel 2>$null)
if (-not $Root) { $Root = (Get-Location).Path }
$Src = Join-Path $Root "docs/standards/tsl_playbook"
$AgentsSrc = Join-Path $Src ".agents"
$GitAttrSrc = Join-Path $Src ".gitattributes"
if (-not (Test-Path $AgentsSrc)) {
throw "Playbook snapshot not found at $AgentsSrc. Run git subtree add first."
}
$timestamp = Get-Date -Format "yyyyMMddHHmmss"
$AgentsDst = Join-Path $Root ".agents"
if (Test-Path $AgentsDst) {
$bak = "$AgentsDst.bak.$timestamp"
Move-Item $AgentsDst $bak
Write-Host "Backed up existing .agents -> $bak"
}
Copy-Item $AgentsSrc $AgentsDst -Recurse -Force
Write-Host "Synced .agents from Playbook."
$GitAttrDst = Join-Path $Root ".gitattributes"
if (Test-Path $GitAttrSrc) {
if (Test-Path $GitAttrDst) {
$bak = "$GitAttrDst.bak.$timestamp"
Move-Item $GitAttrDst $bak
Write-Host "Backed up existing .gitattributes -> $bak"
}
Copy-Item $GitAttrSrc $GitAttrDst -Force
Write-Host "Synced .gitattributes from Playbook."
}
Write-Host "Done."

View File

@ -1,41 +0,0 @@
#!/usr/bin/env sh
set -eu
# Sync TSL Playbook snapshot to project root.
# - Copies docs/standards/tsl_playbook/.agents -> .agents
# - Copies docs/standards/tsl_playbook/.gitattributes -> .gitattributes
# Existing targets are backed up before overwrite.
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SRC="$ROOT/docs/standards/tsl_playbook"
AGENTS_SRC="$SRC/.agents"
GITATTR_SRC="$SRC/.gitattributes"
if [ ! -d "$AGENTS_SRC" ]; then
echo "ERROR: Playbook snapshot not found at $AGENTS_SRC" >&2
echo "Run: git subtree add --prefix docs/standards/tsl_playbook <playbook-url> main --squash" >&2
exit 1
fi
timestamp="$(date +%Y%m%d%H%M%S 2>/dev/null || echo bak)"
AGENTS_DST="$ROOT/.agents"
if [ -e "$AGENTS_DST" ]; then
mv "$AGENTS_DST" "$ROOT/.agents.bak.$timestamp"
echo "Backed up existing .agents -> .agents.bak.$timestamp"
fi
cp -R "$AGENTS_SRC" "$AGENTS_DST"
echo "Synced .agents from Playbook."
if [ -f "$GITATTR_SRC" ]; then
GITATTR_DST="$ROOT/.gitattributes"
if [ -e "$GITATTR_DST" ]; then
mv "$GITATTR_DST" "$ROOT/.gitattributes.bak.$timestamp"
echo "Backed up existing .gitattributes -> .gitattributes.bak.$timestamp"
fi
cp "$GITATTR_SRC" "$GITATTR_DST"
echo "Synced .gitattributes from Playbook."
fi
echo "Done."

View File

@ -0,0 +1,87 @@
@echo off
setlocal enabledelayedexpansion
rem Sync standards snapshot to project root.
rem - Copies <snapshot>\.agents -> <project-root>\.agents\tsl
rem - Copies <snapshot>\.gitattributes -> <project-root>\.gitattributes
rem Existing targets are backed up before overwrite.
set "SCRIPT_DIR=%~dp0"
for /f "delims=" %%R in ('git -C "%SCRIPT_DIR%" rev-parse --show-toplevel 2^>nul') do set "ROOT=%%R"
if "%ROOT%"=="" set "ROOT=%cd%"
for %%I in ("%ROOT%") do set "ROOT=%%~fI"
for %%I in ("%SCRIPT_DIR%..") do set "SRC=%%~fI"
set "AGENTS_SRC=%SRC%\.agents"
set "GITATTR_SRC=%SRC%\.gitattributes"
set "AGENTS_NS=%AGENTS_NS%"
if "%AGENTS_NS%"=="" set "AGENTS_NS=tsl"
set "AGENTS_ROOT=%ROOT%\.agents"
set "AGENTS_DST=%AGENTS_ROOT%\%AGENTS_NS%"
set "GITATTR_DST=%ROOT%\.gitattributes"
if not exist "%AGENTS_SRC%" (
echo ERROR: Standards snapshot not found at "%AGENTS_SRC%".
echo Run: git subtree add --prefix ^<your-prefix^> ^<standards-url^> ^<branch^> --squash
exit /b 1
)
if /I "%SRC%"=="%ROOT%" (
echo Skip: snapshot root equals project root.
goto AfterGitAttr
)
if not exist "%AGENTS_ROOT%" mkdir "%AGENTS_ROOT%"
if exist "%AGENTS_DST%" (
set "RAND=%RANDOM%"
pushd "%AGENTS_ROOT%"
ren "%AGENTS_NS%" "%AGENTS_NS%.bak.!RAND!"
popd
echo Backed up existing %AGENTS_NS% agents -> %AGENTS_NS%.bak.!RAND!
)
xcopy "%AGENTS_SRC%\\*" "%AGENTS_DST%\\" /e /i /y >nul
if errorlevel 1 (
echo ERROR: failed to copy .agents
exit /b 1
)
echo Synced .agents\%AGENTS_NS% from standards.
if not exist "%AGENTS_ROOT%\index.md" (
> "%AGENTS_ROOT%\index.md" echo # .agents多语言
>> "%AGENTS_ROOT%\index.md" echo.
>> "%AGENTS_ROOT%\index.md" echo 本目录用于存放仓库级/语言级的代理规则集。
>> "%AGENTS_ROOT%\index.md" echo.
>> "%AGENTS_ROOT%\index.md" echo 建议约定:
>> "%AGENTS_ROOT%\index.md" echo.
>> "%AGENTS_ROOT%\index.md" echo - `.agents/tsl/`TSL 相关标准(由 `sync_standards.*` 同步)
>> "%AGENTS_ROOT%\index.md" echo - `.agents/cpp/`、`.agents/python/` 等:其他语言的规则集(按需增加)
>> "%AGENTS_ROOT%\index.md" echo.
>> "%AGENTS_ROOT%\index.md" echo 规则发生冲突时,建议以“更靠近代码的目录规则更具体”为准。
echo Created .agents\index.md
)
:SyncGitAttr
if exist "%GITATTR_SRC%" (
for %%I in ("%GITATTR_SRC%") do set "GITATTR_SRC_F=%%~fI"
for %%I in ("%GITATTR_DST%") do set "GITATTR_DST_F=%%~fI"
if /I "!GITATTR_SRC_F!"=="!GITATTR_DST_F!" (
echo Skip: .gitattributes source equals destination.
goto AfterGitAttr
)
if exist "%GITATTR_DST%" (
set "RAND=%RANDOM%"
set "BAK_NAME=.gitattributes.bak.!RAND!"
ren "%GITATTR_DST%" "!BAK_NAME!"
echo Backed up existing .gitattributes -> !BAK_NAME!
)
copy /y "%GITATTR_SRC%" "%GITATTR_DST%" >nul
echo Synced .gitattributes from standards.
)
:AfterGitAttr
echo Done.
endlocal

View File

@ -0,0 +1,82 @@
# Sync standards snapshot to project root.
# - Copies <snapshot>/.agents -> <project-root>/.agents/tsl
# - Copies <snapshot>/.gitattributes -> <project-root>/.gitattributes
# Existing targets are backed up before overwrite.
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$Src = (Resolve-Path (Join-Path $ScriptDir "..")).Path
$Root = (git -C $ScriptDir rev-parse --show-toplevel 2>$null)
if (-not $Root) { $Root = (Get-Location).Path }
$Root = (Resolve-Path $Root).Path
$AgentsSrc = Join-Path $Src ".agents"
$GitAttrSrc = Join-Path $Src ".gitattributes"
if (-not (Test-Path $AgentsSrc)) {
throw "Standards snapshot not found at $AgentsSrc. Run git subtree add first (choose any prefix)."
}
$timestamp = Get-Date -Format "yyyyMMddHHmmss"
$AgentsNs = $env:AGENTS_NS
if (-not $AgentsNs) { $AgentsNs = "tsl" }
if ($AgentsNs -match '[\\/]' -or $AgentsNs -match '\.\.') {
throw "Invalid AGENTS_NS=$AgentsNs"
}
$AgentsRoot = Join-Path $Root ".agents"
$AgentsDst = Join-Path $AgentsRoot $AgentsNs
if ($Src -ieq $Root) {
Write-Host "Skip: snapshot root equals project root."
Write-Host "Done."
exit 0
}
New-Item -ItemType Directory -Path $AgentsRoot -Force | Out-Null
if (Test-Path $AgentsDst) {
$bak = (Join-Path $AgentsRoot "$AgentsNs.bak.$timestamp")
Move-Item $AgentsDst $bak
Write-Host "Backed up existing $AgentsNs agents -> $(Split-Path -Leaf $bak)"
}
New-Item -ItemType Directory -Path $AgentsDst -Force | Out-Null
Copy-Item (Join-Path $AgentsSrc "*") $AgentsDst -Recurse -Force
Write-Host "Synced .agents/$AgentsNs from standards."
$AgentsIndex = Join-Path $AgentsRoot "index.md"
if (-not (Test-Path $AgentsIndex)) {
@"
# .agents多语言
本目录用于存放仓库级/语言级的代理规则集
建议约定
- `.agents/tsl/`TSL 相关标准 `sync_standards.*` 同步
- `.agents/cpp/``.agents/python/` 其他语言的规则集按需增加
规则发生冲突时建议以更靠近代码的目录规则更具体为准
"@ | Set-Content -Path $AgentsIndex -Encoding UTF8
Write-Host "Created .agents/index.md"
}
$GitAttrDst = Join-Path $Root ".gitattributes"
if (Test-Path $GitAttrSrc) {
if ($GitAttrSrc -ieq $GitAttrDst) {
Write-Host "Skip: .gitattributes source equals destination."
Write-Host "Done."
exit 0
}
if (Test-Path $GitAttrDst) {
$bak = "$GitAttrDst.bak.$timestamp"
Move-Item $GitAttrDst $bak
Write-Host "Backed up existing .gitattributes -> $bak"
}
Copy-Item $GitAttrSrc $GitAttrDst -Force
Write-Host "Synced .gitattributes from standards."
}
Write-Host "Done."

83
scripts/sync_standards.sh Normal file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env sh
set -eu
# Sync standards snapshot to project root.
# - Copies <snapshot>/.agents -> <project-root>/.agents/tsl
# - Copies <snapshot>/.gitattributes -> <project-root>/.gitattributes
# Existing targets are backed up before overwrite.
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)"
SRC="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd -P)"
ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || pwd)"
ROOT="$(CDPATH= cd -- "$ROOT" && pwd -P)"
AGENTS_SRC="$SRC/.agents"
GITATTR_SRC="$SRC/.gitattributes"
if [ ! -d "$AGENTS_SRC" ]; then
echo "ERROR: Standards snapshot not found at $AGENTS_SRC" >&2
echo "Run: git subtree add --prefix <your-prefix> <standards-url> <branch> --squash" >&2
exit 1
fi
timestamp="$(date +%Y%m%d%H%M%S 2>/dev/null || echo bak)"
if [ "$SRC" = "$ROOT" ]; then
echo "Skip: snapshot root equals project root."
echo "Done."
exit 0
fi
: "${AGENTS_NS:=tsl}"
case "$AGENTS_NS" in
""|*/*|*\\*|*..*)
echo "ERROR: invalid AGENTS_NS=$AGENTS_NS" >&2
exit 1
;;
esac
AGENTS_ROOT="$ROOT/.agents"
AGENTS_DST="$AGENTS_ROOT/$AGENTS_NS"
mkdir -p "$AGENTS_ROOT"
if [ -e "$AGENTS_DST" ]; then
mv "$AGENTS_DST" "$AGENTS_ROOT/$AGENTS_NS.bak.$timestamp"
echo "Backed up existing $AGENTS_NS agents -> $AGENTS_NS.bak.$timestamp"
fi
cp -R "$AGENTS_SRC" "$AGENTS_DST"
echo "Synced .agents/$AGENTS_NS from standards."
AGENTS_INDEX="$AGENTS_ROOT/index.md"
if [ ! -f "$AGENTS_INDEX" ]; then
cat >"$AGENTS_INDEX" <<'EOF'
# .agents多语言
本目录用于存放仓库级/语言级的代理规则集。
建议约定:
- `.agents/tsl/`TSL 相关标准(由 `sync_standards.*` 同步)
- `.agents/cpp/``.agents/python/` 等:其他语言的规则集(按需增加)
规则发生冲突时,建议以“更靠近代码的目录规则更具体”为准。
EOF
echo "Created .agents/index.md"
fi
echo "Synced agents ruleset to $AGENTS_DST."
GITATTR_DST="$ROOT/.gitattributes"
if [ -f "$GITATTR_SRC" ]; then
if [ "$(CDPATH= cd -- "$(dirname -- "$GITATTR_SRC")" && pwd -P)/$(basename -- "$GITATTR_SRC")" = "$GITATTR_DST" ]; then
echo "Skip: .gitattributes source equals destination."
else
if [ -e "$GITATTR_DST" ]; then
mv "$GITATTR_DST" "$ROOT/.gitattributes.bak.$timestamp"
echo "Backed up existing .gitattributes -> .gitattributes.bak.$timestamp"
fi
cp "$GITATTR_SRC" "$GITATTR_DST"
echo "Synced .gitattributes from standards."
fi
fi
echo "Done."