feat(sync_standards): auto-detect existing languages

This commit is contained in:
csh 2026-01-08 13:33:47 +08:00
parent e97fb00649
commit 4ae2733ad2
6 changed files with 104 additions and 39 deletions

View File

@ -230,15 +230,17 @@ sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp
- `docs/standards/playbook/scripts/sync_standards.bat`(推荐,支持多语言参数)
- 脚本会从快照目录同步到项目根目录,并先备份旧文件(`.bak.*`)。
注:建议固定使用 `--prefix docs/standards/playbook`,因为同步后的 `.agents/*/`
会引用该路径下的标准快照文档(`docs/standards/playbook/docs/...`)。注:默认同步到
`.agents/tsl/`;如需同步 C++ 规则集,推荐直接运行:`sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp`。
建议固定使用 `--prefix docs/standards/playbook`,因为同步后的 `.agents/*/`
会引用该路径下的标准快照文档(`docs/standards/playbook/docs/...`)。无参数时若已存在
`.agents/<lang>/`,将按现有语言同步;否则默认 `.agents/tsl/`。如需同步 C++ 规则集,
推荐直接运行:`sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp`。
这样 clone 任意项目时都能直接读取规范文件,不依赖外部访问权限。
同步脚本行为(目标项目内的最终落地内容):
- 覆盖/更新:`.agents/<AGENTS_NS>/`(默认 `.agents/tsl/`
- 自动识别:未传语言参数且已存在 `.agents/<lang>/` 时,按现有语言同步
- 更新 `.gitattributes`:默认追加缺失规则(可用
`SYNC_GITATTR_MODE=append|block|overwrite|skip` 控制)
- 缺省创建:`.agents/index.md`

View File

@ -21,27 +21,30 @@ for %%I in ("%SCRIPT_DIR%..") do set "SRC=%%~fI"
set "AGENTS_SRC_ROOT=%SRC%\.agents"
set "GITATTR_SRC=%SRC%\.gitattributes"
set "AGENTS_NS=%AGENTS_NS%"
if "%AGENTS_NS%"=="" set "AGENTS_NS=tsl"
echo %AGENTS_NS%| findstr /r "[\\/]" >nul && (
echo ERROR: invalid AGENTS_NS=%AGENTS_NS%
exit /b 1
)
echo %AGENTS_NS%| findstr /c:".." >nul && (
echo ERROR: invalid AGENTS_NS=%AGENTS_NS%
exit /b 1
)
set "AGENTS_ROOT=%ROOT%\.agents"
set "AGENTS_DST=%AGENTS_ROOT%\%AGENTS_NS%"
set "GITATTR_DST=%ROOT%\.gitattributes"
set "SYNC_GITATTR_MODE=%SYNC_GITATTR_MODE%"
if "%SYNC_GITATTR_MODE%"=="" set "SYNC_GITATTR_MODE=append"
rem Multi rulesets: only on outer invocation.
if "%SYNC_STANDARDS_INNER%"=="" (
if not "%~1"=="" (
set "LANG_LIST="
if not "%~1"=="" set "LANG_LIST=%*"
if "%LANG_LIST%"=="" (
if "%AGENTS_NS%"=="" (
if exist "%ROOT%\.agents" (
for /d %%D in ("%ROOT%\.agents\*") do (
set "CAND=%%~nxD"
if exist "%AGENTS_SRC_ROOT%\!CAND!\" (
if defined LANG_LIST (set "LANG_LIST=!LANG_LIST! !CAND!") else set "LANG_LIST=!CAND!"
)
)
)
)
)
if not "%LANG_LIST%"=="" (
set "FIRST=1"
set "SYNC_FIRST=%SYNC_GITATTR_MODE%"
for %%L in (%*) do (
for %%L in (!LANG_LIST!) do (
if "!FIRST!"=="1" (
set "FIRST=0"
set "SYNC_STANDARDS_INNER=1"
@ -59,6 +62,18 @@ if "%SYNC_STANDARDS_INNER%"=="" (
)
)
if "%AGENTS_NS%"=="" set "AGENTS_NS=tsl"
echo %AGENTS_NS%| findstr /r "[\\/]" >nul && (
echo ERROR: invalid AGENTS_NS=%AGENTS_NS%
exit /b 1
)
echo %AGENTS_NS%| findstr /c:".." >nul && (
echo ERROR: invalid AGENTS_NS=%AGENTS_NS%
exit /b 1
)
set "AGENTS_ROOT=%ROOT%\.agents"
set "AGENTS_DST=%AGENTS_ROOT%\%AGENTS_NS%"
set "AGENTS_SRC=%AGENTS_SRC_ROOT%\%AGENTS_NS%"
if not exist "%AGENTS_SRC%" (
rem Backward-compatible fallback: older snapshots used ^<snapshot^>\.agents\* directly.

View File

@ -31,6 +31,17 @@ if (-not (Test-Path $AgentsSrcRoot)) {
$timestamp = Get-Date -Format "yyyyMMddHHmmss"
# Auto-detect languages from existing .agents when no args are provided.
if (-not $env:SYNC_STANDARDS_INNER -and (-not $Langs -or $Langs.Count -eq 0) -and -not $env:AGENTS_NS) {
$agentsRoot = Join-Path $Root ".agents"
if (Test-Path $agentsRoot) {
$autoLangs = @(Get-ChildItem -Path $agentsRoot -Directory | ForEach-Object { $_.Name } | Where-Object { Test-Path (Join-Path $AgentsSrcRoot $_) })
if ($autoLangs.Count -gt 0) {
$Langs = $autoLangs
}
}
}
# Multi rulesets: only on the outer invocation.
if (-not $env:SYNC_STANDARDS_INNER -and $Langs -and $Langs.Count -gt 0) {
$oldInner = $env:SYNC_STANDARDS_INNER

View File

@ -47,6 +47,21 @@ if [ "${SYNC_STANDARDS_INNER:-}" != "1" ]; then
if [ -z "${langs:-}" ] && [ "$#" -gt 0 ]; then
langs="$*"
fi
if [ -z "${langs:-}" ] && [ "$#" -eq 0 ] && [ -z "${AGENTS_NS:-}" ]; then
auto_langs=""
if [ -d "$ROOT/.agents" ]; then
for dir in "$ROOT/.agents"/*; do
[ -d "$dir" ] || continue
ns="$(basename "$dir")"
if [ -d "$AGENTS_SRC_ROOT/$ns" ]; then
auto_langs="${auto_langs:+$auto_langs }$ns"
fi
done
fi
if [ -n "$auto_langs" ]; then
langs="$auto_langs"
fi
fi
if [ -n "${langs:-}" ]; then
sync_mode_first="${SYNC_GITATTR_MODE:-append}"
@ -162,12 +177,8 @@ 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 [ -f "$GITATTR_DST" ]; then
dst_file="$GITATTR_DST"
else
dst_file="/dev/null"
fi
missing_tmp="$(mktemp 2>/dev/null || echo "$ROOT/.gitattributes.missing.$timestamp")"
if [ -f "$GITATTR_DST" ]; then
awk '
function norm(line) {
gsub(/^[ \t]+|[ \t]+$/, "", line)
@ -184,7 +195,20 @@ if [ -f "$GITATTR_SRC" ]; then
if (line == "" || line ~ /^#/) next
if (!seen[line] && !out[line]++) print line
}
' "$dst_file" "$GITATTR_SRC" >"$missing_tmp"
' "$GITATTR_DST" "$GITATTR_SRC" >"$missing_tmp"
else
awk '
function norm(line) {
gsub(/^[ \t]+|[ \t]+$/, "", line)
return line
}
{
line=norm($0)
if (line == "" || line ~ /^#/) next
if (!out[line]++) print line
}
' "$GITATTR_SRC" >"$missing_tmp"
fi
if [ ! -s "$missing_tmp" ]; then
rm -f "$missing_tmp"

View File

@ -68,7 +68,7 @@ sh check_doc_links.sh
- **基础功能**
- 脚本存在且可执行
- 无参数时默认同步 tsl 规则集
- 无参数时默认同步 tsl(已有 `.agents/<lang>/` 则自动识别)
- 单语言同步tsl/cpp
- 多语言同步tsl cpp
- **.gitattributes 同步**

View File

@ -22,6 +22,7 @@ setup() {
teardown() {
# 清理测试目录
if [ -n "$TEST_DIR" ] && [ -d "$TEST_DIR" ]; then
chmod -R u+rwX "$TEST_DIR" 2>/dev/null || true
rm -rf "$TEST_DIR"
fi
}
@ -43,6 +44,18 @@ teardown() {
[ -f ".agents/tsl/index.md" ]
}
@test "sync_standards.sh 无参数时自动识别已有语言" {
cd "$TEST_DIR"
mkdir -p .agents/cpp
echo "# placeholder" > .agents/cpp/index.md
sh "$SCRIPT_PATH"
[ -d ".agents/cpp" ]
[ -f ".agents/cpp/index.md" ]
[ ! -d ".agents/tsl" ]
}
@test "sync_standards.sh tsl - 同步 TSL 规则集" {
cd "$TEST_DIR"
sh "$SCRIPT_PATH" tsl