From ce54b34092ed7178f9b087f10baf8aa8adc7e809 Mon Sep 17 00:00:00 2001 From: Julian Lechner Date: Thu, 24 Sep 2026 21:42:57 +0200 Subject: [PATCH] test(rules): verify nested rule packages --- scripts/tests/test-shell-packages.ps1 | 20 ++++++++++++++--- scripts/tests/test-shell-packages.sh | 31 ++++++++++++++++----------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/scripts/tests/test-shell-packages.ps1 b/scripts/tests/test-shell-packages.ps1 index 3df622b..1de64d7 100644 --- a/scripts/tests/test-shell-packages.ps1 +++ b/scripts/tests/test-shell-packages.ps1 @@ -6,15 +6,29 @@ $sourceAgentCount = @(Get-ChildItem (Join-Path $root 'shared/agents') -Directory $sourceSkillCount = @(Get-ChildItem (Join-Path $root 'shared/skills') -Filter 'SKILL.md' -Recurse).Count $rulesRoot = Join-Path $root 'shared/rules' $ruleSources = @() +$ruleLoadEntries = @() foreach ($ruleFile in Get-ChildItem $rulesRoot -File -Filter '*.md' | Where-Object Name -ne 'general.md') { $ruleSources += [pscustomobject]@{ Path = $ruleFile.Name; Skill = "rules-$($ruleFile.BaseName)" } + $ruleLoadEntries += [pscustomobject]@{ Path = $ruleFile.Name; Skill = "rules-$($ruleFile.BaseName)" } } foreach ($ruleDirectory in Get-ChildItem $rulesRoot -Directory) { - if (Test-Path (Join-Path $ruleDirectory.FullName 'index.md')) { $ruleSources += [pscustomobject]@{ Path = "$($ruleDirectory.Name)/index.md"; Skill = "rules-$($ruleDirectory.Name)" } } + foreach ($ruleFile in Get-ChildItem $ruleDirectory.FullName -File -Filter '*.md' -Recurse) { + $relative = $ruleFile.FullName.Substring($ruleDirectory.FullName.Length).TrimStart([char[]]@('\','/')).Replace('\','/') + if ($relative -eq 'index.md') { + $skill = "rules-$($ruleDirectory.Name)" + $ruleLoadEntries += [pscustomobject]@{ Path = "$($ruleDirectory.Name)/index.md"; Skill = $skill } + } else { + $parts = $relative.Substring(0, $relative.Length - 3).Split([char[]]@('/')) + $parts = @($parts | Where-Object { $_ -ne 'references' }) + $skill = "rules-$($ruleDirectory.Name)-$($parts -join '-')" + } + if ($ruleSources.Skill -contains $skill) { throw "Duplicate generated rule skill name: $skill" } + $ruleSources += [pscustomobject]@{ Path = "$($ruleDirectory.Name)/$relative"; Skill = $skill } + } } $ruleSkillCount = $ruleSources.Count $globalInstructions = Get-Content (Join-Path $root 'shared/global-instructions.md') -Raw -foreach ($ruleSource in $ruleSources) { +foreach ($ruleSource in $ruleLoadEntries) { $ruleInstruction = [char]96 + "rules/$($ruleSource.Path)" + [char]96 + ' / ' + [char]96 + $ruleSource.Skill + [char]96 if (-not $globalInstructions.Contains($ruleInstruction)) { throw "Global instructions are missing rule loading entry: $($ruleSource.Path)" } } @@ -51,7 +65,7 @@ foreach ($shell in @('powershell','bash')) { } $docFile = if ($client -eq 'codex') { 'AGENTS.md' } else { 'CLAUDE.md' } $docContent = Get-Content -LiteralPath (Join-Path $package $docFile) -Raw - if ($docContent -notmatch [regex]::Escape('rules/security.md')) { throw "$package is missing common rule loading instructions." } + if ($docContent -notmatch [regex]::Escape('rules/security/index.md')) { throw "$package is missing common rule loading instructions." } if ($client -eq 'claude') { foreach ($ruleSource in $ruleSources) { $skillPath = Join-Path $package "skills/rules/$($ruleSource.Skill)/SKILL.md" diff --git a/scripts/tests/test-shell-packages.sh b/scripts/tests/test-shell-packages.sh index c1dab7e..d7f3250 100644 --- a/scripts/tests/test-shell-packages.sh +++ b/scripts/tests/test-shell-packages.sh @@ -10,16 +10,26 @@ done root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd) source_agent_count=$(find "$root/shared/agents" -mindepth 1 -maxdepth 1 -type d | wc -l) source_skill_count=$(find "$root/shared/skills" -name SKILL.md | wc -l) -mapfile -t rule_paths < <(find "$root/shared/rules" -mindepth 1 -maxdepth 2 -type f -name '*.md' ! -path '*/references/*' ! -name general.md -printf '%P\n' | sort) +mapfile -t rule_paths < <(find "$root/shared/rules" -mindepth 1 -type f -name '*.md' ! -name general.md -printf '%P\n' | sort) rule_skill_count=${#rule_paths[@]} global_instructions=$(<"$root/shared/global-instructions.md") +rule_skill_name() { + local path=$1 directory relative + if [[ "$path" != */* ]]; then printf 'rules-%s' "${path%.md}"; return; fi + directory=${path%%/*} + relative=${path#*/} + if [[ "$relative" == index.md ]]; then printf 'rules-%s' "$directory"; return; fi + relative=${relative#references/} + relative=${relative%.md} + relative=${relative//\//-} + printf 'rules-%s-%s' "$directory" "$relative" +} for rule_path in "${rule_paths[@]}"; do - case "$rule_path" in - */index.md) skill_name="rules-${rule_path%/index.md}" ;; - *.md) skill_name="rules-${rule_path%.md}" ;; - esac - expected_rule="\`rules/$rule_path\` / \`$skill_name\`" - printf '%s' "$global_instructions" | grep -Fq -- "$expected_rule" + if [[ "$rule_path" != */* || "$rule_path" == */index.md ]]; then + skill_name=$(rule_skill_name "$rule_path") + expected_rule="\`rules/$rule_path\` / \`$skill_name\`" + printf '%s' "$global_instructions" | grep -Fq -- "$expected_rule" + fi done for shell in powershell bash; do for client in codex claude; do @@ -62,13 +72,10 @@ for shell in powershell bash; do doc_file=AGENTS.md [ "$client" != claude ] || doc_file=CLAUDE.md doc_content=$(cat "$package/$doc_file") - printf '%s' "$doc_content" | grep -Fq 'rules/security.md' + printf '%s' "$doc_content" | grep -Fq 'rules/security/index.md' if [ "$client" = claude ]; then for rule_path in "${rule_paths[@]}"; do - case "$rule_path" in - */index.md) skill_name="rules-${rule_path%/index.md}" ;; - *.md) skill_name="rules-${rule_path%.md}" ;; - esac + skill_name=$(rule_skill_name "$rule_path") test -f "$package/skills/rules/$skill_name/SKILL.md" done fi