| 206 | } |
| 207 | |
| 208 | function scanSkillScriptPath(filePath, findings) { |
| 209 | const normalized = filePath.replace(/\\/g, "/"); |
| 210 | const isSkillScript = |
| 211 | normalized.startsWith("skills/") || |
| 212 | /^plugins\/[^/]+\/skills\//.test(normalized); |
| 213 | if (!isSkillScript) { |
| 214 | return; |
| 215 | } |
| 216 | |
| 217 | const extension = path.extname(normalized).toLowerCase(); |
| 218 | if (!SCRIPT_EXTENSIONS.has(extension)) { |
| 219 | return; |
| 220 | } |
| 221 | |
| 222 | addFinding(findings, { |
| 223 | rule_id: "skill-script-touched", |
| 224 | severity: severityLevels.info, |
| 225 | file: normalized, |
| 226 | line: 1, |
| 227 | match: normalized, |
| 228 | reason: |
| 229 | "Script asset under a skill may require external runtime/dependencies.", |
| 230 | suggested_fix: |
| 231 | "Document dependencies, pin versions, and avoid implicit network installs.", |
| 232 | }); |
| 233 | } |
| 234 | |
| 235 | function severityCounts(findings) { |
| 236 | return findings.reduce( |