143 lines
3.4 KiB
Bash
Executable File
143 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
check_dependencies() {
|
|
local missing=()
|
|
command -v jq >/dev/null 2>&1 || missing+=("jq")
|
|
command -v grep >/dev/null 2>&1 || missing+=("grep")
|
|
|
|
if [ ${#missing[@]} -gt 0 ]; then
|
|
echo "ERROR: Missing required dependencies: ${missing[*]}" >&2
|
|
echo "Please install missing tools and try again." >&2
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
check_dependencies || exit 1
|
|
|
|
# Load and validate skill-rules.json
|
|
load_skill_rules() {
|
|
local rules_path="$1"
|
|
|
|
if [ -z "$rules_path" ]; then
|
|
echo "ERROR: No rules path provided" >&2
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -f "$rules_path" ]; then
|
|
echo "ERROR: Rules file not found: $rules_path" >&2
|
|
return 1
|
|
fi
|
|
|
|
if ! jq . "$rules_path" 2>/dev/null; then
|
|
echo "ERROR: Invalid JSON in $rules_path" >&2
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Match keywords (case-insensitive substring matching)
|
|
match_keywords() {
|
|
local text="$1"
|
|
local keywords="$2"
|
|
|
|
if [ -z "$text" ] || [ -z "$keywords" ]; then
|
|
return 1
|
|
fi
|
|
|
|
local lower_text=$(echo "$text" | tr '[:upper:]' '[:lower:]')
|
|
|
|
IFS=',' read -ra KEYWORD_ARRAY <<< "$keywords"
|
|
for keyword in "${KEYWORD_ARRAY[@]}"; do
|
|
local lower_keyword=$(echo "$keyword" | tr '[:upper:]' '[:lower:]' | xargs)
|
|
if [[ "$lower_text" == *"$lower_keyword"* ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
# Match regex patterns (case-insensitive)
|
|
match_patterns() {
|
|
local text="$1"
|
|
local patterns="$2"
|
|
|
|
if [ -z "$text" ] || [ -z "$patterns" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Use bash regex matching for performance (no external process spawning)
|
|
local lower_text=$(echo "$text" | tr '[:upper:]' '[:lower:]')
|
|
|
|
IFS=',' read -ra PATTERN_ARRAY <<< "$patterns"
|
|
for pattern in "${PATTERN_ARRAY[@]}"; do
|
|
pattern=$(echo "$pattern" | xargs | tr '[:upper:]' '[:lower:]')
|
|
|
|
# Use bash's built-in regex matching (much faster than spawning grep)
|
|
if [[ "$lower_text" =~ $pattern ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
# Find matching skills from prompt
|
|
# Returns JSON array of skill names, sorted by priority
|
|
find_matching_skills() {
|
|
local prompt="$1"
|
|
local rules_path="$2"
|
|
local max_skills="${3:-3}"
|
|
|
|
if [ -z "$prompt" ] || [ -z "$rules_path" ]; then
|
|
echo "[]"
|
|
return 0
|
|
fi
|
|
|
|
if ! load_skill_rules "$rules_path" >/dev/null; then
|
|
echo "[]"
|
|
return 1
|
|
fi
|
|
|
|
# Load all skill data in one jq call for performance
|
|
local skill_data=$(jq -r '
|
|
to_entries |
|
|
map(select(.key != "_comment" and .key != "_schema")) |
|
|
map({
|
|
name: .key,
|
|
priority: .value.priority,
|
|
keywords: (.value.promptTriggers.keywords | join(",")),
|
|
patterns: (.value.promptTriggers.intentPatterns | join(","))
|
|
}) |
|
|
.[] |
|
|
"\(.name)|\(.priority)|\(.keywords)|\(.patterns)"
|
|
' "$rules_path")
|
|
|
|
local matches=()
|
|
|
|
while IFS='|' read -r skill priority keywords patterns; do
|
|
# Check if keywords or patterns match
|
|
if match_keywords "$prompt" "$keywords" || match_patterns "$prompt" "$patterns"; then
|
|
matches+=("$priority:$skill")
|
|
fi
|
|
done <<< "$skill_data"
|
|
|
|
# Sort by priority (critical > high > medium > low) and limit to max_skills
|
|
if [ ${#matches[@]} -eq 0 ]; then
|
|
echo "[]"
|
|
return 0
|
|
fi
|
|
|
|
# Sort and format as JSON array
|
|
printf '%s\n' "${matches[@]}" | \
|
|
sed 's/^critical:/0:/; s/^high:/1:/; s/^medium:/2:/; s/^low:/3:/' | \
|
|
sort -t: -k1,1n | \
|
|
head -n "$max_skills" | \
|
|
cut -d: -f2- | \
|
|
jq -R . | \
|
|
jq -s .
|
|
}
|