diff --git a/README.md b/README.md index a112396..f0f81fe 100644 --- a/README.md +++ b/README.md @@ -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//`,将按现有语言同步;否则默认 `.agents/tsl/`。如需同步 C++ 规则集, +推荐直接运行:`sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp`。 这样 clone 任意项目时都能直接读取规范文件,不依赖外部访问权限。 同步脚本行为(目标项目内的最终落地内容): - 覆盖/更新:`.agents//`(默认 `.agents/tsl/`) +- 自动识别:未传语言参数且已存在 `.agents//` 时,按现有语言同步 - 更新 `.gitattributes`:默认追加缺失规则(可用 `SYNC_GITATTR_MODE=append|block|overwrite|skip` 控制) - 缺省创建:`.agents/index.md` diff --git a/scripts/sync_standards.bat b/scripts/sync_standards.bat index 1c2a837..67b571c 100644 --- a/scripts/sync_standards.bat +++ b/scripts/sync_standards.bat @@ -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 ^\.agents\* directly. diff --git a/scripts/sync_standards.ps1 b/scripts/sync_standards.ps1 index 0a2aba7..6f13791 100644 --- a/scripts/sync_standards.ps1 +++ b/scripts/sync_standards.ps1 @@ -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 diff --git a/scripts/sync_standards.sh b/scripts/sync_standards.sh index 6c3dd8f..7639dbd 100644 --- a/scripts/sync_standards.sh +++ b/scripts/sync_standards.sh @@ -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,29 +177,38 @@ 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")" - awk ' - function norm(line) { - gsub(/^[ \t]+|[ \t]+$/, "", line) - return line - } - FNR==NR { - line=norm($0) - if (line == "" || line ~ /^#/) next - seen[line]=1 - next - } - { - line=norm($0) - if (line == "" || line ~ /^#/) next - if (!seen[line] && !out[line]++) print line - } - ' "$dst_file" "$GITATTR_SRC" >"$missing_tmp" + if [ -f "$GITATTR_DST" ]; then + awk ' + function norm(line) { + gsub(/^[ \t]+|[ \t]+$/, "", line) + return line + } + FNR==NR { + line=norm($0) + if (line == "" || line ~ /^#/) next + seen[line]=1 + next + } + { + line=norm($0) + if (line == "" || line ~ /^#/) next + if (!seen[line] && !out[line]++) print line + } + ' "$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" diff --git a/tests/README.md b/tests/README.md index 64a6b80..ea0ac56 100644 --- a/tests/README.md +++ b/tests/README.md @@ -68,7 +68,7 @@ sh check_doc_links.sh - **基础功能**: - 脚本存在且可执行 - - 无参数时默认同步 tsl 规则集 + - 无参数时默认同步 tsl(已有 `.agents//` 则自动识别) - 单语言同步(tsl/cpp) - 多语言同步(tsl cpp) - **.gitattributes 同步**: diff --git a/tests/scripts/test_sync_standards.bats b/tests/scripts/test_sync_standards.bats index 988f657..20f1884 100644 --- a/tests/scripts/test_sync_standards.bats +++ b/tests/scripts/test_sync_standards.bats @@ -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