feat(agents): generate capabilities and rule loading
This commit is contained in:
1 parent
3fad860256
commit
ea2c80817b
4 files changed
+46
-43
No files matched your search
+20
-20
@@ -6,6 +6,7 @@ $shared = Join-Path $root 'shared'
|
||||
$output = Join-Path $root 'generated'
|
||||
$pluginManifest = Join-Path $root 'adapters/plugins.tsv'
|
||||
$ruleSkillManifest = Join-Path $root 'adapters/claude/rule-skills.tsv'
|
||||
$capabilityManifest = Join-Path $root 'adapters/claude/capabilities.tsv'
|
||||
|
||||
if (-not (Test-Path -LiteralPath $pluginManifest)) { throw "Missing plugin manifest: $pluginManifest" }
|
||||
$pluginEntries = @(Import-Csv -LiteralPath $pluginManifest -Delimiter ([char]9))
|
||||
@@ -20,6 +21,7 @@ foreach ($pluginEntry in $pluginEntries) {
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $ruleSkillManifest)) { throw "Missing rule-skill manifest: $ruleSkillManifest" }
|
||||
if (-not (Test-Path -LiteralPath $capabilityManifest)) { throw "Missing capability manifest: $capabilityManifest" }
|
||||
$ruleSkillEntries = @(Import-Csv -LiteralPath $ruleSkillManifest -Delimiter ([char]9) | Sort-Object skill_name)
|
||||
if ($ruleSkillEntries.Count -eq 0) { throw 'Rule-skill manifest must define at least one entry.' }
|
||||
$ruleSkillNames = @()
|
||||
@@ -31,6 +33,18 @@ foreach ($entry in $ruleSkillEntries) {
|
||||
if ($ruleSkillNames -contains $entry.skill_name) { throw "Duplicate rule-skill name in manifest: $($entry.skill_name)" }
|
||||
$ruleSkillNames += $entry.skill_name
|
||||
}
|
||||
$agentTools = @{}
|
||||
foreach ($entry in @(Import-Csv -LiteralPath $capabilityManifest -Delimiter ([char]9))) {
|
||||
if ([string]::IsNullOrWhiteSpace($entry.role) -or [string]::IsNullOrWhiteSpace($entry.tools)) { throw 'Invalid capability manifest row.' }
|
||||
$agentTools[$entry.role] = $entry.tools
|
||||
}
|
||||
$codexRuleLoadingLines = @()
|
||||
foreach ($entry in $ruleSkillEntries) {
|
||||
$rulePath = $entry.rule_file
|
||||
if (Test-Path -LiteralPath (Join-Path $shared "rules/$($entry.rule_file)") -PathType Container) { $rulePath = "$($entry.rule_file)/index.md" }
|
||||
$codexRuleLoadingLines += "- rules/$rulePath for $($entry.trigger)."
|
||||
}
|
||||
$codexRuleLoadingList = $codexRuleLoadingLines -join "`r`n"
|
||||
|
||||
Remove-Item $output -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item $output -ItemType Directory -Force | Out-Null
|
||||
@@ -102,26 +116,9 @@ Detect the languages, frameworks, tools, and change areas from the repository an
|
||||
|
||||
Load rule files when their subject applies:
|
||||
|
||||
- rules/security-auth.md for authentication, authorization, sessions, tokens, permissions, or tenant boundaries.
|
||||
- rules/security-web.md for browser, frontend, cookie, redirect, XSS, or CSRF work.
|
||||
- rules/security-api.md for HTTP APIs, request handling, serialization, or endpoints.
|
||||
- rules/security-data.md for databases, persistence, sensitive data, or multi-tenancy.
|
||||
- rules/security-files.md for files, uploads, archives, paths, processes, IPC, or deserialization.
|
||||
- rules/security-network.md for network access, URLs, TLS, proxies, or SSRF.
|
||||
- rules/security-crypto.md for cryptography, secrets, credentials, keys, or tokens.
|
||||
- rules/security-supply-chain.md for dependencies, packages, plugins, builds, deployments, or CI.
|
||||
- rules/angular/index.md for Angular work.
|
||||
- rules/typescript.md for TypeScript work.
|
||||
- rules/csharp.md for C# or .NET work.
|
||||
- rules/wpf/index.md for WPF work.
|
||||
- rules/ui-ux/index.md for UI or UX decisions.
|
||||
- rules/microsoft.md for Microsoft 365, Azure DevOps, or Teams work.
|
||||
- rules/orchestration.md for delegation, subagent work, or long-running task state.
|
||||
- rules/git.md for Git operations.
|
||||
- rules/refactoring.md for refactoring work.
|
||||
- rules/definition-of-done.md when validating completion.
|
||||
- rules/decision-rule.md when requirements are unresolved, behavior is ambiguous, or a meaningful technical choice remains.
|
||||
__CODEX_RULE_LOADING__
|
||||
'@
|
||||
$codexRuleLoading = $codexRuleLoading.Replace('__CODEX_RULE_LOADING__', $codexRuleLoadingList)
|
||||
|
||||
foreach ($shell in @('powershell','bash')) {
|
||||
New-Item (Join-Path $output "codex-$shell") -ItemType Directory -Force | Out-Null
|
||||
@@ -180,7 +177,10 @@ foreach ($shell in @('powershell','bash')) {
|
||||
if ($client -eq 'codex') {
|
||||
Set-Content (Join-Path $agentsOutput "$name.toml") "name = $(Quote-Toml $name)`r`ndescription = $(Quote-Toml $description)`r`ndeveloper_instructions = $(Quote-Toml $instructions)" -Encoding UTF8
|
||||
} else {
|
||||
Set-Content (Join-Path $agentsOutput "$name.md") "---`r`nname: $name`r`ndescription: $description`r`n---`r`n`r`n$instructions" -Encoding UTF8
|
||||
$tools = $agentTools[$name]
|
||||
$frontmatter = "---`r`nname: $name`r`ndescription: $description`r`n"
|
||||
if ($tools) { $frontmatter += "tools: $tools`r`n" }
|
||||
Set-Content (Join-Path $agentsOutput "$name.md") ($frontmatter + "---`r`n`r`n$instructions") -Encoding UTF8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-22
@@ -13,6 +13,7 @@ shared="$root/shared"
|
||||
output="$root/generated"
|
||||
plugin_manifest="$root/adapters/plugins.tsv"
|
||||
rule_skill_manifest="$root/adapters/claude/rule-skills.tsv"
|
||||
capability_manifest="$root/adapters/claude/capabilities.tsv"
|
||||
|
||||
[ -f "$plugin_manifest" ] || { printf 'Missing plugin manifest: %s\n' "$plugin_manifest" >&2; exit 1; }
|
||||
declare -A plugin_seen
|
||||
@@ -29,6 +30,7 @@ done < "$plugin_manifest"
|
||||
[ "$plugin_count" -gt 0 ] || { printf 'Plugin manifest must define at least one plugin.\n' >&2; exit 1; }
|
||||
|
||||
[ -f "$rule_skill_manifest" ] || { printf 'Missing rule-skill manifest: %s\n' "$rule_skill_manifest" >&2; exit 1; }
|
||||
[ -f "$capability_manifest" ] || { printf 'Missing capability manifest: %s\n' "$capability_manifest" >&2; exit 1; }
|
||||
declare -A rule_skill_seen
|
||||
rule_skill_files=()
|
||||
rule_skill_names=()
|
||||
@@ -45,8 +47,21 @@ while IFS=$'\t' read -r rule_file skill_name trigger; do
|
||||
rule_skill_files+=("$rule_file")
|
||||
rule_skill_names+=("$skill_name")
|
||||
rule_skill_triggers+=("$trigger")
|
||||
done < "$rule_skill_manifest"
|
||||
done < <(tail -n +2 "$rule_skill_manifest" | sort -t$'\t' -k2,2)
|
||||
[ "${#rule_skill_names[@]}" -gt 0 ] || { printf 'Rule-skill manifest must define at least one entry.\n' >&2; exit 1; }
|
||||
codex_rule_loading_list=""
|
||||
for i in "${!rule_skill_names[@]}"; do
|
||||
rule_file=${rule_skill_files[$i]}
|
||||
rule_path="$rule_file"
|
||||
[ -d "$shared/rules/$rule_file" ] && rule_path="$rule_file/index.md"
|
||||
codex_rule_loading_list="${codex_rule_loading_list}- rules/${rule_path} for ${rule_skill_triggers[$i]}."$'\n'
|
||||
done
|
||||
declare -A agent_tools
|
||||
while IFS=$'\t' read -r role tools; do
|
||||
[ "$role" != role ] || continue
|
||||
[ -n "$role" ] && [ -n "$tools" ] || { printf 'Invalid capability manifest row.\n' >&2; exit 1; }
|
||||
agent_tools[$role]="$tools"
|
||||
done < "$capability_manifest"
|
||||
|
||||
copy_directory() {
|
||||
local source=$1 destination=$2
|
||||
@@ -97,27 +112,8 @@ When programming, always load and apply `rules/security.md`. This includes imple
|
||||
Detect the languages, frameworks, tools, and change areas from the repository and the requested work. Load every applicable rule file before editing. Load all matching files when multiple technologies apply.
|
||||
|
||||
Load rule files when their subject applies:
|
||||
|
||||
- rules/security-auth.md for authentication, authorization, sessions, tokens, permissions, or tenant boundaries.
|
||||
- rules/security-web.md for browser, frontend, cookie, redirect, XSS, or CSRF work.
|
||||
- rules/security-api.md for HTTP APIs, request handling, serialization, or endpoints.
|
||||
- rules/security-data.md for databases, persistence, sensitive data, or multi-tenancy.
|
||||
- rules/security-files.md for files, uploads, archives, paths, processes, IPC, or deserialization.
|
||||
- rules/security-network.md for network access, URLs, TLS, proxies, or SSRF.
|
||||
- rules/security-crypto.md for cryptography, secrets, credentials, keys, or tokens.
|
||||
- rules/security-supply-chain.md for dependencies, packages, plugins, builds, deployments, or CI.
|
||||
- rules/angular/index.md for Angular work.
|
||||
- rules/typescript.md for TypeScript work.
|
||||
- rules/csharp.md for C# or .NET work.
|
||||
- rules/wpf/index.md for WPF work.
|
||||
- rules/ui-ux/index.md for UI or UX decisions.
|
||||
- rules/microsoft.md for Microsoft 365, Azure DevOps, or Teams work.
|
||||
- rules/orchestration.md for delegation, subagent work, or long-running task state.
|
||||
- rules/git.md for Git operations.
|
||||
- rules/refactoring.md for refactoring work.
|
||||
- rules/definition-of-done.md when validating completion.
|
||||
- rules/decision-rule.md when requirements are unresolved, behavior is ambiguous, or a meaningful technical choice remains.
|
||||
BLOCK
|
||||
codex_rule_loading="${codex_rule_loading}"$'\n\n'"${codex_rule_loading_list%$'\n'}"
|
||||
|
||||
for shell in powershell bash; do
|
||||
mkdir -p "$output/codex-$shell" "$output/claude-$shell"
|
||||
@@ -178,7 +174,8 @@ for client in codex claude; do
|
||||
if [ "$client" = codex ]; then
|
||||
printf 'name = %s\ndescription = %s\ndeveloper_instructions = %s\n' "$(quote_toml "$name")" "$(quote_toml "$description")" "$(quote_toml "$instructions")" > "$agents_output/$name.toml"
|
||||
else
|
||||
printf '%s\nname: %s\ndescription: %s\n%s\n\n%s\n' '---' "$name" "$description" '---' "$instructions" > "$agents_output/$name.md"
|
||||
tools=${agent_tools[$name]:-}
|
||||
if [ -n "$tools" ]; then printf '%s\nname: %s\ndescription: %s\ntools: %s\n%s\n\n%s\n' '---' "$name" "$description" "$tools" '---' "$instructions" > "$agents_output/$name.md"; else printf '%s\nname: %s\ndescription: %s\n%s\n\n%s\n' '---' "$name" "$description" '---' "$instructions" > "$agents_output/$name.md"; fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
@@ -6,7 +6,7 @@ $cacheDir = Join-Path $root '.ai-session'
|
||||
$cachePath = Join-Path $cacheDir 'repository-context.json'
|
||||
$safeRoot = $root.Replace('\','/')
|
||||
$head = (& git -c "safe.directory=$safeRoot" -C $root rev-parse HEAD 2>$null).Trim()
|
||||
$inputs = @('AI-Instructions.md','adapters/plugins.tsv','adapters/claude/rule-skills.tsv','adapters/codex/config/config.toml','adapters/claude/config/settings.json')
|
||||
$inputs = @('AI-Instructions.md','adapters/plugins.tsv','adapters/claude/rule-skills.tsv','adapters/claude/capabilities.tsv','adapters/prompt-budget-baseline.json','adapters/prompt-budget-baseline.tsv','adapters/codex/config/config.toml','adapters/claude/config/settings.json')
|
||||
$inputs += @(Get-ChildItem $root -File -Recurse | Where-Object { $_.FullName -notmatch '\\(generated|\.git|node_modules|bin|obj|vendor|\.ai-session)\\' -and $_.Extension -in @('.sln','.csproj','.fsproj','.ts','.tsx','.json','.toml','.yaml','.yml','.cs','.fs','.py','.sh','.ps1') } | ForEach-Object { $_.FullName.Substring($root.Length + 1) } | Sort-Object)
|
||||
$keyText = $head + "`n" + (($inputs | Sort-Object -Unique | ForEach-Object { $_ + ':' + (Get-FileHash (Join-Path $root $_) -Algorithm SHA256).Hash }) -join "`n")
|
||||
$key = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($keyText)).TrimEnd('=')
|
||||
|
||||
Reference in new issue
Block a user