Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .agents/scripts/linters-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# - Secretlint for exposed secrets
# - Pattern validation (return statements, positional parameters)
# - Markdown formatting
# - Skill frontmatter validation (name field matches skill-sources.json)
#
# For remote auditing (CodeRabbit, Codacy, SonarCloud), use:
# /code-audit-remote or code-audit-helper.sh
Expand Down Expand Up @@ -620,6 +621,94 @@ check_remote_cli_status() {
return 0
}

# =============================================================================
# Skill Frontmatter Validation
# =============================================================================
# Validates that all imported skills registered in skill-sources.json have a
# 'name' field in their YAML frontmatter matching the registered skill name.
# This prevents opencode startup errors from missing name fields.

check_skill_frontmatter() {
echo -e "${BLUE}Checking Skill Frontmatter...${NC}"

local skill_sources=".agents/configs/skill-sources.json"

if [[ ! -f "$skill_sources" ]]; then
print_info "No skill-sources.json found (skipping)"
return 0
fi

if ! command -v jq &>/dev/null; then
print_info "jq not available (skipping skill frontmatter check)"
return 0
fi

local skill_count
if ! skill_count=$(jq -er '
if (.skills | type) == "array" then (.skills | length)
else error(".skills must be an array")
end
' "$skill_sources" 2>/dev/null); then
print_error "Invalid $skill_sources (cannot parse .skills array)"
return 1
fi

if [[ "$skill_count" -eq 0 ]]; then
print_info "No imported skills to validate"
return 0
fi

local errors=0
local checked=0

local skill_entries
if ! skill_entries=$(jq -er '.skills[] | "\(.name)|\(.local_path)"' "$skill_sources" 2>/dev/null); then
print_error "Failed to read skill entries from $skill_sources"
return 1
fi

while IFS='|' read -r name local_path; do
if [[ ! -f "$local_path" ]]; then
print_warning "Skill file missing: $local_path (skill: $name)"
((errors++)) || true
continue
fi

# Extract name from YAML frontmatter (initial block only)
local fm_name
fm_name=$(awk '
NR == 1 && /^---$/ { in_fm = 1; next }
in_fm && /^---$/ { exit }
in_fm && /^[[:space:]]*name:[[:space:]]*/ {
sub(/^[[:space:]]*name:[[:space:]]*/, "")
sub(/[[:space:]]+#.*$/, "")
gsub(/^["'"'"']|["'"'"']$/, "")
print
exit
}
' "$local_path")
Comment on lines +679 to +689
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The check_skill_frontmatter function reads file paths from skill-sources.json and passes them directly to awk. If a file path starts with a hyphen (e.g., -f/path/to/script), awk will interpret it as an option. An attacker can exploit this to execute arbitrary awk code, which can in turn execute shell commands via the system() function. This is particularly dangerous in CI/CD environments where the linter might be run on untrusted PR content.

Suggested change
fm_name=$(awk '
/^---$/ { in_fm = !in_fm; next }
in_fm && /^name:/ {
sub(/^name: */, "")
gsub(/^["'"'"']|["'"'"']$/, "")
print
exit
}
' "$local_path")
fm_name=$(awk '
/^---$/ { in_fm = !in_fm; next }
in_fm && /^name:/ {
sub(/^name: */, "")
gsub(/^[\"'"'"']|[\"'"'"']$/, "")
print
exit
}
' -- "$local_path")


if [[ -z "$fm_name" ]]; then
print_error "Missing 'name' field in frontmatter: $local_path (expected: $name)"
((errors++)) || true
elif [[ "$fm_name" != "$name" ]]; then
print_error "Name mismatch in $local_path: got '$fm_name', expected '$name'"
((errors++)) || true
fi

((checked++)) || true
done <<<"$skill_entries"

if [[ $errors -eq 0 ]]; then
print_success "Skill frontmatter: $checked skills validated, all have correct 'name' field"
else
print_error "Skill frontmatter: $errors error(s) in $checked skills"
return 1
fi

return 0
}

# =============================================================================
# Bundle-Aware Gate Filtering (t1364.6)
# =============================================================================
Expand Down Expand Up @@ -731,6 +820,11 @@ main() {
echo ""
fi

if ! should_skip_gate "skill-frontmatter"; then
check_skill_frontmatter || exit_code=1
echo ""
fi

check_remote_cli_status
echo ""

Expand Down
1 change: 1 addition & 0 deletions .agents/seo/seo-audit-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: seo-audit
description: "When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions \"SEO audit,\" \"technical SEO,\" \"why am I not ranking,\" \"SEO issues,\" \"on-page SEO,\" \"meta tags review,\" or \"SEO health check.\" For building pages at scale to target keywords, see programmatic-seo. For adding structured data, see schema-markup."
mode: subagent
imported_from: external
Expand Down
1 change: 1 addition & 0 deletions .agents/services/hosting/cloudflare-platform.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: cloudflare-platform
description: "Cloudflare platform development guidance — patterns, gotchas, decision trees, SDK usage for Workers, Pages, KV, D1, R2, AI, Durable Objects, and 60+ products. Use when building or developing ON the Cloudflare platform. For managing Cloudflare resources (DNS, WAF, DDoS, R2 buckets, Workers deployments), use the Cloudflare Code Mode MCP server instead."
mode: subagent
imported_from: external
Expand Down
1 change: 1 addition & 0 deletions .agents/services/hosting/proxmox-full-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: proxmox-full
description: "Complete Proxmox VE hypervisor management via REST API - VMs, containers, snapshots, backups, storage"
mode: subagent
imported_from: clawdhub
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/animation/animejs.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: animejs
description: "Anime.js - Lightweight JavaScript animation library for CSS, SVG, DOM attributes and JS objects"
mode: subagent
imported_from: context7
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/deployment/cloudron-app-packaging-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: cloudron-app-packaging
description: "Official Cloudron app packaging skill - Dockerfile patterns, manifest, addons, build methods"
mode: subagent
imported_from: external
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/deployment/cloudron-app-publishing-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: cloudron-app-publishing
description: "Distribute Cloudron apps via CloudronVersions.json version catalogs"
mode: subagent
imported_from: external
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/deployment/cloudron-server-ops-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: cloudron-server-ops
description: "Manage apps on a Cloudron server using the cloudron CLI"
mode: subagent
imported_from: external
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/productivity/caldav-calendar-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: caldav-calendar
description: "Sync and query CalDAV calendars (iCloud, Google, Fastmail, Nextcloud, etc.) using vdirsyncer + khal"
mode: subagent
imported_from: clawdhub
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/video/heygen-skill.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: heygen
description: "Best practices for HeyGen - AI avatar video creation API"
mode: subagent
imported_from: https://github.com/heygen-com/skills
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/video/remotion.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: remotion
description: "Remotion - Programmatic video creation with React. Animations, compositions, media handling, captions, and rendering."
mode: subagent
imported_from: external
Expand Down
1 change: 1 addition & 0 deletions .agents/tools/video/video-prompt-design.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: video-prompt-design
description: "Video prompt design - AI video generation prompt engineering for Veo 3 and similar models using the 7-component meta prompt framework"
mode: subagent
upstream_url: https://github.com/snubroot/Veo-3-Meta-Framework
Expand Down