diff --git a/README.md b/README.md index a0d6605..caf0346 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,13 @@ Playbook:TSL(`.tsl`/`.tsf`)+ C++ + Python + Markdown(代码格式化) ```bash # Linux/macOS -sh scripts/sync_templates.sh /path/to/project +sh scripts/sync_templates.sh -project-root /path/to/project # PowerShell .\scripts\sync_templates.ps1 -ProjectRoot C:\path\to\project # Windows CMD -scripts\sync_templates.bat C:\path\to\project +scripts\sync_templates.bat -project-root C:\path\to\project ``` **部署行为**: @@ -140,12 +140,13 @@ Layer 3: docs/ (权威静态文档) | 你的情况 | 推荐方式 | 优势 | | -------------------------------- | ------------------------------- | ------------------------------- | -| 新项目,需要持续同步更新 | **方式一:git subtree(推荐)** | 可随时拉取最新标准,版本可追溯 | +| 新项目,需要持续同步更新 | 方式一:git subtree | 可随时拉取最新标准,版本可追溯 | | 只需要一次性引入,不常更新 | 方式二:手动复制快照 | 简单直接,无需 git subtree 知识 | -| 只需要部分语言(如只要 TSL+C++) | 方式三:脚本裁剪复制 | 自动裁剪,只包含所需语言 | +| 只需要部分语言(且希望快照也裁剪) | 方式三:脚本裁剪复制 | 快照只包含所需语言(更小) | | **不确定?** | **方式一:git subtree(推荐)** | 最灵活,后续可随时同步更新 | **大部分情况推荐使用方式一(git subtree)。** +说明:方式一可选择同步哪些语言规则到 `.agents/`,但 `docs/standards/playbook/` 快照仍是全量;方式三会裁剪快照本身。 --- @@ -159,7 +160,7 @@ git subtree add --prefix docs/standards/playbook \ https://git.mytsl.cn/csh/playbook.git main --squash # 2. 同步规则到项目根目录 -sh docs/standards/playbook/scripts/sync_standards.sh tsl +sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl # 3. 提交 git add . @@ -201,19 +202,19 @@ git commit -m ":package: deps(playbook): add tsl standards" 2. **同步到项目根目录**(生成/更新 `.agents//`、更新 `.gitattributes`): ```bash - sh docs/standards/playbook/scripts/sync_standards.sh + sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl ``` 同步 C++ 规则集(同一份快照,不同规则集): ```bash - sh docs/standards/playbook/scripts/sync_standards.sh cpp + sh docs/standards/playbook/scripts/sync_standards.sh -langs cpp ``` 一次同步多个规则集(推荐,减少重复备份 `.gitattributes`): ```bash - sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp + sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl,cpp ``` > 说明:若项目根目录没有 `AGENTS.md`,`sync_standards.*` @@ -239,14 +240,14 @@ git commit -m ":package: deps(playbook): add tsl standards" ```bash git subtree add --prefix docs/standards/playbook https://git.mytsl.cn/csh/playbook.git main --squash -sh docs/standards/playbook/scripts/sync_standards.sh tsl +sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl ``` **旧项目**(已有 `AGENTS.md`): ```bash git subtree pull --prefix docs/standards/playbook https://git.mytsl.cn/csh/playbook.git main --squash -sh docs/standards/playbook/scripts/sync_standards.sh tsl +sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl ``` 旧项目的 `AGENTS.md` 不会被覆盖;如需指向 `.agents/`,请手动对齐内容。 @@ -259,14 +260,14 @@ sh docs/standards/playbook/scripts/sync_standards.sh tsl #!/usr/bin/env sh set -eu -sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp +sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl,cpp # sh docs/standards/python/scripts/sync_standards.sh ``` 也可以直接一次同步多个规则集: ```sh -sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp +sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl,cpp ``` #### 目录约定(建议) @@ -303,16 +304,15 @@ sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp - 脚本会从快照目录同步到项目根目录,并先备份旧文件(`.bak.*`) 建议固定使用 `--prefix docs/standards/playbook`,因为同步后的 `.agents/*/` -会引用该路径下的标准快照文档(`docs/standards/playbook/docs/...`)。无参数时若已存在 -`.agents//`,将按现有语言同步;否则默认 `.agents/tsl/`。如需同步 C++ 规则集, -推荐直接运行:`sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp`。 +会引用该路径下的标准快照文档(`docs/standards/playbook/docs/...`)。同步时需显式指定 +语言参数(`-langs`),如需同步 C++ 规则集,推荐直接运行: +`sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl,cpp`。 这样 clone 任意项目时都能直接读取规范文件,不依赖外部访问权限。 **同步脚本行为**(目标项目内的最终落地内容): -- 覆盖/更新:`.agents//`(默认 `.agents/tsl/`) -- 自动识别:未传语言参数且已存在 `.agents//` 时,按现有语言同步 +- 覆盖/更新:`.agents//`(由 `-langs` 或 `AGENTS_NS` 指定) - 更新 `.gitattributes`:默认追加缺失规则(可用 `SYNC_GITATTR_MODE=append|block|overwrite|skip` 控制) - 缺省创建:`.agents/index.md` @@ -362,19 +362,19 @@ sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp - macOS/Linux: ```bash - sh /scripts/vendor_playbook.sh tsl cpp + sh /scripts/vendor_playbook.sh -project-root -langs tsl,cpp ``` - PowerShell: ```powershell - powershell -File \\scripts\\vendor_playbook.ps1 -DestRoot -Langs tsl,cpp + powershell -File \\scripts\\vendor_playbook.ps1 -ProjectRoot -Langs tsl,cpp ``` - Windows bat: ```bat - \\scripts\\vendor_playbook.bat -langs tsl,cpp + \\scripts\\vendor_playbook.bat -project-root -langs tsl,cpp ``` **脚本会**: @@ -456,7 +456,7 @@ macOS/Linux 示例(目标项目的 `scripts/sync_standards.sh`): #!/usr/bin/env sh set -eu -sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp +sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl,cpp OVERLAY="docs/project/agents_overlay" if [ -d "$OVERLAY" ]; then @@ -490,7 +490,7 @@ if (Test-Path $overlay) { - 若新增"本 Playbook 未覆盖的语言":再引入对应语言的标准仓库(subtree/vendoring 到 `docs/standards//`) - **代理规则**: - - C++:运行 `sh docs/standards/playbook/scripts/sync_standards.sh cpp`(或 + - C++:运行 `sh docs/standards/playbook/scripts/sync_standards.sh -langs cpp`(或 `& "docs/standards/playbook/scripts/sync_standards.ps1" -Langs cpp`),落地到 `.agents/cpp/`(与 `.agents/tsl/` 并行)。 - 其他语言:在目标项目增加 `.agents//`(与 `.agents/tsl/` diff --git a/SKILLS.md b/SKILLS.md index 10ded3f..4c1ca0c 100644 --- a/SKILLS.md +++ b/SKILLS.md @@ -49,38 +49,38 @@ $CODEX_HOME/skills//SKILL.md 本仓库已提供跨平台安装脚本(会把 `codex/skills/*` 复制到 `$CODEX_HOME/skills/`): -- macOS/Linux:`sh scripts/install_codex_skills.sh` -- PowerShell:`powershell -File scripts/install_codex_skills.ps1` -- Windows bat:`scripts/install_codex_skills.bat` +- macOS/Linux:`sh scripts/install_codex_skills.sh -all` +- PowerShell:`powershell -File scripts/install_codex_skills.ps1 -All` +- Windows bat:`scripts/install_codex_skills.bat -all` 用法示例: ```bash # 安装全部 skills -sh scripts/install_codex_skills.sh +sh scripts/install_codex_skills.sh -all # 只安装指定 skills -sh scripts/install_codex_skills.sh style-cleanup code-review-workflow +sh scripts/install_codex_skills.sh -skills style-cleanup,code-review-workflow ``` 如果希望“项目内本地安装”(不污染全局),可用以下方式: ```bash # 安装到当前目录的 .codex/skills/ -sh scripts/install_codex_skills.sh -local +sh scripts/install_codex_skills.sh -local -all # 或手动指定 CODEX_HOME -CODEX_HOME="$(pwd)/.codex" sh scripts/install_codex_skills.sh +CODEX_HOME="$(pwd)/.codex" sh scripts/install_codex_skills.sh -all ``` PowerShell / Windows: ```powershell -powershell -File scripts/install_codex_skills.ps1 -Local +powershell -File scripts/install_codex_skills.ps1 -Local -All ``` ```bat -scripts\install_codex_skills.bat -local +scripts\install_codex_skills.bat -local -all ``` > 注意:Codex 只会从 `CODEX_HOME` 加载 skills;使用本地安装时,启动 Codex 需设置同样的 `CODEX_HOME`。 @@ -89,7 +89,7 @@ scripts\install_codex_skills.bat -local `docs/standards/playbook`),则在目标项目里执行: ```bash -sh docs/standards/playbook/scripts/install_codex_skills.sh +sh docs/standards/playbook/scripts/install_codex_skills.sh -all ``` 安装后重启 `codex`,即可在运行时看到 `## Skills` 列表。 diff --git a/scripts/install_codex_skills.bat b/scripts/install_codex_skills.bat index 2a51c4b..7703785 100644 --- a/scripts/install_codex_skills.bat +++ b/scripts/install_codex_skills.bat @@ -6,9 +6,9 @@ rem - Source: \codex\skills\\ rem - Dest: %CODEX_HOME%\skills\\ (default CODEX_HOME=%USERPROFILE%\.codex) rem rem Usage: -rem install_codex_skills.bat -rem install_codex_skills.bat style-cleanup code-review-workflow -rem install_codex_skills.bat -local +rem install_codex_skills.bat -all +rem install_codex_skills.bat -skills style-cleanup,code-review-workflow +rem install_codex_skills.bat -local -all rem rem Notes: rem - Codex loads skills at startup; restart `codex` after installation. @@ -19,6 +19,8 @@ for %%I in ("%SCRIPT_DIR%..") do set "SRC=%%~fI" set "SKILLS_SRC_ROOT=%SRC%\\codex\\skills" set "LOCAL_MODE=0" +set "INSTALL_ALL=0" +set "SKILLS=" :parse_opts if "%~1"=="" goto opts_done if /I "%~1"=="-help" goto show_help @@ -33,6 +35,23 @@ if /I "%~1"=="-l" ( shift goto parse_opts ) +if /I "%~1"=="-all" ( + set "INSTALL_ALL=1" + shift + goto parse_opts +) +if /I "%~1"=="-skills" ( + if "%~2"=="" ( + echo ERROR: -skills requires a value. + exit /b 1 + ) + set "SKILLS=%~2" + shift + shift + goto parse_opts +) +echo ERROR: Unknown option: %~1 +exit /b 1 goto opts_done :opts_done @@ -48,17 +67,23 @@ if not exist "%SKILLS_SRC_ROOT%" ( if not exist "%SKILLS_DST_ROOT%" mkdir "%SKILLS_DST_ROOT%" -set "HAS_ARGS=0" -if not "%~1"=="" set "HAS_ARGS=1" - -if "%HAS_ARGS%"=="1" ( - for %%S in (%*) do call :InstallOne "%%~S" - goto Done +if "%INSTALL_ALL%"=="1" if not "%SKILLS%"=="" ( + echo ERROR: use either -all or -skills, not both. + exit /b 1 +) +if "%INSTALL_ALL%"=="0" if "%SKILLS%"=="" ( + echo ERROR: -all or -skills is required. + exit /b 1 ) -for /d %%D in ("%SKILLS_SRC_ROOT%\\*") do ( - set "NAME=%%~nD" - if not "!NAME!"=="" if not "!NAME:~0,1!"=="." call :InstallOne "!NAME!" +if "%INSTALL_ALL%"=="1" ( + for /d %%D in ("%SKILLS_SRC_ROOT%\\*") do ( + set "NAME=%%~nD" + if not "!NAME!"=="" if not "!NAME:~0,1!"=="." call :InstallOne "!NAME!" + ) +) else ( + set "SKILLS=%SKILLS:,= %" + for %%S in (%SKILLS%) do call :InstallOne "%%~S" ) :Done @@ -68,10 +93,13 @@ exit /b 0 :show_help echo Usage: -echo install_codex_skills.bat [options] [skill ...] +echo install_codex_skills.bat -all +echo install_codex_skills.bat -skills style-cleanup,code-review-workflow echo. echo Options: echo -local, -l Install to .\\.codex ^(or CODEX_HOME if set^) +echo -skills LIST Comma/space-separated skill names +echo -all Install all skills echo -help, -h Show this help echo. echo Env: diff --git a/scripts/install_codex_skills.ps1 b/scripts/install_codex_skills.ps1 index 8c85bbc..39947b2 100644 --- a/scripts/install_codex_skills.ps1 +++ b/scripts/install_codex_skills.ps1 @@ -17,7 +17,8 @@ param( [switch]$Help, [switch]$Local, - [Parameter(Mandatory = $false, ValueFromRemainingArguments = $true)] + [switch]$All, + [Parameter(Mandatory = $false)] [string[]]$Skills ) @@ -25,16 +26,26 @@ $ErrorActionPreference = "Stop" if ($Help) { Write-Host "Usage:" - Write-Host " powershell -File scripts/install_codex_skills.ps1 [options] [skill ...]" + Write-Host " powershell -File scripts/install_codex_skills.ps1 -All" + Write-Host " powershell -File scripts/install_codex_skills.ps1 -Skills style-cleanup,code-review-workflow" Write-Host "" Write-Host "Options:" Write-Host " -Local Install to ./.codex (or CODEX_HOME if set)." + Write-Host " -Skills Comma/space-separated skill names." + Write-Host " -All Install all skills." Write-Host " -Help Show this help." Write-Host "" Write-Host "Env:" Write-Host " CODEX_HOME Target Codex home (default: ~/.codex)." exit 0 } + +if ($All -and $Skills -and $Skills.Count -gt 0) { + throw "Use either -All or -Skills, not both." +} +if (-not $All -and (-not $Skills -or $Skills.Count -eq 0)) { + throw "Missing -All or -Skills. Use -Help for usage." +} $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $Src = (Resolve-Path (Join-Path $ScriptDir "..")).Path $SkillsSrcRoot = Join-Path $Src "codex/skills" @@ -76,16 +87,19 @@ function Install-One([string]$Name) { Write-Host "Installed: $Name" } -if ($Skills -and $Skills.Count -gt 0) { - foreach ($name in $Skills) { - if (-not $name) { continue } - Install-One $name - } -} else { +if ($All) { foreach ($dir in (Get-ChildItem -Path $SkillsSrcRoot -Directory)) { if ($dir.Name.StartsWith(".")) { continue } Install-One $dir.Name } +} else { + foreach ($item in $Skills) { + if (-not $item) { continue } + foreach ($part in $item.Split(@(',', ' '), [System.StringSplitOptions]::RemoveEmptyEntries)) { + if (-not $part) { continue } + Install-One $part + } + } } Write-Host "Done. Skills installed to: $SkillsDstRoot" diff --git a/scripts/install_codex_skills.sh b/scripts/install_codex_skills.sh index 95decdf..3874955 100644 --- a/scripts/install_codex_skills.sh +++ b/scripts/install_codex_skills.sh @@ -6,9 +6,9 @@ set -eu # - Dest: $CODEX_HOME/skills// (default CODEX_HOME=~/.codex) # # Usage: -# sh scripts/install_codex_skills.sh # install all skills -# sh scripts/install_codex_skills.sh style-cleanup code-review-workflow -# sh scripts/install_codex_skills.sh -local # install to /.codex +# sh scripts/install_codex_skills.sh -all +# sh scripts/install_codex_skills.sh -skills style-cleanup,code-review-workflow +# sh scripts/install_codex_skills.sh -local -all # install to /.codex # # Notes: # - Codex loads skills at startup; restart `codex` after installation. @@ -21,10 +21,14 @@ SKILLS_SRC_ROOT="$SRC/codex/skills" usage() { cat <<'EOF' >&2 Usage: - sh scripts/install_codex_skills.sh [options] [skill ...] + sh scripts/install_codex_skills.sh [options] + sh scripts/install_codex_skills.sh -skills style-cleanup,code-review-workflow + sh scripts/install_codex_skills.sh -all Options: -local, -l Install to ./.codex (or CODEX_HOME if set). + -skills LIST Comma/space-separated skill names. + -all Install all skills. -h, -help Show this help. Env: @@ -33,12 +37,27 @@ EOF } LOCAL_MODE=0 +INSTALL_ALL=0 +SKILLS="" while [ $# -gt 0 ]; do case "$1" in -local|-l) LOCAL_MODE=1 shift ;; + -skills) + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -skills requires a value." >&2 + usage + exit 1 + fi + SKILLS="$2" + shift 2 + ;; + -all) + INSTALL_ALL=1 + shift + ;; -h|-help) usage exit 0 @@ -49,11 +68,24 @@ while [ $# -gt 0 ]; do exit 1 ;; *) - break + echo "ERROR: positional args are not supported; use -skills/-all." >&2 + usage + exit 1 ;; esac done +if [ "$INSTALL_ALL" -eq 1 ] && [ -n "$SKILLS" ]; then + echo "ERROR: use either -all or -skills, not both." >&2 + usage + exit 1 +fi +if [ "$INSTALL_ALL" -eq 0 ] && [ -z "$SKILLS" ]; then + echo "ERROR: -all or -skills is required." >&2 + usage + exit 1 +fi + if [ "$LOCAL_MODE" -eq 1 ]; then LOCAL_CODEX_HOME="$(pwd -P)/.codex" CODEX_HOME="${CODEX_HOME:-$LOCAL_CODEX_HOME}" @@ -87,11 +119,7 @@ install_one() { echo "Installed: $name" } -if [ "$#" -gt 0 ]; then - for name in "$@"; do - install_one "$name" - done -else +if [ "$INSTALL_ALL" -eq 1 ]; then for dir in "$SKILLS_SRC_ROOT"/*; do [ -d "$dir" ] || continue name="$(basename -- "$dir")" @@ -100,6 +128,15 @@ else esac install_one "$name" done +else + old_ifs="${IFS}" + IFS=', ' + set -- $SKILLS + IFS="${old_ifs}" + for name in "$@"; do + [ -n "$name" ] || continue + install_one "$name" + done fi echo "Done. Skills installed to: $SKILLS_DST_ROOT" diff --git a/scripts/sync_standards.bat b/scripts/sync_standards.bat index 02afcbe..4b7806c 100644 --- a/scripts/sync_standards.bat +++ b/scripts/sync_standards.bat @@ -7,7 +7,7 @@ rem - Updates \.gitattributes (append missing rules by default) rem Existing targets are backed up before overwrite. rem rem Multi rulesets: -rem sync_standards.bat tsl cpp +rem sync_standards.bat -langs tsl,cpp rem Notes: rem - When syncing multiple rulesets, .gitattributes is synced only once (first ruleset). @@ -35,14 +35,13 @@ set "GITATTR_DST=%ROOT%\.gitattributes" set "SYNC_GITATTR_MODE=%SYNC_GITATTR_MODE%" if "%SYNC_GITATTR_MODE%"=="" set "SYNC_GITATTR_MODE=append" -goto after_help - :show_help echo Usage: echo sync_standards.bat -echo sync_standards.bat tsl cpp +echo sync_standards.bat -langs tsl,cpp echo. echo Options: +echo -langs Comma/space-separated list of languages ^(required^). echo -h, -help Show this help. echo. echo Env: @@ -51,21 +50,34 @@ echo AGENTS_NS Single ruleset name ^(default: tsl^). echo SYNC_GITATTR_MODE append^|overwrite^|block^|skip ^(default: append^). exit /b 0 -:after_help +set "LANG_LIST=" +:parse_args +if "%~1"=="" goto args_done +if /I "%~1"=="-h" goto show_help +if /I "%~1"=="-help" goto show_help +if /I "%~1"=="-langs" ( + if "%~2"=="" goto missing_langs + set "LANG_LIST=%~2" + shift /1 + shift /1 + goto parse_args +) +echo ERROR: Unknown option: %~1 +exit /b 1 + +:missing_langs +echo ERROR: -langs requires a value. +exit /b 1 + +:args_done +if not "%LANG_LIST%"=="" set "LANG_LIST=%LANG_LIST:,= %" + rem Multi rulesets: only on outer invocation. if "%SYNC_STANDARDS_INNER%"=="" ( - 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!" - ) - ) - ) + echo ERROR: -langs is required. + exit /b 1 ) ) if not "%LANG_LIST%"=="" ( @@ -77,12 +89,12 @@ if "%SYNC_STANDARDS_INNER%"=="" ( set "SYNC_STANDARDS_INNER=1" set "AGENTS_NS=%%~L" set "SYNC_GITATTR_MODE=!SYNC_FIRST!" - call "%~f0" + call "%~f0" -langs %%~L ) else ( set "SYNC_STANDARDS_INNER=1" set "AGENTS_NS=%%~L" set "SYNC_GITATTR_MODE=skip" - call "%~f0" + call "%~f0" -langs %%~L ) ) exit /b 0 diff --git a/scripts/sync_standards.ps1 b/scripts/sync_standards.ps1 index 7a2aa55..34be25b 100644 --- a/scripts/sync_standards.ps1 +++ b/scripts/sync_standards.ps1 @@ -19,11 +19,10 @@ $ErrorActionPreference = "Stop" if ($Help) { Write-Host "Usage:" - Write-Host " powershell -File scripts/sync_standards.ps1" Write-Host " powershell -File scripts/sync_standards.ps1 -Langs tsl,cpp" Write-Host "" Write-Host "Options:" - Write-Host " -Langs Comma/space-separated list or array." + Write-Host " -Langs Comma/space-separated list or array (required)." Write-Host " -Help Show this help." Write-Host "" Write-Host "Env:" @@ -51,15 +50,9 @@ if (-not (Test-Path $AgentsSrcRoot)) { $timestamp = Get-Date -Format "yyyyMMddHHmmss" -# Auto-detect languages from existing .agents when no args are provided. +# Require explicit -Langs on outer invocation unless AGENTS_NS is 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 - } - } + throw "Missing -Langs. Use -Help for usage." } # Multi rulesets: only on the outer invocation. diff --git a/scripts/sync_standards.sh b/scripts/sync_standards.sh index c726d7f..59019eb 100644 --- a/scripts/sync_standards.sh +++ b/scripts/sync_standards.sh @@ -7,7 +7,6 @@ set -eu # Existing targets are backed up before overwrite. # # Multi rulesets: -# sh .../sync_standards.sh tsl cpp # sh .../sync_standards.sh -langs tsl,cpp # Notes: # - When syncing multiple rulesets, .gitattributes is synced only once (first ruleset). @@ -24,12 +23,11 @@ ROOT="$(CDPATH= cd -- "$ROOT" && pwd -P)" usage() { cat <<'EOF' >&2 Usage: - sh scripts/sync_standards.sh - sh scripts/sync_standards.sh tsl cpp + sh scripts/sync_standards.sh -langs tsl sh scripts/sync_standards.sh -langs tsl,cpp Options: - -langs L1,L2 Comma/space-separated list of languages. + -langs L1,L2 Comma/space-separated list of languages (required). -h, -help Show this help. Env: @@ -44,6 +42,31 @@ if [ "${1:-}" = "-h" ] || [ "${1:-}" = "-help" ]; then exit 0 fi +langs="" +while [ $# -gt 0 ]; do + case "$1" in + -langs) + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -langs requires a value." >&2 + usage + exit 1 + fi + langs="$2" + shift 2 + ;; + -*) + echo "ERROR: Unknown option: $1" >&2 + usage + exit 1 + ;; + *) + echo "ERROR: positional args are not supported; use -langs." >&2 + usage + exit 1 + ;; + esac +done + AGENTS_SRC_ROOT="$SRC/rulesets" GITATTR_SRC="$SRC/.gitattributes" @@ -63,28 +86,10 @@ fi # Parse multi rulesets only on the outer invocation. if [ "${SYNC_STANDARDS_INNER:-}" != "1" ]; then - langs="" - if [ "${1:-}" = "-langs" ]; then - langs="${2:-}" - shift 2 - fi - 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 + if [ -z "${langs:-}" ] && [ -z "${AGENTS_NS:-}" ]; then + echo "ERROR: -langs is required." >&2 + usage + exit 1 fi if [ -n "${langs:-}" ]; then sync_mode_first="${SYNC_GITATTR_MODE:-append}" @@ -99,9 +104,9 @@ if [ "${SYNC_STANDARDS_INNER:-}" != "1" ]; then [ -n "$ns" ] || continue if [ "$first" -eq 1 ]; then first=0 - SYNC_STANDARDS_INNER=1 AGENTS_NS="$ns" SYNC_GITATTR_MODE="$sync_mode_first" sh "$0" + SYNC_STANDARDS_INNER=1 AGENTS_NS="$ns" SYNC_GITATTR_MODE="$sync_mode_first" sh "$0" -langs "$ns" else - SYNC_STANDARDS_INNER=1 AGENTS_NS="$ns" SYNC_GITATTR_MODE=skip sh "$0" + SYNC_STANDARDS_INNER=1 AGENTS_NS="$ns" SYNC_GITATTR_MODE=skip sh "$0" -langs "$ns" fi done exit 0 diff --git a/scripts/sync_templates.bat b/scripts/sync_templates.bat index 9b92127..c952d5b 100644 --- a/scripts/sync_templates.bat +++ b/scripts/sync_templates.bat @@ -10,9 +10,9 @@ rem Existing targets are NOT overwritten (skip if exists). rem rem Usage: rem sync_templates.bat # sync to current git root -rem sync_templates.bat # sync to specified project -rem sync_templates.bat -force # overwrite existing files -rem sync_templates.bat -full # append full framework to existing AGENTS.md +rem sync_templates.bat -project-root # sync to specified project +rem sync_templates.bat -force # overwrite existing files +rem sync_templates.bat -full # append full framework to existing AGENTS.md set "SCRIPT_DIR=%~dp0" for %%I in ("%SCRIPT_DIR%..") do set "SRC=%%~fI" @@ -33,17 +33,28 @@ if /I "%~1"=="-full" ( shift goto parse_args ) +if /I "%~1"=="-project-root" ( + if "%~2"=="" ( + echo ERROR: -project-root requires a path. + exit /b 1 + ) + set "PROJECT_ROOT=%~2" + shift + shift + goto parse_args +) if /I "%~1"=="-h" goto show_help if /I "%~1"=="-help" goto show_help -set "PROJECT_ROOT=%~1" -shift -goto parse_args +echo ERROR: positional args are not supported. Use -project-root. +exit /b 1 :show_help echo Usage: -echo sync_templates.bat [options] [project-root] +echo sync_templates.bat [options] +echo sync_templates.bat -project-root ^ echo. echo Options: +echo -project-root PATH Target project root ^(default: git root^) echo -force Overwrite existing files echo -full Append full framework (规则优先级 + 新会话开始时) to existing AGENTS.md echo -h, -help Show this help diff --git a/scripts/sync_templates.ps1 b/scripts/sync_templates.ps1 index 644cd47..53613eb 100644 --- a/scripts/sync_templates.ps1 +++ b/scripts/sync_templates.ps1 @@ -10,7 +10,7 @@ param( [Alias('h', 'help', '?')] [switch]$Help, - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false)] [string]$ProjectRoot, [Parameter(Mandatory = $false)] @@ -33,9 +33,11 @@ $ErrorActionPreference = "Stop" if ($Help) { Write-Host "Usage:" - Write-Host " powershell -File scripts/sync_templates.ps1 [options] [project-root]" + Write-Host " powershell -File scripts/sync_templates.ps1 [options]" + Write-Host " powershell -File scripts/sync_templates.ps1 -ProjectRoot C:\\path\\to\\project" Write-Host "" Write-Host "Options:" + Write-Host " -ProjectRoot PATH Target project root (default: git root)." Write-Host " -ProjectName NAME Replace {{PROJECT_NAME}} placeholder." Write-Host " -Date DATE Replace {{DATE}} placeholder (default: today)." Write-Host " -NoBackup Skip backup of existing files." diff --git a/scripts/sync_templates.sh b/scripts/sync_templates.sh index dd3c90b..15bbd16 100644 --- a/scripts/sync_templates.sh +++ b/scripts/sync_templates.sh @@ -10,10 +10,11 @@ set -eu # # Usage: # sh scripts/sync_templates.sh # sync to current git root -# sh scripts/sync_templates.sh # sync to specified project -# sh scripts/sync_templates.sh -project-name "MyProject" -date "2026-01-20" +# sh scripts/sync_templates.sh -project-root /path/to/project +# sh scripts/sync_templates.sh -project-root /path/to/project -project-name "MyProject" -date "2026-01-20" # # Options: +# -project-root PATH Target project root (default: git root) # -project-name NAME Replace {{PROJECT_NAME}} placeholder # -date DATE Replace {{DATE}} placeholder (default: today) # -no-backup Skip backup of existing files @@ -34,11 +35,27 @@ PROJECT_ROOT="" # Parse arguments while [ $# -gt 0 ]; do case "$1" in + -project-root) + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -project-root requires a path." >&2 + exit 1 + fi + PROJECT_ROOT="$2" + shift 2 + ;; -project-name) + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -project-name requires a value." >&2 + exit 1 + fi PROJECT_NAME="$2" shift 2 ;; -date) + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -date requires a value." >&2 + exit 1 + fi SYNC_DATE="$2" shift 2 ;; @@ -57,9 +74,11 @@ while [ $# -gt 0 ]; do -h|-help) cat <<'EOF' Usage: - sh scripts/sync_templates.sh [options] [project-root] + sh scripts/sync_templates.sh [options] + sh scripts/sync_templates.sh -project-root /path/to/project Options: + -project-root PATH Target project root (default: git root) -project-name NAME Replace {{PROJECT_NAME}} placeholder -date DATE Replace {{DATE}} placeholder (default: today) -no-backup Skip backup of existing files @@ -69,8 +88,8 @@ Options: Examples: sh scripts/sync_templates.sh - sh scripts/sync_templates.sh /path/to/project - sh scripts/sync_templates.sh -full /path/to/project + sh scripts/sync_templates.sh -project-root /path/to/project + sh scripts/sync_templates.sh -project-root /path/to/project -full EOF exit 0 ;; @@ -79,8 +98,8 @@ EOF exit 1 ;; *) - PROJECT_ROOT="$1" - shift + echo "ERROR: positional args are not supported; use -project-root." >&2 + exit 1 ;; esac done @@ -347,4 +366,4 @@ echo "" echo "Next steps:" echo " 1. Edit memory-bank/*.md to fill in project-specific content" echo " 2. Replace remaining {{PLACEHOLDER}} values" -echo " 3. Run sync_standards.sh to sync .agents/ rules" +echo " 3. Run sync_standards.sh -langs to sync .agents/ rules" diff --git a/scripts/vendor_playbook.bat b/scripts/vendor_playbook.bat index d56a2e3..8a24c1f 100644 --- a/scripts/vendor_playbook.bat +++ b/scripts/vendor_playbook.bat @@ -6,12 +6,12 @@ rem then run sync_standards to materialize .agents\\ and .gitattributes in rem the target project root. rem rem Usage: -rem scripts\vendor_playbook.bat (default: tsl) -rem scripts\vendor_playbook.bat tsl cpp -rem scripts\vendor_playbook.bat -langs tsl,cpp -rem scripts\vendor_playbook.bat tsl cpp -apply-templates +rem scripts\vendor_playbook.bat -project-root (default: tsl) +rem scripts\vendor_playbook.bat -project-root -langs tsl,cpp +rem scripts\vendor_playbook.bat -project-root -langs tsl,cpp -apply-templates rem rem Options: +rem -project-root Target project root (required) rem -apply-templates Apply CI/lang templates to project root (skip if exists) rem rem Notes: @@ -26,16 +26,28 @@ if "%~1"=="" goto Usage if "%~1"=="-h" goto Usage if "%~1"=="-help" goto Usage -set "DEST_ROOT=%~1" -shift /1 - +set "DEST_ROOT=" set "LANGS=" set "APPLY_TEMPLATES=0" rem Parse arguments :parse_args if "%~1"=="" goto args_done +if "%~1"=="-project-root" ( + if "%~2"=="" ( + echo ERROR: -project-root requires a path. + exit /b 1 + ) + set "DEST_ROOT=%~2" + shift /1 + shift /1 + goto parse_args +) if "%~1"=="-langs" ( + if "%~2"=="" ( + echo ERROR: -langs requires a value. + exit /b 1 + ) set "LANGS=%~2" shift /1 shift /1 @@ -46,15 +58,15 @@ if "%~1"=="-apply-templates" ( shift /1 goto parse_args ) -if "%LANGS%"=="" ( - set "LANGS=%~1" -) else ( - set "LANGS=%LANGS% %~1" -) -shift /1 -goto parse_args +echo ERROR: positional args are not supported. Use -project-root/-langs. +exit /b 1 :args_done +if "%DEST_ROOT%"=="" ( + echo ERROR: -project-root is required. + exit /b 1 +) + if "%LANGS%"=="" set "LANGS=tsl" set "LANGS=%LANGS:,= %" @@ -182,7 +194,7 @@ set "README=%DEST_PREFIX%\\README.md" >> "%README%" echo 在目标项目根目录执行(多语言一次同步): >> "%README%" echo. >> "%README%" echo ```sh ->> "%README%" echo sh docs/standards/playbook/scripts/sync_standards.sh %LANGS_CSV% +>> "%README%" echo sh docs/standards/playbook/scripts/sync_standards.sh -langs %LANGS_CSV% >> "%README%" echo ``` >> "%README%" echo. >> "%README%" echo 查看规范入口: @@ -195,7 +207,7 @@ set "README=%DEST_PREFIX%\\README.md" >> "%README%" echo 安装到本机(需要先在 `~/.codex/config.toml` 启用 skills;见 `docs/standards/playbook/SKILLS.md`): >> "%README%" echo. >> "%README%" echo ```sh ->> "%README%" echo sh docs/standards/playbook/scripts/install_codex_skills.sh +>> "%README%" echo sh docs/standards/playbook/scripts/install_codex_skills.sh -all >> "%README%" echo ``` >> "%README%" echo. >> "%README%" echo ## CI templates(可选) @@ -240,7 +252,7 @@ if not exist "%PROJECT_AGENTS_INDEX%" ( set "OLD_SYNC_ROOT=%SYNC_ROOT%" set "SYNC_ROOT=%DEST_ROOT_ABS%" pushd "%DEST_ROOT_ABS%" -call "%DEST_PREFIX%\\scripts\\sync_standards.bat" %LANGS% +call "%DEST_PREFIX%\\scripts\\sync_standards.bat" -langs %LANGS_CSV% popd set "SYNC_ROOT=%OLD_SYNC_ROOT%" @@ -356,11 +368,12 @@ exit /b 0 :Usage echo Usage: -echo scripts\vendor_playbook.bat ^ ^(default: tsl^) -echo scripts\vendor_playbook.bat ^ tsl cpp -echo scripts\vendor_playbook.bat ^ -langs tsl,cpp -echo scripts\vendor_playbook.bat ^ tsl cpp -apply-templates +echo scripts\vendor_playbook.bat -project-root ^ ^(default: tsl^) +echo scripts\vendor_playbook.bat -project-root ^ -langs tsl,cpp +echo scripts\vendor_playbook.bat -project-root ^ -langs tsl,cpp -apply-templates echo. echo Options: +echo -project-root Target project root ^(required^) +echo -langs Comma/space-separated list of languages ^(default: tsl^) echo -apply-templates Apply CI/lang templates to project root ^(skip if exists^) exit /b 1 diff --git a/scripts/vendor_playbook.ps1 b/scripts/vendor_playbook.ps1 index 84bff4f..0451944 100644 --- a/scripts/vendor_playbook.ps1 +++ b/scripts/vendor_playbook.ps1 @@ -3,9 +3,9 @@ # 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") -ApplyTemplates +# powershell -File scripts/vendor_playbook.ps1 -ProjectRoot +# powershell -File scripts/vendor_playbook.ps1 -ProjectRoot -Langs tsl,cpp +# powershell -File scripts/vendor_playbook.ps1 -ProjectRoot -Langs @("tsl","cpp") -ApplyTemplates # # Options: # -ApplyTemplates Apply CI/lang templates to project root (skip if exists) @@ -22,7 +22,7 @@ param( [switch]$Help, [Parameter(Mandatory = $false)] - [string]$DestRoot, + [string]$ProjectRoot, [Parameter(Mandatory = $false)] [string[]]$Langs, @@ -35,20 +35,20 @@ $ErrorActionPreference = "Stop" if ($Help) { Write-Host "Usage:" - Write-Host " powershell -File scripts/vendor_playbook.ps1 -DestRoot " - Write-Host " powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs tsl,cpp" - Write-Host " powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs @('tsl','cpp') -ApplyTemplates" + Write-Host " powershell -File scripts/vendor_playbook.ps1 -ProjectRoot " + Write-Host " powershell -File scripts/vendor_playbook.ps1 -ProjectRoot -Langs tsl,cpp" + Write-Host " powershell -File scripts/vendor_playbook.ps1 -ProjectRoot -Langs @('tsl','cpp') -ApplyTemplates" Write-Host "" Write-Host "Options:" - Write-Host " -DestRoot Target project root." + Write-Host " -ProjectRoot Target project root (required)." Write-Host " -Langs Comma/space-separated list or array (default: tsl)." Write-Host " -ApplyTemplates Apply CI/lang templates to project root." Write-Host " -Help Show this help." exit 0 } -if (-not $DestRoot) { - throw "DestRoot is required. Use -Help for usage." +if (-not $ProjectRoot) { + throw "ProjectRoot is required. Use -Help for usage." } function Normalize-Langs([string[]]$InputLangs) { @@ -77,8 +77,8 @@ foreach ($lang in $Langs) { $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 +New-Item -ItemType Directory -Path $ProjectRoot -Force | Out-Null +$DestRootAbs = (Resolve-Path $ProjectRoot).Path $StandardsDir = Join-Path $DestRootAbs "docs/standards" $DestPrefix = Join-Path $StandardsDir "playbook" @@ -207,7 +207,7 @@ if (-not $commit) { $commit = "N/A" } 在目标项目根目录执行(多语言一次同步): ```sh -sh docs/standards/playbook/scripts/sync_standards.sh $langsCsv +sh docs/standards/playbook/scripts/sync_standards.sh -langs $langsCsv ``` 查看规范入口: @@ -220,7 +220,7 @@ sh docs/standards/playbook/scripts/sync_standards.sh $langsCsv 安装到本机(需要先在 `~/.codex/config.toml` 启用 skills;见 `docs/standards/playbook/SKILLS.md`): ```sh -sh docs/standards/playbook/scripts/install_codex_skills.sh +sh docs/standards/playbook/scripts/install_codex_skills.sh -all ``` ## CI templates(可选) diff --git a/scripts/vendor_playbook.sh b/scripts/vendor_playbook.sh index 518a695..e2b3ee0 100644 --- a/scripts/vendor_playbook.sh +++ b/scripts/vendor_playbook.sh @@ -6,12 +6,13 @@ set -eu # the target project root. # # Usage: -# sh scripts/vendor_playbook.sh # default: tsl -# sh scripts/vendor_playbook.sh tsl cpp -# sh scripts/vendor_playbook.sh -langs tsl,cpp -# sh scripts/vendor_playbook.sh tsl cpp -apply-templates +# sh scripts/vendor_playbook.sh -project-root # default: tsl +# sh scripts/vendor_playbook.sh -project-root -langs tsl,cpp +# sh scripts/vendor_playbook.sh -project-root -langs tsl,cpp -apply-templates # # Options: +# -project-root PATH Target project root (required) +# -langs L1,L2 Comma/space-separated list of languages (default: tsl) # -apply-templates Apply CI/lang templates to project root (skip if exists) # # Notes: @@ -26,39 +27,47 @@ SRC="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd -P)" usage() { cat <<'EOF' >&2 Usage: - sh scripts/vendor_playbook.sh # default: tsl - sh scripts/vendor_playbook.sh tsl cpp - sh scripts/vendor_playbook.sh -langs tsl,cpp - sh scripts/vendor_playbook.sh tsl cpp -apply-templates + sh scripts/vendor_playbook.sh -project-root # default: tsl + sh scripts/vendor_playbook.sh -project-root -langs tsl,cpp + sh scripts/vendor_playbook.sh -project-root -langs tsl,cpp -apply-templates Options: + -project-root PATH Target project root (required) + -langs L1,L2 Comma/space-separated list of languages (default: tsl) -apply-templates Apply CI/lang templates to project root (skip if exists) -h, -help Show this help EOF } -if [ "$#" -lt 1 ]; then - usage - exit 1 -fi - if [ "${1:-}" = "-h" ] || [ "${1:-}" = "-help" ]; then usage exit 0 fi -PROJECT_ROOT="$1" -shift - +PROJECT_ROOT="" langs="" APPLY_TEMPLATES=0 # Parse arguments while [ $# -gt 0 ]; do case "$1" in + -project-root) + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -project-root requires a path." >&2 + usage + exit 1 + fi + PROJECT_ROOT="$2" + shift 2 + ;; -langs) - langs="${2:-}" - shift 2 || true + if [ $# -lt 2 ] || [ -z "${2:-}" ]; then + echo "ERROR: -langs requires a value." >&2 + usage + exit 1 + fi + langs="$2" + shift 2 ;; -apply-templates) APPLY_TEMPLATES=1 @@ -69,16 +78,18 @@ while [ $# -gt 0 ]; do exit 1 ;; *) - if [ -z "$langs" ]; then - langs="$1" - else - langs="$langs $1" - fi - shift + echo "ERROR: positional args are not supported; use -project-root/-langs." >&2 + exit 1 ;; esac done +if [ -z "$PROJECT_ROOT" ]; then + echo "ERROR: -project-root is required." >&2 + usage + exit 1 +fi + if [ -z "${langs:-}" ]; then langs="tsl" fi @@ -236,7 +247,7 @@ cat >"$DEST_PREFIX/README.md" </` 则自动识别) - - 单语言同步(tsl/cpp) - - 多语言同步(tsl cpp) + - 单语言同步(`-langs tsl`/`-langs cpp`) + - 多语言同步(`-langs tsl,cpp`) - **.gitattributes 同步**: - 默认模式追加缺失规则 - 保留现有内容 @@ -112,8 +111,8 @@ sh check_doc_links.sh 测试 `scripts/vendor_playbook.sh` 脚本的功能: - **基础功能**: - - 单语言 vendoring - - 多语言 vendoring + - 单语言 vendoring(`-langs tsl`) + - 多语言 vendoring(`-langs tsl,cpp`) - **自动同步**: - 自动执行 sync_standards - **SOURCE.md 生成**: @@ -145,10 +144,12 @@ sh check_doc_links.sh - **安装功能**: - 创建 skills 目录 - 复制 skill 目录(包含 `SKILL.md`) - - 支持指定单个 skill 安装 + - 支持 `-skills` 指定单个 skill 安装 + - 支持 `-all` 安装全部 skills - 同名目录安装前创建备份 - **错误处理**: - 指定不存在的 skill 报错 + - 未传 `-all/-skills` 报错 - **幂等性**: - 多次安装结果一致 diff --git a/tests/scripts/test_install_codex_skills.bats b/tests/scripts/test_install_codex_skills.bats index 9e93aa2..934d4ee 100644 --- a/tests/scripts/test_install_codex_skills.bats +++ b/tests/scripts/test_install_codex_skills.bats @@ -49,7 +49,7 @@ first_skill_name() { [ ! -d "$SKILLS_DST_ROOT" ] - sh "$SCRIPT_PATH" + sh "$SCRIPT_PATH" -all [ -d "$SKILLS_DST_ROOT" ] } @@ -57,7 +57,7 @@ first_skill_name() { @test "安装 - 复制 skill 目录" { skip_if_no_skills - sh "$SCRIPT_PATH" + sh "$SCRIPT_PATH" -all SKILL_DIRS=$(find "$SKILLS_DST_ROOT" -mindepth 1 -maxdepth 1 -type d) [ -n "$SKILL_DIRS" ] @@ -73,7 +73,7 @@ first_skill_name() { SKILL_NAME="$(first_skill_name)" [ -n "$SKILL_NAME" ] - sh "$SCRIPT_PATH" "$SKILL_NAME" + sh "$SCRIPT_PATH" -skills "$SKILL_NAME" [ -d "$SKILLS_DST_ROOT/$SKILL_NAME" ] COUNT=$(find "$SKILLS_DST_ROOT" -mindepth 1 -maxdepth 1 -type d | wc -l) @@ -89,7 +89,7 @@ first_skill_name() { mkdir -p "$SKILLS_DST_ROOT/$SKILL_NAME" echo "marker" > "$SKILLS_DST_ROOT/$SKILL_NAME/marker.txt" - sh "$SCRIPT_PATH" "$SKILL_NAME" + sh "$SCRIPT_PATH" -skills "$SKILL_NAME" BACKUP_DIRS=$(find "$SKILLS_DST_ROOT" -maxdepth 1 -type d -name "$SKILL_NAME.bak.*") [ -n "$BACKUP_DIRS" ] @@ -98,7 +98,7 @@ first_skill_name() { @test "错误处理 - 指定不存在 skill 报错" { skip_if_no_skills - run sh "$SCRIPT_PATH" nonexistent-skill + run sh "$SCRIPT_PATH" -skills nonexistent-skill [ "$status" -ne 0 ] } @@ -106,10 +106,10 @@ first_skill_name() { @test "幂等性 - 多次安装结果一致" { skip_if_no_skills - sh "$SCRIPT_PATH" + sh "$SCRIPT_PATH" -all CHECKSUM1=$(find "$SKILLS_DST_ROOT" -type f -name "SKILL.md" ! -path "$SKILLS_DST_ROOT"'/*.bak.*/*' -exec md5sum {} \; | sort | md5sum) - sh "$SCRIPT_PATH" + sh "$SCRIPT_PATH" -all CHECKSUM2=$(find "$SKILLS_DST_ROOT" -type f -name "SKILL.md" ! -path "$SKILLS_DST_ROOT"'/*.bak.*/*' -exec md5sum {} \; | sort | md5sum) [ "$CHECKSUM1" = "$CHECKSUM2" ] diff --git a/tests/scripts/test_sync_standards.bats b/tests/scripts/test_sync_standards.bats index 6a215ca..5d05bc3 100644 --- a/tests/scripts/test_sync_standards.bats +++ b/tests/scripts/test_sync_standards.bats @@ -35,30 +35,16 @@ teardown() { [ -f "$SCRIPT_PATH" ] } -@test "sync_standards.sh 无参数时同步 tsl 规则集" { +@test "sync_standards.sh - 未传 -langs 报错" { cd "$TEST_DIR" - sh "$SCRIPT_PATH" + run sh "$SCRIPT_PATH" - # 验证输出目录 - [ -d ".agents/tsl" ] - [ -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" ] + [ "$status" -ne 0 ] } @test "sync_standards.sh tsl - 同步 TSL 规则集" { cd "$TEST_DIR" - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl # 验证必须文件 [ -d ".agents/tsl" ] @@ -71,7 +57,7 @@ teardown() { @test "sync_standards.sh cpp - 同步 C++ 规则集" { cd "$TEST_DIR" - sh "$SCRIPT_PATH" cpp + sh "$SCRIPT_PATH" -langs cpp # 验证必须文件 [ -d ".agents/cpp" ] @@ -84,7 +70,7 @@ teardown() { @test "sync_standards.sh tsl cpp - 同步多个规则集" { cd "$TEST_DIR" - sh "$SCRIPT_PATH" tsl cpp + sh "$SCRIPT_PATH" -langs tsl,cpp # 验证两个规则集都存在 [ -d ".agents/tsl" ] @@ -100,7 +86,7 @@ teardown() { cd "$TEST_DIR" [ ! -f ".gitattributes" ] - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl [ -f ".gitattributes" ] grep -q "Added from playbook .gitattributes" .gitattributes @@ -112,7 +98,7 @@ teardown() { echo "# My custom rules" > .gitattributes echo "*.custom binary" >> .gitattributes - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl grep -q "# My custom rules" .gitattributes grep -q "*.custom binary" .gitattributes @@ -127,7 +113,7 @@ teardown() { EOF export SYNC_GITATTR_MODE=block - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl # 验证 block 已更新(不再包含 "Old content") ! grep -q "Old content" .gitattributes @@ -141,7 +127,7 @@ EOF cd "$TEST_DIR" [ ! -f "AGENTS.md" ] - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl [ -f "AGENTS.md" ] grep -q ".agents/" AGENTS.md @@ -151,7 +137,7 @@ EOF cd "$TEST_DIR" echo "# My custom AGENTS.md" > AGENTS.md - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl grep -q "# My custom AGENTS.md" AGENTS.md } @@ -164,7 +150,7 @@ EOF cd "$TEST_DIR" echo "# Original content" > .gitattributes - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl # 验证备份文件存在 [ -f ".gitattributes.bak."* ] || [ -f ".gitattributes.bak" ] @@ -175,7 +161,7 @@ EOF mkdir -p .agents/tsl echo "# Old index" > .agents/tsl/index.md - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl # 验证备份目录存在 [ -d ".agents/tsl.bak."* ] || [ -d ".agents/tsl.bak" ] @@ -193,7 +179,7 @@ EOF cp -r "$PLAYBOOK_ROOT/rulesets/python" docs/standards/playbook/rulesets/ fi - sh "$SCRIPT_PATH" tsl cpp + sh "$SCRIPT_PATH" -langs tsl,cpp # 验证规则集不互相覆盖 [ -d ".agents/tsl" ] @@ -211,7 +197,7 @@ EOF cd "$TEST_DIR" rm -rf docs/standards/playbook/rulesets - run sh "$SCRIPT_PATH" tsl + run sh "$SCRIPT_PATH" -langs tsl [ "$status" -ne 0 ] } @@ -219,7 +205,7 @@ EOF @test "错误处理 - 无效语言参数时报错" { cd "$TEST_DIR" - run sh "$SCRIPT_PATH" invalid_lang + run sh "$SCRIPT_PATH" -langs invalid_lang [ "$status" -ne 0 ] } @@ -232,7 +218,7 @@ EOF cd "$TEST_DIR" export SYNC_GITATTR_MODE=skip - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl [ ! -f ".gitattributes" ] } @@ -242,7 +228,7 @@ EOF echo "# Custom content" > .gitattributes export SYNC_GITATTR_MODE=overwrite - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl # 验证自定义内容被覆盖 ! grep -q "# Custom content" .gitattributes @@ -253,7 +239,7 @@ EOF echo "# Custom rules only" > .gitattributes export SYNC_GITATTR_MODE=append - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl grep -q "Added from playbook .gitattributes" .gitattributes grep -q "\\*.tsl" .gitattributes @@ -264,7 +250,7 @@ EOF cp "$PLAYBOOK_ROOT/.gitattributes" .gitattributes export SYNC_GITATTR_MODE=append - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl ! grep -q "Added from playbook .gitattributes" .gitattributes } @@ -277,11 +263,11 @@ EOF cd "$TEST_DIR" # 第一次同步 - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl CHECKSUM1=$(find rulesets/tsl -type f -exec md5sum {} \; | sort | md5sum) # 第二次同步 - sh "$SCRIPT_PATH" tsl + sh "$SCRIPT_PATH" -langs tsl CHECKSUM2=$(find rulesets/tsl -type f -exec md5sum {} \; | sort | md5sum) [ "$CHECKSUM1" = "$CHECKSUM2" ] diff --git a/tests/scripts/test_sync_templates.bats b/tests/scripts/test_sync_templates.bats index 41189d7..1ae1274 100644 --- a/tests/scripts/test_sync_templates.bats +++ b/tests/scripts/test_sync_templates.bats @@ -23,7 +23,7 @@ teardown() { } @test "sync_templates.sh - 基础同步与占位符替换" { - sh "$SCRIPT_PATH" -project-name "DemoProject" -date "2026-02-03" "$TARGET_DIR" + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -project-name "DemoProject" -date "2026-02-03" [ -d "$TARGET_DIR/memory-bank" ] [ -f "$TARGET_DIR/memory-bank/project-brief.md" ] @@ -45,7 +45,7 @@ teardown() { echo "keep" > "$TARGET_DIR/memory-bank/keep.md" echo "keep" > "$TARGET_DIR/docs/prompts/keep.md" - sh "$SCRIPT_PATH" "$TARGET_DIR" + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" [ -f "$TARGET_DIR/memory-bank/keep.md" ] [ ! -f "$TARGET_DIR/memory-bank/project-brief.md" ] @@ -57,7 +57,7 @@ teardown() { mkdir -p "$TARGET_DIR/memory-bank" echo "marker" > "$TARGET_DIR/memory-bank/marker.txt" - sh "$SCRIPT_PATH" -force "$TARGET_DIR" + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -force [ -f "$TARGET_DIR/memory-bank/project-brief.md" ] [ ! -f "$TARGET_DIR/memory-bank/marker.txt" ] @@ -78,7 +78,7 @@ OLD_FRAMEWORK Footer EOF - sh "$SCRIPT_PATH" -full "$TARGET_DIR" + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -full ! grep -q "OLD_FRAMEWORK" "$TARGET_DIR/AGENTS.md" grep -q "" "$TARGET_DIR/AGENTS.md" diff --git a/tests/scripts/test_vendor_playbook.bats b/tests/scripts/test_vendor_playbook.bats index eb3d459..8615f90 100644 --- a/tests/scripts/test_vendor_playbook.bats +++ b/tests/scripts/test_vendor_playbook.bats @@ -47,7 +47,7 @@ teardown() { @test "vendor_playbook.sh - 单语言 vendoring (tsl)" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证快照目录结构 [ -d "docs/standards/playbook" ] @@ -60,7 +60,7 @@ teardown() { @test "vendor_playbook.sh - 多语言 vendoring (tsl cpp)" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl cpp + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl,cpp # 验证包含两种语言的文档 [ -d "docs/standards/playbook/docs/tsl" ] @@ -76,7 +76,7 @@ teardown() { @test "vendor_playbook.sh - 自动执行 sync_standards" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证根目录已同步规则集 [ -d ".agents/tsl" ] @@ -87,7 +87,7 @@ teardown() { @test "vendor_playbook.sh - 多语言自动同步" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl cpp + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl,cpp # 验证两个规则集都已同步 [ -d ".agents/tsl" ] @@ -102,7 +102,7 @@ teardown() { @test "vendor_playbook.sh - 生成 SOURCE.md" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl [ -f "docs/standards/playbook/SOURCE.md" ] grep -q "Source:" docs/standards/playbook/SOURCE.md @@ -112,7 +112,7 @@ teardown() { @test "vendor_playbook.sh - SOURCE.md 包含 commit hash" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证包含 commit hash(40个十六进制字符) grep -E "[0-9a-f]{40}" docs/standards/playbook/SOURCE.md @@ -121,7 +121,7 @@ teardown() { @test "vendor_playbook.sh - SOURCE.md 包含时间戳" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证包含日期格式 YYYY-MM-DD grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2}" docs/standards/playbook/SOURCE.md @@ -134,7 +134,7 @@ teardown() { @test "裁剪 - 仅包含指定语言的文档" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证包含 TSL 文档 [ -d "docs/standards/playbook/docs/tsl" ] @@ -148,7 +148,7 @@ teardown() { @test "裁剪 - 始终包含 common 目录" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl [ -d "docs/standards/playbook/docs/common" ] [ -f "docs/standards/playbook/docs/common/commit_message.md" ] @@ -157,7 +157,7 @@ teardown() { @test "裁剪 - 包含对应的模板文件" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" cpp + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs cpp # 验证包含 C++ 模板 [ -d "docs/standards/playbook/templates/cpp" ] @@ -171,7 +171,7 @@ teardown() { @test "裁剪 - 包含通用 CI 模板" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl [ -d "docs/standards/playbook/templates/ci" ] } @@ -179,7 +179,7 @@ teardown() { @test "vendor_playbook.sh - -apply-templates 应用模板到项目根目录" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" cpp -apply-templates + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs cpp -apply-templates if [ -f "$PLAYBOOK_ROOT/templates/cpp/.clang-format" ]; then [ -f ".clang-format" ] @@ -198,13 +198,13 @@ teardown() { cd "$TARGET_DIR" # 首次 vendor - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 在快照中添加标记文件 touch docs/standards/playbook/OLD_MARKER # 再次 vendor - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证旧标记不存在(已被覆盖) [ ! -f "docs/standards/playbook/OLD_MARKER" ] @@ -216,7 +216,7 @@ teardown() { # 确保 docs/standards 不存在 [ ! -d "docs/standards" ] - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl [ -d "docs/standards/playbook" ] } @@ -231,7 +231,7 @@ teardown() { missing_dir="$TEST_DIR/missing-project" rm -rf "$missing_dir" - run sh "$SCRIPT_PATH" "$missing_dir" tsl + run sh "$SCRIPT_PATH" -project-root "$missing_dir" -langs tsl [ "$status" -ne 0 ] } @@ -239,7 +239,7 @@ teardown() { @test "错误处理 - 无效语言参数时报错" { cd "$TARGET_DIR" - run sh "$SCRIPT_PATH" "$TARGET_DIR" invalid_lang + run sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs invalid_lang [ "$status" -ne 0 ] } @@ -248,7 +248,7 @@ teardown() { cd "$TARGET_DIR" rm -rf .git - run sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + run sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 应该给出警告但不失败 [ "$status" -eq 0 ] @@ -261,7 +261,7 @@ teardown() { @test "完整性 - 验证所有必要文件已复制" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证关键文件 [ -f "docs/standards/playbook/README.md" ] @@ -274,10 +274,10 @@ teardown() { @test "完整性 - 验证脚本可执行性" { cd "$TARGET_DIR" - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl # 验证同步脚本可执行 - run sh docs/standards/playbook/scripts/sync_standards.sh tsl + run sh docs/standards/playbook/scripts/sync_standards.sh -langs tsl [ "$status" -eq 0 ] } @@ -290,11 +290,11 @@ teardown() { cd "$TARGET_DIR" # 第一次 vendor - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl CHECKSUM1=$(find docs/standards/playbook -type f -name "*.md" ! -name "SOURCE.md" -exec md5sum {} \; | sort | md5sum) # 第二次 vendor - sh "$SCRIPT_PATH" "$TARGET_DIR" tsl + sh "$SCRIPT_PATH" -project-root "$TARGET_DIR" -langs tsl CHECKSUM2=$(find docs/standards/playbook -type f -name "*.md" ! -name "SOURCE.md" -exec md5sum {} \; | sort | md5sum) [ "$CHECKSUM1" = "$CHECKSUM2" ]