Two more efficiency findings from the same code-review pass: - check-vale-style-sync.sh's hook_file_regexes() reparsed both pre-commit manifests from scratch on every call. The final validation loop calls it once per probe (3 probes: skill-audit once, agent-audit twice for its two file shapes), so agent-audit's regex set was being parsed twice for no reason. Now cached per skill in a lazily-populated associative array, with a separate "seen" map so an empty result isn't mistaken for "not yet computed." - skill-size-check.sh read the target file twice (separate awk and wc -w calls) to get line and word counts; now a single awk pass returns both. Also documented, next to MAX_LINES/MAX_WORDS, why those constants are duplicated against skill-audit/scripts/ validate.sh's Python implementation rather than unified — same cross-language/cross-context tradeoff as vale-wrap.sh's duplication, guarded by tests/test-skill-size-check.sh's drift check. Verified: test-check-vale-style-sync.sh 20/20, test-skill-size-check.sh 9/9, full suite 12/12, pre-commit --all-files clean.
72 lines
3.4 KiB
Bash
Executable File
72 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Enforces agentskills.io's skill-authoring.md guidance: keep SKILL.md within
|
|
# 500 lines and roughly 5,000 tokens, so the full body doesn't crowd out
|
|
# conversation history and other active skills once loaded into context. Vale
|
|
# can't express a whole-file length ceiling (its checks operate on text
|
|
# patterns, not raw file size), so this is a plain script instead of a Vale
|
|
# rule.
|
|
#
|
|
# Both ceilings are inclusive: a file at exactly MAX_LINES or MAX_WORDS passes,
|
|
# and only one past it fails. That matches skill-audit/scripts/validate.sh,
|
|
# which has always used `line_count <= 500` as its pass condition — the two
|
|
# previously disagreed at exactly 500 lines, so a SKILL.md could pass its own
|
|
# audit and still be blocked by the commit hook.
|
|
#
|
|
# Token counts aren't computed exactly here — word count (`wc -w`) is used as
|
|
# a proxy. Measured over this repo's 39 in-scope SKILL.md files, characters per
|
|
# word runs min 5.97 / median 6.79 / mean 6.77 / max 7.22. At the standard
|
|
# ~4-characters-per-token English approximation that is 1.49 / 1.70 / 1.69 /
|
|
# 1.81 tokens per word.
|
|
#
|
|
# MAX_WORDS=2770 is therefore calibrated to the corpus WORST case rather than
|
|
# its median: 2770 words at the densest observed 7.22 chars/word is ~20,000
|
|
# characters, or ~5,000 tokens at the 4-characters-per-token approximation. So
|
|
# what this gate guarantees is "under 5,000 tokens even for the densest prose
|
|
# the corpus has produced" — the earlier median-calibrated MAX_WORDS=2900 let
|
|
# such a file sit at exactly the ceiling and still spend ~5,240 tokens. A
|
|
# median-density file at 2770 words spends ~4,700 tokens, so typical prose
|
|
# gives up ~130 words of headroom to close that gap. The largest SKILL.md in
|
|
# the repo is 2,489 words, so no current file is affected.
|
|
#
|
|
# It is a one-sided proxy in the useful direction — nothing under the word
|
|
# ceiling is wildly over the token ceiling — but it is not exact BPE
|
|
# tokenization and does not replace one. Re-measure the corpus before treating
|
|
# any of these numbers as still current.
|
|
|
|
# These constants are intentionally duplicated in
|
|
# skill-audit/scripts/validate.sh (Python) rather than shared from one file:
|
|
# this script is a standalone bash pre-commit hook, that one is an in-skill
|
|
# Python validator invoked in a different context (same rationale as
|
|
# vale-wrap.sh's per-plugin duplication — see its own header comment).
|
|
# tests/test-skill-size-check.sh asserts both files agree on these values, so
|
|
# drift between them fails CI rather than silently diverging.
|
|
MAX_LINES=500
|
|
MAX_WORDS=2770
|
|
FAIL=0
|
|
|
|
for f in "$@"; do
|
|
[[ -f "$f" ]] || continue
|
|
|
|
# Single awk pass computes both line count and word count, avoiding a
|
|
# second read of the file. NR counts the final line even without a
|
|
# trailing newline, matching Python's splitlines() semantics (used by
|
|
# skill-audit/scripts/validate.sh for its own line count) — `wc -l`
|
|
# undercounts by 1 in that case. Word count uses awk's default
|
|
# whitespace-splitting NF, matching `wc -w` semantics.
|
|
read -r lines words <<< "$(awk '{w += NF} END{print NR, w+0}' "$f")"
|
|
|
|
if (( lines > MAX_LINES )); then
|
|
echo "ERROR: $f has $lines lines, exceeding the $MAX_LINES-line ceiling (agentskills.io skill-authoring.md)" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
if (( words > MAX_WORDS )); then
|
|
echo "ERROR: $f has $words words (proxy for tokens), exceeding the $MAX_WORDS-word ceiling (~5,000 tokens, agentskills.io skill-authoring.md)" >&2
|
|
FAIL=1
|
|
fi
|
|
done
|
|
|
|
exit $FAIL
|