fix(build): generate flat Claude skill directories

Claude discovers only skills/<name>/SKILL.md, so 84 nested skills, including
all rule skills, were invisible. Flatten the categorized catalog for Claude,
keep references, and fail the build on duplicate names or a name that differs
from its directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Julian lechnerandClaude Opus 5.5 committed 2026-10-01 11:02:07 +02:00
1 parent 5c1bee043d
commit 3203e4ed67
5 files changed
+43 -13

No files matched your search

+14 -3
View File
@@ -94,7 +94,18 @@ foreach ($shell in @('powershell','bash')) {
New-Item (Join-Path $output "codex-$shell") -ItemType Directory -Force | Out-Null
New-Item (Join-Path $output "claude-$shell") -ItemType Directory -Force | Out-Null
Copy-Directory (Join-Path $shared 'skills') (Join-Path $output "codex-$shell/skills")
Copy-Directory (Join-Path $shared 'skills') (Join-Path $output "claude-$shell/skills")
# Claude discovers only skills/<name>/SKILL.md, so flatten the categorized source tree.
$claudeSkills = Join-Path $output "claude-$shell/skills"
New-Item $claudeSkills -ItemType Directory -Force | Out-Null
Get-ChildItem (Join-Path $shared 'skills') -File | ForEach-Object { Copy-Item $_.FullName (Join-Path $claudeSkills $_.Name) -Force }
$claudeSkillNames = @{}
foreach ($skillFile in Get-ChildItem (Join-Path $shared 'skills') -File -Filter 'SKILL.md' -Recurse) {
$skillName = $skillFile.Directory.Name
if (@(Get-Content -LiteralPath $skillFile.FullName -TotalCount 6) -notcontains "name: $skillName") { throw "Skill name must match its directory: $($skillFile.FullName)" }
if ($claudeSkillNames.ContainsKey($skillName)) { throw "Duplicate Claude skill name: $skillName" }
$claudeSkillNames[$skillName] = $true
Copy-Directory $skillFile.DirectoryName (Join-Path $claudeSkills $skillName)
}
Copy-Directory (Join-Path $shared 'rules') (Join-Path $output "codex-$shell/rules")
Copy-Directory (Join-Path $shared 'hooks') (Join-Path $output "codex-$shell/hooks")
Copy-Directory (Join-Path $shared 'hooks') (Join-Path $output "claude-$shell/hooks")
@@ -117,12 +128,12 @@ foreach ($shell in @('powershell','bash')) {
$ruleName = "rules-$($ruleDirectory.Name)-$($ruleParts -join '-')"
$references = $null
}
if ($ruleSkills.Name -contains $ruleName) { throw "Duplicate generated rule skill name: $ruleName" }
if ($ruleSkills.Name -contains $ruleName -or $claudeSkillNames.ContainsKey($ruleName)) { throw "Duplicate generated rule skill name: $ruleName" }
$ruleSkills += [pscustomobject]@{ Name = $ruleName; Body = $ruleFile.FullName; References = $references }
}
}
foreach ($ruleSkill in $ruleSkills | Sort-Object Name) {
$skillDir = Join-Path $output "claude-$shell/skills/rules/$($ruleSkill.Name)"
$skillDir = Join-Path $claudeSkills $ruleSkill.Name
New-Item $skillDir -ItemType Directory -Force | Out-Null
$ruleContent = Get-Content $ruleSkill.Body -Raw
$ruleTitle = (Get-Content $ruleSkill.Body | Where-Object { $_ -match '^#+\s+' } | Select-Object -First 1) -replace '^#+\s+', ''
+15 -3
View File
@@ -79,7 +79,19 @@ done
for shell in powershell bash; do
mkdir -p "$output/codex-$shell" "$output/claude-$shell"
copy_directory "$shared/skills" "$output/codex-$shell/skills"
copy_directory "$shared/skills" "$output/claude-$shell/skills"
# Claude discovers only skills/<name>/SKILL.md, so flatten the categorized source tree.
claude_skills="$output/claude-$shell/skills"
mkdir -p "$claude_skills"
find "$shared/skills" -maxdepth 1 -type f -exec cp {} "$claude_skills"/ \;
declare -A claude_skill_names=()
while IFS= read -r skill_file; do
skill_source=$(dirname -- "$skill_file")
skill_name=$(basename -- "$skill_source")
head -n 6 "$skill_file" | grep -qx "name: $skill_name" || { printf 'Skill name must match its directory: %s\n' "$skill_file" >&2; exit 1; }
[ -z "${claude_skill_names[$skill_name]+x}" ] || { printf 'Duplicate Claude skill name: %s\n' "$skill_name" >&2; exit 1; }
claude_skill_names[$skill_name]=1
copy_directory "$skill_source" "$claude_skills/$skill_name"
done < <(find "$shared/skills" -type f -name SKILL.md | sort)
copy_directory "$shared/rules" "$output/codex-$shell/rules"
copy_directory "$shared/hooks" "$output/codex-$shell/hooks"
copy_directory "$shared/hooks" "$output/claude-$shell/hooks"
@@ -103,12 +115,12 @@ while IFS= read -r rule_path; do
*.md) skill_name="rules-${rule_path%.md}"; rule_body="$shared/rules/$rule_path"; references_dir='' ;;
*) continue ;;
esac
if [[ -n "${rule_skill_names[$skill_name]:-}" ]]; then
if [[ -n "${rule_skill_names[$skill_name]:-}" || -n "${claude_skill_names[$skill_name]:-}" ]]; then
printf 'Duplicate generated rule skill name: %s\n' "$skill_name" >&2
exit 1
fi
rule_skill_names[$skill_name]=1
skill_dir="$output/claude-$shell/skills/rules/$skill_name"
skill_dir="$claude_skills/$skill_name"
mkdir -p "$skill_dir"
rule_title=$(sed -n 's/^#\{1,6\} *//p' "$rule_body" | head -n 1)
if [ -z "$rule_title" ]; then printf 'Missing rule title in %s\n' "$rule_body" >&2; exit 1; fi